checkpoint rpc county fixed
This commit is contained in:
163
test.py
Normal file
163
test.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
def decode_gwt_rpc(payload):
|
||||
"""
|
||||
Decodes a GWT-RPC payload to extract outage data for Counties.
|
||||
"""
|
||||
# 1. Clean the payload
|
||||
# GWT responses often start with //OK. We strip that.
|
||||
if payload.startswith("//OK"):
|
||||
payload = payload[4:]
|
||||
|
||||
# 2. Parse the FULL payload as JSON
|
||||
# The GWT payload is structurally a JSON array: [stream_data..., [string_table], flags...]
|
||||
try:
|
||||
full_data = json.loads(payload)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error parsing payload JSON: {e}")
|
||||
return None
|
||||
|
||||
# 3. Separate Stream and String Table
|
||||
# The String Table is a list of strings located near the end of the main array.
|
||||
# The "Stream" is everything before that string table.
|
||||
|
||||
string_table = None
|
||||
stream_raw = []
|
||||
|
||||
# Iterate through the parsed array to find the string table (which is a list)
|
||||
for item in full_data:
|
||||
if isinstance(item, list):
|
||||
string_table = item
|
||||
# Once we find the table, we assume the rest are flags and stop adding to stream
|
||||
break
|
||||
else:
|
||||
stream_raw.append(item)
|
||||
|
||||
if not string_table:
|
||||
print("Error: String table not found in payload.")
|
||||
return None
|
||||
|
||||
# 4. Normalize the Stream
|
||||
# The decoder logic relies on integers (1-based indices).
|
||||
# The raw stream might contain floats or strings that we need to cast or filter.
|
||||
stream = []
|
||||
for token in stream_raw:
|
||||
if isinstance(token, int):
|
||||
stream.append(token)
|
||||
elif isinstance(token, float):
|
||||
stream.append(int(token))
|
||||
elif isinstance(token, str):
|
||||
# Sometimes numeric values are sent as strings in the stream
|
||||
try:
|
||||
stream.append(int(float(token)))
|
||||
except ValueError:
|
||||
# If it's a non-numeric string token (like a cache ID), ignore it
|
||||
pass
|
||||
|
||||
# 5. Decode Logic
|
||||
try:
|
||||
# Define the signatures we are looking for in the String Table
|
||||
REGION_SIG = "cc.nisc.oms.clientandserver.v2.pojo.Region/3192921568"
|
||||
INTEGER_SIG = "java.lang.Integer/3438268394"
|
||||
CATEGORY_KEY = "County"
|
||||
|
||||
# Helper to find 1-based index
|
||||
def get_index(val):
|
||||
try: return string_table.index(val) + 1
|
||||
except ValueError: return 0
|
||||
|
||||
region_type_id = get_index(REGION_SIG)
|
||||
integer_type_id = get_index(INTEGER_SIG)
|
||||
county_type_id = get_index(CATEGORY_KEY)
|
||||
|
||||
if region_type_id == 0:
|
||||
print("Error: Region type signature not found in string table.")
|
||||
# Debug: Print first few strings to verify if signatures changed
|
||||
# print("Available strings:", string_table[:10])
|
||||
return None
|
||||
|
||||
results = []
|
||||
i = 0
|
||||
stream_len = len(stream)
|
||||
|
||||
# Iterate through the stream looking for Region objects
|
||||
while i < stream_len:
|
||||
if stream[i] == region_type_id:
|
||||
try:
|
||||
# We found a Region. The next few integers define its properties.
|
||||
# Pointer 'p' is relative to current index 'i'
|
||||
p = i + 1
|
||||
|
||||
# --- Field 1: Total Served ---
|
||||
# Logic: Value is valid if followed by Integer Type ID
|
||||
served = 0
|
||||
val1 = stream[p]
|
||||
p += 1
|
||||
if p < stream_len and stream[p] == integer_type_id:
|
||||
served = val1
|
||||
p += 1 # Skip type ID
|
||||
|
||||
# --- Field 2: Number Out ---
|
||||
out = 0
|
||||
val2 = stream[p]
|
||||
p += 1
|
||||
if p < stream_len and stream[p] == integer_type_id:
|
||||
out = val2
|
||||
p += 1 # Skip type ID
|
||||
|
||||
# --- Field 3: Name Index ---
|
||||
name_idx = stream[p]
|
||||
p += 1
|
||||
|
||||
# --- Field 4: Category Index ---
|
||||
cat_idx = stream[p]
|
||||
|
||||
# Check if this is a County
|
||||
if cat_idx == county_type_id:
|
||||
name = "Unknown"
|
||||
if 0 < name_idx <= len(string_table):
|
||||
name = string_table[name_idx - 1]
|
||||
|
||||
percent = 0.0
|
||||
if served > 0:
|
||||
percent = (out / served) * 100
|
||||
|
||||
results.append({
|
||||
"county": name,
|
||||
"served": served,
|
||||
"out": out,
|
||||
"percent": percent
|
||||
})
|
||||
|
||||
except IndexError:
|
||||
pass
|
||||
i += 1
|
||||
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during stream traversal: {e}")
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
filename = "outage_data.txt"
|
||||
if os.path.exists(filename):
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
raw_content = f.read().strip()
|
||||
|
||||
data = decode_gwt_rpc(raw_content)
|
||||
|
||||
if data:
|
||||
# Sort A-Z
|
||||
data.sort(key=lambda x: x['county'])
|
||||
|
||||
print(f"{'County':<20} | {'Served':>8} | {'Out':>8} | {'Percent':>8}")
|
||||
print("-" * 55)
|
||||
for row in data:
|
||||
print(f"{row['county']:<20} | {row['served']:>8} | {row['out']:>8} | {row['percent']:>7.2f}%")
|
||||
else:
|
||||
print("No data found.")
|
||||
else:
|
||||
print(f"File '{filename}' not found. Please create it and paste the payload.")
|
||||
|
||||
Reference in New Issue
Block a user