+32
-5
README.md
+32
-5
README.md
···
2
2
3
3
A (somewhat barebones) atproto app for creating custom sites without hosting!
4
4
5
+
> [!CAUTION]
6
+
> This software is super duper alpha and not tested thoroughly! Use at your own risk!
7
+
5
8
- Lexicons are located at [`./lexicons`](./lexicons/)
6
9
- Server backend is located at [`./server`](./server/)
7
10
- Upload CLI is located at [`./upload`](./upload/)
8
11
- Web GUI **will be** located at [`./web-gui`](./web-gui/)
9
12
- Fuse tool **will be** located at [`./fuse`](./fuse/)
10
13
11
-
TODO:
14
+
## How to:
15
+
16
+
**View someones site?**
17
+
> Head to `https://<handle>.atcities.dev/` or `https://<did>.did-<method>.atcities.dev/`.
18
+
19
+
**Upload your own site?**
20
+
> Use the upload cli. Installation guide below.
21
+
22
+
**Self host atcities.dev?**
23
+
> Clone this repo and setup the `.env` file for `/server`, then run `deno run run`
24
+
25
+
### CLI installation guide.
26
+
27
+
1. Build from source:
28
+
Prerequisites: `git` `cargo` `rust`
29
+
```sh
30
+
git clone https://tangled.org/@vielle.dev/atcities.dev
31
+
cd atcities.dev/upload
32
+
cargo build
33
+
sudo cp ./target/debug/atcities-upload /bin
34
+
# Reload your shell environment
35
+
atcities-upload --version
36
+
```
37
+
38
+
## Todo:
12
39
13
40
- [x] Resolve `handle.host` and `did.did-method.host` domains to records/blobs
14
41
- [x] Backfill network
···
16
43
- [x] Store blobs for CDN (max ~0.25gb per user)
17
44
- [x] Moderate illegal content or hope that people are niceys
18
45
(Hope that people are niceys)
19
-
- [ ] Finish CLI tool
20
-
- [ ] Sign in via app password
21
-
- [ ] Clear old site
22
-
- [ ] Upload new site
46
+
- [x] Finish CLI tool
47
+
- [x] Sign in via app password
48
+
- [x] Clear old site
49
+
- [x] Upload new site
23
50
- [ ] Fuse uploader
24
51
- [ ] Web GUI uploader
+1
server/deno.json
+1
server/deno.json
···
1
1
{
2
2
"tasks": {
3
3
"dev": "deno run --watch --allow-net --allow-env --allow-sys --allow-read=/usr/bin/ldd,./blobs,./src --allow-write=./blobs --allow-ffi --env-file src/index.ts",
4
+
"run": "deno run --allow-net --allow-env --allow-sys --allow-read=/usr/bin/ldd,./blobs,./src --allow-write=./blobs --allow-ffi --env-file src/index.ts",
4
5
"lexgen": "deno run --allow-env --allow-sys --allow-read=.. --allow-write=./src/lexicons --no-prompt @atcute/lex-cli generate -c ./lex.config.js && cat ./src/lexicons/index.ts | sed \"s/.js/.ts/\" > ./src/lexicons/index.ts",
5
6
"dk": "deno run -A --node-modules-dir npm:drizzle-kit"
6
7
},
+355
-67
upload/Cargo.lock
+355
-67
upload/Cargo.lock
···
22
22
]
23
23
24
24
[[package]]
25
+
name = "addr2line"
26
+
version = "0.25.1"
27
+
source = "registry+https://github.com/rust-lang/crates.io-index"
28
+
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
29
+
dependencies = [
30
+
"gimli",
31
+
]
32
+
33
+
[[package]]
25
34
name = "adler2"
26
35
version = "2.0.1"
27
36
source = "registry+https://github.com/rust-lang/crates.io-index"
···
149
158
dependencies = [
150
159
"proc-macro2",
151
160
"quote",
152
-
"syn 2.0.106",
161
+
"syn 2.0.107",
153
162
]
154
163
155
164
[[package]]
156
165
name = "atcities-upload"
157
-
version = "0.1.0"
166
+
version = "1.0.1"
158
167
dependencies = [
159
168
"clap",
169
+
"env_logger",
160
170
"ignore",
161
171
"jacquard",
172
+
"lexicons",
173
+
"miette",
162
174
"mime_guess",
163
175
"regex",
164
176
"reqwest",
177
+
"thiserror 2.0.17",
165
178
"tokio",
166
179
]
167
180
···
178
191
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
179
192
180
193
[[package]]
194
+
name = "backtrace"
195
+
version = "0.3.76"
196
+
source = "registry+https://github.com/rust-lang/crates.io-index"
197
+
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
198
+
dependencies = [
199
+
"addr2line",
200
+
"cfg-if",
201
+
"libc",
202
+
"miniz_oxide",
203
+
"object",
204
+
"rustc-demangle",
205
+
"windows-link 0.2.1",
206
+
]
207
+
208
+
[[package]]
209
+
name = "backtrace-ext"
210
+
version = "0.2.1"
211
+
source = "registry+https://github.com/rust-lang/crates.io-index"
212
+
checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
213
+
dependencies = [
214
+
"backtrace",
215
+
]
216
+
217
+
[[package]]
181
218
name = "base-x"
182
219
version = "0.2.11"
183
220
source = "registry+https://github.com/rust-lang/crates.io-index"
···
254
291
"proc-macro2",
255
292
"quote",
256
293
"rustversion",
257
-
"syn 2.0.106",
294
+
"syn 2.0.107",
258
295
]
259
296
260
297
[[package]]
···
489
526
"heck 0.5.0",
490
527
"proc-macro2",
491
528
"quote",
492
-
"syn 2.0.106",
529
+
"syn 2.0.107",
493
530
]
494
531
495
532
[[package]]
···
660
697
"proc-macro2",
661
698
"quote",
662
699
"strsim",
663
-
"syn 2.0.106",
700
+
"syn 2.0.107",
664
701
]
665
702
666
703
[[package]]
···
671
708
dependencies = [
672
709
"darling_core",
673
710
"quote",
674
-
"syn 2.0.106",
711
+
"syn 2.0.107",
675
712
]
676
713
677
714
[[package]]
···
711
748
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
712
749
dependencies = [
713
750
"data-encoding",
714
-
"syn 2.0.106",
751
+
"syn 2.0.107",
715
752
]
716
753
717
754
[[package]]
···
764
801
dependencies = [
765
802
"proc-macro2",
766
803
"quote",
767
-
"syn 2.0.106",
804
+
"syn 2.0.107",
768
805
]
769
806
770
807
[[package]]
···
819
856
"heck 0.5.0",
820
857
"proc-macro2",
821
858
"quote",
822
-
"syn 2.0.106",
859
+
"syn 2.0.107",
860
+
]
861
+
862
+
[[package]]
863
+
name = "env_filter"
864
+
version = "0.1.4"
865
+
source = "registry+https://github.com/rust-lang/crates.io-index"
866
+
checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
867
+
dependencies = [
868
+
"log",
869
+
"regex",
870
+
]
871
+
872
+
[[package]]
873
+
name = "env_logger"
874
+
version = "0.11.8"
875
+
source = "registry+https://github.com/rust-lang/crates.io-index"
876
+
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
877
+
dependencies = [
878
+
"anstream",
879
+
"anstyle",
880
+
"env_filter",
881
+
"jiff",
882
+
"log",
823
883
]
824
884
825
885
[[package]]
···
934
994
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
935
995
936
996
[[package]]
997
+
name = "futures-macro"
998
+
version = "0.3.31"
999
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1000
+
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
1001
+
dependencies = [
1002
+
"proc-macro2",
1003
+
"quote",
1004
+
"syn 2.0.107",
1005
+
]
1006
+
1007
+
[[package]]
937
1008
name = "futures-sink"
938
1009
version = "0.3.31"
939
1010
source = "registry+https://github.com/rust-lang/crates.io-index"
···
952
1023
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
953
1024
dependencies = [
954
1025
"futures-core",
1026
+
"futures-io",
1027
+
"futures-macro",
1028
+
"futures-sink",
955
1029
"futures-task",
1030
+
"memchr",
956
1031
"pin-project-lite",
957
1032
"pin-utils",
958
1033
"slab",
959
1034
]
960
1035
961
1036
[[package]]
1037
+
name = "genawaiter"
1038
+
version = "0.99.1"
1039
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1040
+
checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0"
1041
+
dependencies = [
1042
+
"futures-core",
1043
+
"genawaiter-macro",
1044
+
"genawaiter-proc-macro",
1045
+
"proc-macro-hack",
1046
+
]
1047
+
1048
+
[[package]]
1049
+
name = "genawaiter-macro"
1050
+
version = "0.99.1"
1051
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1052
+
checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc"
1053
+
1054
+
[[package]]
1055
+
name = "genawaiter-proc-macro"
1056
+
version = "0.99.1"
1057
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1058
+
checksum = "784f84eebc366e15251c4a8c3acee82a6a6f427949776ecb88377362a9621738"
1059
+
dependencies = [
1060
+
"proc-macro-error 0.4.12",
1061
+
"proc-macro-hack",
1062
+
"proc-macro2",
1063
+
"quote",
1064
+
"syn 1.0.109",
1065
+
]
1066
+
1067
+
[[package]]
962
1068
name = "generic-array"
963
1069
version = "0.14.9"
964
1070
source = "registry+https://github.com/rust-lang/crates.io-index"
···
995
1101
"wasip2",
996
1102
"wasm-bindgen",
997
1103
]
1104
+
1105
+
[[package]]
1106
+
name = "gimli"
1107
+
version = "0.32.3"
1108
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1109
+
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
998
1110
999
1111
[[package]]
1000
1112
name = "globset"
···
1440
1552
1441
1553
[[package]]
1442
1554
name = "indexmap"
1443
-
version = "2.11.4"
1555
+
version = "2.12.0"
1444
1556
source = "registry+https://github.com/rust-lang/crates.io-index"
1445
-
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
1557
+
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
1446
1558
dependencies = [
1447
1559
"equivalent",
1448
1560
"hashbrown 0.16.0",
···
1494
1606
]
1495
1607
1496
1608
[[package]]
1609
+
name = "is_ci"
1610
+
version = "1.2.0"
1611
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1612
+
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
1613
+
1614
+
[[package]]
1497
1615
name = "is_terminal_polyfill"
1498
1616
version = "1.70.1"
1499
1617
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1507
1625
1508
1626
[[package]]
1509
1627
name = "jacquard"
1510
-
version = "0.5.3"
1628
+
version = "0.6.0"
1511
1629
source = "registry+https://github.com/rust-lang/crates.io-index"
1512
-
checksum = "bf257386e29370eb7387093736d59f2aeda3ac692a37481c7201bc5f9cc82fae"
1630
+
checksum = "5857f000e67605995ba7c24c9833f840adf5c063a731a6f72f69e0e3c986791c"
1513
1631
dependencies = [
1514
1632
"bon",
1515
1633
"bytes",
···
1539
1657
1540
1658
[[package]]
1541
1659
name = "jacquard-api"
1542
-
version = "0.5.3"
1660
+
version = "0.6.0"
1543
1661
source = "registry+https://github.com/rust-lang/crates.io-index"
1544
-
checksum = "e67619aa60467ee687633e5face5743835e5f9d8e57c387a8d830cfd2ba8d2c8"
1662
+
checksum = "58132b60473124a34c64c267a1c3390c2e4a4dfd62c801639903c4aefd05f52d"
1545
1663
dependencies = [
1546
1664
"bon",
1547
1665
"bytes",
···
1549
1667
"jacquard-derive",
1550
1668
"miette",
1551
1669
"serde",
1670
+
"serde_ipld_dagcbor",
1552
1671
"thiserror 2.0.17",
1553
1672
]
1554
1673
1555
1674
[[package]]
1556
1675
name = "jacquard-common"
1557
-
version = "0.5.3"
1676
+
version = "0.6.0"
1558
1677
source = "registry+https://github.com/rust-lang/crates.io-index"
1559
-
checksum = "8b1c05d479eee46004ba3ec495e7802b7c02cc429396aeb7296a558b9cb6e6ce"
1678
+
checksum = "f7f1bab0279ae2e29c3383f132a05b9c708585fab62e94292affdf352ce13242"
1560
1679
dependencies = [
1561
1680
"base64 0.22.1",
1562
1681
"bon",
1563
1682
"bytes",
1564
1683
"chrono",
1565
1684
"cid",
1685
+
"genawaiter",
1566
1686
"getrandom 0.3.4",
1567
1687
"http",
1568
1688
"ipld-core",
···
1584
1704
"smol_str",
1585
1705
"thiserror 2.0.17",
1586
1706
"tokio",
1707
+
"tokio-util",
1587
1708
"trait-variant",
1588
1709
"url",
1589
1710
]
1590
1711
1591
1712
[[package]]
1592
1713
name = "jacquard-derive"
1593
-
version = "0.5.3"
1714
+
version = "0.6.0"
1594
1715
source = "registry+https://github.com/rust-lang/crates.io-index"
1595
-
checksum = "aadace50223141e60d16e26a28c8c8a9b647f291814986010234cf1c130367ab"
1716
+
checksum = "a4741844c0638498156338e6230a81ecb54d0a061ffc6f4f54e97b94972a01fb"
1596
1717
dependencies = [
1597
1718
"proc-macro2",
1598
1719
"quote",
1599
-
"syn 2.0.106",
1720
+
"syn 2.0.107",
1600
1721
]
1601
1722
1602
1723
[[package]]
1603
1724
name = "jacquard-identity"
1604
-
version = "0.5.3"
1725
+
version = "0.6.0"
1605
1726
source = "registry+https://github.com/rust-lang/crates.io-index"
1606
-
checksum = "afafcd8fcc26095789aeefe4f54cda4471f1748ba11fa7886184f515362b6339"
1727
+
checksum = "65ae022725ddc09ce03c1a02a97b895279e1d46957c0574a032fa78b81273263"
1607
1728
dependencies = [
1608
1729
"bon",
1609
1730
"bytes",
···
1626
1747
1627
1748
[[package]]
1628
1749
name = "jacquard-oauth"
1629
-
version = "0.5.3"
1750
+
version = "0.6.0"
1630
1751
source = "registry+https://github.com/rust-lang/crates.io-index"
1631
-
checksum = "597e74c6697a449e834936dde22c30165f0f2da0c38b42ec599173b58d73a098"
1752
+
checksum = "8c37269e2ea0c6c3418bf61fb3d342aab87b1bda706ebae49e454f8e50580cab"
1632
1753
dependencies = [
1633
1754
"base64 0.22.1",
1634
1755
"bytes",
···
1660
1781
]
1661
1782
1662
1783
[[package]]
1784
+
name = "jiff"
1785
+
version = "0.2.15"
1786
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1787
+
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
1788
+
dependencies = [
1789
+
"jiff-static",
1790
+
"log",
1791
+
"portable-atomic",
1792
+
"portable-atomic-util",
1793
+
"serde",
1794
+
]
1795
+
1796
+
[[package]]
1797
+
name = "jiff-static"
1798
+
version = "0.2.15"
1799
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1800
+
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
1801
+
dependencies = [
1802
+
"proc-macro2",
1803
+
"quote",
1804
+
"syn 2.0.107",
1805
+
]
1806
+
1807
+
[[package]]
1663
1808
name = "jni"
1664
1809
version = "0.21.1"
1665
1810
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1761
1906
1762
1907
[[package]]
1763
1908
name = "lexicons"
1764
-
version = "0.1.0"
1909
+
version = "1.0.0"
1765
1910
dependencies = [
1766
1911
"bon",
1767
1912
"bytes",
···
1875
2020
source = "registry+https://github.com/rust-lang/crates.io-index"
1876
2021
checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
1877
2022
dependencies = [
2023
+
"backtrace",
2024
+
"backtrace-ext",
1878
2025
"cfg-if",
1879
2026
"miette-derive",
1880
-
"unicode-width",
2027
+
"owo-colors",
2028
+
"supports-color",
2029
+
"supports-hyperlinks",
2030
+
"supports-unicode",
2031
+
"terminal_size",
2032
+
"textwrap",
2033
+
"unicode-width 0.1.14",
1881
2034
]
1882
2035
1883
2036
[[package]]
···
1888
2041
dependencies = [
1889
2042
"proc-macro2",
1890
2043
"quote",
1891
-
"syn 2.0.106",
2044
+
"syn 2.0.107",
1892
2045
]
1893
2046
1894
2047
[[package]]
···
1925
2078
1926
2079
[[package]]
1927
2080
name = "mio"
1928
-
version = "1.0.4"
2081
+
version = "1.1.0"
1929
2082
source = "registry+https://github.com/rust-lang/crates.io-index"
1930
-
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
2083
+
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
1931
2084
dependencies = [
1932
2085
"libc",
1933
2086
"wasi",
1934
-
"windows-sys 0.59.0",
2087
+
"windows-sys 0.61.2",
1935
2088
]
1936
2089
1937
2090
[[package]]
···
2090
2243
]
2091
2244
2092
2245
[[package]]
2246
+
name = "object"
2247
+
version = "0.37.3"
2248
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2249
+
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
2250
+
dependencies = [
2251
+
"memchr",
2252
+
]
2253
+
2254
+
[[package]]
2093
2255
name = "once_cell"
2094
2256
version = "1.21.3"
2095
2257
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2124
2286
dependencies = [
2125
2287
"proc-macro2",
2126
2288
"quote",
2127
-
"syn 2.0.106",
2289
+
"syn 2.0.107",
2128
2290
]
2129
2291
2130
2292
[[package]]
···
2166
2328
"proc-macro2",
2167
2329
"proc-macro2-diagnostics",
2168
2330
"quote",
2169
-
"syn 2.0.106",
2331
+
"syn 2.0.107",
2170
2332
]
2333
+
2334
+
[[package]]
2335
+
name = "owo-colors"
2336
+
version = "4.2.3"
2337
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2338
+
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
2171
2339
2172
2340
[[package]]
2173
2341
name = "p256"
···
2269
2437
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
2270
2438
2271
2439
[[package]]
2440
+
name = "portable-atomic"
2441
+
version = "1.11.1"
2442
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2443
+
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
2444
+
2445
+
[[package]]
2446
+
name = "portable-atomic-util"
2447
+
version = "0.2.4"
2448
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2449
+
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
2450
+
dependencies = [
2451
+
"portable-atomic",
2452
+
]
2453
+
2454
+
[[package]]
2272
2455
name = "potential_utf"
2273
2456
version = "0.1.3"
2274
2457
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2299
2482
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
2300
2483
dependencies = [
2301
2484
"proc-macro2",
2302
-
"syn 2.0.106",
2485
+
"syn 2.0.107",
2303
2486
]
2304
2487
2305
2488
[[package]]
···
2313
2496
2314
2497
[[package]]
2315
2498
name = "proc-macro-error"
2499
+
version = "0.4.12"
2500
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2501
+
checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
2502
+
dependencies = [
2503
+
"proc-macro-error-attr 0.4.12",
2504
+
"proc-macro2",
2505
+
"quote",
2506
+
"syn 1.0.109",
2507
+
"version_check",
2508
+
]
2509
+
2510
+
[[package]]
2511
+
name = "proc-macro-error"
2316
2512
version = "1.0.4"
2317
2513
source = "registry+https://github.com/rust-lang/crates.io-index"
2318
2514
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
2319
2515
dependencies = [
2320
-
"proc-macro-error-attr",
2516
+
"proc-macro-error-attr 1.0.4",
2321
2517
"proc-macro2",
2322
2518
"quote",
2323
2519
"syn 1.0.109",
···
2326
2522
2327
2523
[[package]]
2328
2524
name = "proc-macro-error-attr"
2525
+
version = "0.4.12"
2526
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2527
+
checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
2528
+
dependencies = [
2529
+
"proc-macro2",
2530
+
"quote",
2531
+
"syn 1.0.109",
2532
+
"syn-mid",
2533
+
"version_check",
2534
+
]
2535
+
2536
+
[[package]]
2537
+
name = "proc-macro-error-attr"
2329
2538
version = "1.0.4"
2330
2539
source = "registry+https://github.com/rust-lang/crates.io-index"
2331
2540
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
···
2334
2543
"quote",
2335
2544
"version_check",
2336
2545
]
2546
+
2547
+
[[package]]
2548
+
name = "proc-macro-hack"
2549
+
version = "0.5.20+deprecated"
2550
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2551
+
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
2337
2552
2338
2553
[[package]]
2339
2554
name = "proc-macro2"
···
2352
2567
dependencies = [
2353
2568
"proc-macro2",
2354
2569
"quote",
2355
-
"syn 2.0.106",
2570
+
"syn 2.0.107",
2356
2571
"version_check",
2357
2572
"yansi",
2358
2573
]
···
2585
2800
"url",
2586
2801
"wasm-bindgen",
2587
2802
"wasm-bindgen-futures",
2803
+
"wasm-streams",
2588
2804
"web-sys",
2589
2805
"webpki-roots",
2590
2806
]
···
2664
2880
]
2665
2881
2666
2882
[[package]]
2883
+
name = "rustc-demangle"
2884
+
version = "0.1.26"
2885
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2886
+
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
2887
+
2888
+
[[package]]
2667
2889
name = "rustc-hash"
2668
2890
version = "2.1.1"
2669
2891
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2684
2906
2685
2907
[[package]]
2686
2908
name = "rustls"
2687
-
version = "0.23.32"
2909
+
version = "0.23.33"
2688
2910
source = "registry+https://github.com/rust-lang/crates.io-index"
2689
-
checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40"
2911
+
checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c"
2690
2912
dependencies = [
2691
2913
"once_cell",
2692
2914
"ring",
···
2833
3055
dependencies = [
2834
3056
"proc-macro2",
2835
3057
"quote",
2836
-
"syn 2.0.106",
3058
+
"syn 2.0.107",
2837
3059
]
2838
3060
2839
3061
[[package]]
···
2910
3132
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
2911
3133
2912
3134
[[package]]
2913
-
name = "signal-hook-registry"
2914
-
version = "1.4.6"
2915
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2916
-
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
2917
-
dependencies = [
2918
-
"libc",
2919
-
]
2920
-
2921
-
[[package]]
2922
3135
name = "signature"
2923
3136
version = "2.2.0"
2924
3137
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3009
3222
"ciborium",
3010
3223
"hex_fmt",
3011
3224
"indoc",
3012
-
"proc-macro-error",
3225
+
"proc-macro-error 1.0.4",
3013
3226
"proc-macro2",
3014
3227
"quote",
3015
3228
"serde",
3016
3229
"sha2",
3017
-
"syn 2.0.106",
3230
+
"syn 2.0.107",
3018
3231
"thiserror 1.0.69",
3019
3232
]
3020
3233
···
3037
3250
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
3038
3251
3039
3252
[[package]]
3253
+
name = "supports-color"
3254
+
version = "3.0.2"
3255
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3256
+
checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6"
3257
+
dependencies = [
3258
+
"is_ci",
3259
+
]
3260
+
3261
+
[[package]]
3262
+
name = "supports-hyperlinks"
3263
+
version = "3.1.0"
3264
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3265
+
checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b"
3266
+
3267
+
[[package]]
3268
+
name = "supports-unicode"
3269
+
version = "3.0.0"
3270
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3271
+
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
3272
+
3273
+
[[package]]
3040
3274
name = "syn"
3041
3275
version = "1.0.109"
3042
3276
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3049
3283
3050
3284
[[package]]
3051
3285
name = "syn"
3052
-
version = "2.0.106"
3286
+
version = "2.0.107"
3053
3287
source = "registry+https://github.com/rust-lang/crates.io-index"
3054
-
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
3288
+
checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b"
3055
3289
dependencies = [
3056
3290
"proc-macro2",
3057
3291
"quote",
···
3059
3293
]
3060
3294
3061
3295
[[package]]
3296
+
name = "syn-mid"
3297
+
version = "0.5.4"
3298
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3299
+
checksum = "fea305d57546cc8cd04feb14b62ec84bf17f50e3f7b12560d7bfa9265f39d9ed"
3300
+
dependencies = [
3301
+
"proc-macro2",
3302
+
"quote",
3303
+
"syn 1.0.109",
3304
+
]
3305
+
3306
+
[[package]]
3062
3307
name = "sync_wrapper"
3063
3308
version = "1.0.2"
3064
3309
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3075
3320
dependencies = [
3076
3321
"proc-macro2",
3077
3322
"quote",
3078
-
"syn 2.0.106",
3323
+
"syn 2.0.107",
3079
3324
]
3080
3325
3081
3326
[[package]]
···
3113
3358
]
3114
3359
3115
3360
[[package]]
3361
+
name = "terminal_size"
3362
+
version = "0.4.3"
3363
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3364
+
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
3365
+
dependencies = [
3366
+
"rustix",
3367
+
"windows-sys 0.60.2",
3368
+
]
3369
+
3370
+
[[package]]
3371
+
name = "textwrap"
3372
+
version = "0.16.2"
3373
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3374
+
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
3375
+
dependencies = [
3376
+
"unicode-linebreak",
3377
+
"unicode-width 0.2.2",
3378
+
]
3379
+
3380
+
[[package]]
3116
3381
name = "thiserror"
3117
3382
version = "1.0.69"
3118
3383
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3138
3403
dependencies = [
3139
3404
"proc-macro2",
3140
3405
"quote",
3141
-
"syn 2.0.106",
3406
+
"syn 2.0.107",
3142
3407
]
3143
3408
3144
3409
[[package]]
···
3149
3414
dependencies = [
3150
3415
"proc-macro2",
3151
3416
"quote",
3152
-
"syn 2.0.106",
3417
+
"syn 2.0.107",
3153
3418
]
3154
3419
3155
3420
[[package]]
···
3228
3493
"bytes",
3229
3494
"libc",
3230
3495
"mio",
3231
-
"parking_lot",
3232
3496
"pin-project-lite",
3233
-
"signal-hook-registry",
3234
3497
"socket2 0.6.1",
3235
3498
"tokio-macros",
3236
3499
"windows-sys 0.61.2",
···
3244
3507
dependencies = [
3245
3508
"proc-macro2",
3246
3509
"quote",
3247
-
"syn 2.0.106",
3510
+
"syn 2.0.107",
3248
3511
]
3249
3512
3250
3513
[[package]]
···
3344
3607
dependencies = [
3345
3608
"proc-macro2",
3346
3609
"quote",
3347
-
"syn 2.0.106",
3610
+
"syn 2.0.107",
3348
3611
]
3349
3612
3350
3613
[[package]]
···
3364
3627
dependencies = [
3365
3628
"proc-macro2",
3366
3629
"quote",
3367
-
"syn 2.0.106",
3630
+
"syn 2.0.107",
3368
3631
]
3369
3632
3370
3633
[[package]]
···
3401
3664
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
3402
3665
3403
3666
[[package]]
3667
+
name = "unicode-linebreak"
3668
+
version = "0.1.5"
3669
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3670
+
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
3671
+
3672
+
[[package]]
3404
3673
name = "unicode-width"
3405
3674
version = "0.1.14"
3406
3675
source = "registry+https://github.com/rust-lang/crates.io-index"
3407
3676
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
3677
+
3678
+
[[package]]
3679
+
name = "unicode-width"
3680
+
version = "0.2.2"
3681
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3682
+
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
3408
3683
3409
3684
[[package]]
3410
3685
name = "unsigned-varint"
···
3517
3792
"log",
3518
3793
"proc-macro2",
3519
3794
"quote",
3520
-
"syn 2.0.106",
3795
+
"syn 2.0.107",
3521
3796
"wasm-bindgen-shared",
3522
3797
]
3523
3798
···
3552
3827
dependencies = [
3553
3828
"proc-macro2",
3554
3829
"quote",
3555
-
"syn 2.0.106",
3830
+
"syn 2.0.107",
3556
3831
"wasm-bindgen-backend",
3557
3832
"wasm-bindgen-shared",
3558
3833
]
···
3564
3839
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
3565
3840
dependencies = [
3566
3841
"unicode-ident",
3842
+
]
3843
+
3844
+
[[package]]
3845
+
name = "wasm-streams"
3846
+
version = "0.4.2"
3847
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3848
+
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
3849
+
dependencies = [
3850
+
"futures-util",
3851
+
"js-sys",
3852
+
"wasm-bindgen",
3853
+
"wasm-bindgen-futures",
3854
+
"web-sys",
3567
3855
]
3568
3856
3569
3857
[[package]]
···
3648
3936
dependencies = [
3649
3937
"proc-macro2",
3650
3938
"quote",
3651
-
"syn 2.0.106",
3939
+
"syn 2.0.107",
3652
3940
]
3653
3941
3654
3942
[[package]]
···
3659
3947
dependencies = [
3660
3948
"proc-macro2",
3661
3949
"quote",
3662
-
"syn 2.0.106",
3950
+
"syn 2.0.107",
3663
3951
]
3664
3952
3665
3953
[[package]]
···
4066
4354
dependencies = [
4067
4355
"proc-macro2",
4068
4356
"quote",
4069
-
"syn 2.0.106",
4357
+
"syn 2.0.107",
4070
4358
"synstructure",
4071
4359
]
4072
4360
···
4087
4375
dependencies = [
4088
4376
"proc-macro2",
4089
4377
"quote",
4090
-
"syn 2.0.106",
4378
+
"syn 2.0.107",
4091
4379
]
4092
4380
4093
4381
[[package]]
···
4107
4395
dependencies = [
4108
4396
"proc-macro2",
4109
4397
"quote",
4110
-
"syn 2.0.106",
4398
+
"syn 2.0.107",
4111
4399
"synstructure",
4112
4400
]
4113
4401
···
4150
4438
dependencies = [
4151
4439
"proc-macro2",
4152
4440
"quote",
4153
-
"syn 2.0.106",
4441
+
"syn 2.0.107",
4154
4442
]
+8
-12
upload/Cargo.toml
+8
-12
upload/Cargo.toml
···
4
4
5
5
[package]
6
6
name = "atcities-upload"
7
-
version = "0.1.0"
7
+
version = "1.0.1"
8
8
edition = "2024"
9
9
10
10
[dependencies]
11
-
# lexicons = { path = "./lexicons" }
11
+
lexicons = { path = "./lexicons" }
12
12
clap = { version = "4.5.49", features = ["derive"] }
13
13
ignore = "0.4.23"
14
14
regex = "1.12.2"
15
15
mime_guess = "2.0.5"
16
-
tokio = { version = "1.48.0", features = ["full"] }
17
-
jacquard = { version = "0.5.3", features = ["api", "dns"] }
18
-
reqwest = { version = "0.12.24", features = [
19
-
"__tls",
20
-
"charset",
21
-
"default-tls",
22
-
"h2",
23
-
"http2",
24
-
"system-proxy",
25
-
] }
16
+
tokio = { version = "1.48.0", features = [] }
17
+
jacquard = "0.6.0"
18
+
reqwest = "0.12.24"
19
+
env_logger = "0.11.8"
20
+
miette = { version = "7.6.0", features = ["derive", "fancy"] }
21
+
thiserror = "2.0.17"
+3
-3
upload/lexicons/Cargo.toml
+3
-3
upload/lexicons/Cargo.toml
···
1
1
[package]
2
2
name = "lexicons"
3
-
version = "0.1.0"
3
+
version = "1.0.0"
4
4
edition = "2024"
5
5
6
6
[features]
···
13
13
miette = "7.6.0"
14
14
serde = "1.0.228"
15
15
thiserror = "2.0.17"
16
-
jacquard-common = "0.5.3"
17
-
jacquard-derive = "0.5.3"
16
+
jacquard-common = "0.6.0"
17
+
jacquard-derive = "0.6.0"
+233
-46
upload/src/main.rs
+233
-46
upload/src/main.rs
···
1
1
use clap::{ArgAction, Parser};
2
+
use jacquard::api::com_atproto::repo::apply_writes::{
3
+
self, ApplyWrites, ApplyWritesOutput, ApplyWritesWritesItem,
4
+
};
5
+
use jacquard::client::AgentSessionExt;
6
+
use jacquard::client::MemorySessionStore;
7
+
use jacquard::oauth::loopback::LoopbackConfig;
8
+
use jacquard::oauth::types::AuthorizeOptions;
9
+
use jacquard::types::string::{AtStrError, RecordKey, Rkey};
10
+
use jacquard::{AuthorizationToken, CowStr, atproto, oauth};
2
11
use jacquard::{
3
12
Data,
4
13
api::com_atproto::{self, repo::list_records::ListRecords},
5
14
client::{Agent, credential_session::CredentialSession},
6
15
cowstr::ToCowStr,
7
16
identity::JacquardResolver,
8
-
session::MemorySessionStore,
9
17
types::{ident::AtIdentifier, nsid::Nsid, string::AtprotoStr, uri::Uri},
10
18
xrpc::XrpcExt,
11
19
};
12
-
use std::{path::PathBuf, sync::Arc};
20
+
use miette::{Context, IntoDiagnostic, Result};
21
+
use std::io::Write;
22
+
use std::{collections::HashMap, fs, path::PathBuf};
23
+
24
+
use crate::sitemap::{BlobRef, Sitemap, SitemapNode};
13
25
14
26
mod sitemap;
15
27
mod utils;
16
28
17
-
#[derive(Parser, Debug)]
29
+
#[derive(Parser, Debug, Clone)]
18
30
#[command(version, about, long_about = None)]
19
31
struct Config {
20
32
/// Handle or DID to authenticate
21
-
#[arg(verbatim_doc_comment, short, long)]
33
+
#[arg(verbatim_doc_comment)]
22
34
user: String,
35
+
23
36
/// App password to authenticate the client
24
37
/// Normal passwords also work but are not advised
25
-
#[arg(verbatim_doc_comment, short, long)]
26
-
password: String,
38
+
/// If ommited, oauth will be used instead
39
+
/// Oauth is reccomended where possible.
40
+
#[arg(verbatim_doc_comment, short = 'p', long = "password")]
41
+
password: Option<String>,
27
42
28
43
/// Include dotfiles in upload
29
44
/// Default: false
···
41
56
dir: PathBuf,
42
57
}
43
58
44
-
#[tokio::main]
45
-
async fn main() -> Result<(), ()> {
46
-
// get config items
47
-
let config = Config::parse();
48
-
49
-
// get local site info
50
-
let sitemap =
51
-
sitemap::local_sitemap(config.dir, config.all_files, config.git_ignore).or_else(|err| {
52
-
println!("Error: {}", err);
53
-
Err(())
54
-
})?;
55
-
56
-
// create session
57
-
let client = JacquardResolver::default();
58
-
let store = MemorySessionStore::default();
59
-
let session = CredentialSession::new(Arc::new(store), Arc::new(client));
60
-
61
-
let auth = match session
62
-
.login(config.user.into(), config.password.into(), None, None, None)
63
-
.await
64
-
{
65
-
Ok(val) => {
66
-
println!("Authenticated {} ({})", val.handle, val.did);
67
-
val
68
-
}
69
-
Err(err) => {
70
-
println!("Got error while authenticating:\n{}", err);
71
-
return Err(());
72
-
}
73
-
};
74
-
75
-
let agent = Agent::from(session);
76
-
59
+
async fn live_records(agent: &impl AgentSessionExt, config: Config) -> Result<Vec<String>> {
77
60
// find live site records
78
61
let mut cursor = None;
79
62
let mut remote_records = Vec::new();
63
+
let user = config.user.clone();
64
+
let user = if user.contains(":") {
65
+
AtIdentifier::Did(user.into())
66
+
} else {
67
+
AtIdentifier::Handle(user.into())
68
+
};
80
69
loop {
81
70
let req = com_atproto::repo::list_records::ListRecords::new()
82
71
.collection(
83
72
Nsid::new("dev.atcities.route").expect("failed to generate dev.atcities.route nsid"),
84
73
)
85
-
.repo(AtIdentifier::Did(auth.did.clone()))
74
+
.repo(user.clone())
86
75
.limit(100)
87
76
.maybe_cursor(cursor)
88
77
.build();
···
90
79
let res = agent
91
80
.xrpc(agent.endpoint().await)
92
81
.send::<ListRecords>(&req)
93
-
.await
94
-
.or(Err(()))?
95
-
.into_output()
96
-
.or(Err(()))?;
82
+
.await?
83
+
.into_output()?;
97
84
98
85
for record in res.records {
99
86
match record {
···
126
113
break;
127
114
}
128
115
}
116
+
Ok(remote_records)
117
+
}
129
118
130
-
print!("{remote_records:?}");
119
+
async fn upload_site_blobs(
120
+
agent: &impl AgentSessionExt,
121
+
_config: Config,
122
+
local_sitemap: Sitemap,
123
+
) -> Result<Sitemap> {
124
+
// upload local site blobs
125
+
let mut new_sitemap: Sitemap = HashMap::new();
126
+
for (k, v) in local_sitemap {
127
+
print!("Uploading {k}... ");
128
+
let _ = std::io::stdout().flush();
129
+
let blob = match v.blob {
130
+
BlobRef::Local(path) => path,
131
+
BlobRef::Remote(_) => {
132
+
panic!("Impossible state")
133
+
}
134
+
};
135
+
let blob = fs::read(blob).into_diagnostic()?;
131
136
132
-
// upload local site blobs
137
+
let req = com_atproto::repo::upload_blob::UploadBlob::new()
138
+
.body(blob.into())
139
+
.build();
140
+
let res = agent.send(req).await?.into_output()?;
133
141
142
+
new_sitemap.insert(
143
+
k,
144
+
SitemapNode {
145
+
mime_type: v.mime_type,
146
+
blob: BlobRef::Remote(res.blob.into()),
147
+
},
148
+
);
149
+
150
+
println!("Done!");
151
+
}
152
+
153
+
Ok(new_sitemap)
154
+
}
155
+
156
+
async fn update_remote_site(
157
+
agent: &impl AgentSessionExt,
158
+
config: Config,
159
+
auth: AuthorizationToken<'_>,
160
+
remote_records: Vec<String>,
161
+
new_sitemap: Sitemap,
162
+
) -> Result<ApplyWritesOutput<'static>> {
134
163
// batch delete/upload records
164
+
let mut writes = Vec::new();
165
+
let mut delete_records = remote_records
166
+
.into_iter()
167
+
.map(|x| {
168
+
let rkey = RecordKey(Rkey::new_owned(x)?);
169
+
Ok(ApplyWritesWritesItem::Delete(Box::new(
170
+
apply_writes::Delete::builder()
171
+
.collection(Nsid::raw("dev.atcities.route"))
172
+
.rkey(rkey)
173
+
.build(),
174
+
)))
175
+
})
176
+
.collect::<Result<Vec<ApplyWritesWritesItem<'_>>, AtStrError>>()
177
+
.into_diagnostic()?;
178
+
179
+
let mut create_records = new_sitemap
180
+
.into_iter()
181
+
.map(|(k, v)| {
182
+
let k = match k.as_str() {
183
+
"404.html" => String::from("404"),
184
+
"index.html" => String::from("/"),
185
+
_ => match k.strip_suffix("/index.html") {
186
+
Some(k) => format!("/{k}/"),
187
+
None => format!("/{k}"),
188
+
}
189
+
};
190
+
let rkey =
191
+
utils::url_to_rkey(k).wrap_err("Invalid file path. Could not be converted to rkey")?;
192
+
let rkey = RecordKey(Rkey::new_owned(rkey).into_diagnostic()?);
193
+
let blob = match v.blob {
194
+
BlobRef::Local(_) => panic!("Illegal local blob"),
195
+
BlobRef::Remote(cid) => cid,
196
+
};
197
+
let data = atproto!({
198
+
"page": {
199
+
"$type": "dev.atcities.route#blob",
200
+
"blob": {
201
+
"$type": "blob",
202
+
"ref": {
203
+
"$link": blob.r#ref.as_str()
204
+
},
205
+
"mimeType": blob.mime_type.0.as_str(),
206
+
"size": blob.size
207
+
}
208
+
}
209
+
});
210
+
Ok(ApplyWritesWritesItem::Create(Box::new(
211
+
apply_writes::Create::builder()
212
+
.collection(Nsid::raw("dev.atcities.route"))
213
+
.rkey(rkey)
214
+
.value(data)
215
+
.build(),
216
+
)))
217
+
})
218
+
.collect::<Result<Vec<ApplyWritesWritesItem<'_>>, miette::Error>>()?;
219
+
220
+
writes.append(&mut delete_records);
221
+
writes.append(&mut create_records);
222
+
223
+
let repo = if config.user.contains(":") {
224
+
AtIdentifier::Did(config.user.into())
225
+
} else {
226
+
AtIdentifier::Handle(config.user.into())
227
+
};
228
+
229
+
let req = com_atproto::repo::apply_writes::ApplyWrites::new()
230
+
.repo(repo)
231
+
.writes(writes)
232
+
.build();
233
+
234
+
let res = agent
235
+
.xrpc(agent.endpoint().await)
236
+
.auth(auth)
237
+
.send::<ApplyWrites>(&req)
238
+
.await?
239
+
.into_output()?;
240
+
241
+
Ok(res)
242
+
}
243
+
244
+
#[tokio::main]
245
+
async fn main() -> Result<(), miette::Error> {
246
+
env_logger::init();
247
+
// get config items
248
+
let config = Config::parse();
249
+
250
+
// get local site info
251
+
let local_sitemap =
252
+
sitemap::local_sitemap(config.dir.clone(), config.all_files, config.git_ignore)?;
253
+
254
+
// create session
255
+
if let Some(password) = config.password.clone() {
256
+
let password = password.into();
257
+
let client = JacquardResolver::default();
258
+
let store = MemorySessionStore::default();
259
+
let session = CredentialSession::new(store.into(), client.into());
260
+
261
+
let auth = session
262
+
.login(config.user.clone().into(), password, None, None, None)
263
+
.await?;
264
+
265
+
let agent = Agent::from(session);
266
+
267
+
let remote_sitemap = live_records(&agent, config.clone()).await?;
268
+
let new_sitemap = upload_site_blobs(&agent, config.clone(), local_sitemap).await?;
269
+
let _ = update_remote_site(
270
+
&agent,
271
+
config.clone(),
272
+
AuthorizationToken::Bearer(auth.access_jwt),
273
+
remote_sitemap,
274
+
new_sitemap,
275
+
)
276
+
.await?;
277
+
278
+
println!(
279
+
"Site is now updated. Live at {}",
280
+
utils::site_handle(config.user)
281
+
);
282
+
} else {
283
+
let oauth = oauth::client::OAuthClient::with_memory_store();
284
+
let session = oauth
285
+
.login_with_local_server(
286
+
config.user.clone(),
287
+
AuthorizeOptions::default(),
288
+
LoopbackConfig::default(),
289
+
)
290
+
.await?;
291
+
292
+
// sick and twisted reference mangling BUT it works So
293
+
// tldr: the cowstr is a borrowed cowstr iiuc,
294
+
// so it needs to be turned into an owned cowstr
295
+
// to break reference to session which gets moved
296
+
let auth = session.access_token().await;
297
+
let auth = match auth {
298
+
AuthorizationToken::Bearer(cow_str) => CowStr::copy_from_str(cow_str.as_str()),
299
+
AuthorizationToken::Dpop(cow_str) => CowStr::copy_from_str(cow_str.as_str()),
300
+
};
301
+
302
+
println!("{}", auth);
303
+
304
+
let agent = Agent::from(session);
305
+
306
+
let remote_sitemap = live_records(&agent, config.clone()).await?;
307
+
let new_sitemap = upload_site_blobs(&agent, config.clone(), local_sitemap).await?;
308
+
let _ = update_remote_site(
309
+
&agent,
310
+
config.clone(),
311
+
AuthorizationToken::Dpop(auth),
312
+
remote_sitemap,
313
+
new_sitemap,
314
+
)
315
+
.await?;
316
+
317
+
println!(
318
+
"Site is now updated. Live at {}",
319
+
utils::site_handle(config.user)
320
+
);
321
+
};
135
322
136
323
Ok(())
137
324
}
+16
-40
upload/src/sitemap.rs
+16
-40
upload/src/sitemap.rs
···
1
1
use ignore::WalkBuilder;
2
+
use jacquard::types::blob::Blob;
3
+
use miette::Diagnostic;
2
4
use mime_guess::mime;
3
-
use std::{collections::HashMap, error::Error, fmt, path::PathBuf};
5
+
use std::{collections::HashMap, path::PathBuf};
6
+
use thiserror::Error;
4
7
5
8
pub type Sitemap = HashMap<String, SitemapNode>;
6
9
···
13
16
#[derive(Debug)]
14
17
pub enum BlobRef {
15
18
Local(PathBuf),
16
-
Remote(String),
19
+
Remote(Blob<'static>),
17
20
}
18
21
19
-
#[derive(Debug)]
22
+
#[derive(Debug, Error, Diagnostic)]
20
23
pub enum SitemapErr {
21
-
IoErr(std::io::Error),
22
-
IgnoreErr(ignore::Error),
23
-
StripPrefixErr(std::path::StripPrefixError),
24
+
#[error("IO error: {}", .0)]
25
+
IoErr(#[from] std::io::Error),
26
+
#[error("Error finding files: {}", .0)]
27
+
IgnoreErr(#[from] ignore::Error),
28
+
#[error("Error normalising file paths: {}", .0)]
29
+
StripPrefixErr(#[from] std::path::StripPrefixError),
30
+
#[error("Found non UTF-8 path")]
24
31
NotUTF8Path,
25
32
}
26
33
27
-
impl From<std::io::Error> for SitemapErr {
28
-
fn from(value: std::io::Error) -> Self {
29
-
SitemapErr::IoErr(value)
30
-
}
31
-
}
32
-
33
-
impl From<ignore::Error> for SitemapErr {
34
-
fn from(value: ignore::Error) -> Self {
35
-
SitemapErr::IgnoreErr(value)
36
-
}
37
-
}
38
-
39
-
impl From<std::path::StripPrefixError> for SitemapErr {
40
-
fn from(value: std::path::StripPrefixError) -> Self {
41
-
SitemapErr::StripPrefixErr(value)
42
-
}
43
-
}
44
-
45
-
impl Error for SitemapErr {}
46
-
47
-
impl fmt::Display for SitemapErr {
48
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49
-
match self {
50
-
SitemapErr::IoErr(err) => write!(f, "IO Error: {}", err),
51
-
SitemapErr::IgnoreErr(err) => write!(f, "Ignore Error: {}", err),
52
-
SitemapErr::StripPrefixErr(err) => write!(f, "File Path Error: {}", err),
53
-
SitemapErr::NotUTF8Path => write!(f, "Found a path that was not UTF-8"),
54
-
}
55
-
}
56
-
}
57
-
58
-
pub fn local_sitemap<'a>(
34
+
pub fn local_sitemap(
59
35
dir: PathBuf,
60
36
include_dotfiles: bool,
61
37
use_gitignore: bool,
62
-
) -> Result<Sitemap, SitemapErr> {
38
+
) -> miette::Result<Sitemap, SitemapErr> {
63
39
let prefix = dir.canonicalize()?;
64
40
65
41
let mut res = HashMap::new();
···
86
62
// etc
87
63
let key = file.path().canonicalize()?;
88
64
let key = key.strip_prefix(&prefix)?;
89
-
let key = String::from(key.to_str().ok_or_else(|| SitemapErr::NotUTF8Path)?);
65
+
let key = String::from(key.to_str().ok_or(SitemapErr::NotUTF8Path)?);
90
66
91
67
let mime = mime_guess::from_path(&key);
92
68
let mime = mime.first().unwrap_or(mime::APPLICATION_OCTET_STREAM);
+14
-2
upload/src/utils.rs
+14
-2
upload/src/utils.rs
···
1
1
use regex::Regex;
2
2
3
+
#[allow(dead_code)]
3
4
pub fn rkey_to_url(rkey: String) -> Option<String> {
4
5
let regex = Regex::new(
5
6
// symbols A-Za-z0-9 -._~: are all valid rkey characters
···
32
33
.replace(":3D", "=")
33
34
.replace(":40", "@");
34
35
35
-
return Some(res);
36
+
Some(res)
36
37
}
37
38
38
39
pub fn url_to_rkey(url: String) -> Option<String> {
···
60
61
.replace("=", ":3D")
61
62
.replace("@", ":40");
62
63
63
-
return Some(res);
64
+
Some(res)
65
+
}
66
+
67
+
pub fn site_handle(user: String) -> String {
68
+
if user.contains(":") {
69
+
let user = user.split(":").collect::<Vec<_>>();
70
+
let method = user[1];
71
+
let did = user[2];
72
+
format!("https://{did}.did-{method}.atcities.dev/")
73
+
} else {
74
+
format!("https://{user}.atcities.dev/")
75
+
}
64
76
}