Compare commits
10
Commits
9c34dba248
...
d69dd5d460
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d69dd5d460 | ||
|
|
6d598d2f07 | ||
|
|
4f9bbab97b | ||
|
|
3086bf170f | ||
|
|
fb09420915 | ||
|
|
273ec529c0 | ||
|
|
054f21f664 | ||
|
|
719f7df350 | ||
|
|
964d6a6262 | ||
|
|
1de8ad34bc |
No files matched your search
Generated
+74
-74
@@ -19,9 +19,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.55"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e24af9c57a5a2463ffe401d5340433d21487b76238bae64ee5992ed688b4e753"
|
||||
checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -49,9 +49,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.5.6"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2504b827a8bef941ba3dd64bdffe9cf56ca182908a147edd6189c95fbcae7d"
|
||||
checksum = "c2cc6e8e8c993cb61a005fab8c1e5093a29199b7253b05a6883999312935c1ff"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
@@ -80,9 +80,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.2.4"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da31c0ed7b4690e2c78fe4b880d21cd7db04a346ebc658b4270251b695437f17"
|
||||
checksum = "cf4d047478b986f14a13edad31a009e2e05cb241f9805d0d75e4cba4e129ad4d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
@@ -270,14 +270,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c"
|
||||
checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.9",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -391,9 +391,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
@@ -406,9 +406,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb"
|
||||
checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -446,9 +446,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.19"
|
||||
version = "0.14.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f"
|
||||
checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -475,9 +475,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.2"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
@@ -565,9 +565,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -673,9 +673,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
|
||||
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@@ -782,15 +782,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "6.3.1"
|
||||
version = "6.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225"
|
||||
checksum = "1eb3502504c9c8b06634b38bfdda86a9a8cef6277f3dec4d8b17c115110dd2a3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
@@ -800,9 +800,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.7.1"
|
||||
version = "69.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e"
|
||||
checksum = "8bf3fbc9b931b6c9af85d219c7943c274a6ad26cff7488a2210215edd5f49bf8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
@@ -839,18 +839,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
|
||||
checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
|
||||
checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -885,7 +885,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
"serde",
|
||||
"time 0.3.9",
|
||||
"time 0.3.11",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
@@ -915,9 +915,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -946,9 +946,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -964,9 +964,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.26"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "rss"
|
||||
@@ -1009,18 +1009,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1029,9 +1029,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.81"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -1076,9 +1076,9 @@ checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -1098,9 +1098,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.96"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
|
||||
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1157,9 +1157,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.9"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
|
||||
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
@@ -1168,14 +1168,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.18.2"
|
||||
version = "1.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395"
|
||||
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio 0.8.3",
|
||||
"mio 0.8.4",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
@@ -1188,9 +1188,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1199,9 +1199,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c"
|
||||
checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -1221,9 +1221,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e"
|
||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -1238,9 +1238,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae"
|
||||
checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
@@ -1270,15 +1270,15 @@ checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
|
||||
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"log",
|
||||
@@ -1289,9 +1289,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.21"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c"
|
||||
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1300,11 +1300,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.26"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
|
||||
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
@@ -1321,9 +1321,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.11"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
|
||||
checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"sharded-slab",
|
||||
@@ -1350,9 +1350,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
|
||||
@@ -19,6 +19,9 @@ path = "src/bin/css_gen/main.rs"
|
||||
name = "prepublish"
|
||||
path = "src/bin/prepublish/main.rs"
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
|
||||
[dependencies]
|
||||
libshire = { git = "https://github.com/pantonshire/libshire", features = ["serde"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -83,6 +83,7 @@ body {
|
||||
padding: 0;
|
||||
font-family: Rubik, sans-serif;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.4;
|
||||
font-weight: 300;
|
||||
background-color: #94BFBE;
|
||||
color: white;
|
||||
@@ -134,6 +135,10 @@ li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#page_header {
|
||||
background-color: #94BFBE;
|
||||
color: white;
|
||||
@@ -298,6 +303,16 @@ ul.articles_list {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article_edit {
|
||||
font-size: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article_edit a {
|
||||
color: #898989;
|
||||
}
|
||||
|
||||
.codeblock {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
@@ -360,6 +375,19 @@ ul.articles_list {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.article_content blockquote {
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
border-left: 5px solid #C9C9C9;
|
||||
padding-left: 1rem;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article_content blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 22em) {
|
||||
#page_nav #title_box {
|
||||
font-size: 2rem;
|
||||
@@ -379,12 +407,17 @@ ul.articles_list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
#page_nav #title_box {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#page_footer_content {
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
#page_footer_content ul {
|
||||
grid-template-columns: repeat(3, auto);
|
||||
grid-template-rows: 100%;
|
||||
@@ -394,7 +427,7 @@ ul.articles_list {
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 2rem 1rem 4rem 1rem;
|
||||
padding: 2rem 2rem 4rem 2rem;
|
||||
}
|
||||
|
||||
.article_title {
|
||||
|
||||
+16
-9
@@ -1,19 +1,21 @@
|
||||
bind = "127.0.0.1:8080"
|
||||
concurrency_limit = 128
|
||||
bind = "127.0.0.1:8080"
|
||||
concurrency_limit = 128
|
||||
fs_event_delay_millis = 2000
|
||||
namespace_uuid = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
[site]
|
||||
protocol = "http"
|
||||
domain = "localhost:8080"
|
||||
|
||||
[content]
|
||||
static_dir = "./content/static/"
|
||||
favicon_dir = "./content/favicon/"
|
||||
robots_path = "./content/robots.txt"
|
||||
posts_dir = "./articles/src/"
|
||||
post_media_dir = "./articles/media/"
|
||||
|
||||
fs_event_delay_millis = 2000
|
||||
|
||||
namespace_uuid = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
[self_ref]
|
||||
protocol = "http"
|
||||
domain = "localhost:8080"
|
||||
[github]
|
||||
edit_url = "https://github.com/pantonshire/blog_content/edit/main/src"
|
||||
|
||||
[rss]
|
||||
num_posts = 20
|
||||
@@ -23,3 +25,8 @@ ttl = 360
|
||||
[atom]
|
||||
num_posts = 20
|
||||
title = "Pantonshire"
|
||||
|
||||
[[contact]]
|
||||
name = "Twitter"
|
||||
user = "@pantonshire"
|
||||
url = "https://twitter.com/pantonshire"
|
||||
@@ -7,23 +7,35 @@ use serde::{Deserialize, Deserializer};
|
||||
pub(crate) struct Config {
|
||||
pub bind: SocketAddr,
|
||||
pub concurrency_limit: usize,
|
||||
#[serde(rename = "fs_event_delay_millis", deserialize_with = "deserialize_millis")]
|
||||
pub fs_event_delay: Duration,
|
||||
pub namespace_uuid: Uuid,
|
||||
pub content: ContentConfig,
|
||||
pub github: GithubConfig,
|
||||
pub site: SiteConfig,
|
||||
pub rss: RssConfig,
|
||||
pub atom: AtomConfig,
|
||||
pub contact: Vec<ContactConfig>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub(crate) struct SiteConfig {
|
||||
pub protocol: String,
|
||||
pub domain: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub(crate) struct ContentConfig {
|
||||
pub static_dir: PathBuf,
|
||||
pub favicon_dir: PathBuf,
|
||||
pub robots_path: PathBuf,
|
||||
pub posts_dir: PathBuf,
|
||||
pub post_media_dir: PathBuf,
|
||||
#[serde(rename = "fs_event_delay_millis", deserialize_with = "deserialize_millis")]
|
||||
pub fs_event_delay: Duration,
|
||||
pub namespace_uuid: Uuid,
|
||||
pub self_ref: SelfRefConfig,
|
||||
pub rss: RssConfig,
|
||||
pub atom: AtomConfig,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub(crate) struct SelfRefConfig {
|
||||
pub protocol: String,
|
||||
pub domain: String,
|
||||
pub(crate) struct GithubConfig {
|
||||
pub edit_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
@@ -39,6 +51,13 @@ pub(crate) struct AtomConfig {
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub(crate) struct ContactConfig {
|
||||
pub name: String,
|
||||
pub user: String,
|
||||
pub url: Option<String>,
|
||||
}
|
||||
|
||||
impl str::FromStr for Config {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
use blog::db::ConcurrentPostsStore;
|
||||
|
||||
use crate::Config;
|
||||
|
||||
pub(crate) struct Context {
|
||||
config: Config,
|
||||
posts: ConcurrentPostsStore,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn new(config: Config, posts: ConcurrentPostsStore) -> Self {
|
||||
Self {
|
||||
config,
|
||||
posts,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn posts(&self) -> &ConcurrentPostsStore {
|
||||
&self.posts
|
||||
}
|
||||
}
|
||||
+16
-20
@@ -1,4 +1,5 @@
|
||||
mod config;
|
||||
mod context;
|
||||
mod fs_watcher;
|
||||
mod render;
|
||||
mod service;
|
||||
@@ -27,6 +28,7 @@ use blog::{
|
||||
};
|
||||
|
||||
use config::Config;
|
||||
use context::Context;
|
||||
use render::Renderer;
|
||||
|
||||
fn main() {
|
||||
@@ -42,7 +44,7 @@ fn run() -> Result<(), Error> {
|
||||
|
||||
// Load the configuration from the TOML config file specified by the first command-line
|
||||
// argument.
|
||||
let config = Arc::new({
|
||||
let config = {
|
||||
let config_path = env::args().nth(1)
|
||||
.ok_or(Error::NoConfig)?;
|
||||
|
||||
@@ -53,27 +55,25 @@ fn run() -> Result<(), Error> {
|
||||
|
||||
contents.parse::<Config>()
|
||||
.map_err(Error::BadConfig)?
|
||||
});
|
||||
};
|
||||
|
||||
// Create the data structure used to store the rendered posts. This uses an `Arc` internally,
|
||||
// so clones will point to the same underlying data.
|
||||
let posts_store = ConcurrentPostsStore::new();
|
||||
// Create the global context that will be used and modified throughout the program.
|
||||
let context = Arc::new(Context::new(config, ConcurrentPostsStore::new()));
|
||||
|
||||
let code_renderer = CodeBlockRenderer::new();
|
||||
|
||||
// Create the post renderer and the mpsc channel that will be used to communicate with it.
|
||||
let (renderer, tx) = Renderer::new(
|
||||
config.clone(),
|
||||
posts_store.clone(),
|
||||
context.clone(),
|
||||
code_renderer,
|
||||
config.posts_dir.clone()
|
||||
context.config().content.posts_dir.clone()
|
||||
);
|
||||
|
||||
// Dropping the watcher stops its thread, so keep it alive until the server has stopped.
|
||||
let watcher = fs_watcher::start_watching(
|
||||
tx,
|
||||
&config.posts_dir,
|
||||
config.fs_event_delay
|
||||
&context.config().content.posts_dir,
|
||||
context.config().fs_event_delay
|
||||
)?;
|
||||
|
||||
let renderer_handle = thread::spawn(move || {
|
||||
@@ -88,7 +88,7 @@ fn run() -> Result<(), Error> {
|
||||
.enable_all()
|
||||
.build()
|
||||
.map_err(Error::TokioRuntime)?
|
||||
.block_on(run_server(config, posts_store))?;
|
||||
.block_on(run_server(context))?;
|
||||
|
||||
info!("Stopped server");
|
||||
|
||||
@@ -105,17 +105,13 @@ fn run() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_server(
|
||||
config: Arc<Config>,
|
||||
posts_store: ConcurrentPostsStore,
|
||||
) -> Result<(), Error>
|
||||
{
|
||||
let service = service::site_service(config.clone(), posts_store);
|
||||
async fn run_server(context: Arc<Context>) -> Result<(), Error> {
|
||||
let service = service::site_service(context.clone());
|
||||
|
||||
info!(address = %config.bind, "Starting server");
|
||||
info!(address = %context.config().bind, "Starting server");
|
||||
|
||||
Server::try_bind(&config.bind)
|
||||
.map_err(|err| Error::Bind(config.bind, err))?
|
||||
Server::try_bind(&context.config().bind)
|
||||
.map_err(|err| Error::Bind(context.config().bind, err))?
|
||||
.serve(service.into_make_service())
|
||||
.with_graceful_shutdown(handle_interrupt())
|
||||
.await
|
||||
|
||||
@@ -13,14 +13,12 @@ use tracing::{info, warn, error};
|
||||
use blog::{
|
||||
codeblock::CodeBlockRenderer,
|
||||
post::{Error as ParseError, Post, Id},
|
||||
db::ConcurrentPostsStore,
|
||||
};
|
||||
|
||||
use crate::Config;
|
||||
use crate::Context;
|
||||
|
||||
pub(crate) struct Renderer {
|
||||
config: Arc<Config>,
|
||||
posts: ConcurrentPostsStore,
|
||||
context: Arc<Context>,
|
||||
code_renderer: CodeBlockRenderer,
|
||||
posts_dir_path: PathBuf,
|
||||
rx: mpsc::Receiver<DebouncedEvent>,
|
||||
@@ -28,8 +26,7 @@ pub(crate) struct Renderer {
|
||||
|
||||
impl Renderer {
|
||||
pub(crate) fn new(
|
||||
config: Arc<Config>,
|
||||
posts: ConcurrentPostsStore,
|
||||
context: Arc<Context>,
|
||||
code_renderer: CodeBlockRenderer,
|
||||
posts_dir_path: PathBuf,
|
||||
) -> (Self, mpsc::Sender<DebouncedEvent>)
|
||||
@@ -42,8 +39,7 @@ impl Renderer {
|
||||
tx.send(DebouncedEvent::Rescan).unwrap();
|
||||
|
||||
(Self {
|
||||
config,
|
||||
posts,
|
||||
context,
|
||||
code_renderer,
|
||||
posts_dir_path,
|
||||
rx,
|
||||
@@ -106,7 +102,7 @@ impl Renderer {
|
||||
fn update(&self, target: &EventTarget) {
|
||||
match self.parse_post_from_target(target) {
|
||||
Ok(post) => {
|
||||
let mut guard = self.posts.write_blocking();
|
||||
let mut guard = self.context.posts().write_blocking();
|
||||
guard.insert(post);
|
||||
},
|
||||
Err(err) => {
|
||||
@@ -118,7 +114,7 @@ impl Renderer {
|
||||
#[tracing::instrument(skip(self))]
|
||||
fn rename(&self, old_target: &EventTarget, new_target: &EventTarget) {
|
||||
let post_res = self.parse_post_from_target(new_target);
|
||||
let mut guard = self.posts.write_blocking();
|
||||
let mut guard = self.context.posts().write_blocking();
|
||||
guard.remove(&old_target.id);
|
||||
match post_res {
|
||||
Ok(post) => {
|
||||
@@ -132,7 +128,7 @@ impl Renderer {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
fn remove(&self, target: &EventTarget) {
|
||||
let mut guard = self.posts.write_blocking();
|
||||
let mut guard = self.context.posts().write_blocking();
|
||||
guard.remove(&target.id);
|
||||
}
|
||||
|
||||
@@ -168,7 +164,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
let mut guard = self.posts.write_blocking();
|
||||
let mut guard = self.context.posts().write_blocking();
|
||||
guard.clear();
|
||||
for post in posts {
|
||||
guard.insert(post);
|
||||
@@ -204,7 +200,7 @@ impl Renderer {
|
||||
|
||||
Post::new_from_str(
|
||||
&self.code_renderer,
|
||||
self.config.namespace_uuid,
|
||||
self.context.config().namespace_uuid,
|
||||
target.id.clone(),
|
||||
updated,
|
||||
&contents
|
||||
|
||||
@@ -3,22 +3,19 @@ use std::sync::Arc;
|
||||
use atom_syndication as atom;
|
||||
use axum::{body::Bytes, extract::Extension};
|
||||
|
||||
use blog::{db::ConcurrentPostsStore, time::unix_epoch};
|
||||
use blog::time::unix_epoch;
|
||||
|
||||
use crate::Config;
|
||||
use crate::Context;
|
||||
|
||||
use super::response::Atom;
|
||||
|
||||
pub(super) async fn handle(
|
||||
Extension(config): Extension<Arc<Config>>,
|
||||
Extension(posts): Extension<ConcurrentPostsStore>,
|
||||
) -> Atom<Bytes> {
|
||||
pub(super) async fn handle(Extension(context): Extension<Arc<Context>>) -> Atom<Bytes> {
|
||||
let (atom_entries, updated) = {
|
||||
let guard = posts.read().await;
|
||||
let guard = context.posts().read().await;
|
||||
|
||||
let atom_entries = guard
|
||||
.iter_by_published()
|
||||
.take(config.atom.num_posts)
|
||||
.take(context.config().atom.num_posts)
|
||||
.map(|post| {
|
||||
atom::EntryBuilder::default()
|
||||
.id(format!("urn:uuid:{}", post.uuid()))
|
||||
@@ -27,8 +24,8 @@ pub(super) async fn handle(
|
||||
.links(vec![atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/articles/{}",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain,
|
||||
context.config().site.protocol,
|
||||
context.config().site.domain,
|
||||
post.id()
|
||||
))
|
||||
.rel("alternate".to_owned())
|
||||
@@ -50,21 +47,21 @@ pub(super) async fn handle(
|
||||
|
||||
Atom(
|
||||
atom::FeedBuilder::default()
|
||||
.id(format!("urn:uuid:{}", config.namespace_uuid))
|
||||
.title(config.atom.title.clone())
|
||||
.id(format!("urn:uuid:{}", context.config().namespace_uuid))
|
||||
.title(context.config().atom.title.clone())
|
||||
.updated(updated)
|
||||
.links(vec![
|
||||
atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/atom.xml",
|
||||
config.self_ref.protocol, config.self_ref.domain
|
||||
context.config().site.protocol, context.config().site.domain
|
||||
))
|
||||
.rel("self".to_owned())
|
||||
.build(),
|
||||
atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/articles/",
|
||||
config.self_ref.protocol, config.self_ref.domain
|
||||
context.config().site.protocol, context.config().site.domain
|
||||
))
|
||||
.rel("alternate".to_owned())
|
||||
.mime_type(Some("text/html".to_owned()))
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::Extension;
|
||||
use maud::html;
|
||||
|
||||
use crate::template;
|
||||
use crate::{template, Context};
|
||||
|
||||
use super::response::Html;
|
||||
|
||||
pub(super) async fn handle() -> Html {
|
||||
pub(super) async fn handle(Extension(context): Extension<Arc<Context>>) -> Html {
|
||||
Html::new()
|
||||
.with_title_static("Contact")
|
||||
.with_crawler_permissive()
|
||||
@@ -18,16 +21,15 @@ pub(super) async fn handle() -> Html {
|
||||
"If you want to contact me, you can find me at:"
|
||||
}
|
||||
ul {
|
||||
li {
|
||||
"Twitter: "
|
||||
a href="https://twitter.com/pantonshire" { "@pantonshire" }
|
||||
}
|
||||
li {
|
||||
"Mastodon: "
|
||||
a href="https://tech.lgbt/web/@pantonshire#" { "@pantonshire@tech.lgbt" }
|
||||
}
|
||||
li {
|
||||
"Discord: pantonshire#2076"
|
||||
@for contact in &context.config().contact {
|
||||
li {
|
||||
(contact.name) ": "
|
||||
@if let Some(url) = contact.url.as_deref() {
|
||||
a href=(url) { (contact.user) }
|
||||
} @else {
|
||||
(contact.user)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::Extension;
|
||||
use maud::html;
|
||||
|
||||
use blog::db::ConcurrentPostsStore;
|
||||
|
||||
use crate::template;
|
||||
use crate::{Context, template};
|
||||
|
||||
use super::response::Html;
|
||||
|
||||
pub(super) async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) -> Html {
|
||||
pub(super) async fn handle(Extension(context): Extension<Arc<Context>>) -> Html {
|
||||
Html::new()
|
||||
.with_title_static("Pantonshire")
|
||||
.with_crawler_permissive()
|
||||
@@ -49,7 +49,7 @@ pub(super) async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) ->
|
||||
h2 { "Articles" }
|
||||
p { "Some recent ones:" }
|
||||
ul .articles_list {
|
||||
@for post in posts.read().await.iter_by_published().rev().take(3) {
|
||||
@for post in context.posts().read().await.iter_by_published().rev().take(3) {
|
||||
li {
|
||||
h3 { a href={"/articles/" (post.id())} { (post.title()) } }
|
||||
@if let Some(subtitle) = post.subtitle() {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::{Extension, Path};
|
||||
use maud::html;
|
||||
|
||||
use blog::db::ConcurrentPostsStore;
|
||||
|
||||
use crate::template;
|
||||
use crate::{Context, template};
|
||||
|
||||
use super::response::{Error, Html};
|
||||
|
||||
pub(super) async fn handle(
|
||||
Path(post_id): Path<String>,
|
||||
Extension(posts): Extension<ConcurrentPostsStore>
|
||||
Extension(context): Extension<Arc<Context>>,
|
||||
) -> Result<Html, Error>
|
||||
{
|
||||
let post = posts.get(&post_id)
|
||||
let post = context.posts().get(&post_id)
|
||||
.await
|
||||
.ok_or(Error::PostNotFound)?;
|
||||
|
||||
@@ -32,6 +32,13 @@ pub(super) async fn handle(
|
||||
p .article_subtitle { (subtitle) }
|
||||
}
|
||||
p .article_published_date { "Published " (post.published().format("%Y/%m/%d")) }
|
||||
@if let Some(source_url) = context.config().github.edit_url.as_deref() {
|
||||
p .article_edit {
|
||||
a href={(source_url) "/" (post.id()) ".toml.md"} {
|
||||
"Propose a change on GitHub"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
article .article_content {
|
||||
(post.html())
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::Extension;
|
||||
use maud::html;
|
||||
|
||||
use blog::db::ConcurrentPostsStore;
|
||||
|
||||
use crate::template;
|
||||
use crate::{Context, template};
|
||||
|
||||
use super::response::Html;
|
||||
|
||||
pub(super) async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) -> Html {
|
||||
pub(super) async fn handle(Extension(context): Extension<Arc<Context>>) -> Html {
|
||||
Html::new()
|
||||
.with_title_static("Articles")
|
||||
.with_crawler_permissive()
|
||||
@@ -23,7 +23,7 @@ pub(super) async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) ->
|
||||
"A collection of words I have written, against my better judgement."
|
||||
}
|
||||
ul .articles_list {
|
||||
@for post in posts.read().await.iter_by_published().rev() {
|
||||
@for post in context.posts().read().await.iter_by_published().rev() {
|
||||
li {
|
||||
h3 { a href={"/articles/" (post.id())} { (post.title()) } }
|
||||
@if let Some(subtitle) = post.subtitle() {
|
||||
|
||||
@@ -109,10 +109,6 @@ impl Html {
|
||||
Self { crawler_hints, ..self }
|
||||
}
|
||||
|
||||
pub(super) fn with_crawler_restrictive(self) -> Self {
|
||||
self.with_crawler_hints(CrawlerHints::restrictive())
|
||||
}
|
||||
|
||||
pub(super) fn with_crawler_permissive(self) -> Self {
|
||||
self.with_crawler_hints(CrawlerHints::permissive())
|
||||
}
|
||||
@@ -189,26 +185,6 @@ impl CrawlerHints {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const fn with_index(self, index: bool) -> Self {
|
||||
Self { index, ..self }
|
||||
}
|
||||
|
||||
pub(super) const fn with_follow(self, follow: bool) -> Self {
|
||||
Self { follow, ..self }
|
||||
}
|
||||
|
||||
pub(super) const fn with_archive(self, archive: bool) -> Self {
|
||||
Self { archive, ..self }
|
||||
}
|
||||
|
||||
pub(super) const fn with_snippet(self, snippet: bool) -> Self {
|
||||
Self { snippet, ..self }
|
||||
}
|
||||
|
||||
pub(super) const fn with_image_index(self, image_index: bool) -> Self {
|
||||
Self { image_index, ..self }
|
||||
}
|
||||
|
||||
fn index_str(self) -> &'static str {
|
||||
if self.index {
|
||||
"index"
|
||||
|
||||
@@ -5,24 +5,18 @@ use axum::{
|
||||
extract::Extension,
|
||||
};
|
||||
|
||||
use blog::{
|
||||
db::ConcurrentPostsStore,
|
||||
time::unix_epoch,
|
||||
};
|
||||
use blog::time::unix_epoch;
|
||||
|
||||
use crate::Config;
|
||||
use crate::Context;
|
||||
|
||||
use super::response::Rss;
|
||||
|
||||
pub(super) async fn handle(
|
||||
Extension(config): Extension<Arc<Config>>,
|
||||
Extension(posts): Extension<ConcurrentPostsStore>,
|
||||
) -> Rss<Bytes> {
|
||||
pub(super) async fn handle(Extension(context): Extension<Arc<Context>>) -> Rss<Bytes> {
|
||||
let (rss_items, updated) = {
|
||||
let guard = posts.read().await;
|
||||
let guard = context.posts().read().await;
|
||||
|
||||
let rss_items = guard.iter_by_published()
|
||||
.take(config.rss.num_posts)
|
||||
.take(context.config().rss.num_posts)
|
||||
.map(|post| {
|
||||
rss::ItemBuilder::default()
|
||||
.title(Some(post.title().to_owned()))
|
||||
@@ -32,8 +26,8 @@ pub(super) async fn handle(
|
||||
.build()))
|
||||
.link(Some(format!(
|
||||
"{}://{}/articles/{}",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain,
|
||||
context.config().site.protocol,
|
||||
context.config().site.domain,
|
||||
post.id()
|
||||
)))
|
||||
.pub_date(Some(post.published().to_rfc2822()))
|
||||
@@ -48,12 +42,12 @@ pub(super) async fn handle(
|
||||
};
|
||||
|
||||
Rss(rss::ChannelBuilder::default()
|
||||
.title(config.rss.title.clone())
|
||||
.title(context.config().rss.title.clone())
|
||||
.link(format!(
|
||||
"{}://{}",
|
||||
config.self_ref.protocol, config.self_ref.domain
|
||||
context.config().site.protocol, context.config().site.domain
|
||||
))
|
||||
.ttl(Some(config.rss.ttl.to_string()))
|
||||
.ttl(Some(context.config().rss.ttl.to_string()))
|
||||
.last_build_date(Some(updated.to_rfc2822()))
|
||||
.items(rss_items)
|
||||
.build()
|
||||
|
||||
@@ -11,9 +11,7 @@ use tower::limit::ConcurrencyLimitLayer;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::info;
|
||||
|
||||
use blog::db::ConcurrentPostsStore;
|
||||
|
||||
use crate::Config;
|
||||
use crate::Context;
|
||||
|
||||
use super::{
|
||||
atom,
|
||||
@@ -26,11 +24,7 @@ use super::{
|
||||
static_content,
|
||||
};
|
||||
|
||||
pub(crate) fn service(
|
||||
config: Arc<Config>,
|
||||
posts_store: ConcurrentPostsStore,
|
||||
) -> Router
|
||||
{
|
||||
pub(crate) fn service(context: Arc<Context>) -> Router {
|
||||
Router::new()
|
||||
.route("/", get(index::handle))
|
||||
.route("/contact", get(contact::handle))
|
||||
@@ -38,21 +32,20 @@ pub(crate) fn service(
|
||||
.route("/rss.xml", get(rss::handle))
|
||||
.route("/atom.xml", get(atom::handle))
|
||||
.route("/articles/:post_id", get(post::handle))
|
||||
.route("/robots.txt", static_content::file_service(&config.robots_path, None))
|
||||
.route("/favicon.ico", static_content::file_service(&config.favicon_dir.join("favicon.ico"), None))
|
||||
.route("/favicon-16x16.png", static_content::file_service(&config.favicon_dir.join("favicon-16x16.png"), None))
|
||||
.route("/favicon-32x32.png", static_content::file_service(&config.favicon_dir.join("favicon-32x32.png"), None))
|
||||
.route("/apple-touch-icon.png", static_content::file_service(&config.favicon_dir.join("apple-touch-icon.png"), None))
|
||||
.route("/android-chrome-192x192.png", static_content::file_service(&config.favicon_dir.join("android-chrome-192x192.png"), None))
|
||||
.route("/android-chrome-512x512.png", static_content::file_service(&config.favicon_dir.join("android-chrome-512x512.png"), None))
|
||||
.route("/site.webmanifest", static_content::file_service(&config.favicon_dir.join("site.webmanifest"), None))
|
||||
.nest("/static", static_content::dir_service(&config.static_dir))
|
||||
.nest("/article_media", static_content::dir_service(&config.post_media_dir))
|
||||
.route("/robots.txt", static_content::file_service(&context.config().content.robots_path, None))
|
||||
.route("/favicon.ico", static_content::file_service(&context.config().content.favicon_dir.join("favicon.ico"), None))
|
||||
.route("/favicon-16x16.png", static_content::file_service(&context.config().content.favicon_dir.join("favicon-16x16.png"), None))
|
||||
.route("/favicon-32x32.png", static_content::file_service(&context.config().content.favicon_dir.join("favicon-32x32.png"), None))
|
||||
.route("/apple-touch-icon.png", static_content::file_service(&context.config().content.favicon_dir.join("apple-touch-icon.png"), None))
|
||||
.route("/android-chrome-192x192.png", static_content::file_service(&context.config().content.favicon_dir.join("android-chrome-192x192.png"), None))
|
||||
.route("/android-chrome-512x512.png", static_content::file_service(&context.config().content.favicon_dir.join("android-chrome-512x512.png"), None))
|
||||
.route("/site.webmanifest", static_content::file_service(&context.config().content.favicon_dir.join("site.webmanifest"), None))
|
||||
.nest("/static", static_content::dir_service(&context.config().content.static_dir))
|
||||
.nest("/article_media", static_content::dir_service(&context.config().content.post_media_dir))
|
||||
.fallback(handle_fallback.into_service())
|
||||
.layer(ConcurrencyLimitLayer::new(config.concurrency_limit))
|
||||
.layer(ConcurrencyLimitLayer::new(context.config().concurrency_limit))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(Extension(config))
|
||||
.layer(Extension(posts_store))
|
||||
.layer(Extension(context))
|
||||
}
|
||||
|
||||
async fn handle_fallback(uri: Uri) -> Error {
|
||||
|
||||
+2
-3
@@ -10,14 +10,13 @@ use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
use crate::post::{Post, Id};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConcurrentPostsStore {
|
||||
inner: Arc<RwLock<PostsStore>>,
|
||||
inner: RwLock<PostsStore>,
|
||||
}
|
||||
|
||||
impl ConcurrentPostsStore {
|
||||
pub fn new() -> Self {
|
||||
Self { inner: Arc::new(RwLock::new(PostsStore::new())) }
|
||||
Self { inner: RwLock::new(PostsStore::new()) }
|
||||
}
|
||||
|
||||
pub async fn read(&self) -> RwLockReadGuard<'_, PostsStore> {
|
||||
|
||||
Reference in new issue
Block a user