@@ -76,7 +76,7 @@ route AuthApi where
7676 = VerifyAuth
7777
7878route ClientApi where
79− GET {cursor: Int} /poll headers {authorization: Text}
79+ GET {cursor: Int, timeout: Int} /poll headers {authorization: Text}
8080 -> {events: [PollEvent], cursor: Int, authorized: Bool}
8181 = Poll
8282 /messages
@@ -524,12 +524,12 @@ serve = \req -> case req of
524524 else if not (isValidHex pubkey) || not (isValidHex signature)
525525 then False {}
526526 else verify (bytesFromHex pubkey) (textToBytes challenge) (bytesFromHex signature)
527− set *challenges = if sigValid
528− then do
527+ set *challenges = case matched of
528+ Just {value: _} -> do
529529 c <- challenges
530530 where not (c.pubkey == pubkey && c.challenge == challenge)
531531 yield c
532− else challenges
532+ Nothing {} -> challenges
533533 let existingForKey = do
534534 s <- sessions
535535 where s.pubkey == pubkey
@@ -591,43 +591,49 @@ serve = \req -> case req of
591591 where not (p.pubkey == pubkey)
592592 yield p)
593593
594− Poll {cursor, authorization, respond} -> do
594+ Poll {cursor, timeout, authorization, respond} -> do
595595 t <- now
596+ let clampedTimeout = if timeout < 0 then 0 else if timeout > 60000 then 60000 else timeout
597+ let deadline = t + clampedTimeout
596598 let token = extractToken authorization
597599 result <- atomic do
598− pr <- maybePrune t
600+ tNow <- now
601+ pr <- maybePrune tNow
599602 sessions <- *sessions
600603 messages <- *messages
601604 seqCounter <- *seqCounter
602− let session = lookupSession sessions token t
605+ let session = lookupSession sessions token tNow
603606 let clampedCursor = if cursor < 0 then 0 else if cursor > seqCounter then seqCounter else cursor
604607 let matchingMsgs = case session of
605608 Nothing {} -> []
606609 Just {value: s} -> do
607610 m <- messages
608611 where m.toKey == s.pubkey
609− where m.receivedAt >= t - messageMaxAge
612+ where m.receivedAt >= tNow - messageMaxAge
610613 where m.receivedAt > clampedCursor
611614 yield m
612615 let limitedMsgs = fold (\acc m ->
613616 if count acc >= maxPollEvents then acc
614617 else union acc [m]) [] matchingMsgs
615− let evts = do
616− m <- limitedMsgs
617− yield {id: m.messageId, eventType: "message",
618− payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
619− encryptedBlob: m.encryptedBlob,
620− timestamp: m.timestamp}}
621− let lastReceivedAt = fold (\acc m -> if m.receivedAt > acc then m.receivedAt else acc) clampedCursor limitedMsgs
622618 let authorized = case session of
623619 Nothing {} -> False {}
624620 _ -> True {}
625− let newCursor = case session of
626− Nothing {} -> -1
627− _ -> if count limitedMsgs >= maxPollEvents
628− then lastReceivedAt
629− else if seqCounter > clampedCursor then seqCounter else clampedCursor
630− yield {events: evts, cursor: newCursor, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
621+ if authorized && count limitedMsgs == 0 && tNow < deadline
622+ then retry
623+ else do
624+ let evts = do
625+ m <- limitedMsgs
626+ yield {id: m.messageId, eventType: "message",
627+ payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
628+ encryptedBlob: m.encryptedBlob,
629+ timestamp: m.timestamp}}
630+ let lastReceivedAt = fold (\acc m -> if m.receivedAt > acc then m.receivedAt else acc) clampedCursor limitedMsgs
631+ let newCursor = case session of
632+ Nothing {} -> -1
633+ _ -> if count limitedMsgs >= maxPollEvents
634+ then lastReceivedAt
635+ else if seqCounter > clampedCursor then seqCounter else clampedCursor
636+ yield {events: evts, cursor: newCursor, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
631637 respond {events: result.events, cursor: result.cursor, authorized: result.authorized}
632638 broadcastOfflineGossip t result.peerServers result.expiredLocal
633639
@@ -709,8 +715,7 @@ serve = \req -> case req of
709715
710716 AckMessages {messageIds, authorization, respond} -> do
711717 t <- now
712− let dedupedIds = if count messageIds > maxMessageIds then []
713− else fold (\acc mid ->
718+ let dedupedIds = fold (\acc mid ->
714719 if mid == "" then acc
715720 else if count acc >= maxMessageIds then acc
716721 else if tooLong mid maxMessageIdLen then acc
@@ -1019,6 +1024,12 @@ serve = \req -> case req of
10191024 where o.server == normalizeServerName e.server
10201025 where o.timestamp > e.timestamp
10211026 yield o) > 0)
1027+ where not (e.eventType == "offline" && count (do
1028+ o <- onlineEntries
1029+ where o.pubkey == normalizeHex e.pubkey
1030+ where o.server == normalizeServerName e.server
1031+ where o.timestamp > e.timestamp
1032+ yield o) > 0)
10221033 yield e
10231034 let effectiveEvents = do
10241035 e <- validEvents
@@ -1030,12 +1041,9 @@ serve = \req -> case req of
10301041 else yield {}
10311042 if validRequest && cappedHops > 1 && not (federationSecret == "") && count effectiveEvents > 0
10321043 then do
1033− let senderServers = fold (\acc e ->
1034− if count (do a <- acc; where a == e.server; yield a) > 0 then acc
1035− else union acc [e.server]) (if fromServer == "" then [] else [fromServer]) effectiveEvents
10361044 let targets = do
10371045 s <- gossipResult.gossipPeerServers
1038− where count (do ss <- senderServers; where ss == s; yield ss) == 0
1046+ where not (s == fromServer)
10391047 yield s
10401048 sendToEach targets (\server ->
10411049 fetch (federationScheme ++ server) (RecvGossip {
@@ -1094,8 +1102,7 @@ serve = \req -> case req of
10941102 let originServer = normalizeServerName originServer
10951103 t <- now
10961104 let authorized = verifyFederationAuth authorization
1097− let dedupedIds = if count messageIds > maxMessageIds then []
1098− else fold (\acc mid ->
1105+ let dedupedIds = fold (\acc mid ->
10991106 if mid == "" then acc
11001107 else if count acc >= maxMessageIds then acc
11011108 else if tooLong mid maxMessageIdLen then acc