Add safe snapshot and segment assembly
Add envelope-aware snapshot and segment assembly for structured Monopoly and Arc history records.
This commit is contained in:
parent
a5312520e7
commit
73bb100cd6
8 changed files with 601 additions and 23 deletions
|
|
@ -22,7 +22,12 @@ from nte_history_exporter.constants import (
|
|||
from nte_history_exporter.decoder.boundary import select_continuous_run_from_page_1
|
||||
from nte_history_exporter.decoder.run import fmt_packet_time
|
||||
from nte_history_exporter.mappings import ARC_META
|
||||
from nte_history_exporter.decoder.structured_protocol import StructuredRecord, parse_structured_records
|
||||
from nte_history_exporter.decoder.structured_protocol import (
|
||||
StructuredProtocolAssembler,
|
||||
StructuredRecord,
|
||||
parse_structured_blocks,
|
||||
parse_structured_records,
|
||||
)
|
||||
|
||||
|
||||
def is_arc_history_request(content: bytes) -> bool:
|
||||
|
|
@ -125,7 +130,7 @@ def _arc_metadata(arc_id: str) -> dict[str, Any]:
|
|||
return next((meta for item_id, meta in ARC_META.items() if item_id.casefold() == folded), {})
|
||||
|
||||
|
||||
def _structured_arc_rows(structured_rows: list[StructuredRecord]) -> list[dict[str, Any]]:
|
||||
def structured_arc_rows(structured_rows: list[StructuredRecord]) -> list[dict[str, Any]]:
|
||||
records = []
|
||||
for structured in structured_rows:
|
||||
meta = _arc_metadata(structured.item_id)
|
||||
|
|
@ -149,6 +154,7 @@ def _structured_arc_rows(structured_rows: list[StructuredRecord]) -> list[dict[s
|
|||
"decoder_mode": "structured_fallback",
|
||||
"structured_pool_id": structured.pool_id,
|
||||
"structured_protocol_view": structured.protocol_view,
|
||||
"structured_generation_index": structured.generation_index,
|
||||
}
|
||||
)
|
||||
return records
|
||||
|
|
@ -176,10 +182,10 @@ def parse_arc_response(response: bytes) -> list[dict[str, Any]]:
|
|||
legacy_rows = _parse_legacy_arc_response(response)
|
||||
if legacy_rows:
|
||||
return _enrich_legacy_arc_rows(legacy_rows, structured_rows)
|
||||
return _structured_arc_rows(structured_rows)
|
||||
return structured_arc_rows(structured_rows)
|
||||
|
||||
|
||||
def build_arc_rows_from_pairs(pairs: list[tuple]) -> list[dict[str, Any]]:
|
||||
def _build_primary_arc_rows_from_pairs(pairs: list[tuple]) -> list[dict[str, Any]]:
|
||||
pool = POOL_META["arc_miracle_box"]
|
||||
rows: list[dict[str, Any]] = []
|
||||
for pair in pairs:
|
||||
|
|
@ -209,6 +215,48 @@ def build_arc_rows_from_pairs(pairs: list[tuple]) -> list[dict[str, Any]]:
|
|||
return rows
|
||||
|
||||
|
||||
def build_arc_rows_from_pairs(pairs: list[tuple]) -> list[dict[str, Any]]:
|
||||
primary_rows = _build_primary_arc_rows_from_pairs(pairs)
|
||||
if primary_rows and any(row.get("decoder_mode") != "structured_fallback" for row in primary_rows):
|
||||
return primary_rows
|
||||
|
||||
assembler = StructuredProtocolAssembler()
|
||||
for source_index, pair in enumerate(pairs):
|
||||
assembler.add_blocks(parse_structured_blocks(pair[6], "fork", source_index=source_index))
|
||||
assembled = assembler.rows("fork")
|
||||
if not assembled:
|
||||
return primary_rows
|
||||
|
||||
pool = POOL_META["arc_miracle_box"]
|
||||
rows = []
|
||||
for row_index, (record, structured) in enumerate(
|
||||
zip(structured_arc_rows(assembled), assembled), start=1
|
||||
):
|
||||
source_index = structured.source_index or 0
|
||||
pair = pairs[source_index]
|
||||
page, offset, req_i, req_ts, resp_i, resp_ts, response = pair[:7]
|
||||
rows.append(
|
||||
{
|
||||
**record,
|
||||
"page": page,
|
||||
"offset": offset,
|
||||
"row": row_index,
|
||||
"pool_group_id": pool["id"],
|
||||
"pool_group_name": pool["name"],
|
||||
"request_msg": req_i,
|
||||
"request_time_utc": fmt_packet_time(req_ts),
|
||||
"response_msg": resp_i,
|
||||
"response_time_utc": fmt_packet_time(resp_ts),
|
||||
"response_len": len(response),
|
||||
"record_count": len(assembled),
|
||||
"structured_assembly": "snapshot_segments",
|
||||
"structured_assembly_warning_count": len(assembler.warnings),
|
||||
}
|
||||
)
|
||||
annotate_arc_groups(rows)
|
||||
return rows
|
||||
|
||||
|
||||
def make_arc_uid(timestamp_raw: str, ordinal: int) -> str:
|
||||
source = "|".join([GAME_UID_PART, ARC_SYSTEM, ARC_BANNER_ID, timestamp_raw, str(ordinal)])
|
||||
return hashlib.sha256(source.encode("utf-8")).hexdigest()[:32]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue