@@ -40,9 +40,9 @@ maxForwardRetriesPerServer = 100
4040-- Types
4141-- ============================================
4242
43−type PollEvent = {id: Text, eventType: Text, payload: {encryptedBlob: Text, fromKey: Text, timestamp: Int, toKey: Text}}
43+type PollEvent = {id: Text, eventType: Text, payload: {encryptedBlob: Text, fromKey: Text, timestamp: Timestamp, toKey: Text}}
4444
45−type GossipEvent = {eventType: Text, pubkey: Text, server: Text, timestamp: Int, ttl: Int}
45+type GossipEvent = {eventType: Text, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
4646
4747type PubkeyHex = Text where \s -> isValidHex s && not (tooLong s maxPubkeyLen)
4848type BlobHex = Text where \s -> isValidHex s && not (tooLong s maxBlobLen)
@@ -50,6 +50,8 @@ type SignatureHex = Text where \s -> isValidHex s && not (tooLong s maxSignature
5050type MessageIdHex = Text where \s -> isValidHex s && not (tooLong s maxMessageIdLen)
5151type ServerName = Text where \s -> not (tooLong s maxServerNameLen) && not (isBadServerName s)
5252
53+type Timestamp = Int<Ms>
54+
5355-- ============================================
5456-- Persisted State
5557-- ============================================
@@ -58,13 +60,13 @@ type ServerName = Text where \s -> not (tooLong s maxServerNameLen) && not (isBa
5860
5961*sessions : [{token: Text, pubkey: Text, expiresAt: Int}]
6062
61−*messages : [{messageId: Text, toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Int, originServer: Text, receivedAt: Int}]
63+*messages : [{messageId: Text, toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Timestamp, originServer: Text, receivedAt: Int}]
6264
63−*presence : [{pubkey: Text, server: Text, expiresAt: Int, timestamp: Int}]
65+*presence : [{pubkey: Text, server: Text, expiresAt: Int, timestamp: Timestamp}]
6466
6567*seqCounter : Int
6668
67−*forwards : [{messageId: Text, toServer: Text, createdAt: Int, toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Int}]
69+*forwards : [{messageId: Text, toServer: Text, createdAt: Int, toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Timestamp}]
6870
6971*ackedIds : [{messageId: Text, toKey: Text, ackedAt: Int, originServer: Text}]
7072
@@ -88,7 +90,7 @@ route ClientApi where
8890 -> {events: [PollEvent], cursor: Int, authorized: Bool}
8991 = Poll
9092 /messages
91− POST {to: PubkeyHex, encryptedBlob: BlobHex, timestamp: Int} / headers {authorization: Text}
93+ POST {to: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp} / headers {authorization: Text}
9294 -> {status: Text, messageId: Text}
9395 = SendMessage
9496 POST {messageIds: [MessageIdHex]} /ack headers {authorization: Text}
@@ -103,7 +105,7 @@ route FederationApi where
103105 POST {events: [GossipEvent], hopsRemaining: Int, fromServer: ServerName} /gossip headers {authorization: Text}
104106 -> {ok: Bool}
105107 = RecvGossip
106− POST {toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Int, originServer: ServerName, messageId: MessageIdHex} /forward headers {authorization: Text}
108+ POST {toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp, originServer: ServerName, messageId: MessageIdHex} /forward headers {authorization: Text}
107109 -> {ok: Bool}
108110 = ForwardMessage
109111 POST {messageIds: [Text], originServer: Text, fromServer: ServerName} /ack headers {authorization: Text}
@@ -121,6 +123,9 @@ route Api = AuthApi | ClientApi | FederationApi | MaintenanceApi
121123-- Helpers
122124-- ============================================
123125
126+msToS : Int<Ms> -> Int<S>
127+msToS = \x -> x / 1000
128+
124129hexDigit = \n ->
125130 let n = if n < 0 then 0 else if n > 15 then 15 else n in
126131 if n == 0 then "0" else if n == 1 then "1" else if n == 2 then "2" else if n == 3 then "3"
@@ -414,14 +419,12 @@ sendToEach = \servers action ->
414419 sendToEach rest action
415420
416421pruneExpired = \t -> do
417− challenges <- *challenges
418422 set *challenges = do
419− c <- challenges
423+ c <- *challenges
420424 where c.expiresAt > t
421425 yield c
422− sessions <- *sessions
423426 set *sessions = do
424− s <- sessions
427+ s <- *sessions
425428 where s.expiresAt > t
426429 yield s
427430 presenceBefore <- *presence
@@ -434,19 +437,16 @@ pruneExpired = \t -> do
434437 where p.expiresAt > t
435438 yield p
436439 set *presence = presenceAfter
437− messages <- *messages
438440 set *messages = do
439− m <- messages
441+ m <- *messages
440442 where m.receivedAt >= t - messageMaxAge
441443 yield m
442− forwards <- *forwards
443444 set *forwards = do
444− f <- forwards
445+ f <- *forwards
445446 where f.createdAt >= t - messageMaxAge
446447 yield f
447− ackedIds <- *ackedIds
448448 set *ackedIds = do
449− a <- ackedIds
449+ a <- *ackedIds
450450 where a.ackedAt >= t - messageMaxAge
451451 yield a
452452 yield {expiredLocal: (do
@@ -468,7 +468,7 @@ maybePrune = \t -> do
468468 set *lastPrunedAt = t
469469 pruneExpired t
470470
471−sendBatchedGossipToServer : Text -> [{eventType: Text, pubkey: Text, server: Text, timestamp: Int, ttl: Int}] -> IO {network} {}
471+sendBatchedGossipToServer : Text -> [{eventType: Text, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int}] -> IO {network} {}
472472sendBatchedGossipToServer = \server allEvents ->
473473 if count allEvents == 0
474474 then yield {}
@@ -485,7 +485,7 @@ sendBatchedGossipToServer = \server allEvents ->
485485 Err _ -> yield {}
486486 sendBatchedGossipToServer server rest
487487
488−sendBatchedGossip : [Text] -> [{eventType: Text, pubkey: Text, server: Text, timestamp: Int, ttl: Int}] -> IO {network} {}
488+sendBatchedGossip : [Text] -> [{eventType: Text, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int}] -> IO {network} {}
489489sendBatchedGossip = \peerServers allEvents ->
490490 if count allEvents == 0
491491 then yield {}
@@ -506,7 +506,7 @@ broadcastOfflineGossip = \t peerServers expiredLocal -> do
506506 sendBatchedGossip peerServers gossipEvents
507507 else yield {}
508508
509−retryForwardsForServer : [{encryptedBlob: Text, fromKey: Text, messageId: Text, timestamp: Int, toKey: Text, toServer: Text}] -> Int -> IO {network} {}
509+retryForwardsForServer : [{encryptedBlob: Text, fromKey: Text, messageId: Text, timestamp: Timestamp, toKey: Text, toServer: Text}] -> Int -> IO {network} {}
510510retryForwardsForServer = \entries remaining ->
511511 if count entries == 0 || remaining <= 0
512512 then yield {}
@@ -532,7 +532,7 @@ retryForwardsForServer = \entries remaining ->
532532 Err _ -> yield {}
533533 retryForwardsForServer rest (remaining - 1)
534534
535−retryPendingForwards : [{encryptedBlob: Text, fromKey: Text, messageId: Text, timestamp: Int, toKey: Text, toServer: Text}] -> IO {network} {}
535+retryPendingForwards : [{encryptedBlob: Text, fromKey: Text, messageId: Text, timestamp: Timestamp, toKey: Text, toServer: Text}] -> IO {network} {}
536536retryPendingForwards = \pending -> do
537537 let servers = fold (\acc x ->
538538 if count (do s <- acc; where s == x.toServer; yield s) > 0 then acc
@@ -636,7 +636,7 @@ pollLoop = \token cursor deadline -> do
636636 if result.authorized && count result.events == 0 && t < deadline
637637 then do
638638 let remaining = deadline - t
639− let sleepMs = if remaining > 500 then 500 else remaining
639+ let sleepMs = if remaining > 500 then 500<Ms> else remaining
640640 sleep sleepMs
641641 pollLoop token cursor deadline
642642 else yield result