on master help sign in
Enable iOS AOT+interpreter mode and fix storage path resolution
24d6091iko
client/Buttons.fs+5−9
@@ -23,9 +23,9 @@ module Buttons =
23 Rectangle()
23 Rectangle()
24 .reference(shadowRef)
24 .reference(shadowRef)
25 .fill(SolidColorBrush(Colors.Black))
25 .fill(SolidColorBrush(Colors.Black))
26− .renderTransform(TranslateTransform(12., 12.))
26+ .renderTransform (TranslateTransform(12., 12.))
27
27
28− Rectangle().fill(SolidColorBrush(Constants.accentColor))
28+ Rectangle().fill (SolidColorBrush(Constants.accentColor))
29
29
30 TextBlock(text)
30 TextBlock(text)
31 .foreground(SolidColorBrush(Colors.White))
31 .foreground(SolidColorBrush(Colors.White))
@@ -33,13 +33,9 @@ module Buttons =
33 .fontFamily(FontFamily("avares://Skrepka/Assets/Fonts#Unbounded"))
33 .fontFamily(FontFamily("avares://Skrepka/Assets/Fonts#Unbounded"))
34 .fontWeight(FontWeight.Bold)
34 .fontWeight(FontWeight.Bold)
35 .center()
35 .center()
36− .margin(8.)
36+ .margin (8.)
37
37
38− Button(msg,
39− Rectangle()
40− .strokeThickness(4.)
41− .stroke(SolidColorBrush(Colors.Black))
38+ Button(msg, Rectangle().strokeThickness(4.).stroke(SolidColorBrush(Colors.Black)).margin (-3.))
42− .margin(-3.))
43 .onPointerPressed(fun _ -> animate true)
39 .onPointerPressed(fun _ -> animate true)
44 .onPointerReleased(fun _ -> animate false)
40 .onPointerReleased(fun _ -> animate false)
45 .onPointerExited(fun _ -> animate false)
41 .onPointerExited(fun _ -> animate false)
@@ -47,6 +43,6 @@ module Buttons =
47 .borderThickness(0.)
43 .borderThickness(0.)
48 .padding(0.)
44 .padding(0.)
49 .horizontalAlignment(Avalonia.Layout.HorizontalAlignment.Stretch)
45 .horizontalAlignment(Avalonia.Layout.HorizontalAlignment.Stretch)
50− .verticalAlignment(Avalonia.Layout.VerticalAlignment.Stretch)
46+ .verticalAlignment (Avalonia.Layout.VerticalAlignment.Stretch)
51 }
47 }
52 }
48 }
client/Skrepka.fsproj+2−1
@@ -23,6 +23,7 @@
23 <SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
23 <SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
24 <RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
24 <RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
25 <ValidateXcodeVersion>false</ValidateXcodeVersion>
25 <ValidateXcodeVersion>false</ValidateXcodeVersion>
26+ <UseInterpreter>true</UseInterpreter>
26 </PropertyGroup>
27 </PropertyGroup>
27
28
28 <ItemGroup>
29 <ItemGroup>
@@ -53,7 +54,7 @@
53 <PackageReference Include="Avalonia.iOS" Version="11.3.0" />
54 <PackageReference Include="Avalonia.iOS" Version="11.3.0" />
54 </ItemGroup>
55 </ItemGroup>
55
56
56− <Target Name="AddLaunchScreenToPlist" AfterTargets="_GenerateInfoPList" Condition="$(AvaloniaPlatform) == 'iOS'">
57+ <Target Name="AddLaunchScreenToPlist" AfterTargets="_CompileAppManifest" Condition="$(AvaloniaPlatform) == 'iOS'">
57 <Exec Command="/usr/libexec/PlistBuddy -c 'Add :UILaunchStoryboardName string LaunchScreen' '$(AppBundleDir)/Info.plist'" ContinueOnError="true" />
58 <Exec Command="/usr/libexec/PlistBuddy -c 'Add :UILaunchStoryboardName string LaunchScreen' '$(AppBundleDir)/Info.plist'" ContinueOnError="true" />
58 </Target>
59 </Target>
59
60
client/Store.fs+13−3
@@ -74,9 +74,19 @@ module Store =
74 IsOutgoing = isOutgoing; Status = status }
74 IsOutgoing = isOutgoing; Status = status }
75
75
76 let private appDataDir =
76 let private appDataDir =
77+ let baseDir =
77− let dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Skrepka")
78+ let appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
79+ if String.IsNullOrEmpty(appData) then
80+ // iOS: use the app's Documents directory
81+ let personal = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
82+ if String.IsNullOrEmpty(personal) then
83+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Skrepka")
84+ else
85+ Path.Combine(personal, "Skrepka")
86+ else
87+ Path.Combine(appData, "Skrepka")
78− Directory.CreateDirectory(dir) |> ignore
88+ Directory.CreateDirectory(baseDir) |> ignore
79− dir
89+ baseDir
80
90
81 let private openDb () =
91 let private openDb () =
82 new LiteDatabase(Path.Combine(appDataDir, "skrepka.db"))
92 new LiteDatabase(Path.Combine(appDataDir, "skrepka.db"))
server.knot+55−9
@@ -89,13 +89,16 @@ impl ToJSON MessageStatus where
89
89
90data DeliveryStatus = DsDelivered {} | DsFederated {} | DsQueued {}
90data DeliveryStatus = DsDelivered {} | DsFederated {} | DsQueued {}
91
91
92+isValidBoundedHex : Int -> Text -> Bool
92isValidBoundedHex = \maxLen s -> isValidHex s && not (tooLong s maxLen) && s == normalizeHex s
93isValidBoundedHex = \maxLen s -> isValidHex s && not (tooLong s maxLen) && s == normalizeHex s
93type PubkeyHex = Text where isValidBoundedHex maxPubkeyLen
94type PubkeyHex = Text where isValidBoundedHex maxPubkeyLen
94type BlobHex = Text where isValidBoundedHex maxBlobLen
95type BlobHex = Text where isValidBoundedHex maxBlobLen
95type SignatureHex = Text where isValidBoundedHex maxSignatureLen
96type SignatureHex = Text where isValidBoundedHex maxSignatureLen
97+isValidMessageId : Text -> Bool
96isValidMessageId = isValidBoundedHex maxMessageIdLen
98isValidMessageId = isValidBoundedHex maxMessageIdLen
97type MessageIdHex = Text where isValidMessageId
99type MessageIdHex = Text where isValidMessageId
98type OptionalMessageId = Text where \s -> s == "" || isValidMessageId s
100type OptionalMessageId = Text where \s -> s == "" || isValidMessageId s
101+isValidServerName : Text -> Bool
99isValidServerName = \s -> not (tooLong s maxServerNameLen) && s == normalizeServerName s && not (isBadServerName s)
102isValidServerName = \s -> not (tooLong s maxServerNameLen) && s == normalizeServerName s && not (isBadServerName s)
100type ServerName = Text where isValidServerName
103type ServerName = Text where isValidServerName
101data MessageOrigin = LocalOrigin {} | FederatedOrigin {server: ServerName}
104data MessageOrigin = LocalOrigin {} | FederatedOrigin {server: ServerName}
@@ -188,7 +191,9 @@ route Api = AuthApi | ClientApi | FederationApi | MaintenanceApi
188-- Helpers
191-- Helpers
189-- ============================================
192-- ============================================
190
193
194+any : [a] -> (a -> Bool) -> Bool
191any = \xs pred -> fold (\acc x -> if acc then acc else pred x) (False {}) xs
195any = \xs pred -> fold (\acc x -> if acc then acc else pred x) (False {}) xs
196+none : [a] -> (a -> Bool) -> Bool
192none = \xs pred -> not (any xs pred)
197none = \xs pred -> not (any xs pred)
193when = \cond action -> if cond then action else yield {}
198when = \cond action -> if cond then action else yield {}
194whenOk = \result action -> case result of
199whenOk = \result action -> case result of
@@ -205,10 +210,17 @@ maxBy = \items getKey -> fold (\acc x -> case acc of
205 Nothing {} -> Just {value: x}
210 Nothing {} -> Just {value: x}
206 Just {value: v} -> if getKey x > getKey v then Just {value: x} else acc) Nothing {} items
211 Just {value: v} -> if getKey x > getKey v then Just {value: x} else acc) Nothing {} items
207
212
213+minBy = \items getKey -> fold (\acc x -> case acc of
214+ Nothing {} -> Just {value: x}
215+ Just {value: v} -> if getKey x < getKey v then Just {value: x} else acc) Nothing {} items
216+
217+hexDigit : Int -> Text
208hexDigit = \n -> take 1 (drop (clamp 0 15 n) "0123456789abcdef")
218hexDigit = \n -> take 1 (drop (clamp 0 15 n) "0123456789abcdef")
209
219
220+byteToHex : Int -> Text
210byteToHex = \n -> hexDigit (n / 16) ++ hexDigit (n - (n / 16) * 16)
221byteToHex = \n -> hexDigit (n / 16) ++ hexDigit (n - (n / 16) * 16)
211
222
223+intTo3Hex : Int -> Text
212intTo3Hex = \n ->
224intTo3Hex = \n ->
213 let b0 = n / 65536 in
225 let b0 = n / 65536 in
214 let r0 = n - b0 * 65536 in
226 let r0 = n - b0 * 65536 in
@@ -223,26 +235,35 @@ genTokenN = \n -> if n <= 0 then yield "" else do
223
235
224genToken = genTokenN 8
236genToken = genTokenN 8
225
237
238+tooLong : Text -> Int -> Bool
226tooLong = \s maxLen -> drop maxLen s != ""
239tooLong = \s maxLen -> drop maxLen s != ""
227
240
241+isHexChar : Text -> Bool
228isHexChar = \c -> contains c "0123456789abcdef"
242isHexChar = \c -> contains c "0123456789abcdef"
229
243
244+isValidHexPairs : Text -> Bool
230isValidHexPairs = \s ->
245isValidHexPairs = \s ->
231 if s == "" then True {}
246 if s == "" then True {}
232 else if drop 1 s == "" then False {}
247 else if drop 1 s == "" then False {}
233 else if isHexChar (take 1 s) && isHexChar (take 1 (drop 1 s)) then isValidHexPairs (drop 2 s)
248 else if isHexChar (take 1 s) && isHexChar (take 1 (drop 1 s)) then isValidHexPairs (drop 2 s)
234 else False {}
249 else False {}
235
250
251+isValidHex : Text -> Bool
236isValidHex = \s -> s != "" && isValidHexPairs s
252isValidHex = \s -> s != "" && isValidHexPairs s
237
253
254+normalizeHex : Text -> Text
238normalizeHex = \s -> bytesToHex (bytesFromHex s)
255normalizeHex = \s -> bytesToHex (bytesFromHex s)
239
256
257+isDigitChar : Text -> Bool
240isDigitChar = \c -> contains c "0123456789"
258isDigitChar = \c -> contains c "0123456789"
241
259
260+isAllowedServerChar : Text -> Bool
242isAllowedServerChar = \c -> contains c "0123456789abcdefghijklmnopqrstuvwxyz-.:"
261isAllowedServerChar = \c -> contains c "0123456789abcdefghijklmnopqrstuvwxyz-.:"
243
262
263+containsBadUrlChar : Text -> Bool
244containsBadUrlChar = \s -> any (chars s) (\c -> not (isAllowedServerChar c))
264containsBadUrlChar = \s -> any (chars s) (\c -> not (isAllowedServerChar c))
245
265
266+isCgnatRange : Text -> Bool
246isCgnatRange = \s ->
267isCgnatRange = \s ->
247 take 4 s == "100."
268 take 4 s == "100."
248 && let d4 = take 1 (drop 4 s) in
269 && let d4 = take 1 (drop 4 s) in
@@ -256,31 +277,40 @@ isCgnatRange = \s ->
256 || (d4 == "1" && contains d5 "01" && isDigitChar d6 && threeDigitOctet)
277 || (d4 == "1" && contains d5 "01" && isDigitChar d6 && threeDigitOctet)
257 || (d4 == "1" && d5 == "2" && contains d6 "01234567" && threeDigitOctet))
278 || (d4 == "1" && d5 == "2" && contains d6 "01234567" && threeDigitOctet))
258
279
280+containsMultipleColons : Text -> Bool
259containsMultipleColons = \s -> count (do c <- chars s; where c == ":"; yield c) > 1
281containsMultipleColons = \s -> count (do c <- chars s; where c == ":"; yield c) > 1
260
282
283+hasPatternAfterDot : (Text -> Bool) -> Text -> Bool
261hasPatternAfterDot = \pred s ->
284hasPatternAfterDot = \pred s ->
262 if s == "" then False {}
285 if s == "" then False {}
263 else if take 1 s == "." && pred (drop 1 s) then True {}
286 else if take 1 s == "." && pred (drop 1 s) then True {}
264 else hasPatternAfterDot pred (drop 1 s)
287 else hasPatternAfterDot pred (drop 1 s)
265
288
289+isOctalStart : Text -> Bool
266isOctalStart = \s -> take 1 s == "0" && isDigitChar (take 1 (drop 1 s)) && isAllDigitsOrDotsUntilColonOrEnd (drop 2 s)
290isOctalStart = \s -> take 1 s == "0" && isDigitChar (take 1 (drop 1 s)) && isAllDigitsOrDotsUntilColonOrEnd (drop 2 s)
291+hasOctalOctet : Text -> Bool
267hasOctalOctet = \s -> isOctalStart s || hasPatternAfterDot isOctalStart s
292hasOctalOctet = \s -> isOctalStart s || hasPatternAfterDot isOctalStart s
268
293
294+isHexStart : Text -> Bool
269isHexStart = \s -> take 2 s == "0x" || take 2 s == "0X"
295isHexStart = \s -> take 2 s == "0x" || take 2 s == "0X"
296+hasHexPrefix : Text -> Bool
270hasHexPrefix = \s -> isHexStart s || hasPatternAfterDot isHexStart s
297hasHexPrefix = \s -> isHexStart s || hasPatternAfterDot isHexStart s
271
298
299+isAllDigitsOrDotsUntilColonOrEnd : Text -> Bool
272isAllDigitsOrDotsUntilColonOrEnd = \s ->
300isAllDigitsOrDotsUntilColonOrEnd = \s ->
273 if s == "" then True {}
301 if s == "" then True {}
274 else if take 1 s == ":" then True {}
302 else if take 1 s == ":" then True {}
275 else if isDigitChar (take 1 s) || take 1 s == "." then isAllDigitsOrDotsUntilColonOrEnd (drop 1 s)
303 else if isDigitChar (take 1 s) || take 1 s == "." then isAllDigitsOrDotsUntilColonOrEnd (drop 1 s)
276 else False {}
304 else False {}
277
305
306+isTrailingDots : Text -> Bool
278isTrailingDots = \s ->
307isTrailingDots = \s ->
279 if s == "" then True {}
308 if s == "" then True {}
280 else if take 1 s == ":" then True {}
309 else if take 1 s == ":" then True {}
281 else if take 1 s == "." then isTrailingDots (drop 1 s)
310 else if take 1 s == "." then isTrailingDots (drop 1 s)
282 else False {}
311 else False {}
283
312
313+stripTrailingDot : Text -> Text
284stripTrailingDot = \s ->
314stripTrailingDot = \s ->
285 if s == "" then ""
315 if s == "" then ""
286 else if take 1 s == "." && isTrailingDots (drop 1 s) then stripTrailingDot (drop 1 s)
316 else if take 1 s == "." && isTrailingDots (drop 1 s) then stripTrailingDot (drop 1 s)
@@ -289,17 +319,21 @@ stripTrailingDot = \s ->
289normalizeServerName : Text -> Text
319normalizeServerName : Text -> Text
290normalizeServerName = \s -> toLower (stripTrailingDot s)
320normalizeServerName = \s -> toLower (stripTrailingDot s)
291
321
322+serverHostN : Text
292serverHostN = normalizeServerName serverHost
323serverHostN = normalizeServerName serverHost
293isLocalServer : Text -> Bool
324isLocalServer : Text -> Bool
294isLocalServer = \s -> s == serverHostN
325isLocalServer = \s -> s == serverHostN
295
326
327+containsSuffixN : Text -> Int -> Text -> Bool
296containsSuffixN = \suffix suffixLen s ->
328containsSuffixN = \suffix suffixLen s ->
297 if s == "" then False {}
329 if s == "" then False {}
298 else if take suffixLen s == suffix && (drop suffixLen s == "" || take 1 (drop suffixLen s) == ":") then True {}
330 else if take suffixLen s == suffix && (drop suffixLen s == "" || take 1 (drop suffixLen s) == ":") then True {}
299 else containsSuffixN suffix suffixLen (drop 1 s)
331 else containsSuffixN suffix suffixLen (drop 1 s)
300
332
333+containsSuffix : Text -> Text -> Bool
301containsSuffix = \suffix s -> containsSuffixN suffix (count (chars suffix)) s
334containsSuffix = \suffix s -> containsSuffixN suffix (count (chars suffix)) s
302
335
336+is172Private : Text -> Bool
303is172Private = \sn ->
337is172Private = \sn ->
304 take 4 sn == "172."
338 take 4 sn == "172."
305 && let d1 = take 1 (drop 4 sn) in
339 && let d1 = take 1 (drop 4 sn) in
@@ -309,6 +343,7 @@ is172Private = \sn ->
309 || (d1 == "2" && isDigitChar d2)
343 || (d1 == "2" && isDigitChar d2)
310 || (d1 == "3" && contains d2 "01"))
344 || (d1 == "3" && contains d2 "01"))
311
345
346+isHighOctetPrefix : Text -> Bool
312isHighOctetPrefix = \sn ->
347isHighOctetPrefix = \sn ->
313 take 1 sn == "2"
348 take 1 sn == "2"
314 && let d2 = take 1 (drop 1 sn) in
349 && let d2 = take 1 (drop 1 sn) in
@@ -318,10 +353,12 @@ isHighOctetPrefix = \sn ->
318 || (contains d2 "34" && isDigitChar d3)
353 || (contains d2 "34" && isDigitChar d3)
319 || (d2 == "5" && contains d3 "012345"))
354 || (d2 == "5" && contains d3 "012345"))
320
355
356+matchesHostname : Text -> Text -> Bool
321matchesHostname = \sn name ->
357matchesHostname = \sn name ->
322 let nameLen = count (chars name) in
358 let nameLen = count (chars name) in
323 take nameLen sn == name && (drop nameLen sn == "" || take 1 (drop nameLen sn) == ":")
359 take nameLen sn == name && (drop nameLen sn == "" || take 1 (drop nameLen sn) == ":")
324
360
361+matchesHostnameOrSubdomain : Text -> Text -> Bool
325matchesHostnameOrSubdomain = \sn name ->
362matchesHostnameOrSubdomain = \sn name ->
326 matchesHostname sn name || containsSuffix ("." ++ name) sn
363 matchesHostname sn name || containsSuffix ("." ++ name) sn
327
364
@@ -370,17 +407,17 @@ verifySecret : Text -> Text -> Bool
370verifySecret = \token secret ->
407verifySecret = \token secret ->
371 secret != "" && safeCompare token secret
408 secret != "" && safeCompare token secret
372
409
373−verifyFederationAuth : Text -> Bool
410+verifyAuthWith : (Text -> Bool) -> Text -> Bool
374−verifyFederationAuth = \authorization ->
411+verifyAuthWith = \check authorization ->
375 case extractToken authorization of
412 case extractToken authorization of
376 Nothing {} -> False {}
413 Nothing {} -> False {}
414+ Just {value: token} -> check token
415+
416+verifyFederationAuth : Text -> Bool
377− Just {value: token} -> verifySecret token federationSecret
417+verifyFederationAuth = verifyAuthWith (\token -> verifySecret token federationSecret)
378
418
379verifyMaintenanceAuth : Text -> Bool
419verifyMaintenanceAuth : Text -> Bool
380−verifyMaintenanceAuth = \authorization ->
381− case extractToken authorization of
382− Nothing {} -> False {}
383− Just {value: token} -> verifySecret token federationSecret || verifySecret token maintenanceSecret
420+verifyMaintenanceAuth = verifyAuthWith (\token -> verifySecret token federationSecret || verifySecret token maintenanceSecret)
384
421
385clampTtl : Int<S> -> Int<S>
422clampTtl : Int<S> -> Int<S>
386clampTtl = clamp 1 maxPresenceTtl
423clampTtl = clamp 1 maxPresenceTtl
@@ -394,9 +431,13 @@ deliveryToMessageStatus = \ds -> case ds of
394 DsFederated {} -> MsFederated {}
431 DsFederated {} -> MsFederated {}
395 DsQueued {} -> MsQueued {}
432 DsQueued {} -> MsQueued {}
396
433
434+isQueued : DeliveryStatus -> Bool
435+isQueued = \ds -> case ds of DsQueued {} -> True {}; _ -> False {}
436+
397nextSeqTs : Timestamp -> Timestamp -> Timestamp
437nextSeqTs : Timestamp -> Timestamp -> Timestamp
398nextSeqTs = \t seqCounter -> if t > seqCounter then t else seqCounter + 1
438nextSeqTs = \t seqCounter -> if t > seqCounter then t else seqCounter + 1
399
439
440+takeN : [a] -> Int -> [a]
400takeN = \items n -> (fold (\acc e -> if acc.n >= n then acc else {n: acc.n + 1, items: union acc.items [e]}) {n: 0, items: []} items).items
441takeN = \items n -> (fold (\acc e -> if acc.n >= n then acc else {n: acc.n + 1, items: union acc.items [e]}) {n: 0, items: []} items).items
401
442
402dedupMessageIds : [MessageIdHex] -> [MessageIdHex]
443dedupMessageIds : [MessageIdHex] -> [MessageIdHex]
@@ -440,16 +481,20 @@ evictOldestAckedIds = \items n ->
440 if n <= 0 then items
481 if n <= 0 then items
441 else diff items (boundedSmallest items n (\a -> a.ackedAt))
482 else diff items (boundedSmallest items n (\a -> a.ackedAt))
442
483
484+safeCompareLoop : Text -> Text -> Int -> Int -> Int
443safeCompareLoop = \s1 s2 n result ->
485safeCompareLoop = \s1 s2 n result ->
444 if n <= 0 && s1 == "" && s2 == ""
486 if n <= 0 && s1 == "" && s2 == ""
445 then result
487 then result
446 else safeCompareLoop (drop 1 s1) (drop 1 s2) (n - 1) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
488 else safeCompareLoop (drop 1 s1) (drop 1 s2) (n - 1) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
447
489
490+safeCompare : Text -> Text -> Bool
448safeCompare = \a b ->
491safeCompare = \a b ->
449 safeCompareLoop a b maxTokenLen 0 + (if a == "" then 1 else 0) + (if b == "" then 1 else 0) == 0
492 safeCompareLoop a b maxTokenLen 0 + (if a == "" then 1 else 0) + (if b == "" then 1 else 0) == 0
450
493
451evictOneOldest = \items getKey ->
494evictOneOldest = \items getKey ->
452− diff items (boundedSmallest items 1 getKey)
495+ case minBy items getKey of
496+ Nothing {} -> items
497+ Just {value: v} -> diff items [v]
453
498
454capPerKey = \items matchKey maxPerKey getExpiry t ->
499capPerKey = \items matchKey maxPerKey getExpiry t ->
455 let active = do x <- items; where getExpiry x > t; yield x in
500 let active = do x <- items; where getExpiry x > t; yield x in
@@ -467,6 +512,7 @@ capGlobal = \items maxCount getKey ->
467capPerKeyAndGlobal = \items matchKey maxPerKey getExpiry t maxGlobal ->
512capPerKeyAndGlobal = \items matchKey maxPerKey getExpiry t maxGlobal ->
468 capGlobal (capPerKey items matchKey maxPerKey getExpiry t) maxGlobal getExpiry
513 capGlobal (capPerKey items matchKey maxPerKey getExpiry t) maxGlobal getExpiry
469
514
515+collectPeerServers : [a] -> (a -> Text) -> [Text]
470collectPeerServers = \items getServer ->
516collectPeerServers = \items getServer ->
471 fold (\acc item ->
517 fold (\acc item ->
472 let s = getServer item in
518 let s = getServer item in
@@ -908,7 +954,7 @@ serve = \req -> case req of
908 authorization: federationAuth})
954 authorization: federationAuth})
909 when (any forwardServers (\s -> s == server))
955 when (any forwardServers (\s -> s == server))
910 (whenOk fwdResult (removeForward msgId server)))
956 (whenOk fwdResult (removeForward msgId server)))
911− when (case delivery of DsQueued {} -> True {}; _ -> False {})
957+ when (isQueued delivery)
912 (println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")))
958 (println ("sendMessage: forwards at capacity (" ++ show maxForwardsEntries ++ "), skipping forward tracking")))
913 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
959 broadcastOfflineGossip t result.pr.peerServers result.pr.expiredLocal)
914 _ -> forkBroadcastOffline t result.pr
960 _ -> forkBroadcastOffline t result.pr