on master help sign in
Improve type safety and simplify server: add DeliveryStatus type, eliminate result ADTs
commitc59feb8711edf67b505121d342f66ed8334f3286 authoriko <mail@iko.soy> dateSun 12 Apr 2026, 07:21 (6 months ago) parent59b0e4b
19 files changed+63−186
client/App.fs+13−25 client/obj/Debug/net10.0-ios/iossimulator-arm64/AppManifest.plist client/obj/Debug/net10.0-ios/iossimulator-arm64/_CompileAppManifest.inputs+2−2 client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/_BundleResourceWithLogicalName.items−17 client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/_PartialAppManifest.items−6 client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/asset-manifest.plist−16 client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/Assets.car client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon60x60@2x.png client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon76x76@2x~ipad.png client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/partial-info.plist−31 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/AppManifest.plist client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/_CompileAppManifest.inputs+2−2 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/_BundleResourceWithLogicalName.items−13 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/_PartialAppManifest.items−6 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/asset-manifest.plist−15 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/Assets.car client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/appicon.icns client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/partial-info.plist−10 server.knot+46−43
client/App.fs+13−25
@@ -44,12 +44,6 @@ module App =
4444
4545 type IncomingEvent = { Sender: string; Timestamp: DateTimeOffset; Envelope: Envelope }
4646
47− type PollStatus =
48− | Idle
49− | Polling
50− | Received of string
51− | PollError of string
52−
5347 // ── Model ──
5448
5549 type Model =
@@ -57,7 +51,7 @@ module App =
5751 Auth: AuthState
5852 ServerUrl: string
5953 Contacts: Map<string, Contact>
60− PollStatus: PollStatus
54+ PollStatus: string
6155 Messages: Map<string, ChatMessage list>
6256 Error: string option
6357 PollCursor: int64
@@ -80,7 +74,7 @@ module App =
8074 | DoSend
8175 | SendFailed of string
8276 | DoSaveContact
83− | PollResult of events: IncomingEvent list * ackIds: string list * status: PollStatus * cursor: int64
77+ | PollResult of events: IncomingEvent list * ackIds: string list * status: string * cursor: int64
8478 | CopyPubKey
8579 | DismissError
8680 | StateLoaded of StateLoadResult
@@ -121,11 +115,10 @@ module App =
121115 |> Option.filter (fun bytes -> bytes.Length = 32)
122116
123117 let private contactName (contacts: Map<string, Contact>) (pk: string) =
124− let fallback = truncKey pk
125118 match Map.tryFind pk contacts with
126− | Some c when c.Nickname <> fallback -> c.Nickname
119+ | Some c when c.Nickname <> "" -> c.Nickname
127120 | Some c when c.DisplayName <> "" -> c.DisplayName
128− | _ -> fallback
121+ | _ -> truncKey pk
129122
130123 let private messagesFor (pk: string) (messages: Map<string, ChatMessage list>) =
131124 messages |> Map.tryFind pk |> Option.defaultValue []
@@ -155,7 +148,7 @@ module App =
155148 { m with
156149 Contacts =
157150 if Map.containsKey evt.Sender m.Contacts then m.Contacts
158− else Map.add evt.Sender (newContact evt.Sender (truncKey evt.Sender)) m.Contacts
151+ else Map.add evt.Sender (newContact evt.Sender "") m.Contacts
159152 Messages = m.Messages |> appendMessage evt.Sender message }
160153 | Envelope.DeliveryAck ackIds ->
161154 { m with Messages = m.Messages |> markDelivered evt.Sender ackIds }
@@ -186,7 +179,7 @@ module App =
186179 { Page = Setup
187180 Auth = NoIdentity
188181 ServerUrl = "http://localhost:8080"
189− PollStatus = Idle
182+ PollStatus = ""
190183 Contacts = Map.empty
191184 Messages = Map.empty
192185 Error = None
@@ -217,13 +210,13 @@ module App =
217210 match model.Auth with
218211 | Identified(id, Connecting) ->
219212 let session = { Url = model.ServerUrl; Token = token; Identity = id }
220− { model with Auth = Identified(id, Online token); Page = Conversations; Error = None; PollStatus = Polling },
213+ { model with Auth = Identified(id, Online token); Page = Conversations; Error = None; PollStatus = "polling..." },
221214 [ CmdPoll(session, model.PollCursor) ]
222215 | _ -> model, []
223216
224217 | AuthErr err -> { setConn Offline model with Error = Some err }, []
225218
226− | DoDisconnect -> model |> setConn Offline, []
219+ | DoDisconnect -> { model |> setConn Offline with PollStatus = "" }, []
227220
228221 | DoSend ->
229222 match model.Page, trySession model with
@@ -445,15 +438,15 @@ module App =
445438 let status =
446439 $"evts:{response.Events.Length} msgs:{chatCount} errs:{errors.Length}"
447440 + (match List.tryHead errors with Some e -> $" [{e}]" | None -> "")
448− return PollResult(events, ackIds, Received status, response.Cursor)
441+ return PollResult(events, ackIds, status, response.Cursor)
449442 with
450443 | :? TimeoutException ->
451444 log "poll timeout"
452− return PollResult([], [], Polling, cursor)
445+ return PollResult([], [], "polling...", cursor)
453446 | ex ->
454447 log $"poll error: {ex.Message}"
455448 do! Async.Sleep 3000
456− return PollResult([], [], PollError ex.Message, cursor)
449+ return PollResult([], [], $"poll error: {ex.Message}", cursor)
457450 })
458451
459452 | CmdAckAndDeliver(session, ackIds, events) ->
@@ -514,12 +507,6 @@ module App =
514507
515508 // ── View ──
516509
517− let private formatPollStatus = function
518− | Idle -> ""
519− | Polling -> "polling..."
520− | Received s -> s
521− | PollError msg -> $"poll error: {msg}"
522−
523510 let private viewErrorBanner (error: string option) =
524511 VStack(spacing = 4.) {
525512 match error with
@@ -608,7 +595,8 @@ module App =
608595 }
609596
610597 let pubPrefix = match model.Auth with Identified(id, _) -> id.PubKeyHex.[..7] | _ -> "?"
611− Label($"{connStatusLabel model.Auth} [{pubPrefix}] | {formatPollStatus model.PollStatus}")
598+ let pollInfo = if model.PollStatus <> "" then $" | {model.PollStatus}" else ""
599+ Label($"{connStatusLabel model.Auth} [{pubPrefix}]{pollInfo}")
612600 .font(size = 10.)
613601 .textColor(Colors.DimGray)
614602
client/obj/Debug/net10.0-ios/iossimulator-arm64/AppManifest.plist

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/_CompileAppManifest.inputs+2−2
@@ -5,7 +5,7 @@ ApplicationTitle=Skrepka
55ApplicationVersion=1
66AppManifest=Platforms/iOS/Info.plist
77CompiledAppManifest=obj/Debug/net10.0-ios/iossimulator-arm64/AppManifest.plist
8−DefaultSdkVersion=26.2
8+DefaultSdkVersion=26.4
99FontFilesToRegister=
1010GenerateApplicationManifest=true
1111IsAppExtension=false
@@ -16,7 +16,7 @@ ProjectDir=/Users/iko/Developer/skrepka/client
1616ResourcePrefix=Platforms/iOS/Resources
1717ResourceRules=
1818SdkIsSimulator=True
19−SdkVersion=26.2
19+SdkVersion=26.4
2020SupportedOSPlatformVersion=26.2
2121TargetArchitectures=ARM64
2222TargetFrameworkMoniker=.NETCoreApp,Version=v10.0,Profile=ios
client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/_BundleResourceWithLogicalName.itemsdeleted−17
@@ -1,17 +0,0 @@
1−<?xml version="1.0" encoding="utf-8"?>
2−<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3− <ItemGroup>
4− <_BundleResourceWithLogicalName Include="obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/Assets.car">
5− <Optimize>false</Optimize>
6− <LogicalName>Assets.car</LogicalName>
7− </_BundleResourceWithLogicalName>
8− <_BundleResourceWithLogicalName Include="obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon60x60@2x.png">
9− <Optimize>false</Optimize>
10− <LogicalName>appicon60x60@2x.png</LogicalName>
11− </_BundleResourceWithLogicalName>
12− <_BundleResourceWithLogicalName Include="obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon76x76@2x~ipad.png">
13− <Optimize>false</Optimize>
14− <LogicalName>appicon76x76@2x~ipad.png</LogicalName>
15− </_BundleResourceWithLogicalName>
16− </ItemGroup>
17−</Project>
client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/_PartialAppManifest.itemsdeleted−6
@@ -1,6 +0,0 @@
1−<?xml version="1.0" encoding="utf-8"?>
2−<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3− <ItemGroup>
4− <_PostCompilePartialAppManifest Include="obj/Debug/net10.0-ios/iossimulator-arm64/actool/partial-info.plist" />
5− </ItemGroup>
6−</Project>
client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/asset-manifest.plistdeleted−16
@@ -1,16 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3−<plist version="1.0">
4−<dict>
5− <key>com.apple.actool.compilation-results</key>
6− <dict>
7− <key>output-files</key>
8− <array>
9− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/Assets.car</string>
10− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon60x60@2x.png</string>
11− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon76x76@2x~ipad.png</string>
12− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/partial-info.plist</string>
13− </array>
14− </dict>
15−</dict>
16−</plist>
client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/Assets.cardeleted

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon60x60@2x.pngdeleted

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/bundle/appicon76x76@2x~ipad.pngdeleted

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/actool/partial-info.plistdeleted−31
@@ -1,31 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3−<plist version="1.0">
4−<dict>
5− <key>CFBundleIcons</key>
6− <dict>
7− <key>CFBundlePrimaryIcon</key>
8− <dict>
9− <key>CFBundleIconFiles</key>
10− <array>
11− <string>appicon60x60</string>
12− </array>
13− <key>CFBundleIconName</key>
14− <string>appicon</string>
15− </dict>
16− </dict>
17− <key>CFBundleIcons~ipad</key>
18− <dict>
19− <key>CFBundlePrimaryIcon</key>
20− <dict>
21− <key>CFBundleIconFiles</key>
22− <array>
23− <string>appicon60x60</string>
24− <string>appicon76x76</string>
25− </array>
26− <key>CFBundleIconName</key>
27− <string>appicon</string>
28− </dict>
29− </dict>
30−</dict>
31−</plist>
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/AppManifest.plist

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/_CompileAppManifest.inputs+2−2
@@ -5,7 +5,7 @@ ApplicationTitle=Skrepka
55ApplicationVersion=1
66AppManifest=Platforms/MacCatalyst/Info.plist
77CompiledAppManifest=obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/AppManifest.plist
8−DefaultSdkVersion=26.2
8+DefaultSdkVersion=26.4
99FontFilesToRegister=
1010GenerateApplicationManifest=true
1111IsAppExtension=false
@@ -15,7 +15,7 @@ ProjectDir=/Users/iko/Developer/skrepka/client
1515ResourcePrefix=Platforms/MacCatalyst/Resources
1616ResourceRules=
1717SdkIsSimulator=False
18−SdkVersion=26.2
18+SdkVersion=26.4
1919SupportedOSPlatformVersion=26.2
2020TargetArchitectures=ARM64
2121TargetFrameworkMoniker=.NETCoreApp,Version=v10.0,Profile=maccatalyst
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/_BundleResourceWithLogicalName.itemsdeleted−13
@@ -1,13 +0,0 @@
1−<?xml version="1.0" encoding="utf-8"?>
2−<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3− <ItemGroup>
4− <_BundleResourceWithLogicalName Include="obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/Assets.car">
5− <Optimize>false</Optimize>
6− <LogicalName>Assets.car</LogicalName>
7− </_BundleResourceWithLogicalName>
8− <_BundleResourceWithLogicalName Include="obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/appicon.icns">
9− <Optimize>false</Optimize>
10− <LogicalName>appicon.icns</LogicalName>
11− </_BundleResourceWithLogicalName>
12− </ItemGroup>
13−</Project>
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/_PartialAppManifest.itemsdeleted−6
@@ -1,6 +0,0 @@
1−<?xml version="1.0" encoding="utf-8"?>
2−<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3− <ItemGroup>
4− <_PostCompilePartialAppManifest Include="obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/partial-info.plist" />
5− </ItemGroup>
6−</Project>
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/asset-manifest.plistdeleted−15
@@ -1,15 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3−<plist version="1.0">
4−<dict>
5− <key>com.apple.actool.compilation-results</key>
6− <dict>
7− <key>output-files</key>
8− <array>
9− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/Assets.car</string>
10− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/appicon.icns</string>
11− <string>/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/partial-info.plist</string>
12− </array>
13− </dict>
14−</dict>
15−</plist>
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/Assets.cardeleted

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/bundle/appicon.icnsdeleted

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/actool/partial-info.plistdeleted−10
@@ -1,10 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3−<plist version="1.0">
4−<dict>
5− <key>CFBundleIconFile</key>
6− <string>appicon</string>
7− <key>CFBundleIconName</key>
8− <string>appicon</string>
9−</dict>
10−</plist>
server.knot+46−43
@@ -87,6 +87,20 @@ impl ToJSON MessageStatus where
8787 MsUnauthorized {} -> "unauthorized"
8888 MsRejected {} -> "rejected")
8989
90+data DeliveryStatus = Delivered {} | Federated {} | Queued {}
91+
92+impl ToJSON DeliveryStatus where
93+ toJson ds = toJson (case ds of
94+ Delivered {} -> "delivered"
95+ Federated {} -> "federated"
96+ Queued {} -> "queued")
97+
98+deliveryToStatus : DeliveryStatus -> MessageStatus
99+deliveryToStatus = \ds -> case ds of
100+ Delivered {} -> MsDelivered {}
101+ Federated {} -> MsFederated {}
102+ Queued {} -> MsQueued {}
103+
90104isValidBoundedHex = \maxLen s -> isValidHex s && not (tooLong s maxLen) && s == normalizeHex s
91105type PubkeyHex = Text where isValidBoundedHex maxPubkeyLen
92106type BlobHex = Text where isValidBoundedHex maxBlobLen
@@ -108,12 +122,9 @@ type PresenceEntry = {pubkey: PubkeyHex, server: AnyServerName, expiresAt: Times
108122type ForwardEntry = {messageId: MessageIdHex, toServer: ServerName, createdAt: Timestamp, toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp}
109123type AckedEntry = {messageId: MessageIdHex, toKey: PubkeyHex, ackedAt: Timestamp, originServer: ServerName}
110124data AuthResult = Authorized {pubkey: PubkeyHex} | Unauthorized {}
111−data SendResult = SendUnauthorized {} | SendRejected {} | SendDone {status: MessageStatus, remoteServers: [ServerName], fromKey: PubkeyHex}
125+data SendResult = SendUnauthorized {} | SendRejected {} | SendDone {status: DeliveryStatus, remoteServers: [ServerName], fromKey: PubkeyHex}
112126data VerifyResult = VerifyFailed {} | VerifyOk {peerServers: [ServerName]}
113−data AckResult = AckUnauthorized {} | AckDone {pendingAcks: [AckedEntry], evictedEntries: [AckedEntry]}
114−data LookupResult = LookupUnauthorized {} | LookupDone {server: AnyServerName}
115−data ForwardResult = ForwardDuplicate {} | ForwardStored {} | ForwardFull {}
116−data PollResult = PollUnauthorized {} | PollDone {events: [PollEvent], cursor: Timestamp}
127+type PollResponse = {events: [PollEvent], cursor: Timestamp, authorized: Bool}
117128
118129
119130-- ============================================
@@ -714,7 +725,7 @@ pollOnce = \token cursor -> do
714725 let auth = authenticateSession sessions token t
715726 case auth of
716727 Unauthorized {} ->
717− yield PollUnauthorized {}
728+ yield {events: [], cursor: 0, authorized: False {}}
718729 Authorized {pubkey} -> do
719730 seqCounter <- *seqCounter
720731 messages <- *messages
@@ -731,20 +742,19 @@ pollOnce = \token cursor -> do
731742 encryptedBlob: m.encryptedBlob,
732743 timestamp: m.timestamp}}
733744 let lastReceivedAt = fold (\acc m -> max acc m.receivedAt) clampedCursor limitedMsgs
734− yield PollDone {events: evts, cursor: lastReceivedAt}
745+ yield {events: evts, cursor: lastReceivedAt, authorized: True {}}
735746
736−pollLoop : Text -> Int -> Int<Ms> -> IO {clock} PollResult
747+pollLoop : Text -> Int -> Int<Ms> -> IO {clock} PollResponse
737748pollLoop = \token cursor deadline -> do
738749 result <- pollOnce token cursor
739− case result of
740− PollUnauthorized {} -> yield result
741− PollDone {events} -> do
742− t <- now
743− if count events == 0 && t < deadline
744− then do
745− sleep (clamp 1 500 (deadline - t))
746− pollLoop token cursor deadline
747− else yield result
750+ if not result.authorized then yield result
751+ else do
752+ t <- now
753+ if count result.events == 0 && t < deadline
754+ then do
755+ sleep (clamp 1 500 (deadline - t))
756+ pollLoop token cursor deadline
757+ else yield result
748758
749759-- ============================================
750760-- Request Handler
@@ -817,9 +827,7 @@ serve = \req -> case req of
817827 result <- pollLoop token cursor deadline
818828 tAfterPoll <- now
819829 maybePruneAndBroadcast tAfterPoll
820− yield (respond (case result of
821− PollUnauthorized {} -> {events: [], cursor: 0, authorized: False {}}
822− PollDone r -> {events: r.events, cursor: r.cursor, authorized: True {}}))
830+ yield (respond result)
823831
824832 SendMessage {to, encryptedBlob, timestamp, authorization, respond} -> do
825833 t <- now
@@ -849,9 +857,9 @@ serve = \req -> case req of
849857 forwards <- *forwards
850858 let forwardServers = takeN remoteServers (maxForwardsEntries - count forwards)
851859 let shouldForward = federationEnabled && count forwardServers > 0
852− let status = if localOnline then MsDelivered {}
853− else if shouldForward then MsFederated {}
854− else MsQueued {}
860+ let status = if localOnline then Delivered {}
861+ else if shouldForward then Federated {}
862+ else Queued {}
855863 set *forwards = if shouldForward
856864 then union forwards (do s <- forwardServers; yield {messageId: msgId, toServer: s, createdAt: t, toKey: to, fromKey: fromKey, encryptedBlob: encryptedBlob, timestamp: clampedTs})
857865 else forwards
@@ -867,14 +875,14 @@ serve = \req -> case req of
867875 authorization: federationAuth})
868876 whenOk fwdResult (removeForward msgId server))
869877 case status of
870− MsQueued {} -> println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")
878+ Queued {} -> println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")
871879 _ -> yield {})
872880 _ -> yield {}
873881 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
874882 yield (case result.send of
875883 SendUnauthorized {} -> respond {status: MsUnauthorized {}, messageId: ""}
876884 SendRejected {} -> respond {status: MsRejected {}, messageId: ""}
877− SendDone {status} -> respond {status: status, messageId: msgId})
885+ SendDone {status} -> respond {status: deliveryToStatus status, messageId: msgId})
878886
879887 AckMessages {messageIds, authorization, respond} -> do
880888 t <- now
@@ -884,7 +892,7 @@ serve = \req -> case req of
884892 auth <- authenticateRequest authorization t
885893 case auth of
886894 Unauthorized {} ->
887− yield {pr: pr, ack: AckUnauthorized {}}
895+ yield {pr: pr, authorized: False {}, pendingAcks: [], evictedEntries: []}
888896 Authorized {pubkey} -> do
889897 messages <- *messages
890898 let ackedMessages = do
@@ -902,16 +910,13 @@ serve = \req -> case req of
902910 let evictedEntries = let excessCount = count combinedAckedIds - maxAckedIds in
903911 if excessCount <= 0 then [] else boundedSmallest combinedAckedIds excessCount (\a -> a.ackedAt)
904912 set *ackedIds = diff combinedAckedIds evictedEntries
905− yield {pr: pr, ack: AckDone {pendingAcks: ackedFederated, evictedEntries: evictedEntries}}
913+ yield {pr: pr, authorized: True {}, pendingAcks: ackedFederated, evictedEntries: evictedEntries}
906914 fork (do
907− case result.ack of
908− AckDone {pendingAcks, evictedEntries} ->
909− when federationEnabled (do
910− sendAcksAndClean pendingAcks
911− retryEvictedAcks evictedEntries pendingAcks)
912− _ -> yield {}
915+ when (result.authorized && federationEnabled) (do
916+ sendAcksAndClean result.pendingAcks
917+ retryEvictedAcks result.evictedEntries result.pendingAcks)
913918 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
914− yield (respond {ok: case result.ack of AckDone _ -> True {}; _ -> False {}})
919+ yield (respond {ok: result.authorized})
915920
916921 LookupPresence {pubkey, authorization, respond} -> do
917922 t <- now
@@ -920,7 +925,7 @@ serve = \req -> case req of
920925 auth <- authenticateRequest authorization t
921926 case auth of
922927 Unauthorized {} ->
923− yield {pr: pr, lookup: LookupUnauthorized {}}
928+ yield {pr: pr, server: "", authorized: False {}}
924929 Authorized _ -> do
925930 presence <- *presence
926931 let valid = do
@@ -933,11 +938,9 @@ serve = \req -> case req of
933938 if not (isLocalServer p.server) && dominated then Just {value: p} else acc) Nothing {} valid
934939 let foundServer = if localOnline then serverHostN
935940 else case bestRemote of Just {value: p} -> p.server; Nothing {} -> ""
936− yield {pr: pr, lookup: LookupDone {server: foundServer}}
941+ yield {pr: pr, server: foundServer, authorized: True {}}
937942 forkBroadcastOffline t result.pr
938− yield (case result.lookup of
939− LookupUnauthorized {} -> respond {server: "", authorized: False {}}
940− LookupDone {server} -> respond {server: server, authorized: True {}})
943+ yield (respond {server: result.server, authorized: result.authorized})
941944
942945 RecvGossip {events, hopsRemaining, fromServer, authorization, respond} -> do
943946 t <- now
@@ -999,9 +1002,9 @@ serve = \req -> case req of
9991002 messages <- *messages
10001003 ackedIds <- *ackedIds
10011004 if hasMessage messageId toKey messages || hasMessage messageId toKey ackedIds
1002− then yield {pr: pr, forward: ForwardDuplicate {}}
1005+ then yield {pr: pr, ok: True {}}
10031006 else if countMessagesFor messages toKey t >= maxMessagesPerRecipient
1004− then yield {pr: pr, forward: ForwardFull {}}
1007+ then yield {pr: pr, ok: False {}}
10051008 else do
10061009 seqCounter <- *seqCounter
10071010 let seqTs = nextSeqTs t seqCounter
@@ -1009,9 +1012,9 @@ serve = \req -> case req of
10091012 set *messages = union messages
10101013 [{messageId: messageId, toKey: toKey, fromKey: fromKey,
10111014 encryptedBlob: encryptedBlob, timestamp: clampedTs, origin: FederatedOrigin {server: originServer}, receivedAt: seqTs}]
1012− yield {pr: pr, forward: ForwardStored {}}
1015+ yield {pr: pr, ok: True {}}
10131016 forkBroadcastOffline t result.pr
1014− yield (respond {ok: case result.forward of ForwardFull {} -> False {}; _ -> True {}})
1017+ yield (respond {ok: result.ok})
10151018
10161019 FederationAck {messageIds, originServer, fromServer, authorization, respond} -> do
10171020 t <- now