@@ -87,6 +87,8 @@ impl ToJSON MessageStatus where
8787 MsUnauthorized {} -> "unauthorized"
8888 MsRejected {} -> "rejected")
8989
90+data DeliveryStatus = DsDelivered {} | DsFederated {} | DsQueued {}
91+
9092isValidBoundedHex = \maxLen s -> isValidHex s && not (tooLong s maxLen) && s == normalizeHex s
9193type PubkeyHex = Text where isValidBoundedHex maxPubkeyLen
9294type BlobHex = Text where isValidBoundedHex maxBlobLen
@@ -108,10 +110,9 @@ type PresenceEntry = {pubkey: PubkeyHex, server: AnyServerName, expiresAt: Times
108110type ForwardEntry = {messageId: MessageIdHex, toServer: ServerName, createdAt: Timestamp, toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp}
109111type AckedEntry = {messageId: MessageIdHex, toKey: PubkeyHex, ackedAt: Timestamp, originServer: ServerName}
110112data AuthResult = Authorized {pubkey: PubkeyHex} | Unauthorized {}
111−data SendResult = SendUnauthorized {} | SendRejected {} | SendDone {status: MessageStatus, remoteServers: [ServerName], fromKey: PubkeyHex}
113+data SendResult = SendFailed {status: MessageStatus} | SendDone {delivery: DeliveryStatus, remoteServers: [ServerName], fromKey: PubkeyHex}
112114data VerifyResult = VerifyFailed {} | VerifyOk {peerServers: [ServerName]}
113115data AckResult = AckUnauthorized {} | AckDone {pendingAcks: [AckedEntry], evictedEntries: [AckedEntry]}
114−data LookupResult = LookupUnauthorized {} | LookupDone {server: AnyServerName}
115116type PollResponse = {events: [PollEvent], cursor: Timestamp, authorized: Bool}
116117
117118
@@ -375,6 +376,11 @@ clampTtl = clamp 1 maxPresenceTtl
375376
376377clampTimestamp = \timestamp t -> clamp (t - messageMaxAge) t timestamp
377378
379+deliveryToMessageStatus = \ds -> case ds of
380+ DsDelivered {} -> MsDelivered {}
381+ DsFederated {} -> MsFederated {}
382+ DsQueued {} -> MsQueued {}
383+
378384nextSeqTs = \t seqCounter -> if t > seqCounter then t else seqCounter + 1
379385
380386takeN = \items n -> (fold (\acc e -> if acc.n >= n then acc else {n: acc.n + 1, items: union acc.items [e]}) {n: 0, items: []} items).items
@@ -518,10 +524,11 @@ validGossipEvents = \events t ->
518524 then [{pubkey: e.pubkey, server: e.server, expiresAt: expiresAt, timestamp: e.timestamp, ttl: ttl}]
519525 else []
520526 else []
521− in {
522− online: do e <- events; case e.eventType of GossipOnline {} -> validate e; _ -> [],
523− offline: do e <- events; case e.eventType of GossipOffline {} -> validate e; _ -> []
524− }
527+ in fold (\acc e ->
528+ case e.eventType of
529+ GossipOnline {} -> {online: union acc.online (validate e), offline: acc.offline}
530+ GossipOffline {} -> {online: acc.online, offline: union acc.offline (validate e)}
531+ _ -> acc) {online: [], offline: []} events
525532
526533sendToEach : [ServerName] -> (ServerName -> (a {})) -> a {}
527534sendToEach = \servers action ->
@@ -831,11 +838,11 @@ serve = \req -> case req of
831838 auth <- authenticateRequest authorization t
832839 case auth of
833840 Unauthorized {} ->
834− yield {pr: pr, send: SendUnauthorized {}}
841+ yield {pr: pr, send: SendFailed {status: MsUnauthorized {}}}
835842 Authorized {pubkey: fromKey} -> do
836843 messages <- *messages
837844 if countMessagesFor messages to t >= maxMessagesPerRecipient
838− then yield {pr: pr, send: SendRejected {}}
845+ then yield {pr: pr, send: SendFailed {status: MsRejected {}}}
839846 else do
840847 presence <- *presence
841848 seqCounter <- *seqCounter
@@ -850,15 +857,15 @@ serve = \req -> case req of
850857 forwards <- *forwards
851858 let forwardServers = takeN remoteServers (maxForwardsEntries - count forwards)
852859 let shouldForward = federationEnabled && count forwardServers > 0
853− let status = if localOnline then MsDelivered {}
854− else if shouldForward then MsFederated {}
855− else MsQueued {}
860+ let delivery = if localOnline then DsDelivered {}
861+ else if shouldForward then DsFederated {}
862+ else DsQueued {}
856863 set *forwards = if shouldForward
857864 then union forwards (do s <- forwardServers; yield {messageId: msgId, toServer: s, createdAt: t, toKey: to, fromKey: fromKey, encryptedBlob: encryptedBlob, timestamp: clampedTs})
858865 else forwards
859− yield {pr: pr, send: SendDone {status: status, remoteServers: remoteServers, fromKey: fromKey}}
866+ yield {pr: pr, send: SendDone {delivery: delivery, remoteServers: remoteServers, fromKey: fromKey}}
860867 case result.send of
861− SendDone {status, remoteServers, fromKey} ->
868+ SendDone {delivery, remoteServers, fromKey} ->
862869 fork (do
863870 when (count remoteServers > 0 && federationEnabled) (do
864871 sendToEach remoteServers (\server -> do
@@ -867,15 +874,14 @@ serve = \req -> case req of
867874 timestamp: clampedTs, originServer: serverHostN, messageId: msgId,
868875 authorization: federationAuth})
869876 whenOk fwdResult (removeForward msgId server))
870− case status of
871− MsQueued {} -> println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")
877+ case delivery of
878+ DsQueued {} -> println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")
872879 _ -> yield {})
873880 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
874881 _ -> forkBroadcastOffline t result.pr
875882 yield (case result.send of
876− SendUnauthorized {} -> respond {status: MsUnauthorized {}, messageId: ""}
877− SendRejected {} -> respond {status: MsRejected {}, messageId: ""}
878− SendDone {status} -> respond {status: status, messageId: msgId})
883+ SendFailed {status} -> respond {status: status, messageId: ""}
884+ SendDone {delivery} -> respond {status: deliveryToMessageStatus delivery, messageId: msgId})
879885
880886 AckMessages {messageIds, authorization, respond} -> do
881887 t <- now
@@ -921,7 +927,7 @@ serve = \req -> case req of
921927 auth <- authenticateRequest authorization t
922928 case auth of
923929 Unauthorized {} ->
924− yield {pr: pr, lookup: LookupUnauthorized {}}
930+ yield {pr: pr, server: "", authorized: False {}}
925931 Authorized _ -> do
926932 presence <- *presence
927933 let valid = do
@@ -929,16 +935,15 @@ serve = \req -> case req of
929935 where p.pubkey == pubkey && p.expiresAt > t
930936 yield p
931937 let localOnline = any valid (\p -> isLocalServer p.server)
932− let bestRemote = fold (\acc p ->
933− let dominated = case acc of Nothing {} -> True {}; Just {value: v} -> p.expiresAt > v.expiresAt in
934− if not (isLocalServer p.server) && dominated then Just {value: p} else acc) Nothing {} valid
938+ let remoteValid = do p <- valid; where not (isLocalServer p.server); yield p
939+ let bestRemote = fold (\acc p -> case acc of
940+ Nothing {} -> Just {value: p}
941+ Just {value: v} -> if p.expiresAt > v.expiresAt then Just {value: p} else acc) Nothing {} remoteValid
935942 let foundServer = if localOnline then serverHostN
936943 else case bestRemote of Just {value: p} -> p.server; Nothing {} -> ""
937− yield {pr: pr, lookup: LookupDone {server: foundServer}}
944+ yield {pr: pr, server: foundServer, authorized: True {}}
938945 forkBroadcastOffline t result.pr
939− yield (case result.lookup of
940− LookupUnauthorized {} -> respond {server: "", authorized: False {}}
941− LookupDone {server} -> respond {server: server, authorized: True {}})
946+ yield (respond {server: result.server, authorized: result.authorized})
942947
943948 RecvGossip {events, hopsRemaining, fromServer, authorization, respond} -> do
944949 t <- now