Publishing the roster tags retries until the relay agrees
Same fault the iPhone had. The dirty flag was cleared before the attempt, so a refusal was lost for good: the token was already stored, nothing asked again, and that contact would never have seen a presence. The set is compared against what the relay last accepted instead, and republished until the two agree. The route replaces rather than merges, so repeating a set that already landed changes nothing, which is what makes retrying free. Verified on the live relay: both accounts publish their own digest, and the digests differ, because a token is per pair. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
89474a1fc7
commit
cf811d1bee
@@ -2130,6 +2130,14 @@ class Session(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* §8.9c. What the relay last accepted, so a refusal is retried and a set
|
||||
* that already landed is not sent every pass. In memory on purpose: after
|
||||
* a restart, publishing once more costs a request and settles any
|
||||
* disagreement, where a persisted claim could be wrong and never tested.
|
||||
*/
|
||||
private var publishedDigests: List<String> = emptyList()
|
||||
|
||||
/**
|
||||
* §8.9c. Presence for the contacts this account holds a token for.
|
||||
*
|
||||
@@ -2139,9 +2147,18 @@ class Session(
|
||||
*/
|
||||
private fun presenceFromTokens(): Map<Long, String> {
|
||||
val held = conversations.presenceTokensHeld()
|
||||
if (conversations.rosterTagsDirty) {
|
||||
conversations.rosterTagsDirty = false
|
||||
runCatching { api.publishRosterTags(conversations.rosterTagDigests()) }
|
||||
// Compared against what the relay last ACCEPTED, not driven by a flag
|
||||
// cleared before the attempt. The flag version lost a refusal for
|
||||
// good: the token was already stored, so nothing asked again and that
|
||||
// contact never saw a presence. The route replaces rather than merges,
|
||||
// so repeating a set that already landed changes nothing.
|
||||
val digests = conversations.rosterTagDigests()
|
||||
if (digests.isNotEmpty() && digests != publishedDigests) {
|
||||
runCatching { api.publishRosterTags(digests) }
|
||||
.onSuccess {
|
||||
publishedDigests = digests
|
||||
conversations.rosterTagsDirty = false
|
||||
}
|
||||
}
|
||||
if (held.isEmpty()) return emptyMap()
|
||||
val answers = runCatching { api.presenceByToken(held.keys.toList()) }
|
||||
|
||||
Reference in New Issue
Block a user