EXTREMELY EVIL CACKLING

This commit is contained in:
Allie Signet 2022-07-01 19:27:28 -03:00
parent 462134b36d
commit f64e309425
10 changed files with 1160 additions and 186 deletions

581
Cargo.lock generated
View file

@ -2,6 +2,18 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.7.6"
@ -25,6 +37,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.0"
@ -40,6 +58,12 @@ dependencies = [
"base64",
]
[[package]]
name = "bit_field"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
[[package]]
name = "bitflags"
version = "0.9.1"
@ -80,6 +104,12 @@ dependencies = [
"safemem",
]
[[package]]
name = "bumpalo"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "bytecheck"
version = "0.6.8"
@ -101,6 +131,27 @@ dependencies = [
"syn",
]
[[package]]
name = "bytemuck"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -113,6 +164,66 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "crow"
version = "0.1.0"
@ -120,11 +231,15 @@ dependencies = [
"anyhow",
"base64-url",
"blake2",
"image",
"lmdb-zero",
"matchit",
"multipart",
"rkyv",
"thiserror",
"tiny_http",
"url",
"webp",
]
[[package]]
@ -137,6 +252,15 @@ dependencies = [
"typenum",
]
[[package]]
name = "deflate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f"
dependencies = [
"adler32",
]
[[package]]
name = "digest"
version = "0.10.3"
@ -148,6 +272,28 @@ dependencies = [
"subtle",
]
[[package]]
name = "either"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "exr"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14cc0e06fb5f67e5d6beadf3a382fec9baca1aa751c6d5368fdeee7e5932c215"
dependencies = [
"bit_field",
"deflate",
"flume",
"half",
"inflate",
"lebe",
"smallvec",
"threadpool",
]
[[package]]
name = "fastrand"
version = "1.7.0"
@ -157,6 +303,29 @@ dependencies = [
"instant",
]
[[package]]
name = "flate2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.10.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"pin-project",
"spin",
]
[[package]]
name = "form_urlencoded"
version = "1.0.1"
@ -167,6 +336,18 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-core"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-sink"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]]
name = "gcc"
version = "0.3.55"
@ -190,10 +371,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "gif"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
dependencies = [
"color_quant",
"weezl",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.1"
@ -203,6 +402,15 @@ dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "httparse"
version = "1.7.1"
@ -220,6 +428,35 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "image"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"exr",
"gif",
"jpeg-decoder",
"num-iter",
"num-rational",
"num-traits",
"png",
"scoped_threadpool",
"tiff",
]
[[package]]
name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
dependencies = [
"adler32",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -235,6 +472,45 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "jobserver"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
dependencies = [
"libc",
]
[[package]]
name = "jpeg-decoder"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b"
dependencies = [
"rayon",
]
[[package]]
name = "js-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lebe"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff"
[[package]]
name = "libc"
version = "0.2.126"
@ -251,6 +527,15 @@ dependencies = [
"libc",
]
[[package]]
name = "libwebp-sys"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439fd1885aa28937e7edcd68d2e793cb4a22f8733460d2519fbafd2b215672bf"
dependencies = [
"cc",
]
[[package]]
name = "lmdb-zero"
version = "0.4.4"
@ -263,6 +548,16 @@ dependencies = [
"supercow",
]
[[package]]
name = "lock_api"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
@ -278,12 +573,27 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "matchit"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfc802da7b1cf80aefffa0c7b2f77247c8b32206cc83c270b61264f5b360a80"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -300,10 +610,19 @@ dependencies = [
"unicase",
]
[[package]]
name = "miniz_oxide"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler",
]
[[package]]
name = "multipart"
version = "0.18.0"
source = "git+https://github.com/emily-signet/multipart#8144529477faf92941206320395fc3798c14fdf7"
source = "git+https://github.com/emily-signet/multipart#3ae1cd313be14b94997405fef38e29a2edb60232"
dependencies = [
"buf_redux",
"httparse",
@ -318,6 +637,66 @@ dependencies = [
"twoway",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "num_threads"
version = "0.1.6"
@ -339,6 +718,38 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "png"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
"deflate",
"miniz_oxide",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
@ -419,6 +830,30 @@ dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.2.13"
@ -477,12 +912,39 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "smallvec"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "spin"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d"
dependencies = [
"lock_api",
]
[[package]]
name = "subtle"
version = "2.4.1"
@ -520,6 +982,46 @@ dependencies = [
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]]
name = "tiff"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cfada0986f446a770eca461e8c6566cb879682f7d687c8348aa0c857bd52286"
dependencies = [
"flate2",
"jpeg-decoder",
"weezl",
]
[[package]]
name = "time"
version = "0.3.11"
@ -541,8 +1043,7 @@ checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
[[package]]
name = "tiny_http"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0d6ef4e10d23c1efb862eecad25c5054429a71958b4eeef85eb5e7170b477ca"
source = "git+https://github.com/emily-signet/tiny-http.git#6228d7b6559ef13f6a1a3f46f6f2cf0b306a386a"
dependencies = [
"ascii",
"chunked_transfer",
@ -604,9 +1105,9 @@ checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-normalization"
version = "0.1.20"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd"
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
dependencies = [
"tinyvec",
]
@ -635,6 +1136,76 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
[[package]]
name = "webp"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf022f821f166079a407d000ab57e84de020e66ffbbf4edde999bc7d6e371cae"
dependencies = [
"image",
"libwebp-sys",
]
[[package]]
name = "weezl"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4"
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -9,8 +9,12 @@ edition = "2021"
anyhow = "1.0.58"
base64-url = "1.4.13"
blake2 = "0.10.4"
image = "0.24.2"
lmdb-zero = "0.4.4"
matchit = "0.6.0"
multipart = { git = "https://github.com/emily-signet/multipart", default-features = false, features = ["server", "tiny_http"] }
rkyv = { version = "0.7.39", features = ["strict", "archive_le"] }
tiny_http = "0.11.0"
thiserror = "1.0.31"
tiny_http = { git = "https://github.com/emily-signet/tiny-http.git" }
url = "2.2.2"
webp = "0.2.2"

BIN
db/data.mdb Normal file

Binary file not shown.

BIN
db/lock.mdb Normal file

Binary file not shown.

237
src/lib.rs Normal file
View file

@ -0,0 +1,237 @@
use blake2::Digest;
use lmdb::{traits::FromLmdbBytes, Database, Environment};
use lmdb_zero as lmdb;
use tiny_http::Request;
use std::{str::FromStr, sync::Arc};
use thiserror::Error;
pub trait Handler: Send + Sync {
fn respond<'u>(
&self,
req: Request,
db: &DatabaseContext,
params: matchit::Params<'u, 'u>,
) -> CrowResult<()>;
}
pub mod routes;
#[derive(Error, Debug)]
pub enum CrowError {
#[error(transparent)]
LmdbError(#[from] lmdb::Error),
#[error(transparent)]
IOError(#[from] std::io::Error),
#[error(transparent)]
ImageError(#[from] image::error::ImageError),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub type CrowResult<T> = Result<T, CrowError>;
#[derive(rkyv::Archive, rkyv::Serialize)]
pub struct FileHeader {
file_name: Option<String>,
content_type: Option<String>,
}
impl FromLmdbBytes for ArchivedFileHeader {
fn from_lmdb_bytes(bytes: &[u8]) -> Result<&Self, String> {
Ok(unsafe { rkyv::archived_root::<FileHeader>(bytes) })
}
}
#[derive(rkyv::Serialize, rkyv::Archive, Copy, Debug, Clone)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Copy, Clone))]
#[repr(u8)]
pub enum ImageFormat {
PNG,
WEBP,
JPG,
}
impl FromStr for ImageFormat {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"png" | "PNG" => ImageFormat::PNG,
"webp" | "WEBP" => ImageFormat::WEBP,
"jpg" | "JPG" | "jpeg" | "JPEG" => ImageFormat::JPG,
_ => return Err(()),
})
}
}
impl ImageFormat {
pub const fn to_mime(&self) -> &'static str {
match *self {
ImageFormat::PNG => "image/png",
ImageFormat::JPG => "image/jpeg",
ImageFormat::WEBP => "image/webp",
}
}
}
impl From<ImageFormat> for image::ImageFormat {
fn from(val: ImageFormat) -> Self {
match val {
ImageFormat::PNG => image::ImageFormat::Png,
ImageFormat::WEBP => image::ImageFormat::WebP,
ImageFormat::JPG => image::ImageFormat::Jpeg,
}
}
}
impl From<ArchivedImageFormat> for image::ImageFormat {
fn from(val: ArchivedImageFormat) -> Self {
match val {
ArchivedImageFormat::PNG => image::ImageFormat::Png,
ArchivedImageFormat::WEBP => image::ImageFormat::WebP,
ArchivedImageFormat::JPG => image::ImageFormat::Jpeg,
}
}
}
#[derive(rkyv::Serialize, rkyv::Archive)]
pub struct ImageHeader {
store_format: ImageFormat,
}
impl FromLmdbBytes for ArchivedImageHeader {
fn from_lmdb_bytes(bytes: &[u8]) -> Result<&Self, String> {
Ok(unsafe { rkyv::archived_root::<ImageHeader>(bytes) })
}
}
#[derive(Clone)]
pub struct DatabaseContext {
pub env: Arc<Environment>,
pub metadata_store: Arc<Database<'static>>,
pub binary_store: Arc<Database<'static>>,
pub image_store: Arc<Database<'static>>,
pub image_meta_store: Arc<Database<'static>>,
}
impl DatabaseContext {
pub fn create(path: &str) -> CrowResult<DatabaseContext> {
let env = Arc::new(unsafe {
let mut builder = lmdb::EnvBuilder::new()?;
builder.set_maxdbs(4)?;
builder.open(path, lmdb::open::NOTLS, 0o600)?
});
let binary_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("binary"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
let image_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("image"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
let metadata_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("metadata"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
let image_meta_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("metadata-image"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
Ok(DatabaseContext {
env,
binary_store,
metadata_store,
image_meta_store,
image_store,
})
}
#[inline]
pub fn write_txn(&self) -> CrowResult<lmdb::WriteTransaction<'static>> {
lmdb::WriteTransaction::new(self.env.clone()).map_err(CrowError::from)
}
#[inline]
pub fn read_txn(&self) -> CrowResult<lmdb::ReadTransaction<'static>> {
lmdb::ReadTransaction::new(self.env.clone()).map_err(CrowError::from)
}
}
mod macros {
macro_rules! response {
(err $status:literal $msg:literal) => {
Response::new(
tiny_http::StatusCode($status),
vec![],
$msg.as_bytes(),
None,
None,
)
};
}
macro_rules! single_multipart {
($req:expr) => {
Multipart::from_request($req)
.ok()
.and_then(|v| v.into_entry().into_result().ok())
.flatten()
};
}
macro_rules! fn_to_handler {
($f:ident : $handler_name:ident) => {
pub struct $handler_name;
impl Handler for $handler_name {
fn respond<'u>(
&self,
req: Request,
db: &DatabaseContext,
params: matchit::Params<'u, 'u>,
) -> CrowResult<()> {
$f(req, db, params)
}
}
};
}
macro_rules! parse_base64_hash {
($fr:expr) => {
$fr.and_then(|s| {
let mut out: [u8; 32] = [0; 32];
base64_url::decode_to_slice(s, &mut out).ok()?;
Some(out)
})
};
}
macro_rules! some_or_response {
($opt:expr, or respond to $req:ident with $response:expr) => {
match $opt {
Some(v) => v,
None => {
$req.respond($response)?;
return Ok(());
}
}
};
}
pub(crate) use fn_to_handler;
pub(crate) use parse_base64_hash;
pub(crate) use response;
pub(crate) use single_multipart;
pub(crate) use some_or_response;
}
pub(crate) use macros::*;

View file

@ -1,70 +1,7 @@
extern crate multipart;
extern crate tiny_http;
use std::{sync::Arc, thread};
use blake2::{Blake2s256, Digest};
use lmdb::{Database, Environment, LmdbResultExt};
use lmdb_zero as lmdb;
use multipart::server::Multipart;
use rkyv::option::ArchivedOption;
use std::{io::Read, sync::Arc, thread};
use tiny_http::{Header, Request, Response};
#[derive(rkyv::Archive, rkyv::Serialize)]
pub struct FileHeader {
file_name: Option<String>,
content_type: Option<String>,
}
#[derive(Clone)]
pub struct DatabaseContext {
env: Arc<Environment>,
metadata_store: Arc<Database<'static>>,
binary_store: Arc<Database<'static>>,
image_store: Arc<Database<'static>>,
}
impl DatabaseContext {
pub fn create(path: &str) -> anyhow::Result<DatabaseContext> {
let env = Arc::new(unsafe {
let mut builder = lmdb::EnvBuilder::new()?;
builder.set_maxdbs(3)?;
builder.open(path, lmdb::open::NOTLS, 0o600)?
});
let binary_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("binary"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
let image_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("image"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
let metadata_store = Arc::new(lmdb::Database::open(
env.clone(),
Some("metadata"),
&lmdb::DatabaseOptions::new(lmdb::db::CREATE),
)?);
Ok(DatabaseContext {
env,
binary_store,
metadata_store,
image_store,
})
}
#[inline]
pub fn write_txn(&self) -> anyhow::Result<lmdb::WriteTransaction<'static>> {
lmdb::WriteTransaction::new(self.env.clone()).map_err(anyhow::Error::from)
}
#[inline]
pub fn read_txn(&self) -> anyhow::Result<lmdb::ReadTransaction<'static>> {
lmdb::ReadTransaction::new(self.env.clone()).map_err(anyhow::Error::from)
}
}
use crow::*;
use matchit::Router;
fn main() -> anyhow::Result<()> {
let database_context = DatabaseContext::create("./db")?;
@ -74,22 +11,25 @@ fn main() -> anyhow::Result<()> {
let mut guards = Vec::with_capacity(4);
// router.insert("/upload", &routes::upload::upload_route);
// router.insert("/image", &routes::image::image_route);
for _ in 0..4 {
let server = server.clone();
let db = database_context.clone();
let mut router: Router<&dyn Handler> = Router::new();
router.insert("/get/:id", &routes::get::GetHandler)?;
router.insert("/upload", &routes::upload::UploadHandler)?;
router.insert("/image/upload", &routes::image::ImageUploadHandler)?;
router.insert("/image/get/:id/:format", &routes::image::ImageGetHandler)?;
let guard = thread::spawn(move || loop {
let request = server.recv().unwrap();
// i don't like this alloc
let url = request.url().to_owned();
match request.url() {
"/upload" => {
process_upload(request, &db).unwrap();
}
s if s.starts_with("/get/") => {
process_get(request, &db).unwrap();
}
_ => todo!(),
}
let matched = router.at(&url).unwrap();
matched.value.respond(request, &db, matched.params).unwrap();
});
guards.push(guard);
@ -101,108 +41,3 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
fn process_upload(mut request: Request, db_context: &DatabaseContext) -> anyhow::Result<()> {
if let Some(mut entry) = Multipart::from_request(&mut request)
.ok()
.and_then(|v| v.into_entry().into_result().ok())
.flatten()
{
let mut data: Vec<u8> = Vec::with_capacity(20000);
entry.data.read_to_end(&mut data)?;
let data_hash = Blake2s256::digest(&data);
let txn = db_context.write_txn()?;
let mut accessor = txn.access();
if accessor
.get::<[u8], [u8]>(&db_context.binary_store, data_hash.as_slice())
.to_opt()?
.is_some()
{
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
return Ok(());
}
accessor.put(
&db_context.binary_store,
data_hash.as_slice(),
&data,
lmdb::put::Flags::empty(),
)?;
let header = FileHeader {
file_name: entry.headers.filename,
content_type: entry
.headers
.content_type
.map(|v| v.essence_str().to_owned()),
};
accessor.put(
&db_context.metadata_store,
data_hash.as_slice(),
rkyv::to_bytes::<_, 256>(&header)?.as_slice(),
lmdb::put::Flags::empty(),
)?;
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
drop(accessor);
txn.commit()?;
}
Ok(())
}
fn process_get(request: Request, db_context: &DatabaseContext) -> anyhow::Result<()> {
if let Some(get_id) = request.url().strip_prefix("/get/").and_then(|s| {
let mut out: [u8; 32] = [0; 32];
base64_url::decode_to_slice(s, &mut out).ok()?;
Some(out)
}) {
let read = db_context.read_txn()?;
let access = read.access();
if let Some(data) = access
.get::<[u8], [u8]>(&db_context.binary_store, &get_id)
.to_opt()
.unwrap()
{
let header_bytes = access
.get::<[u8], [u8]>(&db_context.metadata_store, &get_id)
.to_opt()?
.ok_or(anyhow::anyhow!("header missing for file"))?;
let header = unsafe { rkyv::archived_root::<FileHeader>(header_bytes) };
let mut response = Response::new(200.into(), vec![], data, Some(data.len()), None);
if let ArchivedOption::Some(ref file_name) = header.file_name {
response = response.with_header(
Header::from_bytes(
&b"Content-Disposition"[..],
format!("inline; filename=\"{file_name}\"").into_bytes(),
)
.unwrap(),
);
}
if let ArchivedOption::Some(ref mime_type) = header.content_type {
response = response.with_header(
Header::from_bytes(&b"Content-Type"[..], mime_type.as_bytes()).unwrap(),
);
}
request.respond(response)?;
} else {
request.respond(Response::empty(404))?;
}
} else {
request.respond(Response::empty(400))?;
}
Ok(())
}

56
src/routes/get.rs Normal file
View file

@ -0,0 +1,56 @@
use crate::*;
use lmdb::LmdbResultExt;
use lmdb_zero as lmdb;
use rkyv::option::ArchivedOption;
use tiny_http::{Header, Request, Response};
fn get<'u>(
request: Request,
db_context: &DatabaseContext,
params: matchit::Params<'u, 'u>,
) -> CrowResult<()> {
let get_id = some_or_response!(
parse_base64_hash!(params.get("id")), or respond to request with Response::empty(400)
);
let read = db_context.read_txn()?;
let access = read.access();
let data = some_or_response!(
access
.get::<[u8], [u8]>(&db_context.binary_store, &get_id)
.to_opt()?,
or respond to request with
Response::empty(404)
);
let header = access
.get::<[u8], ArchivedFileHeader>(&db_context.metadata_store, &get_id)
.to_opt()?
.ok_or(anyhow::anyhow!("header missing for file"))?;
let mut response = Response::new(200.into(), vec![], data, Some(data.len()), None);
if let ArchivedOption::Some(ref file_name) = header.file_name {
response = response.with_header(
Header::from_bytes(
&b"Content-Disposition"[..],
format!("inline; filename=\"{file_name}\"").into_bytes(),
)
.unwrap(),
);
}
if let ArchivedOption::Some(ref mime_type) = header.content_type {
response = response
.with_header(Header::from_bytes(&b"Content-Type"[..], mime_type.as_bytes()).unwrap());
}
request.respond(response)?;
Ok(())
}
fn_to_handler!(get: GetHandler);

200
src/routes/image.rs Normal file
View file

@ -0,0 +1,200 @@
use crate::*;
use blake2::{Blake2s256, Digest};
use image::{
codecs::{jpeg::JpegEncoder, png::PngEncoder},
ColorType, ImageEncoder,
};
use lmdb::LmdbResultExt;
use lmdb_zero as lmdb;
use multipart::server::Multipart;
use std::{
io::{ErrorKind, Read},
ops::Deref,
};
use tiny_http::{Header, Request, Response};
fn image_upload<'u>(
mut request: Request,
db_context: &DatabaseContext,
_: matchit::Params<'u, 'u>,
) -> CrowResult<()> {
let mut entry = some_or_response!(
single_multipart!(&mut request), or respond to request with Response::empty(400)
);
let mut data: Vec<u8> = Vec::with_capacity(20000);
entry.data.read_to_end(&mut data)?;
let upload_format = image::guess_format(&data)?;
let img = image::load_from_memory_with_format(&data, upload_format)?;
let data_hash = Blake2s256::digest(&img.as_bytes());
let txn = db_context.write_txn()?;
let mut accessor = txn.access();
if accessor
.get::<[u8], [u8]>(&db_context.image_store, data_hash.as_slice())
.to_opt()?
.is_some()
{
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
return Ok(());
}
let store_format = match upload_format {
image::ImageFormat::Jpeg => {
accessor.put(
&db_context.image_store,
data_hash.as_slice(),
&data,
lmdb::put::Flags::empty(),
)?;
ImageFormat::JPG
}
_ => {
// TODO: allow lossy compression via option
let encoded = webp::Encoder::from_image(&img).unwrap().encode_lossless();
accessor.put(
&db_context.image_store,
data_hash.as_slice(),
encoded.deref(),
lmdb::put::Flags::empty(),
)?;
ImageFormat::WEBP
}
};
accessor.put(
&db_context.image_meta_store,
data_hash.as_slice(),
rkyv::to_bytes::<_, 256>(&ImageHeader { store_format })
.unwrap()
.as_slice(),
lmdb::put::Flags::empty(),
)?;
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
drop(accessor);
txn.commit()?;
Ok(())
}
fn image_get<'u>(
mut request: Request,
db_context: &DatabaseContext,
params: matchit::Params<'u, 'u>,
) -> CrowResult<()> {
let (get_id, requested_format) = some_or_response!(
parse_base64_hash!(params.get("id")).zip(
params
.get("format")
.and_then(|s| ImageFormat::from_str(s).ok())
), or respond to request with Response::empty(400)
);
let content_type = requested_format.to_mime();
let read = db_context.read_txn()?;
let access = read.access();
let metadata: &ArchivedImageHeader = some_or_response!(
access
.get::<[u8], ArchivedImageHeader>(&db_context.image_meta_store, &get_id)
.to_opt()?,
or respond to request with
Response::empty(404)
);
let data = access.get::<[u8], [u8]>(&db_context.image_store, &get_id)?;
if metadata.store_format == requested_format {
request.respond(Response::new(
200.into(),
vec![],
data,
Some(data.len()),
None,
))?;
return Ok(());
}
let stored_image = image::load_from_memory_with_format(data, metadata.store_format.into())?;
use ColorType::*;
// catch unsupported transcoding (because of unsupported color format)
// and return a 500
match (stored_image.color(), requested_format) {
(Rgb8 | Rgba8, ImageFormat::WEBP) => (),
(Rgb8 | Rgba8 | L8 | La8, ImageFormat::JPG) => (),
(Rgb8 | Rgba8 | L8 | La8 | Rgba16 | Rgb16 | L16 | La16, ImageFormat::PNG) => (),
_ => {
request.respond(
response!(err 500 "unsupported color channels for the requested image format"),
)?;
return Ok(());
}
}
let mut req_writer = request.extract_writer_impl();
let response = Response::new(
200.into(),
vec![Header::from_bytes(&b"Content-Type"[..], content_type.as_bytes()).unwrap()],
std::io::empty(),
None,
None,
);
Request::ignore_client_closing_errors(response.print_and_write(
&mut req_writer,
request.http_version().clone(),
request.headers(),
false,
None,
None,
|w, _| {
match requested_format {
ImageFormat::WEBP => {
// TODO: make compression quality here configurable
let mem = webp::Encoder::from_image(&stored_image)
.unwrap()
.encode(95.0);
w.write_all(mem.deref())
}
ImageFormat::JPG => JpegEncoder::new(w)
.encode_image(&stored_image)
.map_err(|e| std::io::Error::new(ErrorKind::Other, e)),
ImageFormat::PNG => PngEncoder::new(w)
.write_image(
stored_image.as_bytes(),
stored_image.width(),
stored_image.height(),
stored_image.color(),
)
.map_err(|e| std::io::Error::new(ErrorKind::Other, e)),
}
},
))?;
Request::ignore_client_closing_errors(req_writer.flush())?;
if let Some(sender) = request.notify_when_responded.take() {
sender.send(()).unwrap();
}
drop(req_writer);
drop(request);
Ok(())
}
fn_to_handler!(image_upload: ImageUploadHandler);
fn_to_handler!(image_get: ImageGetHandler);

3
src/routes/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod get;
pub mod image;
pub mod upload;

68
src/routes/upload.rs Normal file
View file

@ -0,0 +1,68 @@
use crate::*;
use blake2::{Blake2s256, Digest};
use lmdb::LmdbResultExt;
use lmdb_zero as lmdb;
use multipart::server::Multipart;
use std::io::Read;
use tiny_http::{Request, Response};
fn upload<'u>(
mut request: Request,
db_context: &DatabaseContext,
_: matchit::Params<'u, 'u>,
) -> CrowResult<()> {
let mut entry = some_or_response!(
single_multipart!(&mut request), or respond to request with Response::empty(400)
);
let mut data: Vec<u8> = Vec::with_capacity(20000);
entry.data.read_to_end(&mut data)?;
let data_hash = Blake2s256::digest(&data);
let txn = db_context.write_txn()?;
let mut accessor = txn.access();
if accessor
.get::<[u8], [u8]>(&db_context.binary_store, data_hash.as_slice())
.to_opt()?
.is_some()
{
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
return Ok(());
}
accessor.put(
&db_context.binary_store,
data_hash.as_slice(),
&data,
lmdb::put::Flags::empty(),
)?;
let header = FileHeader {
file_name: entry.headers.filename,
content_type: entry
.headers
.content_type
.map(|v| v.essence_str().to_owned()),
};
accessor.put(
&db_context.metadata_store,
data_hash.as_slice(),
rkyv::to_bytes::<_, 256>(&header).unwrap().as_slice(),
lmdb::put::Flags::empty(),
)?;
request.respond(Response::from_string(base64_url::encode(&data_hash)))?;
drop(accessor);
txn.commit()?;
Ok(())
}
fn_to_handler!(upload: UploadHandler);