diff options
| author | pepper <3782201+rohvani@users.noreply.github.com> | 2026-09-21 17:31:12 -0400 |
|---|---|---|
| committer | pepper <3782201+rohvani@users.noreply.github.com> | 2026-09-23 15:24:07 -0400 |
| commit | 40a7b0866c55196cd1e0dced29c83a3cb0301c1d (patch) | |
| tree | 7d78fe7e770a81293928dbf7df4b719f50967239 | |
| parent | 6c8205c204c64edb4ab83fe1d70506cebe1236f6 (diff) | |
Derive conversation identity from validated participants
Derive direct conversation IDs from the account and resident at request
and validation time. Remove their duplicate storage and the validator's
redundant conversation-ID argument.
Remove the first-list flag because empty coverage already schedules first
discovery. Retain strict list/page identity checks and add an assertion
rejecting another conversation's response.
| -rw-r--r-- | indra/newview/llchatservicehistory.cpp | 20 | ||||
| -rw-r--r-- | indra/newview/llchatservicehistorycore.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llchatservicehistorycore.h | 2 | ||||
| -rw-r--r-- | indra/newview/tests/llchatservicehistorycore_test.cpp | 20 |
4 files changed, 20 insertions, 26 deletions
diff --git a/indra/newview/llchatservicehistory.cpp b/indra/newview/llchatservicehistory.cpp index d9055fe372..ec1d64d970 100644 --- a/indra/newview/llchatservicehistory.cpp +++ b/indra/newview/llchatservicehistory.cpp @@ -138,7 +138,6 @@ struct Metadata struct Resident { // Discovery identity and the durable service range already covered. - std::string conversation_id; std::string advertised_token; std::string covered_token; U32 archive_serial = 0; @@ -185,7 +184,6 @@ struct Runtime // Discovery and archive-maintenance state. bool initialized_archives = false; - bool list_valid = false; bool list_needed = true; bool list_retry_used = false; @@ -1161,14 +1159,12 @@ bool processList(const LLSD& body, bool& confirm_activity_discovery) setWorkActive(pair.first, false); } } - const bool first_list = !sRuntime.list_valid; for (const ListEntry& entry : entries) { Resident& resident = sRuntime.residents[entry.resident_id]; const bool placeholder = std::find(sRuntime.queue.begin(), sRuntime.queue.end(), entry.resident_id) != sRuntime.queue.end(); const bool changed = resident.advertised_token != entry.last_msg_id; - resident.conversation_id = entry.conversation_id; resident.advertised_token = entry.last_msg_id; resident.listed = true; resident.activity_discovery = DISCOVERY_NONE; @@ -1177,16 +1173,14 @@ bool processList(const LLSD& body, bool& confirm_activity_discovery) resident.metadata.state = META_UNREQUESTED; } - // Queue only when discovery or archive coverage says the head may contain - // unseen rows; token equality is not used as a TimeUUID ordering claim. - if (!placeholder && (first_list || changed || - resident.covered_token != resident.advertised_token)) + // Empty coverage queues first discovery. Later lists queue changed or + // uncovered heads; token equality is not a TimeUUID ordering claim. + if (!placeholder && (changed || resident.covered_token != resident.advertised_token)) { resident.retry_used = false; queueResident(entry.resident_id, false); } } - sRuntime.list_valid = true; return true; } @@ -1293,7 +1287,7 @@ void syncResident(const LLUUID& id, const CapabilityContext& context, U32 epoch) // Resolve prerequisites before starting a pass. Only the manager erases // residents; its checked waits terminate before a reference can become stale. - if (!resident.listed || resident.conversation_id.empty()) + if (!resident.listed) { resident.activity_discovery = DISCOVERY_NONE; resident.snapshot.head_preview.clear(); @@ -1345,6 +1339,7 @@ void syncResident(const LLUUID& id, const CapabilityContext& context, U32 epoch) bool had_boundary = !needs_prepare && resident.summary.state == ARCHIVE_VALID && resident.summary.has_oldest; TimeUuidKey stored_newest = resident.summary.newest; + const std::string conversation_id = directConversationId(sRuntime.agent_id, id); std::vector<Row> staged; size_t staged_bytes = 0; U32 returned_rows = 0; @@ -1388,7 +1383,7 @@ void syncResident(const LLUUID& id, const CapabilityContext& context, U32 epoch) } resident.first_request_started = true; LLSD post; - post["conversation_id"] = resident.conversation_id; + post["conversation_id"] = conversation_id; post["limit"] = 100; if (!cursor.empty()) { @@ -1410,8 +1405,7 @@ void syncResident(const LLUUID& id, const CapabilityContext& context, U32 epoch) return; } Page page; - if (!validateHistoryPage(response.body, sRuntime.agent_id, id, - resident.conversation_id, cursor, + if (!validateHistoryPage(response.body, sRuntime.agent_id, id, cursor, sRuntime.deleted_before_ticks, page)) { return; diff --git a/indra/newview/llchatservicehistorycore.cpp b/indra/newview/llchatservicehistorycore.cpp index 4223f57155..88b890e7a1 100644 --- a/indra/newview/llchatservicehistorycore.cpp +++ b/indra/newview/llchatservicehistorycore.cpp @@ -760,7 +760,7 @@ bool validateConversationList(const LLSD& value, const LLUUID& agent_id, // resident conversations can have a local history archive. if (resident.notNull()) { - entries.push_back({resident, conversation, token}); + entries.push_back({resident, token}); } } @@ -769,11 +769,11 @@ bool validateConversationList(const LLSD& value, const LLUUID& agent_id, bool validateHistoryPage(const LLSD& value, const LLUUID& agent_id, const LLUUID& resident_id, - const std::string& conversation_id, const std::string& requested_cursor, U64 deleted_before_ticks, Page& page) { page = Page(); + const std::string conversation_id = directConversationId(agent_id, resident_id); // The service echoes the exact conversation and fixed page size. Coercible LLSD // types are rejected so paging state cannot drift across malformed responses. diff --git a/indra/newview/llchatservicehistorycore.h b/indra/newview/llchatservicehistorycore.h index 957243cfba..60ecbf59a8 100644 --- a/indra/newview/llchatservicehistorycore.h +++ b/indra/newview/llchatservicehistorycore.h @@ -57,7 +57,6 @@ namespace LLChatServiceHistoryCore struct ListEntry { LLUUID resident_id; - std::string conversation_id; std::string last_msg_id; }; @@ -150,7 +149,6 @@ namespace LLChatServiceHistoryCore std::vector<ListEntry>& entries); bool validateHistoryPage(const LLSD& value, const LLUUID& agent_id, const LLUUID& resident_id, - const std::string& conversation_id, const std::string& requested_cursor, U64 deleted_before_ticks, Page& page); diff --git a/indra/newview/tests/llchatservicehistorycore_test.cpp b/indra/newview/tests/llchatservicehistorycore_test.cpp index 4f28f85317..38f77de4af 100644 --- a/indra/newview/tests/llchatservicehistorycore_test.cpp +++ b/indra/newview/tests/llchatservicehistorycore_test.cpp @@ -118,21 +118,21 @@ template<> template<> void object_t::test<4>() Page page; ensure("strict descending page", validateHistoryPage( - wirePage(rows), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), + wirePage(rows), AGENT, RESIDENT, "", 0, page)); ensure_equals("all rows retained", page.rows.size(), size_t(2)); ensure_equals("oldest cursor", page.next_cursor, std::string(FIRST)); // The deletion boundary is inclusive and ends paging, but not validation. ensure("cutoff page accepted", validateHistoryPage( - wirePage(rows), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), "", 1, page)); + wirePage(rows), AGENT, RESIDENT, "", 1, page)); ensure_equals("only newer rows retained", page.rows.size(), size_t(1)); ensure_equals("newer row retained", page.rows.front().msg_id, std::string(SECOND)); ensure("cutoff ends paging", page.terminal && page.next_cursor.empty()); rows.append(wireRow("00000000-0000-1000-8000-000000000000")); rows[2]["dialog"] = 99; ensure("invalid row below cutoff rejected", !validateHistoryPage( - wirePage(rows), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), "", 1, page)); + wirePage(rows), AGENT, RESIDENT, "", 1, page)); } template<> template<> void object_t::test<5>() @@ -144,21 +144,25 @@ template<> template<> void object_t::test<5>() Page page; ensure("ascending page rejected", !validateHistoryPage( - wirePage(rows), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), + wirePage(rows), AGENT, RESIDENT, "", 0, page)); // Ordering alone rejects duplicates, including replay of the preceding page's cursor. rows[1] = rows[0]; ensure("duplicate row rejected", !validateHistoryPage( - wirePage(rows), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), "", 0, page)); + wirePage(rows), AGENT, RESIDENT, "", 0, page)); rows.erase(1); ensure("cursor row cannot repeat on the next page", !validateHistoryPage( - wirePage(rows, FIRST), AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), FIRST, 0, page)); + wirePage(rows, FIRST), AGENT, RESIDENT, FIRST, 0, page)); LLSD wrong = wirePage(LLSD::emptyArray()); + wrong["conversation_id"] = directConversationId(AGENT, LLUUID::null); + ensure("another conversation rejected", !validateHistoryPage( + wrong, AGENT, RESIDENT, "", 0, page)); + wrong = wirePage(LLSD::emptyArray()); wrong["limit"] = "100"; ensure("coercible type rejected", !validateHistoryPage( - wrong, AGENT, RESIDENT, directConversationId(AGENT, RESIDENT), "", 0, page)); + wrong, AGENT, RESIDENT, "", 0, page)); } template<> template<> void object_t::test<6>() @@ -1047,8 +1051,6 @@ template<> template<> void object_t::test<36>() validateConversationList(list, AGENT, entries)); ensure_equals("only the resident is scheduled", entries.size(), size_t(1)); ensure_equals("resident identity preserved", entries.front().resident_id, RESIDENT); - ensure_equals("conversation identity preserved", entries.front().conversation_id, - peer["conversation_id"].asString()); ensure_equals("history token preserved", entries.front().last_msg_id, std::string(SECOND)); } } |
