on master help sign in
Simplify code and improve type safety: eliminate IncomingMessage, type-safe Connecting state, reuse postJson in poll
7816ce8iko
client/ApiClient.fs+6−9
@@ -30,7 +30,7 @@ module ApiClient =
30 c.Timeout <- TimeSpan.FromSeconds(60.)
30 c.Timeout <- TimeSpan.FromSeconds(60.)
31 c
31 c
32
32
33− let private postJson (url: string) (body: string) (token: string option) =
33+ let private postJsonWith (httpClient: HttpClient) (url: string) (body: string) (token: string option) =
34 async {
34 async {
35 let request = new HttpRequestMessage(HttpMethod.Post, url)
35 let request = new HttpRequestMessage(HttpMethod.Post, url)
36 request.Content <- new StringContent(body, Encoding.UTF8, "application/json")
36 request.Content <- new StringContent(body, Encoding.UTF8, "application/json")
@@ -38,11 +38,13 @@ module ApiClient =
38 token
38 token
39 |> Option.iter (fun t -> request.Headers.Add("Authorization", $"Bearer {t}"))
39 |> Option.iter (fun t -> request.Headers.Add("Authorization", $"Bearer {t}"))
40
40
41− let! response = client.SendAsync(request) |> awaitTask
41+ let! response = httpClient.SendAsync(request) |> awaitTask
42 let! text = response.Content.ReadAsStringAsync() |> awaitTask
42 let! text = response.Content.ReadAsStringAsync() |> awaitTask
43 return JsonDocument.Parse(text)
43 return JsonDocument.Parse(text)
44 }
44 }
45
45
46+ let private postJson url body token = postJsonWith client url body token
47+
46 let private getJson (url: string) (token: string) =
48 let private getJson (url: string) (token: string) =
47 async {
49 async {
48 let request = new HttpRequestMessage(HttpMethod.Get, url)
50 let request = new HttpRequestMessage(HttpMethod.Get, url)
@@ -99,13 +101,8 @@ module ApiClient =
99
101
100 let poll (serverUrl: string) (token: string) (cursor: uint64) =
102 let poll (serverUrl: string) (token: string) (cursor: uint64) =
101 async {
103 async {
102− let request = new HttpRequestMessage(HttpMethod.Post, $"{serverUrl}/poll")
103− request.Content <- new StringContent(JsonSerializer.Serialize({| cursor = cursor; timeout = 30000 |}), Encoding.UTF8, "application/json")
104+ let body = JsonSerializer.Serialize({| cursor = cursor; timeout = 30000 |})
104− request.Headers.Add("Authorization", $"Bearer {token}")
105+ let! doc = postJsonWith pollClient $"{serverUrl}/poll" body (Some token)
105−
106− let! response = pollClient.SendAsync(request) |> awaitTask
107− let! text = response.Content.ReadAsStringAsync() |> awaitTask
108− let doc = JsonDocument.Parse(text)
109 let root = expectObject doc "/poll"
106 let root = expectObject doc "/poll"
110 let cursor = root.GetProperty("cursor").GetUInt64()
107 let cursor = root.GetProperty("cursor").GetUInt64()
111
108
client/App.fs+16−27
@@ -21,12 +21,6 @@ module App =
21 Timestamp: DateTimeOffset
21 Timestamp: DateTimeOffset
22 IsOutgoing: bool }
22 IsOutgoing: bool }
23
23
24− type IncomingMessage =
25− { FromPubkey: string
26− Body: string
27− Timestamp: int64
28− MessageId: string }
29−
30 [<CLIMutable>]
24 [<CLIMutable>]
31 type TextEnvelope =
25 type TextEnvelope =
32 { ``type``: string
26 { ``type``: string
@@ -47,11 +41,11 @@ module App =
47
41
48 type ConnState =
42 type ConnState =
49 | Offline
43 | Offline
50− | Connecting
44+ | Connecting of Identity
51 | Online of Session
45 | Online of Session
52
46
53 type PollResultData =
47 type PollResultData =
54− { Messages: IncomingMessage list
48+ { Messages: (string * ChatMessage) list
55 Status: string
49 Status: string
56 Cursor: uint64 }
50 Cursor: uint64 }
57
51
@@ -183,12 +177,12 @@ module App =
183 | DoConnect ->
177 | DoConnect ->
184 match model.Identity with
178 match model.Identity with
185 | Some id ->
179 | Some id ->
186− { model with Conn = Connecting }, [ CmdConnect(model.ServerUrl, id) ]
180+ { model with Conn = Connecting id }, [ CmdConnect(model.ServerUrl, id) ]
187 | None -> { model with Error = Some "No identity generated" }, []
181 | None -> { model with Error = Some "No identity generated" }, []
188
182
189 | AuthOk token ->
183 | AuthOk token ->
190− match model.Conn, model.Identity with
184+ match model.Conn with
191− | Connecting, Some id ->
185+ | Connecting id ->
192 let session = { Url = model.ServerUrl; Token = token; Identity = id }
186 let session = { Url = model.ServerUrl; Token = token; Identity = id }
193 { model with Conn = Online session; Page = Conversations; Error = None },
187 { model with Conn = Online session; Page = Conversations; Error = None },
194 [ CmdPoll(session, model.PollCursor) ]
188 [ CmdPoll(session, model.PollCursor) ]
@@ -225,19 +219,13 @@ module App =
225 let model' =
219 let model' =
226 incoming
220 incoming
227 |> List.fold
221 |> List.fold
228− (fun m msg ->
222+ (fun m (fromPubkey, chatMsg) ->
229− if messagesFor msg.FromPubkey m.Messages |> List.exists (fun x -> x.Id = msg.MessageId) then
223+ if messagesFor fromPubkey m.Messages |> List.exists (fun x -> x.Id = chatMsg.Id) then
230 m
224 m
231 else
225 else
232− let chatMsg =
233− { Id = msg.MessageId
234− Body = msg.Body
235− Timestamp = DateTimeOffset.FromUnixTimeSeconds(msg.Timestamp)
236− IsOutgoing = false }
237−
238 { m with
226 { m with
239− Contacts = m.Contacts |> addContactIfNew { Pubkey = msg.FromPubkey; Nickname = truncKey msg.FromPubkey }
227+ Contacts = m.Contacts |> addContactIfNew { Pubkey = fromPubkey; Nickname = truncKey fromPubkey }
240− Messages = m.Messages |> appendMessage msg.FromPubkey chatMsg })
228+ Messages = m.Messages |> appendMessage fromPubkey chatMsg })
241 { model with PollStatus = status; PollCursor = newCursor }
229 { model with PollStatus = status; PollCursor = newCursor }
242
230
243 let cmds =
231 let cmds =
@@ -276,7 +264,7 @@ module App =
276
264
277 | StateLoaded { Identity = None } -> model, []
265 | StateLoaded { Identity = None } -> model, []
278 | StateLoaded { Identity = Some identity; Data = dataOpt } ->
266 | StateLoaded { Identity = Some identity; Data = dataOpt } ->
279− let model' = { model with Identity = Some identity; Conn = Connecting }
267+ let model' = { model with Identity = Some identity; Conn = Connecting identity }
280
268
281 let model' =
269 let model' =
282 match dataOpt with
270 match dataOpt with
@@ -324,10 +312,11 @@ module App =
324 let envelope = JsonSerializer.Deserialize<TextEnvelope>(plaintext)
312 let envelope = JsonSerializer.Deserialize<TextEnvelope>(plaintext)
325
313
326 if envelope.``type`` = "text" then
314 if envelope.``type`` = "text" then
327− Ok { FromPubkey = senderHex
315+ Ok(senderHex,
316+ { Id = envelope.id
328 Body = envelope.body
317 Body = envelope.body
329− Timestamp = payload.Timestamp
318+ Timestamp = DateTimeOffset.FromUnixTimeSeconds(payload.Timestamp)
330− MessageId = envelope.id }
319+ IsOutgoing = false })
331 else
320 else
332 Error "unknown type"
321 Error "unknown type"
333 | None -> Error "decrypt failed"
322 | None -> Error "decrypt failed"
@@ -488,7 +477,7 @@ module App =
488
477
489 match model.Conn with
478 match model.Conn with
490 | Offline -> Button("Connect", DoConnect)
479 | Offline -> Button("Connect", DoConnect)
491− | Connecting -> Label("Connecting...").centerTextHorizontal()
480+ | Connecting _ -> Label("Connecting...").centerTextHorizontal()
492 | Online _ ->
481 | Online _ ->
493 Button("Disconnect", DoDisconnect)
482 Button("Disconnect", DoDisconnect)
494 Button("Go to Conversations", Nav Conversations)
483 Button("Go to Conversations", Nav Conversations)
@@ -501,7 +490,7 @@ module App =
501 let connStr =
490 let connStr =
502 match model.Conn with
491 match model.Conn with
503 | Offline -> "OFFLINE"
492 | Offline -> "OFFLINE"
504− | Connecting -> "CONNECTING"
493+ | Connecting _ -> "CONNECTING"
505 | Online _ -> "ONLINE"
494 | Online _ -> "ONLINE"
506
495
507 let contactNames =
496 let contactNames =
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4
@@ -162,11 +162,11 @@
162 </data>
162 </data>
163 <key>Skrepka.dll</key>
163 <key>Skrepka.dll</key>
164 <data>
164 <data>
165− +r8/McvWcZyDH15Tlxw+A2YZSqA=
165+ HO+rGAQB+KP+O6GLdnrpg4gXNTo=
166 </data>
166 </data>
167 <key>Skrepka.pdb</key>
167 <key>Skrepka.pdb</key>
168 <data>
168 <data>
169− 7zDN9fLf1e4bib8C9qjD5OXl3h8=
169+ gVY2miH2VNwTxjVewvuMbzDx/GU=
170 </data>
170 </data>
171 <key>Sodium.Core.dll</key>
171 <key>Sodium.Core.dll</key>
172 <data>
172 <data>
@@ -1382,14 +1382,14 @@
1382 <dict>
1382 <dict>
1383 <key>hash2</key>
1383 <key>hash2</key>
1384 <data>
1384 <data>
1385− eu/QLEnyJRtXlclZnchcx4K7yYLiVH8cqgv9VmdInys=
1385+ D1zjN3wi4JGWYPuOGUv3OatZGfdLQhYyE2a3FQRO3Sk=
1386 </data>
1386 </data>
1387 </dict>
1387 </dict>
1388 <key>Skrepka.pdb</key>
1388 <key>Skrepka.pdb</key>
1389 <dict>
1389 <dict>
1390 <key>hash2</key>
1390 <key>hash2</key>
1391 <data>
1391 <data>
1392− pw4SQcQwk/RuJxp+aK9kDVeLoqstIlHDM6TY71IG6F0=
1392+ Qdm9JVWHZq1+ocF6a6hRUFeaSuFiylZp+ykwgIfTQ3A=
1393 </data>
1393 </data>
1394 </dict>
1394 </dict>
1395 <key>Sodium.Core.dll</key>
1395 <key>Sodium.Core.dll</key>
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2
@@ -240,14 +240,14 @@
240 <dict>
240 <dict>
241 <key>hash2</key>
241 <key>hash2</key>
242 <data>
242 <data>
243− YxPtcfpGxa+IKDOrDbOsu1NtXsc5daoFGZDbf16at/Q=
243+ iGYj1YzZ1prtD0NbQ3DXzBIxx8GfZCXBBkeG+NhAlAg=
244 </data>
244 </data>
245 </dict>
245 </dict>
246 <key>MonoBundle/Skrepka.pdb</key>
246 <key>MonoBundle/Skrepka.pdb</key>
247 <dict>
247 <dict>
248 <key>hash2</key>
248 <key>hash2</key>
249 <data>
249 <data>
250− DyrAjXWRy1gvOE/NF4Imut7V+kKP3kTubqBKbjn9eik=
250+ gc3cHrHWiW0qjPSnbfHqE/s8LkMQGikr2nzPGAaHEgE=
251 </data>
251 </data>
252 </dict>
252 </dict>
253 <key>MonoBundle/Sodium.Core.dll</key>
253 <key>MonoBundle/Sodium.Core.dll</key>
client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+e6337c83d5e6108acdc6927de577a601ea6949b4")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+79a607dd3a4773a3bae1ef20240a704c153f91da")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−febc92d682ab55304ab763b41325b2810feafbce3abb3916e01645680f754010
1+2cd69f5b98b69e1a72e3f4bd87ef1f300a712fcc06d03dda524b6c00fdfe5200
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt−22
@@ -333,25 +333,3 @@
333/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb
333/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb
334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
336−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stamp
337−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stamp
338−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stamp
339−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stamp
340−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stamp
341−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stamp
342−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stamp
343−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stamp
344−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stamp
345−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stamp
346−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stamp
347−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stamp
348−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stamp
349−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stamp
350−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stamp
351−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stamp
352−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stamp
353−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stamp
354−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stamp
355−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stamp
356−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stamp
357−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xml
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/e6337c83d5e6108acdc6927de577a601ea6949b4/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/79a607dd3a4773a3bae1ef20240a704c153f91da/*"}}
client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+e6337c83d5e6108acdc6927de577a601ea6949b4")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+79a607dd3a4773a3bae1ef20240a704c153f91da")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−786da36e5c8bb4572c2194d3d1b64b25fa7ad4d4e4fbac83233c30ec5fd7b804
1+20452108ea7920252e262f31e3d85af043c1d46fd7b19b9a54754e30a319f325
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/e6337c83d5e6108acdc6927de577a601ea6949b4/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/79a607dd3a4773a3bae1ef20240a704c153f91da/*"}}
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll

Binary file not shown.