Compare commits
2 commits
2fa22a2752
...
d2976b2684
Author | SHA1 | Date | |
---|---|---|---|
d2976b2684 | |||
573ea75167 |
8 changed files with 233 additions and 563 deletions
445
Cargo.lock
generated
445
Cargo.lock
generated
|
@ -26,69 +26,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.82"
|
||||
|
@ -103,9 +40,6 @@ checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
|||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
"humansize",
|
||||
"num-traits",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -126,12 +60,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
|
@ -309,7 +241,7 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
|
@ -336,15 +268,6 @@ version = "0.21.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
|
@ -367,7 +290,6 @@ dependencies = [
|
|||
"comrak",
|
||||
"console-subscriber",
|
||||
"fronma",
|
||||
"notify",
|
||||
"scc",
|
||||
"serde",
|
||||
"syntect",
|
||||
|
@ -402,22 +324,10 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48bc1c27654127a24c476d40198746860ef56475f41a601bfa5c4d0f832968f0"
|
||||
dependencies = [
|
||||
"bitcode_derive",
|
||||
"bytemuck",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcode_derive"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2966755a19aad59ee2aae91e2d48842c667a99d818ec72168efdab07200701cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -476,56 +386,10 @@ version = "0.4.38"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim 0.11.1",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.3"
|
||||
|
@ -553,30 +417,21 @@ dependencies = [
|
|||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "comrak"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0436149c9f6a1935b13306206c739b1ba84fa81f551b5eb87fc2ca7a13700af"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"derive_builder",
|
||||
"entities",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"shell-words",
|
||||
"slug",
|
||||
"syntect",
|
||||
"typed-arena",
|
||||
"unicode_categories",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -616,12 +471,6 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
|
@ -666,7 +515,7 @@ dependencies = [
|
|||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
|
@ -745,16 +594,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
|
@ -775,18 +614,6 @@ dependencies = [
|
|||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.28"
|
||||
|
@ -822,15 +649,6 @@ dependencies = [
|
|||
"serde_yaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
|
@ -937,12 +755,6 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
|
@ -1023,15 +835,6 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humansize"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
|
@ -1109,29 +912,6 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -1164,26 +944,6 @@ dependencies = [
|
|||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
|
@ -1208,35 +968,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1249,12 +980,6 @@ version = "0.2.153"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.2.0"
|
||||
|
@ -1267,22 +992,6 @@ version = "0.5.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
|
@ -1348,7 +1057,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
@ -1363,35 +1071,6 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "6.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
|
@ -1454,41 +1133,12 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
|
@ -1648,15 +1298,6 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.4"
|
||||
|
@ -1707,19 +1348,6 @@ version = "0.1.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.15"
|
||||
|
@ -1751,12 +1379,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sdd"
|
||||
version = "0.2.0"
|
||||
|
@ -1846,17 +1468,11 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -1902,12 +1518,6 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -1965,16 +1575,6 @@ dependencies = [
|
|||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.58"
|
||||
|
@ -2047,7 +1647,6 @@ dependencies = [
|
|||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
|
@ -2228,7 +1827,6 @@ version = "0.1.40"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
|
@ -2265,17 +1863,6 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
|
@ -2283,15 +1870,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2327,12 +1911,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
|
@ -2455,15 +2033,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
@ -2612,12 +2181,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
|
43
Cargo.toml
43
Cargo.toml
|
@ -11,26 +11,43 @@ tokio-console = ["dep:console-subscriber"]
|
|||
[profile.release]
|
||||
lto = "fat"
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
strip = true
|
||||
|
||||
[dependencies]
|
||||
askama = { version = "0.12.1", features = ["with-axum"] }
|
||||
askama_axum = "0.4.0"
|
||||
axum = { version = "0.7.5", features = ["macros"] }
|
||||
bitcode = { version = "0.6.0", features = ["serde"] }
|
||||
chrono = { version = "0.4.37", features = ["serde"] }
|
||||
askama = { version = "0.12.1", features = [
|
||||
"with-axum",
|
||||
], default-features = false }
|
||||
askama_axum = { version = "0.4.0", default-features = false }
|
||||
axum = { version = "0.7.5", features = [
|
||||
"http1",
|
||||
"json",
|
||||
"query",
|
||||
"macros",
|
||||
"tokio",
|
||||
"tracing",
|
||||
], default-features = false }
|
||||
bitcode = { version = "0.6.0", features = ["serde"], default-features = false }
|
||||
chrono = { version = "0.4.37", features = [
|
||||
"std",
|
||||
"serde",
|
||||
], default-features = false }
|
||||
color-eyre = "0.6.3"
|
||||
comrak = { version = "0.22.0", features = ["syntect"] }
|
||||
comrak = { version = "0.22.0", features = [
|
||||
"syntect",
|
||||
], default-features = false }
|
||||
console-subscriber = { version = "0.2.0", optional = true }
|
||||
fronma = "0.2.0"
|
||||
notify = "6.1.1"
|
||||
scc = { version = "2.1.0", features = ["serde"] }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
syntect = "5.2.0"
|
||||
thiserror = "1.0.58"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
tokio-util = "0.7.10"
|
||||
tokio = { version = "1.37.0", features = [
|
||||
"fs",
|
||||
"macros",
|
||||
"rt-multi-thread",
|
||||
"signal",
|
||||
] }
|
||||
tokio-util = { version = "0.7.10", default-features = false }
|
||||
toml = "0.8.12"
|
||||
tower-http = { version = "0.5.2", features = [
|
||||
"compression-gzip",
|
||||
|
@ -38,5 +55,7 @@ tower-http = { version = "0.5.2", features = [
|
|||
"trace",
|
||||
], default-features = false }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
zstd = "0.13.1"
|
||||
tracing-subscriber = { version = "0.3.18", features = [
|
||||
"env-filter",
|
||||
], default-features = false }
|
||||
zstd = { version = "0.13.1", default-features = false }
|
||||
|
|
41
README.md
41
README.md
|
@ -24,9 +24,10 @@ blazingly fast markdown blog software written in rust memory safe
|
|||
- [ ] make date parsing less strict
|
||||
- [ ] make date formatting better
|
||||
- [ ] date formatting respects user timezone
|
||||
- [ ] clean up imports and require less features
|
||||
- [x] clean up imports and require less features
|
||||
- [ ] improve home page
|
||||
- [ ] tags
|
||||
- [x] tags (backend)
|
||||
- [ ] tags (frontend)
|
||||
- [x] be blazingly fast
|
||||
- [x] 100+ MiB binary size
|
||||
|
||||
|
@ -35,26 +36,30 @@ blazingly fast markdown blog software written in rust memory safe
|
|||
the default configuration with comments looks like this
|
||||
|
||||
```toml
|
||||
# main settings
|
||||
host = "0.0.0.0" # ip to listen on
|
||||
port = 3000 # port to listen on
|
||||
title = "bingus-blog" # title of the website
|
||||
description = "blazingly fast markdown blog software written in rust memory safe" # description of the website
|
||||
posts_dir = "posts" # where posts are stored
|
||||
markdown_access = true # allow users to see the raw markdown of a post
|
||||
raw_access = true # allow users to see the raw markdown of a post
|
||||
|
||||
[cache] # cache settings
|
||||
enable = true # save metadata and rendered posts into RAM
|
||||
# highly recommended, only turn off if absolutely necessary
|
||||
cleanup = true # clean cache, highly recommended
|
||||
#cleanup_interval = 86400000 # clean the cache regularly instead of just at startu
|
||||
# uncomment to enable
|
||||
persistence = true # save the cache to on shutdown and load on startup
|
||||
file = "cache" # file to save the cache to
|
||||
compress = true # compress the cache file
|
||||
compression_level = 3 # zstd compression level, 3 is recommended
|
||||
[dirs]
|
||||
posts = "posts" # where posts are stored
|
||||
media = "media" # directory served under /media/
|
||||
|
||||
[render] # post rendering settings
|
||||
[http]
|
||||
host = "0.0.0.0" # ip to listen on
|
||||
port = 3000 # port to listen on
|
||||
|
||||
[cache]
|
||||
enable = true # save metadata and rendered posts into RAM
|
||||
# highly recommended, only turn off if absolutely necessary
|
||||
cleanup = true # clean cache, highly recommended
|
||||
#cleanup_interval = 86400000 # clean the cache regularly instead of just at startup
|
||||
# uncomment to enable
|
||||
persistence = true # save the cache to on shutdown and load on startup
|
||||
file = "cache" # file to save the cache to
|
||||
compress = true # compress the cache file
|
||||
compression_level = 3 # zstd compression level, 3 is recommended
|
||||
|
||||
[render]
|
||||
syntect.load_defaults = false # include default syntect themes
|
||||
syntect.themes_dir = "themes" # directory to include themes from
|
||||
syntect.theme = "Catppuccin Mocha" # theme file name (without `.tmTheme`)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use std::{
|
||||
env,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::env;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use color_eyre::eyre::{bail, Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -40,28 +38,60 @@ pub struct CacheConfig {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
pub struct HttpConfig {
|
||||
pub host: IpAddr,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct DirsConfig {
|
||||
pub posts: PathBuf,
|
||||
pub media: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub posts_dir: PathBuf,
|
||||
pub raw_access: bool,
|
||||
pub num_posts: usize,
|
||||
pub dirs: DirsConfig,
|
||||
pub http: HttpConfig,
|
||||
pub render: RenderConfig,
|
||||
pub cache: CacheConfig,
|
||||
pub markdown_access: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
host: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||
port: 3000,
|
||||
title: "bingus-blog".into(),
|
||||
description: "blazingly fast markdown blog software written in rust memory safe".into(),
|
||||
raw_access: true,
|
||||
num_posts: 5,
|
||||
dirs: Default::default(),
|
||||
http: Default::default(),
|
||||
render: Default::default(),
|
||||
posts_dir: "posts".into(),
|
||||
cache: Default::default(),
|
||||
markdown_access: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DirsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
posts: "posts".into(),
|
||||
media: "media".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HttpConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
host: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||
port: 3000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
45
src/error.rs
45
src/error.rs
|
@ -1,9 +1,10 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use axum::{http::StatusCode, response::IntoResponse};
|
||||
use askama_axum::Template;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use thiserror::Error;
|
||||
|
||||
// fronma is too lazy to implement std::error::Error for their own types
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct FronmaError(fronma::error::Error);
|
||||
|
@ -45,3 +46,43 @@ impl IntoResponse for PostError {
|
|||
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub type AppResult<T> = Result<T, AppError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AppError {
|
||||
#[error("failed to fetch post: {0}")]
|
||||
PostError(#[from] PostError),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for AppError {
|
||||
#[inline(always)]
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::PostError(PostError::IoError(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "error.html")]
|
||||
struct ErrorTemplate {
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let status_code = match &self {
|
||||
AppError::PostError(err) => match err {
|
||||
PostError::NotFound(_) => StatusCode::NOT_FOUND,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
},
|
||||
//_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
(
|
||||
status_code,
|
||||
ErrorTemplate {
|
||||
error: self.to_string(),
|
||||
},
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
|
109
src/main.rs
109
src/main.rs
|
@ -17,13 +17,13 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
|
||||
use askama_axum::Template;
|
||||
use axum::extract::{MatchedPath, Path, State};
|
||||
use axum::http::{Request, StatusCode};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use axum::http::Request;
|
||||
use axum::response::{IntoResponse, Redirect, Response};
|
||||
use axum::routing::{get, Router};
|
||||
use axum::Json;
|
||||
use color_eyre::eyre::{self, Context};
|
||||
use thiserror::Error;
|
||||
use serde::Deserialize;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::task::JoinSet;
|
||||
|
@ -36,7 +36,7 @@ use tracing::{debug, error, info, info_span, warn, Span};
|
|||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::PostError;
|
||||
use crate::error::{AppResult, PostError};
|
||||
use crate::post::{PostManager, PostMetadata, RenderStats};
|
||||
|
||||
type ArcState = Arc<AppState>;
|
||||
|
@ -64,59 +64,46 @@ struct ViewPostTemplate {
|
|||
markdown_access: bool,
|
||||
}
|
||||
|
||||
type AppResult<T> = Result<T, AppError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum AppError {
|
||||
#[error("failed to fetch post: {0}")]
|
||||
PostError(#[from] PostError),
|
||||
#[derive(Deserialize)]
|
||||
struct QueryParams {
|
||||
tag: Option<String>,
|
||||
#[serde(rename = "n")]
|
||||
num_posts: Option<usize>,
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for AppError {
|
||||
#[inline(always)]
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::PostError(PostError::IoError(value))
|
||||
}
|
||||
}
|
||||
async fn index(
|
||||
State(state): State<ArcState>,
|
||||
Query(query): Query<QueryParams>,
|
||||
) -> AppResult<IndexTemplate> {
|
||||
let posts = state
|
||||
.posts
|
||||
.get_max_n_posts_with_optional_tag_sorted(query.num_posts, query.tag.as_ref())
|
||||
.await?;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "error.html")]
|
||||
struct ErrorTemplate {
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let status_code = match &self {
|
||||
AppError::PostError(err) => match err {
|
||||
PostError::NotFound(_) => StatusCode::NOT_FOUND,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
},
|
||||
//_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
(
|
||||
status_code,
|
||||
ErrorTemplate {
|
||||
error: self.to_string(),
|
||||
},
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
async fn index(State(state): State<ArcState>) -> AppResult<IndexTemplate> {
|
||||
Ok(IndexTemplate {
|
||||
title: state.config.title.clone(),
|
||||
description: state.config.description.clone(),
|
||||
posts: state.posts.list_posts().await?,
|
||||
posts,
|
||||
})
|
||||
}
|
||||
|
||||
async fn all_posts(
|
||||
State(state): State<ArcState>,
|
||||
Query(query): Query<QueryParams>,
|
||||
) -> AppResult<Json<Vec<PostMetadata>>> {
|
||||
let posts = state
|
||||
.posts
|
||||
.get_max_n_posts_with_optional_tag_sorted(query.num_posts, query.tag.as_ref())
|
||||
.await?;
|
||||
|
||||
Ok(Json(posts))
|
||||
}
|
||||
|
||||
async fn post(State(state): State<ArcState>, Path(name): Path<String>) -> AppResult<Response> {
|
||||
if name.ends_with(".md") && state.config.markdown_access {
|
||||
if name.ends_with(".md") && state.config.raw_access {
|
||||
let mut file = tokio::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(state.config.posts_dir.join(&name))
|
||||
.open(state.config.dirs.posts.join(&name))
|
||||
.await?;
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
@ -129,18 +116,13 @@ async fn post(State(state): State<ArcState>, Path(name): Path<String>) -> AppRes
|
|||
meta: post.0,
|
||||
rendered: post.1,
|
||||
rendered_in: post.2,
|
||||
markdown_access: state.config.markdown_access,
|
||||
markdown_access: state.config.raw_access,
|
||||
};
|
||||
|
||||
Ok(page.into_response())
|
||||
}
|
||||
}
|
||||
|
||||
async fn all_posts(State(state): State<ArcState>) -> AppResult<Json<Vec<PostMetadata>>> {
|
||||
let posts = state.posts.list_posts().await?;
|
||||
Ok(Json(posts))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> eyre::Result<()> {
|
||||
#[cfg(feature = "tokio-console")]
|
||||
|
@ -160,6 +142,8 @@ async fn main() -> eyre::Result<()> {
|
|||
.await
|
||||
.context("couldn't load configuration")?;
|
||||
|
||||
let socket_addr = SocketAddr::new(config.http.host, config.http.port);
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
let cancellation_token = CancellationToken::new();
|
||||
|
||||
|
@ -198,7 +182,7 @@ async fn main() -> eyre::Result<()> {
|
|||
let cache =
|
||||
bitcode::deserialize(serialized.as_slice()).context("failed to parse cache")?;
|
||||
Ok::<PostManager, color_eyre::Report>(PostManager::new_with_cache(
|
||||
config.posts_dir.clone(),
|
||||
config.dirs.posts.clone(),
|
||||
config.render.clone(),
|
||||
cache,
|
||||
))
|
||||
|
@ -210,7 +194,7 @@ async fn main() -> eyre::Result<()> {
|
|||
error!("failed to load cache: {}", err);
|
||||
info!("using empty cache");
|
||||
PostManager::new_with_cache(
|
||||
config.posts_dir.clone(),
|
||||
config.dirs.posts.clone(),
|
||||
config.render.clone(),
|
||||
Default::default(),
|
||||
)
|
||||
|
@ -218,13 +202,13 @@ async fn main() -> eyre::Result<()> {
|
|||
}
|
||||
} else {
|
||||
PostManager::new_with_cache(
|
||||
config.posts_dir.clone(),
|
||||
config.dirs.posts.clone(),
|
||||
config.render.clone(),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
PostManager::new(config.posts_dir.clone(), config.render.clone())
|
||||
PostManager::new(config.dirs.posts.clone(), config.render.clone())
|
||||
};
|
||||
|
||||
let state = Arc::new(AppState { config, posts });
|
||||
|
@ -265,16 +249,10 @@ async fn main() -> eyre::Result<()> {
|
|||
.layer(
|
||||
TraceLayer::new_for_http()
|
||||
.make_span_with(|request: &Request<_>| {
|
||||
let matched_path = request
|
||||
.extensions()
|
||||
.get::<MatchedPath>()
|
||||
.map(MatchedPath::as_str);
|
||||
|
||||
info_span!(
|
||||
"request",
|
||||
method = ?request.method(),
|
||||
path = ?request.uri().path(),
|
||||
matched_path,
|
||||
)
|
||||
})
|
||||
.on_response(|response: &Response<_>, duration: Duration, span: &Span| {
|
||||
|
@ -285,14 +263,9 @@ async fn main() -> eyre::Result<()> {
|
|||
)
|
||||
.with_state(state.clone());
|
||||
|
||||
let listener = TcpListener::bind((state.config.host, state.config.port))
|
||||
let listener = TcpListener::bind(socket_addr)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"couldn't listen on {}",
|
||||
SocketAddr::new(state.config.host, state.config.port)
|
||||
)
|
||||
})?;
|
||||
.with_context(|| format!("couldn't listen on {}", socket_addr))?;
|
||||
let local_addr = listener
|
||||
.local_addr()
|
||||
.context("couldn't get socket address")?;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::hash::{DefaultHasher, Hash, Hasher};
|
|||
|
||||
use scc::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::config::RenderConfig;
|
||||
use crate::post::PostMetadata;
|
||||
|
@ -107,7 +107,7 @@ impl Cache {
|
|||
if get_mtime(k).is_some_and(|mtime| mtime == v.mtime) {
|
||||
true
|
||||
} else {
|
||||
tracing::debug!("removing {k} from cache");
|
||||
debug!("removing {k} from cache");
|
||||
i += 1;
|
||||
false
|
||||
}
|
||||
|
@ -115,6 +115,6 @@ impl Cache {
|
|||
.await;
|
||||
|
||||
let new_size = self.0.len();
|
||||
tracing::debug!("removed {i} entries ({old_size} -> {new_size} entries)");
|
||||
debug!("removed {i} entries ({old_size} -> {new_size} entries)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ struct FrontMatter {
|
|||
pub icon: Option<String>,
|
||||
pub created_at: Option<DateTime<Utc>>,
|
||||
pub modified_at: Option<DateTime<Utc>>,
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl FrontMatter {
|
||||
|
@ -43,11 +45,12 @@ impl FrontMatter {
|
|||
icon: self.icon,
|
||||
created_at: self.created_at.or_else(|| created.map(|t| t.into())),
|
||||
modified_at: self.modified_at.or_else(|| modified.map(|t| t.into())),
|
||||
tags: self.tags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct PostMetadata {
|
||||
pub name: String,
|
||||
pub title: String,
|
||||
|
@ -56,6 +59,7 @@ pub struct PostMetadata {
|
|||
pub icon: Option<String>,
|
||||
pub created_at: Option<DateTime<Utc>>,
|
||||
pub modified_at: Option<DateTime<Utc>>,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
use crate::filters;
|
||||
|
@ -66,10 +70,10 @@ struct Post<'a> {
|
|||
pub rendered_markdown: String,
|
||||
}
|
||||
|
||||
// format: TOTAL OP1 OP2
|
||||
#[allow(unused)]
|
||||
pub enum RenderStats {
|
||||
Cached(Duration),
|
||||
// format: Total, Parsed in, Rendered in
|
||||
ParsedAndRendered(Duration, Duration, Duration),
|
||||
}
|
||||
|
||||
|
@ -146,7 +150,10 @@ impl PostManager {
|
|||
Ok((metadata, post, (parsing, rendering)))
|
||||
}
|
||||
|
||||
pub async fn list_posts(&self) -> Result<Vec<PostMetadata>, PostError> {
|
||||
pub async fn list_posts(
|
||||
&self,
|
||||
filter: impl Fn(&PostMetadata) -> bool,
|
||||
) -> Result<Vec<PostMetadata>, PostError> {
|
||||
let mut posts = Vec::new();
|
||||
|
||||
let mut read_dir = fs::read_dir(&self.dir).await?;
|
||||
|
@ -166,10 +173,25 @@ impl PostManager {
|
|||
|
||||
if let Some(cache) = self.cache.as_ref()
|
||||
&& let Some(hit) = cache.lookup_metadata(&name, mtime).await
|
||||
&& filter(&hit)
|
||||
{
|
||||
posts.push(hit)
|
||||
} else if let Ok((metadata, ..)) = self.parse_and_render(name, path).await {
|
||||
posts.push(metadata);
|
||||
posts.push(hit);
|
||||
} else {
|
||||
match self.parse_and_render(name, path).await {
|
||||
Ok((metadata, ..)) => {
|
||||
if filter(&metadata) {
|
||||
posts.push(metadata);
|
||||
}
|
||||
}
|
||||
Err(err) => match err {
|
||||
PostError::IoError(ref io_err)
|
||||
if matches!(io_err.kind(), io::ErrorKind::NotFound) =>
|
||||
{
|
||||
warn!("TOCTOU: {}", err)
|
||||
}
|
||||
_ => return Err(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +199,24 @@ impl PostManager {
|
|||
Ok(posts)
|
||||
}
|
||||
|
||||
// third entry in the tuple is whether it got rendered and if so, how long did it take
|
||||
pub async fn get_max_n_posts_with_optional_tag_sorted(
|
||||
&self,
|
||||
n: Option<usize>,
|
||||
tag: Option<&String>,
|
||||
) -> Result<Vec<PostMetadata>, PostError> {
|
||||
let mut posts = self
|
||||
.list_posts(|metadata| !tag.is_some_and(|tag| !metadata.tags.contains(tag)))
|
||||
.await?;
|
||||
posts.sort_unstable_by_key(|metadata| metadata.created_at.unwrap_or_default());
|
||||
|
||||
if let Some(n) = n {
|
||||
posts = Vec::from(&posts[posts.len().saturating_sub(n)..]);
|
||||
}
|
||||
|
||||
posts.reverse();
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn get_post(
|
||||
&self,
|
||||
name: &str,
|
||||
|
|
Loading…
Reference in a new issue