@@ -33,6 +33,7 @@ maxSessionsPerKey = 10
3333challengeExpiry = 60000 -- 1 minute in milliseconds
3434sessionExpiry = 3600000 -- 1 hour in milliseconds
3535onlineGossipTtl = 3600 -- 1 hour in seconds
36+offlineGossipMinTtl = 60 -- minimum TTL for offline gossip events in seconds
3637
3738-- ============================================
3839-- Types
@@ -323,7 +324,10 @@ extractToken = \authHeader ->
323324 else ""
324325
325326verifyFederationAuth = \authorization ->
326− not (federationSecret == "") && safeCompare (extractToken authorization) federationSecret
327+ let token = extractToken authorization
328+ let result = safeCompare token (if federationSecret == "" then "x" else federationSecret)
329+ let secretSet = if federationSecret == "" then 0 else 1
330+ (if result then 1 else 0) * secretSet > 0
327331
328332verifyMaintenanceAuth = \authorization ->
329333 let token = extractToken authorization
@@ -344,7 +348,10 @@ evictOldestAckedIds = \items n ->
344348 if acc.size < n
345349 then
346350 let newHeap = union acc.heap [a]
347− {size: count newHeap, heap: newHeap, heapMax: if a.ackedAt > acc.heapMax then a.ackedAt else acc.heapMax}
351+ let newSize = count newHeap
352+ if newSize > acc.size
353+ then {size: newSize, heap: newHeap, heapMax: if a.ackedAt > acc.heapMax then a.ackedAt else acc.heapMax}
354+ else acc
348355 else if a.ackedAt < acc.heapMax
349356 then
350357 let removed = fold (\r x ->
@@ -358,8 +365,8 @@ evictOldestAckedIds = \items n ->
358365 in diff items toEvict
359366
360367safeCompareLoop = \s1 s2 n result ->
361− if n <= 0 && s1 == "" && s2 == ""
362− then result
368+ if n <= 0
369+ then result + (if s1 == "" then 0 else 1) + (if s2 == "" then 0 else 1)
363370 else safeCompareLoop (drop 1 s1) (drop 1 s2) (n - 1) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
364371
365372safeCompare = \a b ->
@@ -457,7 +464,7 @@ broadcastOfflineGossip = \t peerServers expiredLocal -> do
457464 if count (do a <- acc; where a.pubkey == p.pubkey; where a.expiresAt >= p.expiresAt; yield a) > 0 then acc
458465 else union
459466 (do a <- acc; where not (a.pubkey == p.pubkey); yield a)
460− [{pubkey: p.pubkey, ttl: clampTtl ((p.expiresAt - p.timestamp) / 1000), expiresAt: p.expiresAt}]) [] expiredLocal
467+ [{pubkey: p.pubkey, ttl: (let rawTtl = (p.expiresAt - p.timestamp) / 1000 in clampTtl (if rawTtl < offlineGossipMinTtl then offlineGossipMinTtl else rawTtl)), expiresAt: p.expiresAt}]) [] expiredLocal
461468 if not (federationSecret == "") && count expiredEntries > 0 && count peerServers > 0
462469 then do
463470 let gossipEvents = do
@@ -535,7 +542,10 @@ pollOnce = \token cursor ->
535542 if acc.size < maxPollEvents
536543 then
537544 let newHeap = union acc.heap [m]
538− {size: count newHeap, heap: newHeap, heapMax: if m.receivedAt > acc.heapMax then m.receivedAt else acc.heapMax}
545+ let newSize = count newHeap
546+ if newSize > acc.size
547+ then {size: newSize, heap: newHeap, heapMax: if m.receivedAt > acc.heapMax then m.receivedAt else acc.heapMax}
548+ else acc
539549 else if m.receivedAt < acc.heapMax
540550 then
541551 let removed = fold (\r x ->
@@ -857,45 +867,48 @@ serve = \req -> case req of
857867 yield {messageId: m.messageId, toKey: m.toKey, ackedAt: t, originServer: m.originServer}
858868 sendAcksAndClean pendingAcks originServers
859869 else yield {}
860− evictedEntries <- atomic do
861− ackedIds <- *ackedIds
862− let excessCount = count ackedIds - maxAckedIds
863− if excessCount <= 0
864− then yield []
865− else do
866− let afterEviction = evictOldestAckedIds ackedIds excessCount
867− let evicted = diff ackedIds afterEviction
868− set *ackedIds = afterEviction
869− yield evicted
870− let evictedToRetry = do
871− a <- evictedEntries
872− where count (do m <- fedMessages; where m.messageId == a.messageId; where m.toKey == a.toKey; yield m) == 0
873− yield a
874− if count evictedToRetry > 0 && not (federationSecret == "")
870+ if result.ok
875871 then do
876− let evictedOriginServers = fold (\acc a ->
877− if count (do s <- acc; where s == a.originServer; yield s) > 0 then acc
878− else union acc [a.originServer]) [] evictedToRetry
879− sendToEach evictedOriginServers (\server ->
880− catch (do
881− fetch (federationScheme ++ server) (FederationAck {
882− authorization: "Bearer " ++ federationSecret,
883− messageIds: (do a <- evictedToRetry; where a.originServer == server; yield a.messageId),
884− originServer: server, fromServer: serverHostN})
885− yield {}) (\err -> do
886− println ("federation: error sending evicted ack to " ++ server ++ ": " ++ show err)
887− evicted <- atomic do
888− ackedIds <- *ackedIds
889− let reinsert = do a <- evictedToRetry; where a.originServer == server; yield a
890− let combined = union ackedIds reinsert
891− let excess = count combined - maxAckedIds
892− let afterEviction = if excess <= 0 then combined
893− else evictOldestAckedIds combined excess
872+ evictedEntries <- atomic do
873+ ackedIds <- *ackedIds
874+ let excessCount = count ackedIds - maxAckedIds
875+ if excessCount <= 0
876+ then yield []
877+ else do
878+ let afterEviction = evictOldestAckedIds ackedIds excessCount
879+ let evicted = diff ackedIds afterEviction
894880 set *ackedIds = afterEviction
895− yield (count combined - count afterEviction)
896− if evicted > 0
897− then println ("federation: evicted " ++ show evicted ++ " old ack entries to reinsert failed acks for " ++ server)
898− else yield {}))
881+ yield evicted
882+ let evictedToRetry = do
883+ a <- evictedEntries
884+ where count (do m <- fedMessages; where m.messageId == a.messageId; where m.toKey == a.toKey; yield m) == 0
885+ yield a
886+ if count evictedToRetry > 0 && not (federationSecret == "")
887+ then do
888+ let evictedOriginServers = fold (\acc a ->
889+ if count (do s <- acc; where s == a.originServer; yield s) > 0 then acc
890+ else union acc [a.originServer]) [] evictedToRetry
891+ sendToEach evictedOriginServers (\server ->
892+ catch (do
893+ fetch (federationScheme ++ server) (FederationAck {
894+ authorization: "Bearer " ++ federationSecret,
895+ messageIds: (do a <- evictedToRetry; where a.originServer == server; yield a.messageId),
896+ originServer: server, fromServer: serverHostN})
897+ yield {}) (\err -> do
898+ println ("federation: error sending evicted ack to " ++ server ++ ": " ++ show err)
899+ evicted <- atomic do
900+ ackedIds <- *ackedIds
901+ let reinsert = do a <- evictedToRetry; where a.originServer == server; yield a
902+ let combined = union ackedIds reinsert
903+ let excess = count combined - maxAckedIds
904+ let afterEviction = if excess <= 0 then combined
905+ else evictOldestAckedIds combined excess
906+ set *ackedIds = afterEviction
907+ yield (count combined - count afterEviction)
908+ if evicted > 0
909+ then println ("federation: evicted " ++ show evicted ++ " old ack entries to reinsert failed acks for " ++ server)
910+ else yield {}))
911+ else yield {}
899912 else yield {}
900913 broadcastOfflineGossip t result.peerServers result.expiredLocal
901914