on master help sign in
Simplify server.knot: remove workarounds for fixed Knot compiler issues
df3fc05iko
server.knot+15−30
@@ -203,7 +203,7 @@ type PollEvent = {encryptedBlob: BlobHex}
203-- kind still parses. `handleRecvGossip` ignores any event whose `eventType` it
203-- kind still parses. `handleRecvGossip` ignores any event whose `eventType` it
204-- doesn't recognize or that carries no pubkey — that is the forward-compat
204-- doesn't recognize or that carries no pubkey — that is the forward-compat
205-- fallback (the old `GossipUnknown` variant).
205-- fallback (the old `GossipUnknown` variant).
206−type GossipEvent = {eventType: Text, pubkey: Maybe PubkeyHex}
206+type GossipEvent = {eventType: Text, pubkey: Maybe Text}
207
207
208-- /messages is all-or-nothing per call: either every message in the batch is
208-- /messages is all-or-nothing per call: either every message in the batch is
209-- enqueued (delivered, federated, or buffered for federation), or none are
209-- enqueued (delivered, federated, or buffered for federation), or none are
@@ -239,9 +239,9 @@ type ServerName = Text where isValidServerName
239type Timestamp = Int<Ms>
239type Timestamp = Int<Ms>
240
240
241-- Outstanding nonce issued by /auth/challenge; consumed by /auth/verify.
241-- Outstanding nonce issued by /auth/challenge; consumed by /auth/verify.
242−type Challenge = {pubkey: PubkeyHex, challenge: Text, expiresAt: Timestamp, ip: Text}
242+type Challenge = {pubkey: Text, challenge: Text, expiresAt: Timestamp, ip: Text}
243-- An issued bearer token bound to (pubkey, ip, expiry).
243-- An issued bearer token bound to (pubkey, ip, expiry).
244−type Session = {token: Text, pubkey: PubkeyHex, expiresAt: Timestamp, ip: Text}
244+type Session = {token: Text, pubkey: Text, expiresAt: Timestamp, ip: Text}
245-- Mailbox row: a stored message awaiting recipient pickup or federation forward.
245-- Mailbox row: a stored message awaiting recipient pickup or federation forward.
246-- Storage TTL is fixed at `messageMaxAge`, so expiry is derived from
246-- Storage TTL is fixed at `messageMaxAge`, so expiry is derived from
247-- `receivedAt`. Any send time the sender wants to convey lives inside
247-- `receivedAt`. Any send time the sender wants to convey lives inside
@@ -250,14 +250,14 @@ type Session = {token: Text, pubkey: PubkeyHex, expiresAt: Timestamp, ip: Text}
250-- presence re-announce of `toKey` doesn't trigger a duplicate delivery.
250-- presence re-announce of `toKey` doesn't trigger a duplicate delivery.
251-- (Single-field record rows, not bare names: the Knot runtime cannot persist
251-- (Single-field record rows, not bare names: the Knot runtime cannot persist
252-- a nested relation of scalars.)
252-- a nested relation of scalars.)
253−type Message = {toKey: PubkeyHex, encryptedBlob: BlobHex, receivedAt: Timestamp, deliveredTo: [{server: ServerName}]}
253+type Message = {toKey: Text, encryptedBlob: BlobHex, receivedAt: Timestamp, deliveredTo: [{server: Text}]}
254-- Last-known location of a pubkey, either local (`server == serverHost`) or
254-- Last-known location of a pubkey, either local (`server == serverHost`) or
255-- learned from a peer via gossip. Multiple entries per pubkey are allowed.
255-- learned from a peer via gossip. Multiple entries per pubkey are allowed.
256−type PresenceEntry = {pubkey: PubkeyHex, server: ServerName, expiresAt: Timestamp}
256+type PresenceEntry = {pubkey: Text, server: Text, expiresAt: Timestamp}
257-- A message queued for cross-server delivery to `toServer`. `retries` is
257-- A message queued for cross-server delivery to `toServer`. `retries` is
258-- incremented by `retryPendingForwards` until `maxForwardRetries` is hit.
258-- incremented by `retryPendingForwards` until `maxForwardRetries` is hit.
259-- Identity is derived from `encryptedBlob` (see `Message`).
259-- Identity is derived from `encryptedBlob` (see `Message`).
260−type ForwardEntry = {toServer: ServerName, toKey: PubkeyHex, encryptedBlob: BlobHex, retries: Int}
260+type ForwardEntry = {toServer: Text, toKey: Text, encryptedBlob: BlobHex, retries: Int}
261-- Running failure counter for a peer; keyed by `server`. Drives `shouldRetryServer`.
261-- Running failure counter for a peer; keyed by `server`. Drives `shouldRetryServer`.
262-- `failedAt` is the start time of the last recorded attempt; `failures: 0` is
262-- `failedAt` is the start time of the last recorded attempt; `failures: 0` is
263-- the post-success tombstone (no backoff, kept so the timestamp can outrank
263-- the post-success tombstone (no backoff, kept so the timestamp can outrank
@@ -411,20 +411,6 @@ stripTrailingDot = \s -> if hasSuffix "." s
411then stripTrailingDot (take (length s - 1) s)
411then stripTrailingDot (take (length s - 1) s)
412else s
412else s
413
413
414−-- Compare two Text values for equality. Works around the refined-type
415−-- subtyping issue where comparing a PubkeyHex with a Text using ==
416−-- requires both sides to share the same type — this helper upcasts both
417−-- to Text before comparing.
418−textEq : Text -> Text -> Bool
419−textEq = \a b -> a == b
420−
421−-- Membership check that works across refined-type boundaries. `elem`
422−-- requires both the needle and the list elements to share a type, but
423−-- `PubkeyHex` and `Text` are related by subtyping, not equality. This
424−-- helper compares as `Text` on both sides.
425−textElem : Text -> [Text] -> Bool
426−textElem = \x xs -> any (\y -> x == y) xs
427−
428-- True when `s` refers to this server.
414-- True when `s` refers to this server.
429isLocalServer : Text -> Bool
415isLocalServer : Text -> Bool
430isLocalServer = \s -> s == serverHost
416isLocalServer = \s -> s == serverHost
@@ -739,7 +725,7 @@ forwardMatches = \blob server f -> f.encryptedBlob == blob && f.toServer == serv
739-- Replace any local presence rows for `pubkey` with one fresh row at
725-- Replace any local presence rows for `pubkey` with one fresh row at
740-- `expiry`, and return the post-update peer broadcast set. Caller wraps in
726-- `expiry`, and return the post-update peer broadcast set. Caller wraps in
741-- `atomic`.
727-- `atomic`.
742−refreshLocalPresence : PubkeyHex -> Timestamp -> IO {rw *presence} [Text]
728+refreshLocalPresence : Text -> Timestamp -> IO {rw *presence} [Text]
743refreshLocalPresence = \pubkey expiry -> do
729refreshLocalPresence = \pubkey expiry -> do
744 pres <- *presence
730 pres <- *presence
745 *presence = union (filter (\p -> not (p.pubkey == pubkey && isLocalServer p.server)) pres) [
731 *presence = union (filter (\p -> not (p.pubkey == pubkey && isLocalServer p.server)) pres) [
@@ -757,7 +743,7 @@ refreshLocalPresence = \pubkey expiry -> do
757-- One sweep over every state ref: drops expired rows in a single atomic block.
743-- One sweep over every state ref: drops expired rows in a single atomic block.
758-- Returns the locally-expired presence rows whose pubkey has no other live
744-- Returns the locally-expired presence rows whose pubkey has no other live
759-- local session, so the caller can broadcast offline gossip for them.
745-- local session, so the caller can broadcast offline gossip for them.
760−pruneExpired : Int<Ms> -> IO {rw *challenges, rw *forwardFailures, rw *messages, rw *presence, rw *sessions} [PubkeyHex]
746+pruneExpired : Int<Ms> -> IO {rw *challenges, rw *forwardFailures, rw *messages, rw *presence, rw *sessions} [Text]
761pruneExpired = \t -> atomic do
747pruneExpired = \t -> atomic do
762 ch <- *challenges
748 ch <- *challenges
763 *challenges = filter (\x -> x.expiresAt > t) ch
749 *challenges = filter (\x -> x.expiresAt > t) ch
@@ -998,7 +984,7 @@ handlePoll = \cursor authorization clientIp -> do
998-- the wait transaction reads `*messages` and `retry`s until a row matching
984-- the wait transaction reads `*messages` and `retry`s until a row matching
999-- this pubkey/cursor is committed; the timer wins on idle. Either way we
985-- this pubkey/cursor is committed; the timer wins on idle. Either way we
1000-- re-collect at the new wall time, so a timeout returns an empty page.
986-- re-collect at the new wall time, so a timeout returns an empty page.
1001−doPoll : {clampedCursor: Timestamp, pubkey: PubkeyHex | a} -> Timestamp -> IO {r *messages, clock} {cursor: Timestamp, events: [{encryptedBlob: BlobHex}]}
987+doPoll : {clampedCursor: Timestamp, pubkey: Text | a} -> Timestamp -> IO {r *messages, clock} {cursor: Timestamp, events: [{encryptedBlob: BlobHex}]}
1002doPoll = \s t -> do
988doPoll = \s t -> do
1003 let collectAt = \tnow -> atomic (do
989 let collectAt = \tnow -> atomic (do
1004 msgs <- *messages
990 msgs <- *messages
@@ -1200,21 +1186,20 @@ handleRecvGossip = \events fromServer -> do
1200 -- works around with an explicit `isValidExactHex 64` check). Reject a
1186 -- works around with an explicit `isValidExactHex 64` check). Reject a
1201 -- malformed key here so a peer can't poison `*presence` with non-hex
1187 -- malformed key here so a peer can't poison `*presence` with non-hex
1202 -- rows that then spawn bogus-`toKey` forward entries.
1188 -- rows that then spawn bogus-`toKey` forward entries.
1203− Just {value: pubkey} -> if not isValidExactHex 64 pubkey
1189+ Just {value: pk} -> if not isValidExactHex 64 pk
1204 then acc
1190 then acc
1205 else if e.eventType == "online"
1191 else if e.eventType == "online"
1206 then {
1192 then {
1207− touched: union acc.touched [pubkey],
1193+ touched: union acc.touched [pk],
1208− added: union acc.added [{pubkey, server: fromServer, expiresAt: t + onlineGossipTtl}]
1194+ added: union acc.added [{pubkey: pk, server: fromServer, expiresAt: t + onlineGossipTtl}]
1209 }
1195 }
1210 else if e.eventType == "offline"
1196 else if e.eventType == "offline"
1211− then {acc.added, touched: union acc.touched [pubkey]}
1197+ then {acc.added, touched: union acc.touched [pk]}
1212 else acc
1198 else acc
1213 Nothing {} -> acc) {touched: ([] : [Text]), added: ([] : [PresenceEntry])} events
1199 Nothing {} -> acc) {touched: ([] : [Text]), added: ([] : [PresenceEntry])} events
1214− let kept = filter (\p -> p.server != fromServer || not textElem p.pubkey collected.touched) pres
1200+ let kept = filter (\p -> p.server != fromServer || not elem p.pubkey collected.touched) pres
1215 *presence = union kept collected.added
1201 *presence = union kept collected.added
1216− let addedKeys : [Text] = map (\p -> p.pubkey) collected.added
1217− yield (filter (\pk -> not any (\p -> textEq p.pubkey pk && p.server == fromServer && p.expiresAt > t) pres) addedKeys))
1202+ yield (filter (\pk -> not any (\p -> p.pubkey == pk && p.server == fromServer && p.expiresAt > t) pres) (map (\p -> p.pubkey) collected.added)))
1218 fork (forEach newlyOnline (\pk -> forwardQueuedToServer pk fromServer))
1203 fork (forEach newlyOnline (\pk -> forwardQueuedToServer pk fromServer))
1219 yield (Ok {value: {}})
1204 yield (Ok {value: {}})
1220
1205