@@ -305,9 +305,6 @@ type RateEntry = {key: Text, windowStart: Timestamp, count: Int}
305305*lastPresenceRefresh : Timestamp
306306-- Wall time of process start; gates /ready (must be ≤ lastPrunedAt).
307307*startedAt : Timestamp
308−-- Random 64-bit-ish identity stamped at startup. Clients echo it back on /poll;
309−-- any mismatch means the server restarted and the client must reset its cursor.
310−*serverGeneration : Int
311308
312309-- ============================================
313310-- Routes
@@ -326,7 +323,7 @@ route AuthApi where
326323 POST {pubkey: PubkeyHex, challenge: Text, signature: SignatureHex, revokeOthers: Bool} /auth/verify headers {clientIp: Text} -> {token: Text, expiresAt: Timestamp} = VerifyAuth
327324
328325route ClientApi where
329− POST {cursor: Timestamp, generation: Int} /poll headers {authorization: Text, clientIp: Text} -> {events: [PollEvent], cursor: Timestamp, generation: Int} = Poll
326+ POST {cursor: Timestamp} /poll headers {authorization: Text, clientIp: Text} -> {events: [PollEvent], cursor: Timestamp} = Poll
330327 POST {messages: [{to: PubkeyHex, encryptedBlob: BlobHex}]} /messages headers {authorization: Text, clientIp: Text} -> {} = SendMessages
331328
332329route FederationApi where
@@ -913,33 +910,26 @@ handleVerifyAuth = \pubkey challenge signature revokeOthers clientIp -> do
913910-- ============================================
914911-- Handler: poll
915912-- ============================================
916−-- Long-poll. The client supplies a cursor (last-seen `receivedAt`) and the
917−-- server's last-known `generation` (server identity for cursor validity). We:
918−-- * If the generation mismatches, reset the cursor and signal `cursorReset`.
913+-- Long-poll. The client supplies a cursor (last-seen `receivedAt`). We:
919914-- * Ack-and-drop everything <= the cursor (treating poll progress as ack).
920915-- * Wait on `pollWakeup` (bumped by send/heartbeat) and return new events
921916-- plus piggybacked sender-side expirations/deliveries.
922917
923−-- POST /poll: top-level dispatch. Validates the global rate gate, detects a
924−-- generation mismatch (server restart) to force a cursor reset, then hands
925−-- off to `pollOnce` for the actual long-poll body. Clients detect a server
926−-- restart by comparing the `generation` they sent to the one returned.
927−handlePoll : Int -> Int -> Text -> Text -> IO {r *pollWakeup, r *serverGeneration, r *sessions, rw *forwards, rw *globalRateCount, rw *globalRateWindowStart, rw *messages, clock} (Result HttpError {cursor: Timestamp, events: [PollEvent], generation: Int})
928−handlePoll = \cursor generation authorization clientIp -> do
918+-- POST /poll: top-level dispatch. Validates the global rate gate, then hands
919+-- off to `pollOnce` for the actual long-poll body.
920+handlePoll : Int -> Text -> Text -> IO {r *pollWakeup, r *sessions, rw *forwards, rw *globalRateCount, rw *globalRateWindowStart, rw *messages, clock} (Result HttpError {cursor: Timestamp, events: [PollEvent]})
921+handlePoll = \cursor authorization clientIp -> do
929922 t <- now
930− serverGen <- *serverGeneration
931923 g <- checkGlobalRate t
932924 if g
933925 then yield (Err {error: {status: 429, message: "rate_limited"}})
934− else do
935− let cursorWasReset = generation != serverGen && cursor > 0
936− pollOnce authorization (if cursorWasReset then 0 else cursor) clientIp serverGen t
926+ else pollOnce authorization cursor clientIp t
937927
938928-- Body of a single poll. Treats the cursor advance as an implicit ack
939929-- (`ackPolledMessages`), then runs `doPoll` to collect events (or block
940930-- until wakeup) and assembles the response.
941−pollOnce : Text -> Int -> Text -> Int -> Int<Ms> -> IO {r *pollWakeup, r *sessions, rw *forwards, rw *messages, clock} (Result HttpError {cursor: Timestamp, events: [PollEvent], generation: Int})
942−pollOnce = \authorization cursor clientIp serverGen t -> do
931+pollOnce : Text -> Int -> Text -> Int<Ms> -> IO {r *pollWakeup, r *sessions, rw *forwards, rw *messages, clock} (Result HttpError {cursor: Timestamp, events: [PollEvent]})
932+pollOnce = \authorization cursor clientIp t -> do
943933 setup <- atomic withSessionAuth authorization t clientIp (yield (Nothing {})) (\pubkey -> do
944934 let clampedCursor = clamp 0 t cursor
945935 when (clampedCursor > 0) (ackPolledMessages pubkey clampedCursor)
@@ -950,7 +940,7 @@ pollOnce = \authorization cursor clientIp serverGen t -> do
950940 Just {value: s} -> do
951941 pollResult <- doPoll s t
952942 yield (Ok {
953− value: {pollResult.events, pollResult.cursor, generation: serverGen}
943+ value: {pollResult.events, pollResult.cursor}
954944 })
955945
956946-- One pass: collect events at `t`. If empty, retry-wait on `pollWakeup`
@@ -1230,7 +1220,7 @@ api : Server Api _
12301220api = serve Api where
12311221 ReqChallenge = \{pubkey, clientIp} -> handleChallenge pubkey clientIp
12321222 VerifyAuth = \{pubkey, challenge, signature, revokeOthers, clientIp} -> handleVerifyAuth pubkey challenge signature revokeOthers clientIp
1233− Poll = \{cursor, generation, authorization, clientIp} -> handlePoll cursor generation authorization clientIp
1223+ Poll = \{cursor, authorization, clientIp} -> handlePoll cursor authorization clientIp
12341224 SendMessages = \{messages, authorization, clientIp} -> handleSendMessages messages authorization clientIp
12351225 RecvGossip = \{events, fromServer} -> handleRecvGossip events fromServer
12361226 ForwardMessage = \{toKey, encryptedBlob, fromServer} -> handleForwardMessage toKey encryptedBlob fromServer
@@ -1265,17 +1255,14 @@ pollHeartbeat = do
12651255-- ============================================
12661256-- Entry Point
12671257-- ============================================
1268−-- Stamp `startedAt` and a fresh `serverGeneration` (used by clients to detect
1269−-- server restarts and reset their poll cursor), spawn the two background
1270−-- loops, and start the listener.
1258+-- Stamp `startedAt`, spawn the two background loops, and start the listener.
12711259
12721260-- Entry point: stamp startup metadata, fork the background loops, and start
12731261-- the HTTP listener.
12741262main : IO _ {}
12751263main = do
12761264 t <- now
1277− genJitter <- randomInt 1000000
1278− atomic (do *startedAt = t; *serverGeneration = t * 1000 + genJitter)
1265+ atomic (do *startedAt = t)
12791266 logInfo ("Skrepka relay server starting on " ++ bindHost ++ ":" ++ show listenPort ++ " ...")
12801267 logInfo (" federation: " ++ (if federationEnabled then "enabled" else "disabled"))
12811268 fork backgroundPrune