tangled
alpha
login
or
join now
aleeve.dev
/
ott
2
fork
atom
Scalable and distributed custom feed generator, ott - on that topic
2
fork
atom
overview
issues
pulls
pipelines
Prepare to setup xrpcs from smokesignals hello-world
aleeve.dev
5 months ago
37059112
eb692f97
+750
-26
5 changed files
expand all
collapse all
unified
split
crates
Cargo.lock
ott-xrpc
Cargo.toml
src
lib.rs
main.rs
webcontext.rs
+402
-24
crates/Cargo.lock
···
9
9
checksum = "ffd5e23cd33dd73c030d1c424967eb2fbdc917d89e0bdcf1162edc4cf504f756"
10
10
dependencies = [
11
11
"anyhow",
12
12
-
"thiserror",
12
12
+
"thiserror 2.0.17",
13
13
]
14
14
15
15
[[package]]
···
49
49
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
50
50
dependencies = [
51
51
"libc",
52
52
+
]
53
53
+
54
54
+
[[package]]
55
55
+
name = "anstream"
56
56
+
version = "0.6.21"
57
57
+
source = "registry+https://github.com/rust-lang/crates.io-index"
58
58
+
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
59
59
+
dependencies = [
60
60
+
"anstyle",
61
61
+
"anstyle-parse",
62
62
+
"anstyle-query",
63
63
+
"anstyle-wincon",
64
64
+
"colorchoice",
65
65
+
"is_terminal_polyfill",
66
66
+
"utf8parse",
67
67
+
]
68
68
+
69
69
+
[[package]]
70
70
+
name = "anstyle"
71
71
+
version = "1.0.13"
72
72
+
source = "registry+https://github.com/rust-lang/crates.io-index"
73
73
+
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
74
74
+
75
75
+
[[package]]
76
76
+
name = "anstyle-parse"
77
77
+
version = "0.2.7"
78
78
+
source = "registry+https://github.com/rust-lang/crates.io-index"
79
79
+
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
80
80
+
dependencies = [
81
81
+
"utf8parse",
82
82
+
]
83
83
+
84
84
+
[[package]]
85
85
+
name = "anstyle-query"
86
86
+
version = "1.1.4"
87
87
+
source = "registry+https://github.com/rust-lang/crates.io-index"
88
88
+
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
89
89
+
dependencies = [
90
90
+
"windows-sys 0.60.2",
91
91
+
]
92
92
+
93
93
+
[[package]]
94
94
+
name = "anstyle-wincon"
95
95
+
version = "3.0.10"
96
96
+
source = "registry+https://github.com/rust-lang/crates.io-index"
97
97
+
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
98
98
+
dependencies = [
99
99
+
"anstyle",
100
100
+
"once_cell_polyfill",
101
101
+
"windows-sys 0.60.2",
52
102
]
53
103
54
104
[[package]]
···
202
252
"serde",
203
253
"serde_ipld_dagcbor",
204
254
"serde_json",
205
205
-
"thiserror",
255
255
+
"thiserror 2.0.17",
206
256
"tokio",
207
257
"tracing",
208
258
"urlencoding",
209
259
]
210
260
211
261
[[package]]
262
262
+
name = "atproto-oauth"
263
263
+
version = "0.13.0"
264
264
+
source = "registry+https://github.com/rust-lang/crates.io-index"
265
265
+
checksum = "3ea205901c33d074a1b498591d0511bcd788b6772ec0ca6e09a92c4327ddbdff"
266
266
+
dependencies = [
267
267
+
"anyhow",
268
268
+
"async-trait",
269
269
+
"atproto-identity",
270
270
+
"base64",
271
271
+
"chrono",
272
272
+
"ecdsa",
273
273
+
"elliptic-curve",
274
274
+
"k256",
275
275
+
"lru",
276
276
+
"multibase",
277
277
+
"p256",
278
278
+
"p384",
279
279
+
"rand 0.8.5",
280
280
+
"reqwest",
281
281
+
"reqwest-chain",
282
282
+
"reqwest-middleware",
283
283
+
"serde",
284
284
+
"serde_ipld_dagcbor",
285
285
+
"serde_json",
286
286
+
"sha2",
287
287
+
"thiserror 2.0.17",
288
288
+
"tokio",
289
289
+
"tracing",
290
290
+
"ulid",
291
291
+
]
292
292
+
293
293
+
[[package]]
294
294
+
name = "atproto-record"
295
295
+
version = "0.13.0"
296
296
+
source = "registry+https://github.com/rust-lang/crates.io-index"
297
297
+
checksum = "0550f74423ca745132dc07ba1cb01f2f08243a7bf7497f5c3f2185a774c92ca2"
298
298
+
dependencies = [
299
299
+
"anyhow",
300
300
+
"atproto-identity",
301
301
+
"base64",
302
302
+
"chrono",
303
303
+
"serde",
304
304
+
"serde_ipld_dagcbor",
305
305
+
"serde_json",
306
306
+
"thiserror 2.0.17",
307
307
+
]
308
308
+
309
309
+
[[package]]
310
310
+
name = "atproto-xrpcs"
311
311
+
version = "0.13.0"
312
312
+
source = "registry+https://github.com/rust-lang/crates.io-index"
313
313
+
checksum = "d2bd3c09bc3e7bbc04fd7271d25184c607644adc4c365633468184edb94094ac"
314
314
+
dependencies = [
315
315
+
"anyhow",
316
316
+
"async-trait",
317
317
+
"atproto-identity",
318
318
+
"atproto-oauth",
319
319
+
"atproto-record",
320
320
+
"axum",
321
321
+
"base64",
322
322
+
"chrono",
323
323
+
"elliptic-curve",
324
324
+
"hickory-resolver",
325
325
+
"http",
326
326
+
"rand 0.8.5",
327
327
+
"reqwest",
328
328
+
"reqwest-chain",
329
329
+
"reqwest-middleware",
330
330
+
"serde",
331
331
+
"serde_json",
332
332
+
"thiserror 2.0.17",
333
333
+
"tokio",
334
334
+
"tracing",
335
335
+
]
336
336
+
337
337
+
[[package]]
212
338
name = "autocfg"
213
339
version = "1.5.0"
214
340
source = "registry+https://github.com/rust-lang/crates.io-index"
···
236
362
"dunce",
237
363
"fs_extra",
238
364
"libloading",
365
365
+
]
366
366
+
367
367
+
[[package]]
368
368
+
name = "axum"
369
369
+
version = "0.8.6"
370
370
+
source = "registry+https://github.com/rust-lang/crates.io-index"
371
371
+
checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871"
372
372
+
dependencies = [
373
373
+
"axum-core",
374
374
+
"axum-macros",
375
375
+
"bytes",
376
376
+
"form_urlencoded",
377
377
+
"futures-util",
378
378
+
"http",
379
379
+
"http-body",
380
380
+
"http-body-util",
381
381
+
"hyper",
382
382
+
"hyper-util",
383
383
+
"itoa",
384
384
+
"matchit",
385
385
+
"memchr",
386
386
+
"mime",
387
387
+
"percent-encoding",
388
388
+
"pin-project-lite",
389
389
+
"serde_core",
390
390
+
"serde_json",
391
391
+
"serde_path_to_error",
392
392
+
"serde_urlencoded",
393
393
+
"sync_wrapper",
394
394
+
"tokio",
395
395
+
"tower",
396
396
+
"tower-layer",
397
397
+
"tower-service",
398
398
+
"tracing",
399
399
+
]
400
400
+
401
401
+
[[package]]
402
402
+
name = "axum-core"
403
403
+
version = "0.5.5"
404
404
+
source = "registry+https://github.com/rust-lang/crates.io-index"
405
405
+
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
406
406
+
dependencies = [
407
407
+
"bytes",
408
408
+
"futures-core",
409
409
+
"http",
410
410
+
"http-body",
411
411
+
"http-body-util",
412
412
+
"mime",
413
413
+
"pin-project-lite",
414
414
+
"sync_wrapper",
415
415
+
"tower-layer",
416
416
+
"tower-service",
417
417
+
"tracing",
418
418
+
]
419
419
+
420
420
+
[[package]]
421
421
+
name = "axum-macros"
422
422
+
version = "0.5.0"
423
423
+
source = "registry+https://github.com/rust-lang/crates.io-index"
424
424
+
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
425
425
+
dependencies = [
426
426
+
"proc-macro2",
427
427
+
"quote",
428
428
+
"syn 2.0.106",
239
429
]
240
430
241
431
[[package]]
···
428
618
"iana-time-zone",
429
619
"js-sys",
430
620
"num-traits",
621
621
+
"serde",
431
622
"wasm-bindgen",
432
623
"windows-link 0.2.1",
433
624
]
···
458
649
]
459
650
460
651
[[package]]
652
652
+
name = "clap"
653
653
+
version = "4.5.48"
654
654
+
source = "registry+https://github.com/rust-lang/crates.io-index"
655
655
+
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
656
656
+
dependencies = [
657
657
+
"clap_builder",
658
658
+
"clap_derive",
659
659
+
]
660
660
+
661
661
+
[[package]]
662
662
+
name = "clap_builder"
663
663
+
version = "4.5.48"
664
664
+
source = "registry+https://github.com/rust-lang/crates.io-index"
665
665
+
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
666
666
+
dependencies = [
667
667
+
"anstream",
668
668
+
"anstyle",
669
669
+
"clap_lex",
670
670
+
"strsim",
671
671
+
]
672
672
+
673
673
+
[[package]]
674
674
+
name = "clap_derive"
675
675
+
version = "4.5.47"
676
676
+
source = "registry+https://github.com/rust-lang/crates.io-index"
677
677
+
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
678
678
+
dependencies = [
679
679
+
"heck",
680
680
+
"proc-macro2",
681
681
+
"quote",
682
682
+
"syn 2.0.106",
683
683
+
]
684
684
+
685
685
+
[[package]]
686
686
+
name = "clap_lex"
687
687
+
version = "0.7.5"
688
688
+
source = "registry+https://github.com/rust-lang/crates.io-index"
689
689
+
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
690
690
+
691
691
+
[[package]]
461
692
name = "cmake"
462
693
version = "0.1.54"
463
694
source = "registry+https://github.com/rust-lang/crates.io-index"
···
467
698
]
468
699
469
700
[[package]]
701
701
+
name = "colorchoice"
702
702
+
version = "1.0.4"
703
703
+
source = "registry+https://github.com/rust-lang/crates.io-index"
704
704
+
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
705
705
+
706
706
+
[[package]]
470
707
name = "concurrent-queue"
471
708
version = "2.5.0"
472
709
source = "registry+https://github.com/rust-lang/crates.io-index"
···
799
1036
"digest",
800
1037
"elliptic-curve",
801
1038
"rfc6979",
1039
1039
+
"serdect",
802
1040
"signature",
803
1041
"spki",
804
1042
]
···
1023
1261
"semver",
1024
1262
"serde",
1025
1263
"siphasher",
1026
1026
-
"thiserror",
1264
1264
+
"thiserror 2.0.17",
1027
1265
"tokio",
1028
1266
"toml",
1029
1267
"tracing",
···
1042
1280
"lz4_flex",
1043
1281
"serde",
1044
1282
"snap",
1045
1045
-
"thiserror",
1283
1283
+
"thiserror 2.0.17",
1046
1284
"zstd",
1047
1285
]
1048
1286
···
1069
1307
"semver",
1070
1308
"serde",
1071
1309
"serde_yaml",
1072
1072
-
"thiserror",
1310
1310
+
"thiserror 2.0.17",
1073
1311
"toml",
1074
1312
"tracing",
1075
1313
]
···
1094
1332
"pin-project",
1095
1333
"rustls-pemfile",
1096
1334
"socket2 0.5.10",
1097
1097
-
"thiserror",
1335
1335
+
"thiserror 2.0.17",
1098
1336
"tokio",
1099
1337
"tracing",
1100
1338
"wasm-bindgen-futures",
···
1119
1357
"flv-util",
1120
1358
"once_cell",
1121
1359
"semver",
1122
1122
-
"thiserror",
1360
1360
+
"thiserror 2.0.17",
1123
1361
"tokio-util",
1124
1362
"tracing",
1125
1363
]
···
1149
1387
"fluvio-stream-model",
1150
1388
"paste",
1151
1389
"static_assertions",
1152
1152
-
"thiserror",
1390
1390
+
"thiserror 2.0.17",
1153
1391
"tracing",
1154
1392
]
1155
1393
···
1162
1400
"eyre",
1163
1401
"fluvio-protocol",
1164
1402
"fluvio-smartmodule-derive",
1165
1165
-
"thiserror",
1403
1403
+
"thiserror 2.0.17",
1166
1404
"tracing",
1167
1405
]
1168
1406
···
1197
1435
"once_cell",
1198
1436
"pin-project",
1199
1437
"semver",
1200
1200
-
"thiserror",
1438
1438
+
"thiserror 2.0.17",
1201
1439
"tokio",
1202
1440
"tokio-util",
1203
1441
"tracing",
···
1269
1507
"event-listener",
1270
1508
"schemars",
1271
1509
"serde",
1272
1272
-
"thiserror",
1510
1510
+
"thiserror 2.0.17",
1273
1511
"toml",
1274
1512
"tracing",
1275
1513
]
···
1613
1851
"once_cell",
1614
1852
"rand 0.9.2",
1615
1853
"ring",
1616
1616
-
"thiserror",
1854
1854
+
"thiserror 2.0.17",
1617
1855
"tinyvec",
1618
1856
"tokio",
1619
1857
"tracing",
···
1636
1874
"rand 0.9.2",
1637
1875
"resolv-conf",
1638
1876
"smallvec",
1639
1639
-
"thiserror",
1877
1877
+
"thiserror 2.0.17",
1640
1878
"tokio",
1641
1879
"tracing",
1642
1880
]
···
1709
1947
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
1710
1948
1711
1949
[[package]]
1950
1950
+
name = "httpdate"
1951
1951
+
version = "1.0.3"
1952
1952
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1953
1953
+
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
1954
1954
+
1955
1955
+
[[package]]
1712
1956
name = "humantime"
1713
1957
version = "2.3.0"
1714
1958
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1738
1982
"http",
1739
1983
"http-body",
1740
1984
"httparse",
1985
1985
+
"httpdate",
1741
1986
"itoa",
1742
1987
"pin-project-lite",
1743
1988
"pin-utils",
···
2021
2266
]
2022
2267
2023
2268
[[package]]
2269
2269
+
name = "is_terminal_polyfill"
2270
2270
+
version = "1.70.1"
2271
2271
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2272
2272
+
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
2273
2273
+
2274
2274
+
[[package]]
2024
2275
name = "itertools"
2025
2276
version = "0.13.0"
2026
2277
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2232
2483
]
2233
2484
2234
2485
[[package]]
2486
2486
+
name = "matchit"
2487
2487
+
version = "0.8.4"
2488
2488
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2489
2489
+
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
2490
2490
+
2491
2491
+
[[package]]
2235
2492
name = "md-5"
2236
2493
version = "0.10.6"
2237
2494
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2252
2509
version = "0.3.17"
2253
2510
source = "registry+https://github.com/rust-lang/crates.io-index"
2254
2511
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
2512
2512
+
2513
2513
+
[[package]]
2514
2514
+
name = "mime_guess"
2515
2515
+
version = "2.0.5"
2516
2516
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2517
2517
+
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
2518
2518
+
dependencies = [
2519
2519
+
"mime",
2520
2520
+
"unicase",
2521
2521
+
]
2255
2522
2256
2523
[[package]]
2257
2524
name = "minimal-lexical"
···
2436
2703
]
2437
2704
2438
2705
[[package]]
2706
2706
+
name = "once_cell_polyfill"
2707
2707
+
version = "1.70.1"
2708
2708
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2709
2709
+
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
2710
2710
+
2711
2711
+
[[package]]
2439
2712
name = "openssl"
2440
2713
version = "0.10.73"
2441
2714
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2543
2816
name = "ott-xrpc"
2544
2817
version = "0.1.0"
2545
2818
dependencies = [
2819
2819
+
"anyhow",
2820
2820
+
"async-trait",
2546
2821
"atproto-identity",
2822
2822
+
"atproto-xrpcs",
2823
2823
+
"axum",
2824
2824
+
"clap",
2825
2825
+
"http",
2826
2826
+
"reqwest",
2827
2827
+
"serde",
2828
2828
+
"serde_json",
2829
2829
+
"tokio",
2547
2830
]
2548
2831
2549
2832
[[package]]
···
2555
2838
"ecdsa",
2556
2839
"elliptic-curve",
2557
2840
"primeorder",
2841
2841
+
"serdect",
2558
2842
"sha2",
2559
2843
]
2560
2844
···
2567
2851
"ecdsa",
2568
2852
"elliptic-curve",
2569
2853
"primeorder",
2854
2854
+
"serdect",
2570
2855
"sha2",
2571
2856
]
2572
2857
···
2789
3074
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
2790
3075
dependencies = [
2791
3076
"elliptic-curve",
3077
3077
+
"serdect",
2792
3078
]
2793
3079
2794
3080
[[package]]
···
2823
3109
"rustc-hash",
2824
3110
"rustls",
2825
3111
"socket2 0.6.0",
2826
2826
-
"thiserror",
3112
3112
+
"thiserror 2.0.17",
2827
3113
"tokio",
2828
3114
"tracing",
2829
3115
"web-time",
···
2844
3130
"rustls",
2845
3131
"rustls-pki-types",
2846
3132
"slab",
2847
2847
-
"thiserror",
3133
3133
+
"thiserror 2.0.17",
2848
3134
"tinyvec",
2849
3135
"tracing",
2850
3136
"web-time",
···
2964
3250
dependencies = [
2965
3251
"getrandom 0.2.16",
2966
3252
"libredox",
2967
2967
-
"thiserror",
3253
3253
+
"thiserror 2.0.17",
2968
3254
]
2969
3255
2970
3256
[[package]]
···
3032
3318
"bytes",
3033
3319
"encoding_rs",
3034
3320
"futures-core",
3321
3321
+
"futures-util",
3035
3322
"h2",
3036
3323
"http",
3037
3324
"http-body",
···
3043
3330
"js-sys",
3044
3331
"log",
3045
3332
"mime",
3333
3333
+
"mime_guess",
3046
3334
"native-tls",
3047
3335
"percent-encoding",
3048
3336
"pin-project-lite",
···
3067
3355
]
3068
3356
3069
3357
[[package]]
3358
3358
+
name = "reqwest-chain"
3359
3359
+
version = "1.0.0"
3360
3360
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3361
3361
+
checksum = "da5c014fb79a8227db44a0433d748107750d2550b7fca55c59a3d7ee7d2ee2b2"
3362
3362
+
dependencies = [
3363
3363
+
"anyhow",
3364
3364
+
"async-trait",
3365
3365
+
"http",
3366
3366
+
"reqwest-middleware",
3367
3367
+
]
3368
3368
+
3369
3369
+
[[package]]
3370
3370
+
name = "reqwest-middleware"
3371
3371
+
version = "0.4.2"
3372
3372
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3373
3373
+
checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e"
3374
3374
+
dependencies = [
3375
3375
+
"anyhow",
3376
3376
+
"async-trait",
3377
3377
+
"http",
3378
3378
+
"reqwest",
3379
3379
+
"serde",
3380
3380
+
"thiserror 1.0.69",
3381
3381
+
"tower-service",
3382
3382
+
]
3383
3383
+
3384
3384
+
[[package]]
3070
3385
name = "resolv-conf"
3071
3386
version = "0.7.5"
3072
3387
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3409
3724
]
3410
3725
3411
3726
[[package]]
3727
3727
+
name = "serde_path_to_error"
3728
3728
+
version = "0.1.20"
3729
3729
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3730
3730
+
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
3731
3731
+
dependencies = [
3732
3732
+
"itoa",
3733
3733
+
"serde",
3734
3734
+
"serde_core",
3735
3735
+
]
3736
3736
+
3737
3737
+
[[package]]
3412
3738
name = "serde_spanned"
3413
3739
version = "0.6.9"
3414
3740
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3622
3948
"serde_json",
3623
3949
"sha2",
3624
3950
"smallvec",
3625
3625
-
"thiserror",
3951
3951
+
"thiserror 2.0.17",
3626
3952
"tokio",
3627
3953
"tokio-stream",
3628
3954
"tracing",
···
3705
4031
"smallvec",
3706
4032
"sqlx-core",
3707
4033
"stringprep",
3708
3708
-
"thiserror",
4034
4034
+
"thiserror 2.0.17",
3709
4035
"tracing",
3710
4036
"whoami",
3711
4037
]
···
3742
4068
"smallvec",
3743
4069
"sqlx-core",
3744
4070
"stringprep",
3745
3745
-
"thiserror",
4071
4071
+
"thiserror 2.0.17",
3746
4072
"tracing",
3747
4073
"whoami",
3748
4074
]
···
3766
4092
"serde",
3767
4093
"serde_urlencoded",
3768
4094
"sqlx-core",
3769
3769
-
"thiserror",
4095
4095
+
"thiserror 2.0.17",
3770
4096
"tracing",
3771
4097
"url",
3772
4098
]
···
3890
4216
3891
4217
[[package]]
3892
4218
name = "thiserror"
4219
4219
+
version = "1.0.69"
4220
4220
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4221
4221
+
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
4222
4222
+
dependencies = [
4223
4223
+
"thiserror-impl 1.0.69",
4224
4224
+
]
4225
4225
+
4226
4226
+
[[package]]
4227
4227
+
name = "thiserror"
3893
4228
version = "2.0.17"
3894
4229
source = "registry+https://github.com/rust-lang/crates.io-index"
3895
4230
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
3896
4231
dependencies = [
3897
3897
-
"thiserror-impl",
4232
4232
+
"thiserror-impl 2.0.17",
4233
4233
+
]
4234
4234
+
4235
4235
+
[[package]]
4236
4236
+
name = "thiserror-impl"
4237
4237
+
version = "1.0.69"
4238
4238
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4239
4239
+
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
4240
4240
+
dependencies = [
4241
4241
+
"proc-macro2",
4242
4242
+
"quote",
4243
4243
+
"syn 2.0.106",
3898
4244
]
3899
4245
3900
4246
[[package]]
···
4103
4449
"tokio",
4104
4450
"tower-layer",
4105
4451
"tower-service",
4452
4452
+
"tracing",
4106
4453
]
4107
4454
4108
4455
[[package]]
···
4216
4563
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
4217
4564
4218
4565
[[package]]
4566
4566
+
name = "ulid"
4567
4567
+
version = "1.2.1"
4568
4568
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4569
4569
+
checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe"
4570
4570
+
dependencies = [
4571
4571
+
"rand 0.9.2",
4572
4572
+
"web-time",
4573
4573
+
]
4574
4574
+
4575
4575
+
[[package]]
4576
4576
+
name = "unicase"
4577
4577
+
version = "2.8.1"
4578
4578
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4579
4579
+
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
4580
4580
+
4581
4581
+
[[package]]
4219
4582
name = "unicode-bidi"
4220
4583
version = "0.3.18"
4221
4584
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4283
4646
version = "1.0.4"
4284
4647
source = "registry+https://github.com/rust-lang/crates.io-index"
4285
4648
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
4649
4649
+
4650
4650
+
[[package]]
4651
4651
+
name = "utf8parse"
4652
4652
+
version = "0.2.2"
4653
4653
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4654
4654
+
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
4286
4655
4287
4656
[[package]]
4288
4657
name = "uuid"
···
4474
4843
4475
4844
[[package]]
4476
4845
name = "widestring"
4477
4477
-
version = "1.2.0"
4846
4846
+
version = "1.2.1"
4478
4847
source = "registry+https://github.com/rust-lang/crates.io-index"
4479
4479
-
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
4848
4848
+
checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
4480
4849
4481
4850
[[package]]
4482
4851
name = "winapi"
···
4619
4988
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
4620
4989
dependencies = [
4621
4990
"windows-targets 0.52.6",
4991
4991
+
]
4992
4992
+
4993
4993
+
[[package]]
4994
4994
+
name = "windows-sys"
4995
4995
+
version = "0.60.2"
4996
4996
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4997
4997
+
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
4998
4998
+
dependencies = [
4999
4999
+
"windows-targets 0.53.5",
4622
5000
]
4623
5001
4624
5002
[[package]]
···
4860
5238
"pharos",
4861
5239
"rustc_version",
4862
5240
"send_wrapper",
4863
4863
-
"thiserror",
5241
5241
+
"thiserror 2.0.17",
4864
5242
"wasm-bindgen",
4865
5243
"wasm-bindgen-futures",
4866
5244
"web-sys",
+17
crates/ott-xrpc/Cargo.toml
···
3
3
version = "0.1.0"
4
4
edition = "2024"
5
5
6
6
+
[[bin]]
7
7
+
name = "atproto-xrpcs-helloworld"
8
8
+
path = "src/main.rs"
9
9
+
test = false
10
10
+
bench = false
11
11
+
doc = true
12
12
+
6
13
[dependencies]
14
14
+
anyhow = "1.0.100"
15
15
+
async-trait = "0.1.89"
7
16
atproto-identity = "0.13.0"
17
17
+
atproto-xrpcs = "0.13.0"
18
18
+
axum = "0.8.6"
19
19
+
clap = { version = "4.5.48", features = ["derive", "env"] }
20
20
+
http = "1.3.1"
21
21
+
reqwest = "0.12.23"
22
22
+
serde = { version = "1.0.228", features = ["derive"] }
23
23
+
serde_json = "1.0.145"
24
24
+
tokio = { version = "1.47.1", features = ["full"] }
+1
crates/ott-xrpc/src/lib.rs
···
1
1
+
pub mod webcontext;
+154
-2
crates/ott-xrpc/src/main.rs
···
1
1
-
fn main() {
2
2
-
println!("Hello, world!");
1
1
+
use anyhow::Result;
2
2
+
use atproto_identity::{
3
3
+
config::{default_env, optional_env, require_env, version, DnsNameservers},
4
4
+
key::{identify_key, to_public},
5
5
+
};
6
6
+
use atproto_xrpcs::authorization::ResolvingAuthorization;
7
7
+
use axum::{
8
8
+
extract::{Query, State},
9
9
+
response::{Html, IntoResponse, Response},
10
10
+
routing::get,
11
11
+
Json, Router,
12
12
+
};
13
13
+
use clap::Parser;
14
14
+
use http::{HeaderMap, StatusCode};
15
15
+
use ott_xrpc::webcontext::{ContextConfig, ServiceDID, ServiceDocument, WebContext};
16
16
+
use serde::Deserialize;
17
17
+
use serde_json::json;
18
18
+
19
19
+
/// AT Protocol XRPC Hello World Service
20
20
+
#[derive(Parser)]
21
21
+
#[command(
22
22
+
name = "atproto-xrpcs-helloworld",
23
23
+
version,
24
24
+
about = "AT Protocol XRPC Hello World demonstration service",
25
25
+
long_about = "
26
26
+
A demonstration XRPC service implementation showcasing the AT Protocol ecosystem.
27
27
+
This service provides a simple \"Hello, World!\" endpoint that supports both
28
28
+
authenticated and unauthenticated requests.
29
29
+
30
30
+
FEATURES:
31
31
+
- AT Protocol identity resolution and DID document management
32
32
+
- XRPC service endpoint with optional authentication
33
33
+
- DID:web identity publishing via .well-known endpoints
34
34
+
- JWT-based request authentication using AT Protocol standards
35
35
+
36
36
+
ENVIRONMENT VARIABLES:
37
37
+
SERVICE_KEY Private key for service identity (required)
38
38
+
EXTERNAL_BASE External hostname for service endpoints (required)
39
39
+
PORT HTTP server port (default: 8080)
40
40
+
PLC_HOSTNAME PLC directory hostname (default: plc.directory)
41
41
+
USER_AGENT HTTP User-Agent header (auto-generated)
42
42
+
DNS_NAMESERVERS Custom DNS nameservers (optional)
43
43
+
CERTIFICATE_BUNDLES Additional CA certificates (optional)
44
44
+
45
45
+
ENDPOINTS:
46
46
+
GET / HTML index page
47
47
+
GET /.well-known/did.json DID document (DID:web)
48
48
+
GET /.well-known/atproto-did AT Protocol DID identifier
49
49
+
GET /xrpc/.../Hello Hello World XRPC endpoint
50
50
+
"
51
51
+
)]
52
52
+
struct Args {}
53
53
+
54
54
+
#[tokio::main]
55
55
+
async fn main() -> Result<()> {
56
56
+
let _args = Args::parse();
57
57
+
58
58
+
let plc_hostname = default_env("PLC_HOSTNAME", "plc.directory");
59
59
+
60
60
+
let external_base = require_env("EXTERNAL_BASE")?;
61
61
+
let port = default_env("PORT", "8080");
62
62
+
let service_did = format!("did:web:{}", external_base);
63
63
+
let dns_nameservers: DnsNameservers = optional_env("DNS_NAMESERVERS").try_into()?;
64
64
+
65
65
+
let private_service_key = require_env("SERVICE_KEY")?;
66
66
+
let private_service_key_data = identify_key(&private_service_key)?;
67
67
+
let public_service_key_data = to_public(&private_service_key_data)?;
68
68
+
let public_service_key = public_service_key_data.to_string();
69
69
+
let default_user_agent = format!(
70
70
+
"atproto-identity-rs ({}; +https://tangled.sh/@smokesignal.events/atproto-identity-rs)",
71
71
+
version()?
72
72
+
);
73
73
+
let user_agent = default_env("USER_AGENT", &default_user_agent);
74
74
+
75
75
+
let config = ContextConfig {
76
76
+
public_service_key,
77
77
+
private_service_key_data,
78
78
+
service_did,
79
79
+
plc_hostname,
80
80
+
external_base,
81
81
+
dns_nameservers,
82
82
+
user_agent,
83
83
+
};
84
84
+
let web_context = WebContext::new(config).unwrap();
85
85
+
86
86
+
let router = Router::new()
87
87
+
.route("/", get(handle_index))
88
88
+
.route("/.well-known/did.json", get(handle_wellknown_did_web))
89
89
+
.route(
90
90
+
"/.well-known/atproto-did",
91
91
+
get(handle_wellknown_atproto_did),
92
92
+
)
93
93
+
.route(
94
94
+
"/xrpc/garden.lexicon.ngerakines.helloworld.Hello",
95
95
+
get(handle_xrpc_hello_world),
96
96
+
)
97
97
+
.with_state(web_context);
98
98
+
99
99
+
let bind_address = format!("0.0.0.0:{}", port);
100
100
+
let listener = tokio::net::TcpListener::bind(&bind_address).await?;
101
101
+
102
102
+
// Start the web server in the background
103
103
+
let server_handle = tokio::spawn(async move {
104
104
+
if let Err(e) = axum::serve(listener, router).await {
105
105
+
eprintln!("Server error: {}", e);
106
106
+
}
107
107
+
});
108
108
+
109
109
+
println!(
110
110
+
"XRPC Hello World service started on http://0.0.0.0:{}",
111
111
+
port
112
112
+
);
113
113
+
114
114
+
// Keep the server running
115
115
+
server_handle.await.unwrap();
116
116
+
117
117
+
Ok(())
118
118
+
}
119
119
+
120
120
+
async fn handle_index() -> Html<&'static str> {
121
121
+
Html("<html><body><h1>Hello, World!</h1></body></html>")
122
122
+
}
123
123
+
124
124
+
// /.well-known/did.json
125
125
+
async fn handle_wellknown_did_web(
126
126
+
service_document: State<ServiceDocument>,
127
127
+
) -> Json<serde_json::Value> {
128
128
+
Json(service_document.0 .0)
129
129
+
}
130
130
+
131
131
+
// /.well-known/atproto-did
132
132
+
async fn handle_wellknown_atproto_did(service_did: State<ServiceDID>) -> Response {
133
133
+
(StatusCode::OK, service_did.0 .0).into_response()
134
134
+
}
135
135
+
136
136
+
#[derive(Deserialize)]
137
137
+
struct HelloParameters {
138
138
+
subject: Option<String>,
139
139
+
}
140
140
+
141
141
+
// /xrpc/garden.lexicon.ngerakines.helloworld.Hello
142
142
+
async fn handle_xrpc_hello_world(
143
143
+
parameters: Query<HelloParameters>,
144
144
+
headers: HeaderMap,
145
145
+
authorization: Option<ResolvingAuthorization>,
146
146
+
) -> Json<serde_json::Value> {
147
147
+
println!("headers {headers:?}");
148
148
+
let subject = parameters.subject.as_deref().unwrap_or("World");
149
149
+
let message = if authorization.is_none() {
150
150
+
format!("Hello, {subject}!")
151
151
+
} else {
152
152
+
format!("Hello, authenticated {subject}!")
153
153
+
};
154
154
+
Json(json!({ "message": message }))
3
155
}
+176
crates/ott-xrpc/src/webcontext.rs
···
1
1
+
use anyhow::Result;
2
2
+
use async_trait::async_trait;
3
3
+
use atproto_identity::config::{optional_env, CertificateBundles, DnsNameservers};
4
4
+
use atproto_identity::resolve::{HickoryDnsResolver, SharedIdentityResolver};
5
5
+
use atproto_identity::{
6
6
+
key::{KeyData, KeyProvider},
7
7
+
resolve::InnerIdentityResolver,
8
8
+
storage_lru::LruDidDocumentStorage,
9
9
+
};
10
10
+
use serde_json::json;
11
11
+
use std::ops::Deref;
12
12
+
use std::{collections::HashMap, num::NonZeroUsize, sync::Arc};
13
13
+
14
14
+
use atproto_identity::{resolve::IdentityResolver, storage::DidDocumentStorage};
15
15
+
use axum::extract::FromRef;
16
16
+
17
17
+
#[derive(Clone)]
18
18
+
pub struct SimpleKeyProvider {
19
19
+
keys: HashMap<String, KeyData>,
20
20
+
}
21
21
+
22
22
+
impl Default for SimpleKeyProvider {
23
23
+
fn default() -> Self {
24
24
+
Self::new()
25
25
+
}
26
26
+
}
27
27
+
28
28
+
impl SimpleKeyProvider {
29
29
+
pub fn new() -> Self {
30
30
+
Self {
31
31
+
keys: HashMap::new(),
32
32
+
}
33
33
+
}
34
34
+
}
35
35
+
36
36
+
#[async_trait]
37
37
+
impl KeyProvider for SimpleKeyProvider {
38
38
+
async fn get_private_key_by_id(&self, key_id: &str) -> anyhow::Result<Option<KeyData>> {
39
39
+
Ok(self.keys.get(key_id).cloned())
40
40
+
}
41
41
+
}
42
42
+
43
43
+
#[derive(Clone)]
44
44
+
pub struct ServiceDocument(pub serde_json::Value);
45
45
+
46
46
+
#[derive(Clone)]
47
47
+
pub struct ServiceDID(pub String);
48
48
+
49
49
+
pub struct InnerWebContext {
50
50
+
pub http_client: reqwest::Client,
51
51
+
pub document_storage: Arc<dyn DidDocumentStorage>,
52
52
+
pub key_provider: Arc<dyn KeyProvider>,
53
53
+
pub service_document: ServiceDocument,
54
54
+
pub service_did: ServiceDID,
55
55
+
pub identity_resolver: Arc<dyn IdentityResolver>,
56
56
+
}
57
57
+
58
58
+
#[derive(Clone, FromRef)]
59
59
+
pub struct WebContext(pub Arc<InnerWebContext>);
60
60
+
61
61
+
pub struct ContextConfig {
62
62
+
pub public_service_key: String,
63
63
+
pub private_service_key_data: KeyData,
64
64
+
pub service_did: String,
65
65
+
pub plc_hostname: String,
66
66
+
pub external_base: String,
67
67
+
pub dns_nameservers: DnsNameservers,
68
68
+
pub user_agent: String,
69
69
+
}
70
70
+
71
71
+
impl WebContext {
72
72
+
pub fn new(config: ContextConfig) -> Result<Self> {
73
73
+
let signing_key_storage = HashMap::from_iter(vec![(
74
74
+
config.public_service_key.clone(),
75
75
+
config.private_service_key_data.clone(),
76
76
+
)]);
77
77
+
78
78
+
let certificate_bundles: CertificateBundles =
79
79
+
optional_env("CERTIFICATE_BUNDLES").try_into()?;
80
80
+
81
81
+
let mut client_builder = reqwest::Client::builder();
82
82
+
for ca_certificate in certificate_bundles.as_ref() {
83
83
+
let cert = std::fs::read(ca_certificate)?;
84
84
+
let cert = reqwest::Certificate::from_pem(&cert)?;
85
85
+
client_builder = client_builder.add_root_certificate(cert);
86
86
+
}
87
87
+
88
88
+
client_builder = client_builder.user_agent(config.user_agent);
89
89
+
let http_client = client_builder.build()?;
90
90
+
91
91
+
let dns_resolver = HickoryDnsResolver::create_resolver(config.dns_nameservers.as_ref());
92
92
+
93
93
+
let service_did = config.service_did.clone();
94
94
+
let external_base = config.external_base;
95
95
+
let service_document = ServiceDocument(json!({
96
96
+
"@context": vec!["https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1"],
97
97
+
"id": service_did,
98
98
+
"verificationMethod":[{
99
99
+
"id": format!("{service_did}#atproto"),
100
100
+
"type":"Multikey",
101
101
+
"controller": service_did,
102
102
+
"publicKeyMultibase": config.public_service_key
103
103
+
}],
104
104
+
"service":[{
105
105
+
"id":"#helloworld",
106
106
+
"type":"HelloWorldService",
107
107
+
"serviceEndpoint":format!("https://{external_base}")
108
108
+
}]
109
109
+
}
110
110
+
));
111
111
+
112
112
+
let service_did = ServiceDID(config.service_did);
113
113
+
114
114
+
let identity_resolver = Arc::new(SharedIdentityResolver(Arc::new(InnerIdentityResolver {
115
115
+
dns_resolver: Arc::new(dns_resolver),
116
116
+
http_client: http_client.clone(),
117
117
+
plc_hostname: config.plc_hostname,
118
118
+
})));
119
119
+
120
120
+
let web_context = Self(Arc::new(InnerWebContext {
121
121
+
http_client: http_client.clone(),
122
122
+
document_storage: Arc::new(LruDidDocumentStorage::new(NonZeroUsize::new(255).unwrap())),
123
123
+
key_provider: Arc::new(SimpleKeyProvider {
124
124
+
keys: signing_key_storage,
125
125
+
}),
126
126
+
service_document,
127
127
+
service_did,
128
128
+
identity_resolver,
129
129
+
}));
130
130
+
Ok(web_context)
131
131
+
}
132
132
+
}
133
133
+
134
134
+
impl Deref for WebContext {
135
135
+
type Target = InnerWebContext;
136
136
+
137
137
+
fn deref(&self) -> &Self::Target {
138
138
+
&self.0
139
139
+
}
140
140
+
}
141
141
+
142
142
+
impl FromRef<WebContext> for reqwest::Client {
143
143
+
fn from_ref(context: &WebContext) -> Self {
144
144
+
context.0.http_client.clone()
145
145
+
}
146
146
+
}
147
147
+
148
148
+
impl FromRef<WebContext> for ServiceDocument {
149
149
+
fn from_ref(context: &WebContext) -> Self {
150
150
+
context.0.service_document.clone()
151
151
+
}
152
152
+
}
153
153
+
154
154
+
impl FromRef<WebContext> for ServiceDID {
155
155
+
fn from_ref(context: &WebContext) -> Self {
156
156
+
context.0.service_did.clone()
157
157
+
}
158
158
+
}
159
159
+
160
160
+
impl FromRef<WebContext> for Arc<dyn DidDocumentStorage> {
161
161
+
fn from_ref(context: &WebContext) -> Self {
162
162
+
context.0.document_storage.clone()
163
163
+
}
164
164
+
}
165
165
+
166
166
+
impl FromRef<WebContext> for Arc<dyn KeyProvider> {
167
167
+
fn from_ref(context: &WebContext) -> Self {
168
168
+
context.0.key_provider.clone()
169
169
+
}
170
170
+
}
171
171
+
172
172
+
impl FromRef<WebContext> for Arc<dyn IdentityResolver> {
173
173
+
fn from_ref(context: &WebContext) -> Self {
174
174
+
context.0.identity_resolver.clone()
175
175
+
}
176
176
+
}