on master help sign in
Extract gossip predicates, flatten validation, simplify event handling
commitf4d37c22efe1c611f1e26330703855536736e15a authoriko <mail@iko.soy> dateSat 11 Apr 2026, 15:01 (6 months ago) parentdddd66f
27 files changed+71−91
client/App.fs+44−43 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+15−13
client/App.fs+44−43
@@ -37,9 +37,11 @@ module App =
3737 | Identified of identity: Identity * conn: ConnStatus
3838
3939 type DecryptedEvent =
40− | IncomingChat of senderPubkey: string * message: ChatMessage
41− | IncomingDeliveryAck of senderPubkey: string * ackIds: string list
42− | IncomingProfile of senderPubkey: string * profile: Profile
40+ | ChatMsg of ChatMessage
41+ | DeliveryAck of ackIds: string list
42+ | ProfileUpdate of Profile
43+
44+ type IncomingEvent = { Sender: string; Event: DecryptedEvent }
4345
4446 type PollReceived = { Events: int; Messages: int; Errors: int; FirstError: string option }
4547
@@ -83,7 +85,7 @@ module App =
8385 | SendFailed of string
8486 | SendOk
8587 | DoSaveContact
86− | PollResult of events: DecryptedEvent list * status: PollStatus * cursor: int64
88+ | PollResult of events: IncomingEvent list * status: PollStatus * cursor: int64
8789 | CopyPubKey
8890 | DismissError
8991 | StateLoaded of StateLoadResult
@@ -130,13 +132,10 @@ module App =
130132
131133 let private contactName (contacts: Map<string, Contact>) (pk: string) =
132134 let fallback = truncKey pk
133− contacts
134− |> Map.tryFind pk
135− |> Option.map (fun c ->
136− if c.Nickname <> fallback then c.Nickname
137− elif c.DisplayName <> "" then c.DisplayName
138− else fallback)
139− |> Option.defaultValue fallback
135+ match Map.tryFind pk contacts with
136+ | Some c when c.Nickname <> fallback -> c.Nickname
137+ | Some c when c.DisplayName <> "" -> c.DisplayName
138+ | _ -> fallback
140139
141140 let private messagesFor (pk: string) (messages: Map<string, ChatMessage list>) =
142141 messages |> Map.tryFind pk |> Option.defaultValue []
@@ -157,17 +156,18 @@ module App =
157156 let private withProfile (p: Profile) (c: Contact) =
158157 { c with DisplayName = p.DisplayName; Bio = p.Bio; PhotoBase64 = p.PhotoBase64 }
159158
160− let private applyEvent (m: Model) = function
161− | IncomingChat(senderPubkey, message) ->
159+ let private applyEvent (m: Model) (evt: IncomingEvent) =
160+ match evt.Event with
161+ | ChatMsg message ->
162162 { m with
163163 Contacts =
164− if Map.containsKey senderPubkey m.Contacts then m.Contacts
165− else Map.add senderPubkey (newContact senderPubkey (truncKey senderPubkey)) m.Contacts
166− Messages = m.Messages |> appendMessage senderPubkey message }
167− | IncomingDeliveryAck(senderPubkey, ackIds) ->
168− { m with Messages = m.Messages |> markDelivered senderPubkey ackIds }
169− | IncomingProfile(senderPubkey, profile) ->
170− { m with Contacts = m.Contacts |> Map.change senderPubkey (Option.map (withProfile profile)) }
164+ if Map.containsKey evt.Sender m.Contacts then m.Contacts
165+ else Map.add evt.Sender (newContact evt.Sender (truncKey evt.Sender)) m.Contacts
166+ Messages = m.Messages |> appendMessage evt.Sender message }
167+ | DeliveryAck ackIds ->
168+ { m with Messages = m.Messages |> markDelivered evt.Sender ackIds }
169+ | ProfileUpdate profile ->
170+ { m with Contacts = m.Contacts |> Map.change evt.Sender (Option.map (withProfile profile)) }
171171
172172 let private trySession model =
173173 match model.Auth with
@@ -363,17 +363,18 @@ module App =
363363 }
364364 |> Async.Start)
365365
366+ [<RequireQualifiedAccess>]
366367 type private Envelope =
367368 | TextMessage of id: string * body: string
368369 | DeliveryAck of ackIds: string list
369370 | ProfileMessage of profile: Profile
370371
371372 let private serializeEnvelope = function
372− | TextMessage(id, body) ->
373+ | Envelope.TextMessage(id, body) ->
373374 JsonSerializer.Serialize({| ``type`` = "text"; id = id; body = body |})
374− | DeliveryAck ackIds ->
375+ | Envelope.DeliveryAck ackIds ->
375376 JsonSerializer.Serialize({| ``type`` = "delivery.ack"; id = Guid.NewGuid().ToString(); ack_ids = ackIds |})
376− | ProfileMessage profile ->
377+ | Envelope.ProfileMessage profile ->
377378 JsonSerializer.Serialize({| ``type`` = "profile"; id = Guid.NewGuid().ToString(); timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); display_name = profile.DisplayName; bio = profile.Bio; photo = profile.PhotoBase64 |})
378379
379380 let private sendEnvelope (session: Session) (recipientHex: string) (envelope: Envelope) =
@@ -394,49 +395,49 @@ module App =
394395 let root = doc.RootElement
395396 match root.GetProperty("type").GetString() with
396397 | "text" ->
397− Some(TextMessage(root.GetProperty("id").GetString(), root.GetProperty("body").GetString()))
398+ Some(Envelope.TextMessage(root.GetProperty("id").GetString(), root.GetProperty("body").GetString()))
398399 | "delivery.ack" ->
399400 let ackIds = root.GetProperty("ack_ids").EnumerateArray() |> Seq.map _.GetString() |> Seq.toList
400− Some(DeliveryAck ackIds)
401+ Some(Envelope.DeliveryAck ackIds)
401402 | "profile" ->
402403 let displayName = root.GetProperty("display_name").GetString()
403404 let bio = tryGetJsonString root "bio" |> Option.defaultValue ""
404405 let photo = tryGetJsonString root "photo" |> Option.defaultValue ""
405− Some(ProfileMessage { DisplayName = displayName; Bio = bio; PhotoBase64 = photo })
406+ Some(Envelope.ProfileMessage { DisplayName = displayName; Bio = bio; PhotoBase64 = photo })
406407 | _ -> None
407408
409+ let private toDecryptedEvent timestamp = function
410+ | Envelope.TextMessage(id, body) ->
411+ ChatMsg
412+ { Id = id; Body = body
413+ Timestamp = DateTimeOffset.FromUnixTimeSeconds(timestamp)
414+ IsOutgoing = false
415+ Status = DeliveryStatus.Delivered }
416+ | Envelope.DeliveryAck ackIds -> DeliveryAck ackIds
417+ | Envelope.ProfileMessage profile -> ProfileUpdate profile
418+
408419 let private decryptEvent (privKey: byte[]) (payload: EventPayload) =
409420 try
410421 let blob = Crypto.fromHex payload.EncryptedBlob
411−
412422 match Crypto.decrypt privKey blob with
413423 | Some(plaintext, senderHex) ->
414424 match parseEnvelope plaintext with
415− | Some(TextMessage(id, body)) ->
416− Ok(IncomingChat(senderHex,
417− { Id = id; Body = body
418− Timestamp = DateTimeOffset.FromUnixTimeSeconds(payload.Timestamp)
419− IsOutgoing = false
420− Status = DeliveryStatus.Delivered }))
421− | Some(DeliveryAck ackIds) ->
422− Ok(IncomingDeliveryAck(senderHex, ackIds))
423− | Some(ProfileMessage profile) ->
424− Ok(IncomingProfile(senderHex, profile))
425+ | Some envelope -> Ok { Sender = senderHex; Event = toDecryptedEvent payload.Timestamp envelope }
425426 | None -> Error "unknown envelope type"
426427 | None -> Error "decrypt failed"
427428 with ex ->
428429 Error $"parse: {ex.Message}"
429430
430− let private sendDeliveryAcks (session: Session) (events: DecryptedEvent list) =
431+ let private sendDeliveryAcks (session: Session) (events: IncomingEvent list) =
431432 async {
432433 let chatsBySender =
433434 events
434− |> List.choose (function IncomingChat(senderPubkey, msg) -> Some(senderPubkey, msg.Id) | _ -> None)
435+ |> List.choose (fun evt -> match evt.Event with ChatMsg msg -> Some(evt.Sender, msg.Id) | _ -> None)
435436 |> List.groupBy fst
436437 |> List.map (fun (sender, pairs) -> sender, List.map snd pairs)
437438
438439 for sender, msgIds in chatsBySender do
439− try do! sendEnvelope session sender (DeliveryAck msgIds) |> Async.Ignore
440+ try do! sendEnvelope session sender (Envelope.DeliveryAck msgIds) |> Async.Ignore
440441 with _ -> ()
441442 }
442443
@@ -454,7 +455,7 @@ module App =
454455 | CmdSend(session, recipientHex, text, messageId) ->
455456 asyncCmd (async {
456457 try
457− let! status = sendEnvelope session recipientHex (TextMessage(messageId, text))
458+ let! status = sendEnvelope session recipientHex (Envelope.TextMessage(messageId, text))
458459 match messageStatusToError status with
459460 | Some err -> return SendFailed err
460461 | None -> return SendOk
@@ -484,7 +485,7 @@ module App =
484485
485486 do! sendDeliveryAcks session events
486487
487− let chatCount = events |> List.sumBy (function IncomingChat _ -> 1 | _ -> 0)
488+ let chatCount = events |> List.sumBy (fun e -> match e.Event with ChatMsg _ -> 1 | _ -> 0)
488489 let status = Received { Events = response.Events.Length; Messages = chatCount; Errors = errors.Length; FirstError = List.tryHead errors }
489490 return PollResult(events, status, response.Cursor)
490491 with
@@ -536,7 +537,7 @@ module App =
536537 Cmd.ofEffect (fun _ ->
537538 async {
538539 for recipientHex in recipientHexes do
539− try do! sendEnvelope session recipientHex (ProfileMessage profile) |> Async.Ignore
540+ try do! sendEnvelope session recipientHex (Envelope.ProfileMessage profile) |> Async.Ignore
540541 with _ -> ()
541542 } |> Async.Start)
542543
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− OjZtkz0VbSsZAPLqo/EwqAhSduU=
169+ q+RBTy5zY6JI9PxhrcWbfRvoL18=
170170 </data>
171171 <key>Skrepka.pdb</key>
172172 <data>
173− 288OaA4YI1RkDT0OJaEP/3YzPMc=
173+ NYWrt6DxlK+IUv/o6TjGg/EXk0I=
174174 </data>
175175 <key>Sodium.Core.dll</key>
176176 <data>
@@ -1393,14 +1393,14 @@
13931393 <dict>
13941394 <key>hash2</key>
13951395 <data>
1396− GATWVaegaBDKB/p62UIV/s9+8HLonMfOJQDIur7CkO8=
1396+ zGao9cc9uvzxMlIB65ZxAxYwkb+5koDw9sBTW54bflw=
13971397 </data>
13981398 </dict>
13991399 <key>Skrepka.pdb</key>
14001400 <dict>
14011401 <key>hash2</key>
14021402 <data>
1403− xqtzoyoQh4wNTDI5bDqxqXQt8uNenDqsbW18iqrMsVs=
1403+ iNV/dAt3PmF/Vbjcomf5Qozaj2oQDkDdwcsenxrta+M=
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− p4a7Jz8sihEyuUmS+Y+uK2NzEHAlqdpvMP8DN36P+GY=
254+ siIFHcakElVsJvGoDeaziJTyMHVboq2iWuRQU4ojFSs=
255255 </data>
256256 </dict>
257257 <key>MonoBundle/Skrepka.pdb</key>
258258 <dict>
259259 <key>hash2</key>
260260 <data>
261− pmSRC/TvVv/BifxqaC+vH+uL3c1xcWkV07N+dOnKDCw=
261+ oQAGpHBMs/0ySIEif7Oklne5RyNCSo42UIKWMeP3w5I=
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+c2421eb18cd299aa1aa49d08e6aac0aff8c6c2b0")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+dddd66f0bf97c47fa53d616a7c0df16842361244")>]
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−42712c0ef894cb13fa15e474d67e6d25426158a6759d2d78deb6c136776fb18b
1+76de582629b12d03b2d9bbd1d57cf53dfb188fbf4e6496f51ba6519a0f83d3b2
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/c2421eb18cd299aa1aa49d08e6aac0aff8c6c2b0/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/dddd66f0bf97c47fa53d616a7c0df16842361244/*"}}
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+c2421eb18cd299aa1aa49d08e6aac0aff8c6c2b0")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+dddd66f0bf97c47fa53d616a7c0df16842361244")>]
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−306144550fbf863e667cabc76cbd65bf3da202cb8745fb510e5ee9d5bdd466b3
1+0ee050de77dfa27f84bf6e8bcff1935f31e0cbcc80fd35a7cd647eb5ffb919b9
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/c2421eb18cd299aa1aa49d08e6aac0aff8c6c2b0/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/dddd66f0bf97c47fa53d616a7c0df16842361244/*"}}
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+15−13
@@ -78,6 +78,10 @@ impl FromJSON GossipEventType where
7878 else if s == "offline" then GossipOffline {}
7979 else GossipUnknown {}
8080
81+isKnownEvent = \et -> case et of GossipUnknown {} -> False {}; _ -> True {}
82+isOnlineEvent = \et -> case et of GossipOnline {} -> True {}; _ -> False {}
83+isOfflineEvent = \et -> case et of GossipOffline {} -> True {}; _ -> False {}
84+
8185type GossipEvent = {eventType: GossipEventType, pubkey: PubkeyHex, server: ServerName, timestamp: Timestamp, ttl: Int<S>}
8286
8387type ValidGossipEntry = {eventType: GossipEventType, pubkey: PubkeyHex, server: ServerName, expiresAt: Timestamp, timestamp: Timestamp, ttl: Int<S>}
@@ -514,14 +518,12 @@ countMessagesFor = \messages toKey t ->
514518validGossipEvents : [GossipEvent] -> Timestamp -> [ValidGossipEntry]
515519validGossipEvents = \events t -> do
516520 e <- events
517− case e.eventType of
518− GossipUnknown {} -> []
519− _ -> do
520− where e.server != serverHostN && e.timestamp <= t + clockSkewTolerance
521− let ttl = clampTtl e.ttl
522− let expiresAt = e.timestamp + ttl * 1000
523− where expiresAt > t
524− yield {eventType: e.eventType, pubkey: e.pubkey, server: e.server, expiresAt: expiresAt, timestamp: e.timestamp, ttl: ttl}
521+ where isKnownEvent e.eventType
522+ where e.server != serverHostN && e.timestamp <= t + clockSkewTolerance
523+ let ttl = clampTtl e.ttl
524+ let expiresAt = e.timestamp + ttl * 1000
525+ where expiresAt > t
526+ yield {eventType: e.eventType, pubkey: e.pubkey, server: e.server, expiresAt: expiresAt, timestamp: e.timestamp, ttl: ttl}
525527
526528sendToEach : [ServerName] -> (ServerName -> (a {})) -> a {}
527529sendToEach = \servers action ->
@@ -895,7 +897,7 @@ serve = \req -> case req of
895897 m <- ackedMessages
896898 case m.origin of
897899 FederatedOrigin {server} -> yield {messageId: m.messageId, toKey: m.toKey, ackedAt: t, originServer: server}
898− LocalOrigin {} -> []
900+ _ -> []
899901 ackedIds <- *ackedIds
900902 let combinedAckedIds = union ackedIds ackedFederated
901903 let evictedEntries = let excessCount = count combinedAckedIds - maxAckedIds in
@@ -908,9 +910,9 @@ serve = \req -> case req of
908910 when federationEnabled (do
909911 sendAcksAndClean pendingAcks
910912 retryEvictedAcks evictedEntries pendingAcks)
911− AckUnauthorized {} -> yield {}
913+ _ -> yield {}
912914 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
913− yield (respond {ok: case result.ack of AckDone _ -> True {}; AckUnauthorized {} -> False {}})
915+ yield (respond {ok: case result.ack of AckDone _ -> True {}; _ -> False {}})
914916
915917 LookupPresence {pubkey, authorization, respond} -> do
916918 t <- now
@@ -943,8 +945,8 @@ serve = \req -> case req of
943945 then rejectFederation t respond
944946 else do
945947 let allValidEntries = validGossipEvents events t
946− let onlineEntries = do e <- allValidEntries; case e.eventType of GossipOnline {} -> yield e; _ -> []
947− let trustedOffline = do e <- allValidEntries; case e.eventType of GossipOffline {} -> do where e.server == fromServer; yield e; _ -> []
948+ let onlineEntries = do e <- allValidEntries; where isOnlineEvent e.eventType; yield e
949+ let trustedOffline = do e <- allValidEntries; where isOfflineEvent e.eventType && e.server == fromServer; yield e
948950 let filteredOnline = resolveByTimestamp onlineEntries trustedOffline
949951 let filteredOffline = resolveByTimestamp trustedOffline onlineEntries
950952 let deduped = mergeByPubkeyServer [] filteredOnline