on master help sign in
Simplify code: combine where clauses, factor broadcastOfflineGossip, parameterize sendBatchedGossip hops, optimize eviction
commit63578618d8e9cfccf64d0eeb1e1ded23ac863caa authoriko <mail@iko.soy> dateFri 10 Apr 2026, 12:55 (6 months ago) parent5c34fab
28 files changed+61−94
client/ApiClient.fs+2−1 client/App.fs+19−23 client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4 client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2 client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt−23 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll server.knot+28−35
client/ApiClient.fs+2−1
@@ -96,8 +96,9 @@ module ApiClient =
9696
9797 match doc.RootElement.TryGetProperty("error") with
9898 | true, err ->
99+ let msg = err.GetString()
99100 doc.Dispose()
100− return failwith $"{url}: {err.GetString()}"
101+ return failwith $"{url}: {msg}"
101102 | _ -> return doc
102103 }
103104
client/App.fs+19−23
@@ -111,10 +111,9 @@ module App =
111111 else contacts @ [ contact ]
112112
113113 let private upsertContact (contact: Contact) (contacts: Contact list) =
114− if contacts |> List.exists (fun c -> c.Pubkey = contact.Pubkey) then
115− contacts |> List.map (fun c -> if c.Pubkey = contact.Pubkey then contact else c)
116− else
117− contacts @ [ contact ]
114+ match contacts |> List.tryFindIndex (fun c -> c.Pubkey = contact.Pubkey) with
115+ | Some i -> contacts |> List.updateAt i contact
116+ | None -> contacts @ [ contact ]
118117
119118 let private pubKeyHex model =
120119 match model.Auth with
@@ -202,11 +201,11 @@ module App =
202201 model', CmdSend(session, pk, compose, id) :: saveCmd model'
203202 | _ -> model, []
204203
205− | Sent(Ok result) ->
206− match result.Status with
207− | ApiClient.Rejected -> { model with Error = Some "Message rejected by server" }, []
208− | ApiClient.Unauthorized -> { model with Error = Some "Not authorized to deliver message" }, []
209− | _ -> model, []
204+ | Sent(Ok { Status = ApiClient.Rejected }) ->
205+ { model with Error = Some "Message rejected by server" }, []
206+ | Sent(Ok { Status = ApiClient.Unauthorized }) ->
207+ { model with Error = Some "Not authorized to deliver message" }, []
208+ | Sent(Ok _) -> model, []
210209 | Sent(Error err) -> { model with Error = Some $"Send failed: {err}" }, []
211210
212211 | PollResult(incoming, status, newCursor) ->
@@ -219,12 +218,11 @@ module App =
219218 Messages = m.Messages |> appendMessage fromPubkey chatMsg })
220219 { model with PollStatus = status; PollCursor = newCursor }
221220
222− let cmds =
223− match trySession model' with
224− | Some session -> [ CmdPoll(session, model'.PollCursor) ]
225− | None -> []
226−
227− model', cmds @ (if incoming.IsEmpty then [] else saveCmd model')
221+ model',
222+ [ match trySession model' with
223+ | Some session -> CmdPoll(session, model'.PollCursor)
224+ | None -> ()
225+ if not incoming.IsEmpty then yield! saveCmd model' ]
228226
229227 | SetNewPubkey pk ->
230228 match model.Page with
@@ -289,14 +287,14 @@ module App =
289287 | Some(plaintext, senderHex) ->
290288 let envelope = JsonSerializer.Deserialize<TextEnvelope>(plaintext)
291289
292− if envelope.Type = "text" then
290+ match envelope.Type with
291+ | "text" ->
293292 Ok(senderHex,
294293 { Id = envelope.Id
295294 Body = envelope.Body
296295 Timestamp = DateTimeOffset.FromUnixTimeSeconds(payload.Timestamp)
297296 IsOutgoing = false })
298− else
299− Error "unknown type"
297+ | t -> Error $"unknown type: {t}"
300298 | None -> Error "decrypt failed"
301299 with ex ->
302300 Error $"parse: {ex.Message}"
@@ -459,7 +457,7 @@ module App =
459457 |> String.concat ", "
460458
461459 let totalMsgs =
462− model.Messages |> Map.fold (fun acc _ msgs -> acc + List.length msgs) 0
460+ model.Messages |> Map.values |> Seq.sumBy List.length
463461
464462 ContentPage(
465463 ScrollView(
@@ -491,16 +489,14 @@ module App =
491489 .textColor(Colors.Gray)
492490
493491 for c in model.Contacts do
494− let lastMsg =
492+ let preview =
495493 model.Messages
496494 |> Map.tryFind c.Pubkey
497495 |> Option.bind List.tryLast
498496 |> Option.map _.Body
497+ |> Option.map (fun b -> if b.Length > 40 then b.[..39] + "..." else b)
499498 |> Option.defaultValue ""
500499
501− let preview =
502− if lastMsg.Length > 40 then lastMsg.[..39] + "..." else lastMsg
503−
504500 Button($"{c.Nickname}\n{preview}", Nav(Chat(c.Pubkey, "")))
505501 })
506502 .padding(20.)
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4
@@ -166,11 +166,11 @@
166166 </data>
167167 <key>Skrepka.dll</key>
168168 <data>
169− 5V7ZArTTdWWdtF2EQw4DfWAWqsI=
169+ lezBPlMGgvvXPLrij5BGxw+mSWU=
170170 </data>
171171 <key>Skrepka.pdb</key>
172172 <data>
173− SsPgpZXl35VDuHCOYCegZuLqIVg=
173+ GEoIFmupvmKvjt37aNX0Nqhf4Mw=
174174 </data>
175175 <key>Sodium.Core.dll</key>
176176 <data>
@@ -1393,14 +1393,14 @@
13931393 <dict>
13941394 <key>hash2</key>
13951395 <data>
1396− EjrAHE9wqEvTYF+Siheu21r0UjeHDIZTT38w82FXRYU=
1396+ lOwwpy7OvL/VnkdUcEg8WtWpvQYej7RHx+vgMXJ9cIk=
13971397 </data>
13981398 </dict>
13991399 <key>Skrepka.pdb</key>
14001400 <dict>
14011401 <key>hash2</key>
14021402 <data>
1403− cqhfrvM9zLFFTemz+KoZd7JckLQGVacy+ANck7D2x18=
1403+ jNIcynqsu5mNKMdxE4ue6lbnHnYvri+aDBLPMWQYh38=
14041404 </data>
14051405 </dict>
14061406 <key>Sodium.Core.dll</key>
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2
@@ -251,14 +251,14 @@
251251 <dict>
252252 <key>hash2</key>
253253 <data>
254− fVOogHexeXD8oGEEo57l14SmUBycR/4qC7AH6BhBs7k=
254+ BX5Ln9e/MG90UXlzW6/mp4ZMKIk3SNBv7i3Ncys57PE=
255255 </data>
256256 </dict>
257257 <key>MonoBundle/Skrepka.pdb</key>
258258 <dict>
259259 <key>hash2</key>
260260 <data>
261− ZOxyEQ1fCheg8RSrL3C6orb8q4+ouFNQ6lWNgWyrhPo=
261+ BFNi5ZeloXd05sYpCvJxbfM96QQYZ1yINRFxIEAItGE=
262262 </data>
263263 </dict>
264264 <key>MonoBundle/Sodium.Core.dll</key>
client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
1010[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
1111[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
1212[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+01f5f207fb604677f732e61a361f792f91a2b5c4")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+5c34fab63923cdb1b780a7e5a5ce5fae72adf78e")>]
1414[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
1515[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
1616[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−e0e8e8e8cd6c9e5da1d472b9aaaa2bf913ad3f59c98c11e0e07666057c474551
1+5ce28345d4f1ab17ca4f1637108170a533a9e7a3ae603bd386f96f4a7115bf28
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt−23
@@ -334,26 +334,3 @@
334334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
335335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
336336/Users/iko/Developer/skrepka/client/bin/Debug/net10.0-ios/iossimulator-arm64/LiteDB.dll
337−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stamp
338−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stamp
339−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stamp
340−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/LiteDB.stamp
341−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stamp
342−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stamp
343−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stamp
344−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stamp
345−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stamp
346−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stamp
347−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stamp
348−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stamp
349−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stamp
350−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stamp
351−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stamp
352−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stamp
353−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stamp
354−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stamp
355−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stamp
356−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stamp
357−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stamp
358−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stamp
359−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xml
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/01f5f207fb604677f732e61a361f792f91a2b5c4/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/5c34fab63923cdb1b780a7e5a5ce5fae72adf78e/*"}}
client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
1010[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
1111[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
1212[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+01f5f207fb604677f732e61a361f792f91a2b5c4")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+5c34fab63923cdb1b780a7e5a5ce5fae72adf78e")>]
1414[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
1515[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
1616[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−b4711a8c2112127a9d16499cf889271fa4c029a6ea108d24c78bcc77f6729544
1+619a20356f5e49038371f33a93f265cb66ee99cf70d2100710b5c8d26eea4f99
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/01f5f207fb604677f732e61a361f792f91a2b5c4/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/5c34fab63923cdb1b780a7e5a5ce5fae72adf78e/*"}}
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll

Binary file not shown.

server.knot+28−35
@@ -555,8 +555,7 @@ pruneExpired = \t -> do
555555 yield a
556556 yield {expiredLocal: (do
557557 p <- presenceBefore
558− where p.expiresAt <= t
559− where p.server == serverHostN
558+ where p.expiresAt <= t && p.server == serverHostN
560559 where none presenceAfter (\q -> q.pubkey == p.pubkey && q.server == serverHostN)
561560 yield p), peerServers: peerServersBefore}
562561
@@ -576,17 +575,17 @@ forEachBatch = \items batchSize process ->
576575 process batch
577576 forEachBatch rest batchSize process
578577
579−sendBatchedGossipToServer : Text -> [GossipEvent] -> IO {network} {}
580−sendBatchedGossipToServer = \server allEvents ->
578+sendBatchedGossipToServer : Text -> [GossipEvent] -> Int -> IO {network} {}
579+sendBatchedGossipToServer = \server allEvents hops ->
581580 forEachBatch allEvents maxGossipEvents (\batch -> do
582581 _ <- fetch (federationScheme ++ server) (RecvGossip {
583582 authorization: "Bearer " ++ federationSecret,
584− events: batch, hopsRemaining: 2, fromServer: serverHostN})
583+ events: batch, hopsRemaining: hops, fromServer: serverHostN})
585584 yield {})
586585
587−sendBatchedGossip : [Text] -> [GossipEvent] -> IO {network} {}
588−sendBatchedGossip = \peerServers allEvents ->
589− sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents)
586+sendBatchedGossip : [Text] -> [GossipEvent] -> Int -> IO {network} {}
587+sendBatchedGossip = \peerServers allEvents hops ->
588+ sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents hops)
590589
591590broadcastOfflineGossip = \t peerServers expiredLocal ->
592591 when (federationEnabled && count peerServers > 0 && count expiredLocal > 0) (do
@@ -597,7 +596,7 @@ broadcastOfflineGossip = \t peerServers expiredLocal ->
597596 let gossipEvents = do
598597 e <- expiredEntries
599598 yield {eventType: "offline", pubkey: e.pubkey, server: serverHostN, timestamp: e.expiresAt, ttl: e.ttl}
600− sendBatchedGossip peerServers gossipEvents)
599+ sendBatchedGossip peerServers gossipEvents 2)
601600
602601forkBroadcastOffline = \t result ->
603602 fork (broadcastOfflineGossip t result.peerServers result.expiredLocal)
@@ -765,18 +764,20 @@ serve = \req -> case req of
765764 then collectPeerServers updatedPresence (\p -> p.server)
766765 else []
767766 yield {pr: pr, verify: VerifyOk {peerServers: peerServers}}
768− fork (case result.verify of
769− VerifyOk {peerServers} -> do
770− when federationEnabled
771− (sendToEach peerServers (\server -> do
772− _ <- fetch (federationScheme ++ server) (RecvGossip {
773− authorization: "Bearer " ++ federationSecret,
774− events: [{eventType: "online", pubkey: pubkey, server: serverHostN, timestamp: t, ttl: onlineGossipTtl}], hopsRemaining: 2, fromServer: serverHostN})
775− yield {}))
776− broadcastOfflineGossip t result.pr.peerServers
777− (do p <- result.pr.expiredLocal; where not (p.pubkey == pubkey); yield p)
778− _ ->
779− broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
767+ let expiredLocal = case result.verify of
768+ VerifyOk _ -> do p <- result.pr.expiredLocal; where not (p.pubkey == pubkey); yield p
769+ _ -> result.pr.expiredLocal
770+ fork (do
771+ case result.verify of
772+ VerifyOk {peerServers} ->
773+ when federationEnabled
774+ (sendToEach peerServers (\server -> do
775+ _ <- fetch (federationScheme ++ server) (RecvGossip {
776+ authorization: "Bearer " ++ federationSecret,
777+ events: [{eventType: "online", pubkey: pubkey, server: serverHostN, timestamp: t, ttl: onlineGossipTtl}], hopsRemaining: 2, fromServer: serverHostN})
778+ yield {}))
779+ _ -> yield {}
780+ broadcastOfflineGossip t result.pr.peerServers expiredLocal)
780781 yield (case result.verify of
781782 VerifyFailed _ -> respond {token: "", expiresAt: 0}
782783 VerifyOk _ -> respond {token: token, expiresAt: expiry})
@@ -867,8 +868,7 @@ serve = \req -> case req of
867868 let ackedMessages = do
868869 m <- messages
869870 mid <- dedupedIds
870− where m.messageId == mid
871− where m.toKey == pubkey
871+ where m.messageId == mid && m.toKey == pubkey
872872 yield m
873873 set *messages = diff messages ackedMessages
874874 let ackedFederated = do
@@ -877,12 +877,9 @@ serve = \req -> case req of
877877 yield {messageId: m.messageId, toKey: m.toKey, ackedAt: t, originServer: m.originServer}
878878 ackedIds <- *ackedIds
879879 let combinedAckedIds = union ackedIds ackedFederated
880− let excessCount = count combinedAckedIds - maxAckedIds
881− let afterEviction = if excessCount <= 0 then combinedAckedIds
882− else evictOldestAckedIds combinedAckedIds excessCount
883− let evictedEntries = if excessCount <= 0 then []
884− else diff combinedAckedIds afterEviction
885− set *ackedIds = afterEviction
880+ let evictedEntries = let excessCount = count combinedAckedIds - maxAckedIds in
881+ if excessCount <= 0 then [] else boundedSmallest combinedAckedIds excessCount (\a -> a.ackedAt)
882+ set *ackedIds = diff combinedAckedIds evictedEntries
886883 yield {pr: pr, ack: AckDone {pendingAcks: ackedFederated, evictedEntries: evictedEntries}}
887884 fork (do
888885 case result.ack of
@@ -1021,16 +1018,12 @@ serve = \req -> case req of
10211018 when (not gossipResult.withinCapacity)
10221019 (println ("gossip: presence at capacity (" ++ show maxPresenceEntries ++ "), limiting new entries from " ++ fromServer))
10231020 fork (do
1024− when (cappedHops > 1 && federationEnabled && count effectiveEvents > 0) (do
1021+ when (cappedHops > 1 && federationEnabled && count effectiveEvents > 0) (
10251022 let targets = do
10261023 s <- gossipResult.gossipPeerServers
10271024 where not (s == fromServer)
10281025 yield s
1029− sendToEach targets (\server -> do
1030− _ <- fetch (federationScheme ++ server) (RecvGossip {
1031− authorization: "Bearer " ++ federationSecret,
1032− events: effectiveEvents, hopsRemaining: cappedHops - 1, fromServer: serverHostN})
1033− yield {}))
1026+ in sendBatchedGossip targets effectiveEvents (cappedHops - 1))
10341027 let pr = gossipResult.pr
10351028 broadcastOfflineGossip t pr.peerServers pr.expiredLocal)
10361029 yield (respond {ok: True {}})