diff --git a/Cargo.lock b/Cargo.lock index afa9b4f..35f84da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,22 +145,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "async-compression" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" -dependencies = [ - "bzip2", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "zstd", - "zstd-safe", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -230,6 +214,51 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 0.1.2", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -246,14 +275,10 @@ dependencies = [ ] [[package]] -name = "base58ck" -version = "0.1.0" +name = "base58" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" -dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", -] +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] name = "base64" @@ -331,62 +356,25 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitcoin" -version = "0.32.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" -dependencies = [ - "base58ck", - "bech32", - "bitcoin-internals 0.3.0", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", - "hex_lit", - "secp256k1", - "serde", -] - [[package]] name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" -[[package]] -name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" -dependencies = [ - "serde", -] - [[package]] name = "bitcoin-io" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" -[[package]] -name = "bitcoin-units" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" -dependencies = [ - "bitcoin-internals 0.3.0", - "serde", -] - [[package]] name = "bitcoin_hashes" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ - "bitcoin-internals 0.2.0", + "bitcoin-internals", "hex-conservative 0.1.2", ] @@ -472,27 +460,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "candle-core" version = "0.8.1" @@ -561,8 +528,6 @@ version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -720,20 +685,20 @@ dependencies = [ [[package]] name = "config" -version = "0.14.1" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" +checksum = "e26695492a475c4a091cfda61446d5ba01aac2e1dfbcd27a12fdd11aa2e32596" dependencies = [ "async-trait", "convert_case", "json5", - "nom", "pathdiff", "ron", "rust-ini", "serde", "serde_json", "toml", + "winnow 0.7.0", "yaml-rust2", ] @@ -883,41 +848,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn", -] - [[package]] name = "der" version = "0.7.9" @@ -936,7 +866,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -1129,6 +1058,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fedimint-tonic-lnd" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df03ca33b5116de3051c1e233fe341e23b04c4913c7b16042497924559bc2a2e" +dependencies = [ + "hex", + "http-body 0.4.6", + "hyper 0.14.31", + "hyper-rustls 0.24.2", + "prost", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "tokio", + "tokio-stream", + "tonic", + "tonic-build", + "tower", +] + [[package]] name = "ffmpeg-rs-raw" version = "0.1.0" @@ -1169,14 +1118,10 @@ dependencies = [ ] [[package]] -name = "flate2" -version = "1.0.35" +name = "fixedbitset" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flume" @@ -1558,15 +1503,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "hashlink" version = "0.9.1" @@ -1618,12 +1554,6 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - [[package]] name = "hkdf" version = "0.12.4" @@ -1775,6 +1705,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.31", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.3" @@ -1785,13 +1729,25 @@ dependencies = [ "http 1.2.0", "hyper 1.5.1", "hyper-util", - "rustls", + "rustls 0.23.20", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.1", "tower-service", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.31", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -1968,12 +1924,6 @@ dependencies = [ "syn", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "1.0.3" @@ -2003,7 +1953,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -2019,9 +1968,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ "cfb", ] @@ -2092,15 +2041,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.76" @@ -2222,6 +2162,12 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "md-5" version = "0.10.6" @@ -2305,6 +2251,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "native-tls" version = "0.2.12" @@ -2322,18 +2274,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "negentropy" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe" - -[[package]] -name = "negentropy" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a88da9dd148bbcdce323dd6ac47d369b4769d4a3b78c6c52389b9269f77932" - [[package]] name = "nom" version = "7.1.3" @@ -2346,46 +2286,27 @@ dependencies = [ [[package]] name = "nostr" -version = "0.37.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aad4b767bbed24ac5eb4465bfb83bc1210522eb99d67cf4e547ec2ec7e47786" +checksum = "d90b55eff1f0747d9e423972179672e1aacac3d3ccee4c1281147eaa90d6491e" dependencies = [ - "async-trait", "base64 0.22.1", "bech32", "bip39", - "bitcoin", + "bitcoin_hashes 0.14.0", "cbc", "chacha20", "chacha20poly1305", "getrandom", "instant", - "negentropy 0.3.1", - "negentropy 0.4.3", - "once_cell", "scrypt", + "secp256k1", "serde", "serde_json", "unicode-normalization", "url", ] -[[package]] -name = "nostr-cursor" -version = "0.1.0" -source = "git+https://git.v0l.io/Kieran/nostr_backup_proc.git?branch=main#3d64dccb0ec208e9c77b967c30670b52dbc18183" -dependencies = [ - "anyhow", - "async-compression", - "async-stream", - "hex", - "log", - "serde", - "serde_json", - "tokio", - "tokio-stream", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2751,6 +2672,36 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.7.0", +] + +[[package]] +name = "pin-project" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -2826,6 +2777,16 @@ dependencies = [ "log", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -2857,6 +2818,59 @@ dependencies = [ "yansi", ] +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + [[package]] name = "pulp" version = "0.18.22" @@ -3042,7 +3056,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.5.1", - "hyper-rustls", + "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", "ipnet", @@ -3053,11 +3067,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "system-configuration", "tokio", "tokio-native-tls", @@ -3185,6 +3199,7 @@ name = "route96" version = "0.4.0" dependencies = [ "anyhow", + "base58", "base64 0.22.1", "candle-core", "candle-nn", @@ -3192,6 +3207,7 @@ dependencies = [ "chrono", "clap", "config", + "fedimint-tonic-lnd", "ffmpeg-rs-raw", "hex", "http-range-header", @@ -3200,16 +3216,12 @@ dependencies = [ "log", "mime2ext", "nostr", - "nostr-cursor", "pretty_env_logger", - "regex", "reqwest", "rocket", "serde", - "serde_with", "sha2", "sqlx", - "sqlx-postgres", "tokio", "tokio-util", "uuid", @@ -3237,12 +3249,13 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" dependencies = [ "cfg-if", "ordered-multimap", + "trim-in-place", ] [[package]] @@ -3270,6 +3283,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.20" @@ -3278,11 +3303,20 @@ checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -3298,6 +3332,16 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -3382,13 +3426,22 @@ dependencies = [ "sha2", ] +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "secp256k1" version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.0", "rand", "secp256k1-sys", "serde", @@ -3458,7 +3511,6 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -3495,36 +3547,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.7.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sha1" version = "0.10.6" @@ -3677,7 +3699,7 @@ dependencies = [ "futures-io", "futures-util", "hashbrown 0.14.5", - "hashlink 0.9.1", + "hashlink", "hex", "indexmap 2.7.0", "log", @@ -3904,6 +3926,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -4113,6 +4141,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.4.0" @@ -4134,13 +4172,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls", + "rustls 0.23.20", "tokio", ] @@ -4199,9 +4247,78 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.20", ] +[[package]] +name = "tonic" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.21.7", + "bytes", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "tokio", + "tokio-rustls 0.24.1", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -4270,6 +4387,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "try-lock" version = "0.2.5" @@ -4806,6 +4929,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" @@ -4820,13 +4952,13 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yaml-rust2" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" +checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" dependencies = [ "arraydeque", "encoding_rs", - "hashlink 0.8.4", + "hashlink", ] [[package]] @@ -4946,31 +5078,3 @@ dependencies = [ "num_enum", "thiserror 1.0.69", ] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index 7e34570..6e456aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,6 @@ name = "route96" version = "0.4.0" edition = "2021" -[[bin]] -name = "void_cat_migrate" -required-features = ["bin-void-cat-migrate"] - -[[bin]] -name = "void_cat_forced_migrate" -required-features = ["bin-void-cat-force-migrate"] - [[bin]] name = "route96" path = "src/bin/main.rs" @@ -19,22 +11,18 @@ path = "src/bin/main.rs" name = "route96" [features] -default = ["nip96", "blossom", "analytics", "ranges", "react-ui"] +default = ["nip96", "blossom", "analytics", "react-ui", "payments"] media-compression = ["dep:ffmpeg-rs-raw", "dep:libc"] -labels = ["nip96", "dep:candle-core", "dep:candle-nn", "dep:candle-transformers"] +labels = ["media-compression", "dep:candle-core", "dep:candle-nn", "dep:candle-transformers"] nip96 = ["media-compression"] blossom = [] -bin-void-cat-migrate = ["dep:sqlx-postgres"] -bin-void-cat-force-migrate = ["dep:regex", "dep:nostr-cursor"] -torrent-v2 = [] analytics = [] -void-cat-redirects = ["dep:sqlx-postgres"] -ranges = ["dep:http-range-header"] react-ui = [] +payments = ["dep:fedimint-tonic-lnd"] [dependencies] log = "0.4.21" -nostr = "0.37.0" +nostr = "0.39.0" pretty_env_logger = "0.5.0" rocket = { version = "0.5.1", features = ["json"] } tokio = { version = "1.37.0", features = ["rt", "rt-multi-thread", "macros"] } @@ -45,21 +33,19 @@ uuid = { version = "1.8.0", features = ["v4", "serde"] } anyhow = "^1.0.82" sha2 = "0.10.8" sqlx = { version = "0.8.1", features = ["mysql", "runtime-tokio", "chrono", "uuid"] } -config = { version = "0.14.0", features = ["yaml"] } +config = { version = "0.15.7", features = ["yaml"] } chrono = { version = "0.4.38", features = ["serde"] } -serde_with = { version = "3.8.1", features = ["hex"] } reqwest = { version = "0.12.8", features = ["stream"] } clap = { version = "4.5.18", features = ["derive"] } mime2ext = "0.1.53" -infer = "0.16.0" +infer = "0.19.0" tokio-util = { version = "0.7.13", features = ["io", "io-util"] } +http-range-header = { version = "0.4.2" } +base58 = "0.2.0" libc = { version = "0.2.153", optional = true } ffmpeg-rs-raw = { git = "https://git.v0l.io/Kieran/ffmpeg-rs-raw.git", rev = "a63b88ef3c8f58c7c0ac57d361d06ff0bb3ed385", optional = true } candle-core = { git = "https://git.v0l.io/huggingface/candle.git", tag = "0.8.1", optional = true } candle-nn = { git = "https://git.v0l.io/huggingface/candle.git", tag = "0.8.1", optional = true } candle-transformers = { git = "https://git.v0l.io/huggingface/candle.git", tag = "0.8.1", optional = true } -sqlx-postgres = { version = "0.8.2", optional = true, features = ["chrono", "uuid"] } -http-range-header = { version = "0.4.2", optional = true } -nostr-cursor = { git = "https://git.v0l.io/Kieran/nostr_backup_proc.git", branch = "main", optional = true } -regex = { version = "1.11.1", optional = true } \ No newline at end of file +fedimint-tonic-lnd = { version = "0.2.0", optional = true, features = ["invoicesrpc"] } \ No newline at end of file diff --git a/README.md b/README.md index 9b1841a..b532c43 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Image hosting service - [BUD-05](https://github.com/hzrd149/blossom/blob/master/buds/05.md) - [BUD-06](https://github.com/hzrd149/blossom/blob/master/buds/06.md) - [BUD-08](https://github.com/hzrd149/blossom/blob/master/buds/08.md) + - [BUD-10](https://github.com/hzrd149/blossom/pull/57) - Image compression to WebP - Blurhash calculation - AI image labeling ([ViT224](https://huggingface.co/google/vit-base-patch16-224)) @@ -45,4 +46,10 @@ docker run --rm -it \ ``` ### Manual -See [install.md](docs/debian.md) \ No newline at end of file +See [install.md](docs/debian.md) + +## Blossom only mode (No FFMPEG) +If you don't want to support NIP-96 or any media compression you can build like so: +```bash +cargo build --release --no-default-features --features blossom +``` \ No newline at end of file diff --git a/config.prod.yaml b/config.prod.yaml index c490aba..3870ebf 100644 --- a/config.prod.yaml +++ b/config.prod.yaml @@ -1,17 +1,5 @@ -# Listen address for webserver listen: "0.0.0.0:8000" - -# Database connection string (MYSQL) database: "mysql://root:root@db:3306/route96" - -# Directory to store uploads storage_dir: "/app/data" - -# Maximum support filesize for uploading max_upload_bytes: 104857600 - -# Public facing url public_url: "http://localhost:8000" - -# Whitelisted pubkeys, leave out to disable -# whitelist: ["63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed"] \ No newline at end of file diff --git a/config.yaml b/config.yaml index d6e47f7..539e425 100644 --- a/config.yaml +++ b/config.yaml @@ -13,19 +13,37 @@ max_upload_bytes: 5e+9 # Public facing url public_url: "http://localhost:8000" -# Whitelisted pubkeys, leave out to disable +# (Optional) Whitelisted pubkeys, leave out to disable # whitelist: ["63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed"] -# Path for ViT(224) image model (https://huggingface.co/google/vit-base-patch16-224) -vit_model: - model: "/home/kieran/Downloads/falcon_nsfw.safetensors" - config: "/home/kieran/Downloads/falcon_nsfw.json" +# (Optional) Path for ViT(224) image model (https://huggingface.co/google/vit-base-patch16-224) +# vit_model: +# model: "falcon_nsfw.safetensors" +# config: "falcon_nsfw.json" -# Analytics support +# (Optional) Analytics support # plausible_url: "https://plausible.com/" -# Support legacy void -# void_cat_database: "postgres://postgres:postgres@localhost:41911/void" +# (Optional) Legacy file path for void.cat uploads +# void_cat_files: "/my/void.cat/data" -# Legacy file path for void.cat uploads -# void_cat_files: "/my/void.cat/data" \ No newline at end of file +# (Optional) Payment system config +payments: + # (Optional) Fiat currency used to track exchange rate along with invoices + # If [cost] is using a fiat currency, exchange rates will always be stored + # in that currency, so this config is not needed + fiat: "USD" + # LND node config + lnd: + endpoint: "https://mylnd:10002" + tls: "tls.crt" + macaroon: "admin.macaroon" + # Cost per unit (BTC/USD/EUR/AUD/CAD/JPY/GBP) + cost: + currency: "BTC" + amount: 0.00000100 + # Unit metric used to calculate quote (GBSpace, GBEgress) + unit: "GBSpace" + # Billing interval (day / month / year) + interval: + month: 1 \ No newline at end of file diff --git a/migrations/20250202135844_payments.sql b/migrations/20250202135844_payments.sql new file mode 100644 index 0000000..f31c40e --- /dev/null +++ b/migrations/20250202135844_payments.sql @@ -0,0 +1,22 @@ +-- Add migration script here +alter table users + add column paid_until timestamp, + add column paid_space integer unsigned not null; + +create table payments +( + payment_hash binary(32) not null primary key, + user_id integer unsigned not null, + created timestamp default current_timestamp, + amount integer unsigned not null, + is_paid bit(1) not null, + days_value integer unsigned not null, + size_value integer unsigned not null, + index integer unsigned not null, + rate double not null, + + constraint fk_payments_user + foreign key (user_id) references users (id) + on delete cascade + on update restrict +); \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs index 10446c6..3017743 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -73,7 +73,13 @@ async fn main() -> Result<(), Error> { .attach(Shield::new()) // disable .mount( "/", - routes![root, get_blob, head_blob, routes::void_cat_redirect, routes::void_cat_redirect_head], + routes![ + root, + get_blob, + head_blob, + routes::void_cat_redirect, + routes::void_cat_redirect_head + ], ) .mount("/admin", routes::admin_routes()); @@ -95,6 +101,10 @@ async fn main() -> Result<(), Error> { { rocket = rocket.mount("/", routes![routes::get_blob_thumb]); } + #[cfg(feature = "payments")] + { + rocket = rocket.mount("/", routes::payment::routes()); + } let jh = start_background_tasks(db, fs); diff --git a/src/bin/void_cat_forced_migrate.rs b/src/bin/void_cat_forced_migrate.rs deleted file mode 100644 index 4d2ec2e..0000000 --- a/src/bin/void_cat_forced_migrate.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clap::Parser; -use log::{info, warn}; -use nostr::serde_json; -use nostr_cursor::cursor::NostrCursor; -use regex::Regex; -use rocket::futures::StreamExt; -use std::collections::{HashMap, HashSet}; -use std::path::PathBuf; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; -use uuid::Uuid; - -#[derive(Parser, Debug)] -#[command(version, about)] -struct ProgramArgs { - /// Directory pointing to archives to scan - #[arg(short, long)] - pub archive: PathBuf, - - /// Output path .csv - #[arg(short, long)] - pub output: PathBuf, -} - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - pretty_env_logger::init(); - - let args: ProgramArgs = ProgramArgs::parse(); - - let mut report: HashMap> = HashMap::new(); - - let mut binding = NostrCursor::new(args.archive); - let mut cursor = Box::pin(binding.walk()); - let matcher = Regex::new(r"void\.cat/d/(\w+)")?; - while let Some(Ok(e)) = cursor.next().await { - if e.content.contains("void.cat") { - let links = matcher.captures_iter(&e.content).collect::>(); - for link in links { - let g = link.get(1).unwrap().as_str(); - let base58 = if let Ok(b) = nostr::bitcoin::base58::decode(g) { - b - } else { - warn!("Invalid base58 id {}", g); - continue; - }; - let _uuid = if let Ok(u) = Uuid::from_slice_le(base58.as_slice()) { - u - } else { - warn!("Invalid uuid {}", g); - continue; - }; - info!("Got link: {} => {}", g, e.pubkey); - if let Some(ur) = report.get_mut(&e.pubkey) { - ur.insert(g.to_string()); - } else { - report.insert(e.pubkey.clone(), HashSet::from([g.to_string()])); - } - } - } - } - - let json = serde_json::to_string(&report)?; - File::create(args.output) - .await? - .write_all(json.as_bytes()) - .await?; - - Ok(()) -} diff --git a/src/bin/void_cat_migrate.rs b/src/bin/void_cat_migrate.rs deleted file mode 100644 index 2c08fa1..0000000 --- a/src/bin/void_cat_migrate.rs +++ /dev/null @@ -1,147 +0,0 @@ -use anyhow::Error; -use clap::Parser; -use config::Config; -use log::{info, warn}; -use nostr::bitcoin::base58; -use route96::db::{Database, FileUpload}; -use route96::filesystem::FileStore; -use route96::settings::Settings; -use route96::void_db::VoidCatDb; -use route96::void_file::VoidFile; -use std::path::PathBuf; -use tokio::io::{AsyncWriteExt, BufWriter}; - -#[derive(Debug, Clone, clap::ValueEnum)] -enum ArgOperation { - Migrate, - ExportNginxRedirects, -} - -#[derive(Parser, Debug)] -#[command(version, about)] -struct Args { - /// Database connection string for void.cat DB - #[arg(long)] - pub database: String, - - /// Path to filestore on void.cat - #[arg(long)] - pub data_path: String, - - #[arg(long)] - pub operation: ArgOperation, -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - pretty_env_logger::init(); - - let builder = Config::builder() - .add_source(config::File::with_name("config.yaml")) - .add_source(config::Environment::with_prefix("APP")) - .build()?; - - let settings: Settings = builder.try_deserialize()?; - - let db = Database::new(&settings.database).await?; - let fs = FileStore::new(settings.clone()); - - let args: Args = Args::parse(); - - let db_void = VoidCatDb::connect(&args.database).await?; - - match args.operation { - ArgOperation::Migrate => { - let mut page = 0; - loop { - let files = db_void.list_files(page).await?; - if files.is_empty() { - break; - } - for f in files { - if let Err(e) = migrate_file(&f, &db, &fs, &args).await { - warn!("Failed to migrate file: {}, {}", &f.id, e); - } - } - page += 1; - } - } - ArgOperation::ExportNginxRedirects => { - let path: PathBuf = args.data_path.parse()?; - let conf_path = &path.join("nginx.conf"); - info!("Writing redirects to {}", conf_path.to_str().unwrap()); - let mut fout = BufWriter::new(tokio::fs::File::create(conf_path).await?); - let mut page = 0; - loop { - let files = db_void.list_files(page).await?; - if files.is_empty() { - break; - } - for f in files { - let legacy_id = base58::encode(f.id.to_bytes_le().as_slice()); - let redirect = format!("location ^\\/d\\/{}(?:\\.\\w+)?$ {{\n\treturn 301 https://nostr.download/{};\n}}\n", &legacy_id, &f.digest); - fout.write_all(redirect.as_bytes()).await?; - } - page += 1; - } - } - } - - Ok(()) -} - -async fn migrate_file( - f: &VoidFile, - db: &Database, - fs: &FileStore, - args: &Args, -) -> Result<(), Error> { - let pubkey_vec = hex::decode(&f.email)?; - let id_vec = hex::decode(&f.digest)?; - - // copy file - let src_path = PathBuf::new() - .join(&args.data_path) - .join(VoidFile::map_to_path(&f.id)); - let dst_path = fs.map_path(&id_vec); - if src_path.exists() && !dst_path.exists() { - info!( - "Copying file: {} from {} => {}", - &f.id, - src_path.to_str().unwrap(), - dst_path.to_str().unwrap() - ); - - tokio::fs::create_dir_all(dst_path.parent().unwrap()).await?; - tokio::fs::copy(src_path, dst_path).await?; - } else if dst_path.exists() { - info!("File already exists {}, continuing...", &f.id); - } else { - anyhow::bail!("Source file not found {}", src_path.to_str().unwrap()); - } - let uid = db.upsert_user(&pubkey_vec).await?; - info!("Mapped user {} => {}", &f.email, uid); - - let md: Option> = f.media_dimensions.as_ref().map(|s| s.split("x").collect()); - let fu = FileUpload { - id: id_vec, - name: f.name.clone(), - size: f.size as u64, - mime_type: f.mime_type.clone(), - created: f.uploaded, - width: match &md { - Some(s) => Some(s[0].parse::()?), - None => None, - }, - height: match &md { - Some(s) => Some(s[1].parse::()?), - None => None, - }, - blur_hash: None, - alt: f.description.clone(), - duration: None, - bitrate: None, - }; - db.add_file(&fu, uid).await?; - Ok(()) -} diff --git a/src/db.rs b/src/db.rs index b678057..a9bd06b 100644 --- a/src/db.rs +++ b/src/db.rs @@ -61,6 +61,10 @@ pub struct User { pub pubkey: Vec, pub created: DateTime, pub is_admin: bool, + #[cfg(feature = "payments")] + pub paid_until: Option>, + #[cfg(feature = "payments")] + pub paid_space: u64, } #[cfg(feature = "labels")] diff --git a/src/filesystem.rs b/src/filesystem.rs index 6dbcbc5..fe51b34 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,6 +1,5 @@ #[cfg(feature = "labels")] use crate::db::FileLabel; -use crate::processing::can_compress; #[cfg(feature = "labels")] use crate::processing::labeling::label_frame; #[cfg(feature = "media-compression")] @@ -18,6 +17,7 @@ use std::path::PathBuf; use tokio::fs::File; use tokio::io::{AsyncRead, AsyncReadExt}; use uuid::Uuid; +use crate::can_compress; #[derive(Clone)] pub enum FileSystemResult { @@ -180,6 +180,7 @@ impl FileStore { } } + #[cfg(feature = "media-compression")] async fn compress_file(&self, input: &PathBuf, mime_type: &str) -> Result { let compressed_result = compress_file(input, mime_type, &self.temp_dir())?; #[cfg(feature = "labels")] diff --git a/src/lib.rs b/src/lib.rs index 0423c35..77bc648 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,9 @@ pub mod filesystem; pub mod processing; pub mod routes; pub mod settings; -#[cfg(any(feature = "void-cat-redirects", feature = "bin-void-cat-migrate"))] -pub mod void_db; pub mod void_file; + + +pub fn can_compress(mime_type: &str) -> bool { + mime_type.starts_with("image/") +} diff --git a/src/processing/mod.rs b/src/processing/mod.rs index e9f320b..c21e15a 100644 --- a/src/processing/mod.rs +++ b/src/processing/mod.rs @@ -5,6 +5,7 @@ use ffmpeg_rs_raw::{Decoder, Demuxer, DemuxerInfo, Encoder, Scaler, StreamType, use std::path::{Path, PathBuf}; use std::ptr; use uuid::Uuid; +use crate::can_compress; #[cfg(feature = "labels")] pub mod labeling; @@ -136,10 +137,6 @@ pub struct NewFileProcessorResult { pub bitrate: u32, } -pub fn can_compress(mime_type: &str) -> bool { - mime_type.starts_with("image/") -} - pub fn compress_file( path: &Path, mime_type: &str, diff --git a/src/routes/admin.rs b/src/routes/admin.rs index 071a7f4..8672ee8 100644 --- a/src/routes/admin.rs +++ b/src/routes/admin.rs @@ -53,6 +53,10 @@ pub struct SelfUser { pub is_admin: bool, pub file_count: u64, pub total_size: u64, + #[cfg(feature = "payments")] + pub paid_until: u64, + #[cfg(feature = "payments")] + pub quota: u64, } #[derive(Serialize)] @@ -77,6 +81,12 @@ async fn admin_get_self(auth: Nip98Auth, db: &State) -> AdminResponse< is_admin: user.is_admin, file_count: s.file_count, total_size: s.total_size, + paid_until: if let Some(u) = &user.paid_until { + u.timestamp() as u64 + } else { + 0 + }, + quota: user.paid_space, }) } Err(_) => AdminResponse::error("User not found"), diff --git a/src/routes/mod.rs b/src/routes/mod.rs index d64d75d..64a701b 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -10,6 +10,7 @@ pub use crate::routes::nip96::nip96_routes; use crate::settings::Settings; use crate::void_file::VoidFile; use anyhow::Error; +use base58::FromBase58; use http_range_header::{parse_range_header, EndPosition, StartPosition}; use log::{debug, warn}; use nostr::Event; @@ -33,6 +34,8 @@ mod blossom; mod nip96; mod admin; +#[cfg(feature = "payments")] +pub mod payment; pub struct FilePayload { pub file: File, @@ -183,58 +186,44 @@ impl<'r> Responder<'r, 'static> for FilePayload { response.set_header(Header::new("cache-control", "max-age=31536000, immutable")); // handle ranges - #[cfg(feature = "ranges")] - { - const MAX_UNBOUNDED_RANGE: u64 = 1024 * 1024; - // only use range response for files > 1MiB - if self.info.size < MAX_UNBOUNDED_RANGE { - response.set_sized_body(None, self.file); - } else { - response.set_header(Header::new("accept-ranges", "bytes")); - if let Some(r) = request.headers().get("range").next() { - if let Ok(ranges) = parse_range_header(r) { - if ranges.ranges.len() > 1 { - warn!( - "Multipart ranges are not supported, fallback to non-range request" - ); - response.set_streamed_body(self.file); - } else { - let single_range = ranges.ranges.first().unwrap(); - let range_start = match single_range.start { - StartPosition::Index(i) => i, - StartPosition::FromLast(i) => self.info.size - i, - }; - let range_end = match single_range.end { - EndPosition::Index(i) => i, - EndPosition::LastByte => { - (range_start + MAX_UNBOUNDED_RANGE).min(self.info.size) - } - }; - let r_len = range_end - range_start; - let r_body = RangeBody::new(self.file, range_start..range_end); - - response.set_status(Status::PartialContent); - response.set_header(Header::new("content-length", r_len.to_string())); - response.set_header(Header::new( - "content-range", - format!( - "bytes {}-{}/{}", - range_start, - range_end - 1, - self.info.size - ), - )); - response.set_streamed_body(Box::pin(r_body)); - } - } - } else { - response.set_sized_body(None, self.file); - } - } - } - #[cfg(not(feature = "ranges"))] - { + const MAX_UNBOUNDED_RANGE: u64 = 1024 * 1024; + // only use range response for files > 1MiB + if self.info.size < MAX_UNBOUNDED_RANGE { response.set_sized_body(None, self.file); + } else { + response.set_header(Header::new("accept-ranges", "bytes")); + if let Some(r) = request.headers().get("range").next() { + if let Ok(ranges) = parse_range_header(r) { + if ranges.ranges.len() > 1 { + warn!("Multipart ranges are not supported, fallback to non-range request"); + response.set_streamed_body(self.file); + } else { + let single_range = ranges.ranges.first().unwrap(); + let range_start = match single_range.start { + StartPosition::Index(i) => i, + StartPosition::FromLast(i) => self.info.size - i, + }; + let range_end = match single_range.end { + EndPosition::Index(i) => i, + EndPosition::LastByte => { + (range_start + MAX_UNBOUNDED_RANGE).min(self.info.size) + } + }; + let r_len = range_end - range_start; + let r_body = RangeBody::new(self.file, range_start..range_end); + + response.set_status(Status::PartialContent); + response.set_header(Header::new("content-length", r_len.to_string())); + response.set_header(Header::new( + "content-range", + format!("bytes {}-{}/{}", range_start, range_end - 1, self.info.size), + )); + response.set_streamed_body(Box::pin(r_body)); + } + } + } else { + response.set_sized_body(None, self.file); + } } if let Ok(ct) = ContentType::from_str(&self.info.mime_type) { @@ -437,9 +426,7 @@ pub async fn void_cat_redirect(id: &str, settings: &State) -> Option {}", id, f.display()); if let Ok(f) = NamedFile::open(f).await { @@ -459,8 +446,7 @@ pub async fn void_cat_redirect_head(id: &str) -> VoidCatFile { } else { id }; - let uuid = - uuid::Uuid::from_slice_le(nostr::bitcoin::base58::decode(id).unwrap().as_slice()).unwrap(); + let uuid = uuid::Uuid::from_slice_le(id.from_base58().unwrap().as_slice()).unwrap(); VoidCatFile { status: Status::Ok, uuid: Header::new("X-UUID", uuid.to_string()), diff --git a/src/routes/payment.rs b/src/routes/payment.rs new file mode 100644 index 0000000..a84175f --- /dev/null +++ b/src/routes/payment.rs @@ -0,0 +1,55 @@ +use crate::auth::nip98::Nip98Auth; +use crate::db::Database; +use crate::settings::{PaymentAmount, PaymentInterval, PaymentUnit, Settings}; +use rocket::serde::json::Json; +use rocket::{routes, Route, State}; +use serde::{Deserialize, Serialize}; + +pub fn routes() -> Vec { + routes![get_payment] +} + +#[derive(Deserialize, Serialize)] +struct PaymentInfo { + /// Billing quota metric + pub unit: PaymentUnit, + + /// Amount of time to bill units (GB/mo, Gb Egress/day etc.) + pub interval: PaymentInterval, + + /// Value amount of payment + pub cost: PaymentAmount, +} + +#[derive(Deserialize, Serialize)] +struct PaymentRequest { + /// Number of units requested to make payment + pub units: f32, + + /// Quantity of orders to make + pub quantity: u16, +} + +#[derive(Deserialize, Serialize)] +struct PaymentResponse {} + +#[rocket::get("/payment")] +async fn get_payment(settings: &State) -> Option> { + settings.payments.as_ref().map(|p| { + Json::from(PaymentInfo { + unit: p.unit.clone(), + interval: p.interval.clone(), + cost: p.cost.clone(), + }) + }) +} + +#[rocket::post("/payment", data = "", format = "json")] +async fn req_payment( + auth: Nip98Auth, + db: &State, + settings: &State, + req: Json, +) -> Json { + Json::from(PaymentResponse {}) +} diff --git a/src/settings.rs b/src/settings.rs index bb6abce..94cf19c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -30,11 +30,12 @@ pub struct Settings { /// Analytics tracking pub plausible_url: Option, - #[cfg(feature = "void-cat-redirects")] - pub void_cat_database: Option, - /// Path to void.cat uploads (files-v2) pub void_cat_files: Option, + + #[cfg(feature = "payments")] + /// Payment options for paid storage + pub payments: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -42,3 +43,65 @@ pub struct VitModelConfig { pub model: PathBuf, pub config: PathBuf, } + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PaymentConfig { + /// LND connection details + pub lnd: LndConfig, + + /// Pricing per unit + pub cost: PaymentAmount, + + /// What metric to bill payments on + pub unit: PaymentUnit, + + /// Billing interval time per unit + pub interval: PaymentInterval, + + /// Fiat base currency to store exchange rates along with invoice + pub fiat: Option, +} + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PaymentAmount { + pub currency: Currency, + pub amount: f32, +} + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Currency { + BTC, + USD, + EUR, + GBP, + JPY, + CAD, + AUD, +} + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PaymentUnit { + GBSpace, + GBEgress, +} + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum PaymentInterval { + Day(u16), + Month(u16), + Year(u16), +} + +#[cfg(feature = "payments")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LndConfig { + pub endpoint: String, + pub tls: PathBuf, + pub macaroon: PathBuf, +}