@@ -309,7 +309,6 @@ route ClientApi where
309route FederationApi where
309route FederationApi where
310 POST {events: [GossipEventType], fromServer: ServerName} /federation/gossip -> {} = RecvGossip
310 POST {events: [GossipEventType], fromServer: ServerName} /federation/gossip -> {} = RecvGossip
311 POST {toKey: PubkeyHex, encryptedBlob: BlobHex} /federation/forward -> {} = ForwardMessage
311 POST {toKey: PubkeyHex, encryptedBlob: BlobHex} /federation/forward -> {} = ForwardMessage
312− POST {forwards: [{toKey: PubkeyHex, encryptedBlob: BlobHex}]} /federation/forward-batch -> {results: [{ok: Bool}]} = FederationBatchForward
314route Api = AuthApi | ClientApi | FederationApi
313route Api = AuthApi | ClientApi | FederationApi
@@ -1108,29 +1107,24 @@ handleRecvGossip = \events fromServer -> do
1108 yield (Ok {value: {}})
1107 yield (Ok {value: {}})
1110-- Store a federated/forwarded message into the local mailbox. Caller wraps in `atomic`.
1109-- Store a federated/forwarded message into the local mailbox. Caller wraps in `atomic`.
1111−-- Returns "" on success, otherwise an error code:
1110+-- Returns "" on success, otherwise an error code: "no_presence" | "rate_limited".
1112−-- "no_presence" | "rate_limited" (only when checkRecvRate).
1114-- The presence gate requires the recipient to be **currently locally online**
1112-- The presence gate requires the recipient to be **currently locally online**
1115-- (not just visible to gossip somewhere). Without that, an A → B forward based
1113-- (not just visible to gossip somewhere). Without that, an A → B forward based
1116-- on stale gossip about R could land on B with no actively-polling client and
1114-- on stale gossip about R could land on B with no actively-polling client and
1117-- get stuck. If B refuses, A retries via `retryPendingForwards` against the
1115-- get stuck. If B refuses, A retries via `retryPendingForwards` against the
1118-- next presence target.
1116-- next presence target.
1119−storeFederated : PubkeyHex -> BlobHex -> Bool -> Int<Ms> -> IO {rw *messages, rw *pollWakeup, r *presence, rw *recvRates, rw *seqCounter} Text
1117+storeFederated : PubkeyHex -> BlobHex -> Int<Ms> -> IO {rw *messages, rw *pollWakeup, r *presence, rw *recvRates, rw *seqCounter} Text
1120−storeFederated = \toKey encryptedBlob checkRecvRate t -> do
1118+storeFederated = \toKey encryptedBlob t -> do
1121 pres <- *presence
1119 pres <- *presence
1122 msgs <- *messages
1120 msgs <- *messages
1123 if not any pres (\p -> p.pubkey == toKey && isLocalServer p.server && p.expiresAt > t)
1121 if not any pres (\p -> p.pubkey == toKey && isLocalServer p.server && p.expiresAt > t)
1124 then yield "no_presence"
1122 then yield "no_presence"
1126− limited <- if checkRecvRate
1128− rRates <- *recvRates
1124+ rRates <- *recvRates
1129− let r = checkRate rRates toKey maxRecvRatePerKey recvRateWindowMs t
1125+ let r = checkRate rRates toKey maxRecvRatePerKey recvRateWindowMs t
1130− *recvRates = r.entries
1126+ *recvRates = r.entries
1132− else yield (False {})
1133− if limited
1127+ if r.limited
1134 then yield "rate_limited"
1128 then yield "rate_limited"
1136 seq <- *seqCounter
1130 seq <- *seqCounter
@@ -1146,24 +1140,11 @@ storeFederated = \toKey encryptedBlob checkRecvRate t -> do
1146handleForwardMessage : PubkeyHex -> BlobHex -> IO {rw *messages, rw *pollWakeup, r *presence, rw *recvRates, rw *seqCounter, clock} (Result HttpError {})
1140handleForwardMessage : PubkeyHex -> BlobHex -> IO {rw *messages, rw *pollWakeup, r *presence, rw *recvRates, rw *seqCounter, clock} (Result HttpError {})
1147handleForwardMessage = \toKey encryptedBlob -> do
1141handleForwardMessage = \toKey encryptedBlob -> do
1148 t <- now
1142 t <- now
1149− result <- atomic storeFederated toKey encryptedBlob (True {}) t
1143+ result <- atomic storeFederated toKey encryptedBlob t
1150 if result == ""
1144 if result == ""
1151 then yield (Ok {value: {}})
1145 then yield (Ok {value: {}})
1152 else yield (Err {error: {status: if result == "no_presence" then 404 else 429, message: result}})
1146 else yield (Err {error: {status: if result == "no_presence" then 404 else 429, message: result}})
1154−-- POST /federation/forward-batch: bulk variant of `handleForwardMessage`.
1155−-- Skips per-entry recv-rate charging.
1156−handleFederationBatchForward : [{encryptedBlob: BlobHex, toKey: PubkeyHex | a}] -> IO {clock} (Result HttpError {results: [{ok: Bool}]})
1157−handleFederationBatchForward = \forwards -> do
1159− if count forwards > maxBatchSize
1160− then yield (Err {error: {status: 400, message: "invalid_request"}})
1162− results <- mapEach (takeRelation maxBatchSize forwards) (\e -> do
1163− result <- atomic storeFederated e.toKey e.encryptedBlob (False {}) t
1164− yield {ok: result == ""})
1165− yield (Ok {value: {results}})
1167-- ============================================
1148-- ============================================
1168-- Dispatch
1149-- Dispatch
1169-- ============================================
1150-- ============================================
@@ -1181,7 +1162,6 @@ api = serve Api where
1181 SendMessages = \{messages, authorization, xForwardedFor} -> handleSendMessages messages authorization (clientIpOf xForwardedFor)
1162 SendMessages = \{messages, authorization, xForwardedFor} -> handleSendMessages messages authorization (clientIpOf xForwardedFor)
1182 RecvGossip = \{events, fromServer} -> handleRecvGossip events fromServer
1163 RecvGossip = \{events, fromServer} -> handleRecvGossip events fromServer
1183 ForwardMessage = \{toKey, encryptedBlob} -> handleForwardMessage toKey encryptedBlob
1164 ForwardMessage = \{toKey, encryptedBlob} -> handleForwardMessage toKey encryptedBlob
1184− FederationBatchForward = \{forwards} -> handleFederationBatchForward forwards
1186-- ============================================
1166-- ============================================
1187-- Background loops
1167-- Background loops