From a8bc61f40ce9061cd63a43a2fe07c9a4bb899a64 Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 11:47:02 +0200 Subject: [PATCH 01/19] feat: boxygit add . --- .gitignore | 2 + Cargo.lock | 1413 +++++++++++++++ Cargo.toml | 24 + config.yaml | 20 + examples/example-server/Cargo.lock | 2615 +++++++++++++++++++++++++++ examples/example-server/Cargo.toml | 9 + examples/example-server/src/main.rs | 41 + src/config.rs | 81 + src/db.rs | 131 ++ src/main.rs | 90 + src/services.rs | 3 + src/services/api.rs | 92 + src/services/controller.rs | 60 + src/services/proxy.rs | 50 + src/types.rs | 69 + 15 files changed, 4700 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 config.yaml create mode 100644 examples/example-server/Cargo.lock create mode 100644 examples/example-server/Cargo.toml create mode 100644 examples/example-server/src/main.rs create mode 100644 src/config.rs create mode 100644 src/db.rs create mode 100644 src/main.rs create mode 100644 src/services.rs create mode 100644 src/services/api.rs create mode 100644 src/services/controller.rs create mode 100644 src/services/proxy.rs create mode 100644 src/types.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f6a3dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +examples/*/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4e73c9b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1413 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bcrypt" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92758ad6077e4c76a6cadbce5005f666df70d4f13b19976b1a8062eef880040f" +dependencies = [ + "base64", + "blowfish", + "getrandom 0.3.3", + "subtle", + "zeroize", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "boxy" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64", + "bcrypt", + "http-body-util", + "hyper", + "hyper-util", + "json", + "log", + "nanoid", + "pretty_env_logger", + "ring", + "serde", + "serde_yaml_bw", + "string-builder", + "thiserror", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "postgres-protocol" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.1", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml_bw" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11309a97d567d5ad04b61ec22e33a15f77c689273acca34efd72aa4181207480" +dependencies = [ + "base64", + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "string-builder" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd10a070fb1f2796a288abec42695db4682a82b6f12ffacd60fb8d5ad3a4a12" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.9.1", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0c511d3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "boxy" +version = "0.1.0" +edition = "2024" + +[dependencies] +hyper = { version = "1.6.0", features = ["full"]} +tokio = { version = "1.45.1", features = ["full"]} +http-body-util = "0.1.3" +hyper-util = { version = "0.1.14", features = ["full"]} +log = "0.4.27" +pretty_env_logger = "0.5.0" +anyhow = "1.0.98" +thiserror = "2.0.12" +tokio-postgres = "0.7.13" +bcrypt = "0.17.0" +ring = "0.17.14" +nanoid = "0.4.0" +serde_yaml_bw = "2.1.1" +serde = "1.0.219" +base64 = "0.22.1" +string-builder = "0.2.0" +json = "0.12.4" + diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..b3d0032 --- /dev/null +++ b/config.yaml @@ -0,0 +1,20 @@ +db: + host: '127.0.0.1' + user: 'postgres' + password: 'trust' + +proxy: + listen: 127.0.0.1 + port: 8005 + +api: + listen: 127.0.0.1 + port: 8006 + +hosts: # ignore this it doesn't function + - hostname: localhost:8005 + address: localhost:8000 + +clients: + - name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend) + secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 diff --git a/examples/example-server/Cargo.lock b/examples/example-server/Cargo.lock new file mode 100644 index 0000000..dd62fef --- /dev/null +++ b/examples/example-server/Cargo.lock @@ -0,0 +1,2615 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "devise" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" +dependencies = [ + "devise_core", + "quote", +] + +[[package]] +name = "devise_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" +dependencies = [ + "bitflags", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "example-server" +version = "0.1.0" +dependencies = [ + "reqwest", + "rocket", + "serde_json", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic 0.6.1", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.6.0", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.3.1", + "httparse", + "memchr", + "mime", + "spin", + "tokio", + "tokio-util", + "version_check", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pear" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "redox_syscall" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rocket" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" +dependencies = [ + "async-stream", + "async-trait", + "atomic 0.5.3", + "binascii", + "bytes", + "either", + "figment", + "futures", + "indexmap", + "log", + "memchr", + "multer", + "num_cpus", + "parking_lot", + "pin-project-lite", + "rand", + "ref-cast", + "rocket_codegen", + "rocket_http", + "serde", + "state", + "tempfile", + "time", + "tokio", + "tokio-stream", + "tokio-util", + "ubyte", + "version_check", + "yansi", +] + +[[package]] +name = "rocket_codegen" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" +dependencies = [ + "devise", + "glob", + "indexmap", + "proc-macro2", + "quote", + "rocket_http", + "syn", + "unicode-xid", + "version_check", +] + +[[package]] +name = "rocket_http" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" +dependencies = [ + "cookie", + "either", + "futures", + "http 0.2.12", + "hyper 0.14.32", + "indexmap", + "log", + "memchr", + "pear", + "percent-encoding", + "pin-project-lite", + "ref-cast", + "serde", + "smallvec", + "stable-pattern", + "state", + "time", + "tokio", + "uncased", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "rustls" +version = "0.23.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069a8df149a16b1a12dcc31497c3396a173844be3cac4bd40c9e7671fef96671" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable-pattern" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" +dependencies = [ + "memchr", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ubyte" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" +dependencies = [ + "serde", +] + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "serde", + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/examples/example-server/Cargo.toml b/examples/example-server/Cargo.toml new file mode 100644 index 0000000..dbb70d6 --- /dev/null +++ b/examples/example-server/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "example-server" +version = "0.1.0" +edition = "2024" + +[dependencies] +reqwest = { version = "0.12.22", features = ["json", "blocking"] } +rocket = "0.5.1" +serde_json = "1.0.141" diff --git a/examples/example-server/src/main.rs b/examples/example-server/src/main.rs new file mode 100644 index 0000000..b19cced --- /dev/null +++ b/examples/example-server/src/main.rs @@ -0,0 +1,41 @@ +use std::{collections::HashMap, fmt::format}; + +use rocket::{build, get, launch, routes}; +use serde_json::json; + +extern crate rocket; + +const BOXY_ADDRESS: &str = "localhost"; +const BOXY_PORT: u16 = 8006; + +const CLIENT_NAME: &str = "eu-central-1"; +const CLIENT_SECRET: &str = "password123"; + +#[get("/")] +fn index() -> &'static str { + "Hello world!" +} + +#[launch] +fn rocket() -> _ { + // This is the example backend client. (The stereo.cat backend for example). + let client = reqwest::blocking::Client::new(); + + // We define the port of the server running locally and the hostname we want to route to it. + let body = json!({ + "port": 8000, + "hostname": "localhost:8005", + }); + + // Send it to Boxy's API + let res = client + .post(format!("http://{}:{}/register", BOXY_ADDRESS, BOXY_PORT)) + .basic_auth(CLIENT_NAME, Some(CLIENT_SECRET)) + .json(&body) + .send() + .unwrap(); + + println!("{}", res.text().unwrap()); + + build().mount("/", routes![index]) +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..1e055a0 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,81 @@ +use std::error::Error; + +use serde::{Deserialize, Serialize}; +use tokio::{fs::File, io::AsyncReadExt}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Proxy { + pub listen: String, + pub port: u16, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Db { + pub host: String, + pub user: String, + pub port: Option, + pub password: Option, + pub database: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Api { + pub listen: String, + pub port: u16, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Client { + pub name: String, + pub secret: String, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Host { + pub hostname: String, + pub address: String, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct Config { + pub db: Db, + pub proxy: Proxy, + pub api: Api, + pub clients: Vec, + pub hosts: Vec, +} + +impl Db { + pub async fn to_string(&self) -> String { + let mut builder = String::new(); + + builder += format!( + "host={} port={} user={} dbname={}", + self.host, + self.port.unwrap_or(5432), + self.user, + self.database.clone().unwrap_or(self.user.clone()), + ) + .as_str(); + + match &self.password { + Some(x) => builder += format!(" password={}", x).as_str(), + None => {} + } + + builder + } +} + +impl Config { + pub async fn get() -> Result> { + let mut file = File::open("./config.yaml").await?; + let mut contents = String::new(); + + file.read_to_string(&mut contents).await?; + + let config: Self = serde_yaml_bw::from_str::(&contents)?; + + Ok(config) + } +} diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..b880979 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,131 @@ +use std::{error::Error, net::{IpAddr, SocketAddr}}; + +use tokio_postgres::{Client, Socket, tls::MakeTlsConnect}; + +const ENDPOINT_TABLE: &str = "endpoints"; +const HOSTS_RELATION_TABLE: &str = "hosts"; + +#[derive(Debug)] +pub struct BoxyDatabase { + pub client: Client, +} + +pub struct Endpoint { + pub id: Option, + pub address: IpAddr, + pub port: u16, + pub callback: String, +} + +impl Endpoint { + pub async fn new(id: Option, address: IpAddr, port: u16, callback: String) -> Self { + Self { + id, + address, + port, + callback, + } + } + pub async fn get_by_hostname( + db: &BoxyDatabase, + hostname: String, + ) -> Result, Box> { + let mut result: Vec = Vec::new(); + + let rows = db + .client + .query( + format!( + "SELECT {ENDPOINT_TABLE}.* FROM {HOSTS_RELATION_TABLE} + JOIN {ENDPOINT_TABLE} ON {HOSTS_RELATION_TABLE}.endpoint_id = {ENDPOINT_TABLE}.id + WHERE {HOSTS_RELATION_TABLE}.hostname = $1" + ).as_str(), + &[&hostname], + ) + .await?; + + for row in rows { + result.push(Self { + id: row.get("id"), + address: row.get("address"), + port: row.get::<&str, i32>("port") as u16, + callback: row.get("callback"), + }); + } + + Ok(result) + } +} + +impl Endpoint { + pub async fn register( + &mut self, + db: &mut BoxyDatabase, + hostname: String, + ) -> Result<(), Box> { + let tx = db.client.transaction().await?; + + let endpoint_id: i32 = tx + .query_one( + format!( + "INSERT INTO {ENDPOINT_TABLE} (address,port,callback) VALUES ($1, $2, $3) RETURNING id").as_str(), + &[ + &self.address, + &(self.port as i32), + &self.callback, + ], + ) + .await? + .get("id"); + + tx.execute( + format!("INSERT INTO {HOSTS_RELATION_TABLE} (endpoint_id,hostname) VALUES ($1,$2)") + .as_str(), + &[&endpoint_id, &hostname], + ) + .await?; + + tx.commit().await?; + + self.id = Some(endpoint_id); + + Ok(()) + } +} + +impl BoxyDatabase { + pub async fn new(c: Client) -> Result> { + c.execute( + format!( + "CREATE TABLE IF NOT EXISTS {ENDPOINT_TABLE} + ( + id serial PRIMARY KEY, + address inet NOT NULL, + port integer CHECK (port >= 0 AND port <= 65535) NOT NULL, + callback text + ) + " + ) + .as_str(), + &[], + ) + .await?; + + c.execute( + format!( + "CREATE TABLE IF NOT EXISTS {HOSTS_RELATION_TABLE} + ( + id SERIAL PRIMARY KEY, + endpoint_id int REFERENCES {HOSTS_RELATION_TABLE}(id), + hostname text + ) + " + ) + .as_str(), + &[], + ) + .await?; + + Ok(BoxyDatabase { client: c }) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9c9cf9e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,90 @@ +mod config; +mod db; +mod services; +mod types; + +use std::{env, sync::Arc}; + +use bcrypt::{DEFAULT_COST, bcrypt}; +use config::Config; +use db::BoxyDatabase; +use log::{error, info}; +use nanoid::nanoid; +use ring::rand::SystemRandom; +use services::{api::ApiService, controller::ControllerService}; +use tokio::{fs::File, io::AsyncReadExt, sync::Mutex}; +use tokio_postgres::{NoTls, tls::NoTlsError}; +use types::Server; + +#[tokio::main] +async fn main() -> Result<(), Box> { + pretty_env_logger::formatted_builder() + .filter(None, log::LevelFilter::Info) + .init(); + + let args: Vec = env::args().collect(); + + if args.len() > 1 { + match args[1].as_str() { + "hash" => { + if args.len() < 3 { + error!("You need to specify a string to hash."); + return Ok(()); + } + + let hash = bcrypt::hash(&args[2], DEFAULT_COST).unwrap(); + info!("Generated Hash: {}", hash); + + return Ok(()); + } + _ => {} + } + } + + let config = Config::get().await.unwrap(); + + let db_string = config.db.to_string().await; + + info!("Database string: {}", db_string); + + let (client, conn) = tokio_postgres::connect(db_string.as_str(), NoTls) + .await + .unwrap(); + + tokio::spawn(async move { + if let Err(e) = conn.await { + error!("Error while connecting to database: {}", e); + } + }); + + let database = Box::new(BoxyDatabase::new(client).await.unwrap()); + + let database_shared = Arc::new(Mutex::new(Box::leak(database))); + + let api_svc = ApiService { + database: database_shared.clone(), + config: config.clone(), + _address: None + }; + + let svc = ControllerService { + database: database_shared, + }; + + let api_server = Server::new(api_svc, (config.api.listen, config.api.port)) + .await + .unwrap(); + + let proxy_server = Server::new(svc, (config.proxy.listen, config.proxy.port)) + .await + .unwrap(); + + tokio::task::spawn(async move { + api_server.handle().await; + }); + + // We don't put this on a separate thread because we'd be wasting the main thread. + proxy_server.handle().await; + + Ok(()) +} diff --git a/src/services.rs b/src/services.rs new file mode 100644 index 0000000..e8b28e6 --- /dev/null +++ b/src/services.rs @@ -0,0 +1,3 @@ +pub mod proxy; +pub mod controller; +pub mod api; diff --git a/src/services/api.rs b/src/services/api.rs new file mode 100644 index 0000000..b8a107a --- /dev/null +++ b/src/services/api.rs @@ -0,0 +1,92 @@ +use std::{hash, net::{IpAddr, SocketAddr}, pin::Pin, sync::Arc}; + +use base64::{Engine, prelude::BASE64_STANDARD}; +use bcrypt::DEFAULT_COST; +use http_body_util::{BodyExt, Full}; +use hyper::{ + body::{Bytes, Incoming}, service::Service, Method, Request, Response, StatusCode, Uri +}; +use log::{info, trace}; +use tokio::{net::TcpStream, sync::Mutex}; + +use crate::{ + config::{Client, Config}, db::{BoxyDatabase, Endpoint}, types::{GeneralBody, GeneralResponse, TcpIntercept} +}; + +#[derive(Debug, Clone)] +pub struct ApiService { + pub database: Arc>, + pub config: Config, + pub _address: Option, +} + +async fn default_response() -> Response>> { + Response::builder() + .status(404) + .body(GeneralBody::Right(Full::from(Bytes::from( + "That route doesn't exist.", + )))) + .unwrap() +} + +async fn custom_resp(e: StatusCode, m: String) -> Response>> { + Response::builder() + .status(e) + .body(GeneralBody::Right(Full::from(Bytes::from(m)))) + .unwrap() +} + +impl TcpIntercept for ApiService { + fn handle(&mut self, stream: &TcpStream) { + self._address = Some(stream.peer_addr().unwrap().ip()); + } +} + +impl Service> for ApiService { + type Response = GeneralResponse; + type Error = hyper::Error; + type Future = Pin> + Send>>; + + fn call(&self, req: Request) -> Self::Future { + let database = self.database.clone(); + let config = self.config.clone(); + let address = self._address.clone().unwrap(); + Box::pin(async move { + match *req.method() { + Method::POST => match req.uri().path() { + "/register" => { + let encoded_header = req.headers().get(hyper::header::AUTHORIZATION).unwrap().to_str().unwrap(); + + let auth_string = String::from_utf8(BASE64_STANDARD.decode(&encoded_header[6..]).unwrap()).unwrap(); + + let auth_string_split: Vec<&str> = auth_string.split(':').collect(); + + let name = auth_string_split.first().unwrap(); + let secret = auth_string_split.get(1).unwrap(); + + let matched_clients: Vec<&Client> = config.clients.iter().filter(|x| x.name.eq(name)).collect(); + + let client = matched_clients.first().unwrap(); + + if !bcrypt::verify(secret, client.secret.as_str()).unwrap() { + return Ok(custom_resp(StatusCode::UNAUTHORIZED, "Invalid credentials.".to_string()).await); + } + + let body = String::from_utf8(req.collect().await.unwrap().to_bytes().iter().cloned().collect::>()).unwrap(); + let json = json::parse(body.as_str()).unwrap(); + + info!("body: {}", body); + + let mut endpoint = Endpoint::new(None, address, json["port"].as_u16().unwrap(), json["callback"].as_str().unwrap_or("/").to_string()).await; + + endpoint.register(*database.lock().await, json["hostname"].as_str().unwrap().to_string()).await.unwrap(); + + Ok(custom_resp(StatusCode::OK, "yay".to_string()).await) + } + _ => Ok(default_response().await), + }, + _ => Ok(default_response().await), + } + }) + } +} diff --git a/src/services/controller.rs b/src/services/controller.rs new file mode 100644 index 0000000..eee4b1c --- /dev/null +++ b/src/services/controller.rs @@ -0,0 +1,60 @@ +use std::{pin::Pin, sync::Arc}; + +use http_body_util::Full; +use hyper::{ + Request, Response, + body::{Bytes, Incoming}, + service::Service, +}; +use log::error; +use tokio::sync::Mutex; + +use crate::{ + config::{self, Client, Config, Host}, + db::{BoxyDatabase, Endpoint}, + types::{GeneralBody, GeneralResponse, TcpIntercept}, +}; + +use super::proxy::ProxyService; + +#[derive(Debug, Clone)] +pub struct ControllerService { + pub database: Arc>, +} + +impl TcpIntercept for ControllerService { + fn handle(&mut self, stream: &tokio::net::TcpStream) { + } +} + +impl Service> for ControllerService { + type Response = GeneralResponse; + type Error = hyper::Error; + type Future = Pin> + Send>>; + + fn call(&self, req: Request) -> Self::Future { + let database = self.database.clone(); + Box::pin(async move { + let hostname = req + .headers() + .get(hyper::header::HOST) + .unwrap() + .to_str() + .unwrap() + .to_string(); + + let endpoints = Endpoint::get_by_hostname(*database.lock().await, hostname.clone()) + .await + .unwrap(); + + let endpoint = endpoints.first().unwrap(); + + let proxy = ProxyService { + address: format!("{}:{}", endpoint.address.clone(), endpoint.port), + hostname, + }; + + proxy.call(req).await + }) + } +} diff --git a/src/services/proxy.rs b/src/services/proxy.rs new file mode 100644 index 0000000..c0e7e7d --- /dev/null +++ b/src/services/proxy.rs @@ -0,0 +1,50 @@ +use std::pin::Pin; + +use hyper::{Request, body::Incoming, service::Service}; +use hyper_util::rt::TokioIo; +use log::error; +use tokio::net::TcpStream; + +use crate::types::{GeneralResponse, to_general_response}; + +#[derive(Debug, Clone)] +pub struct ProxyService { + pub address: String, + pub hostname: String, +} + +impl Service> for ProxyService { + type Response = GeneralResponse; + type Error = hyper::Error; + type Future = Pin> + Send>>; + + fn call(&self, incoming: Request) -> Self::Future { + let address = self.address.clone(); + let hostname = self.hostname.clone(); + Box::pin(async move { + let stream = TcpStream::connect(address).await.unwrap(); + let io = TokioIo::new(stream); + + let (mut sender, conn) = hyper::client::conn::http1::Builder::new() + .handshake(io) + .await + .unwrap(); + + tokio::spawn(async move { + if let Err(err) = conn.await { + error!("Could not open connection to backend: {err}"); + } + }); + + let (mut parts, body_stream) = incoming.into_parts(); + + parts + .headers + .insert(hyper::header::HOST, hostname.parse().unwrap()); + + let req = Request::from_parts(parts, body_stream); + + Ok(to_general_response(sender.send_request(req).await.unwrap())) + }) + } +} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..c96f5ae --- /dev/null +++ b/src/types.rs @@ -0,0 +1,69 @@ +use std::error::Error; + +use http_body_util::{Either, Full}; +use hyper::{ + Request, Response, + body::{Body, Bytes, Incoming}, + server::conn::http1, + service::{HttpService, Service}, +}; +use hyper_util::rt::TokioIo; +use log::error; +use tokio::net::{TcpListener, TcpStream}; + +pub type GeneralResponse = Response; +pub type GeneralBody = Either>; + +pub fn to_general_response(res: Response) -> GeneralResponse { + let (parts, body) = res.into_parts(); + Response::from_parts(parts, GeneralBody::Left(body)) +} + +pub struct Server { + listener: TcpListener, + service: S, +} + +pub trait TcpIntercept { + fn handle(&mut self, stream: &TcpStream); +} + +impl Server +where + S: TcpIntercept, + S: Service> + Clone + Send + 'static, + S: HttpService + Clone + Send, + ::Error: Into>, + ::Data: Send, + S::ResBody: Send, + >::Future: Send, +{ + pub async fn handle(&self) { + loop { + let (stream, _) = self.listener.accept().await.unwrap(); + + let mut svc_clone = self.service.clone(); + svc_clone.handle(&stream); + + let io = TokioIo::new(stream); + tokio::task::spawn(async move { + if let Err(err) = http1::Builder::new() + .writev(false) + .serve_connection(io, svc_clone) + .await + { + error!("Error while trying to serve connection: {err}") + }; + }); + } + } + + pub async fn new(service: S, a: (String, u16)) -> Result> { + Ok(Self { + listener: TcpListener::bind(&a).await?, + service, + }) + } +} +/* +*/ From 0c68399210546d3440bec34702e45acc9425aa5b Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 12:35:03 +0200 Subject: [PATCH 02/19] chore: clean up, rename types.rs to server.rs --- config.yaml | 2 +- src/config.rs | 21 ++++++++- src/db.rs | 5 ++- src/main.rs | 20 ++++++--- src/{types.rs => server.rs} | 4 +- src/services.rs | 4 +- src/services/api.rs | 88 +++++++++++++++++++++++++++---------- src/services/controller.rs | 5 +-- src/services/proxy.rs | 2 +- 9 files changed, 110 insertions(+), 41 deletions(-) rename src/{types.rs => server.rs} (95%) diff --git a/config.yaml b/config.yaml index b3d0032..602b3e2 100644 --- a/config.yaml +++ b/config.yaml @@ -17,4 +17,4 @@ hosts: # ignore this it doesn't function clients: - name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend) - secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 + hashed_secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 diff --git a/src/config.rs b/src/config.rs index 1e055a0..719f3c9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -27,7 +27,26 @@ pub struct Api { #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Client { pub name: String, - pub secret: String, + pub hashed_secret: String, +} + +impl Client { + pub async fn verify(us: String, config: Config) -> bool { + // us stands for user:secret btw + let us_split: Vec<&str> = us.split(':').collect(); + + let name = us_split.first().unwrap(); + let secret = us_split.last().unwrap(); + + let client: Client = config + .clients + .into_iter() + .filter(|x| x.name.eq(name)) + .nth(0) + .unwrap(); + + return bcrypt::verify(secret, client.hashed_secret.as_str()).unwrap(); + } } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] diff --git a/src/db.rs b/src/db.rs index b880979..86c691d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,4 +1,7 @@ -use std::{error::Error, net::{IpAddr, SocketAddr}}; +use std::{ + error::Error, + net::{IpAddr, SocketAddr}, +}; use tokio_postgres::{Client, Socket, tls::MakeTlsConnect}; diff --git a/src/main.rs b/src/main.rs index 9c9cf9e..42844c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod config; mod db; +mod server; mod services; -mod types; use std::{env, sync::Arc}; @@ -11,16 +11,20 @@ use db::BoxyDatabase; use log::{error, info}; use nanoid::nanoid; use ring::rand::SystemRandom; +use server::Server; use services::{api::ApiService, controller::ControllerService}; use tokio::{fs::File, io::AsyncReadExt, sync::Mutex}; use tokio_postgres::{NoTls, tls::NoTlsError}; -use types::Server; + +const VERSION: &str = "v0.1a"; #[tokio::main] async fn main() -> Result<(), Box> { - pretty_env_logger::formatted_builder() - .filter(None, log::LevelFilter::Info) - .init(); + if env::var("RUST_LOG").is_err() { + unsafe { env::set_var("RUST_LOG", "info") }; + } + + pretty_env_logger::init(); let args: Vec = env::args().collect(); @@ -37,6 +41,10 @@ async fn main() -> Result<(), Box> { return Ok(()); } + "version" => { + info!("Version: {}", VERSION); + return Ok(()); + } _ => {} } } @@ -64,7 +72,7 @@ async fn main() -> Result<(), Box> { let api_svc = ApiService { database: database_shared.clone(), config: config.clone(), - _address: None + _address: None, }; let svc = ControllerService { diff --git a/src/types.rs b/src/server.rs similarity index 95% rename from src/types.rs rename to src/server.rs index c96f5ae..f35f836 100644 --- a/src/types.rs +++ b/src/server.rs @@ -25,7 +25,7 @@ pub struct Server { } pub trait TcpIntercept { - fn handle(&mut self, stream: &TcpStream); + fn stream(&mut self, stream: &TcpStream); } impl Server @@ -43,7 +43,7 @@ where let (stream, _) = self.listener.accept().await.unwrap(); let mut svc_clone = self.service.clone(); - svc_clone.handle(&stream); + svc_clone.stream(&stream); let io = TokioIo::new(stream); tokio::task::spawn(async move { diff --git a/src/services.rs b/src/services.rs index e8b28e6..168dbf8 100644 --- a/src/services.rs +++ b/src/services.rs @@ -1,3 +1,3 @@ -pub mod proxy; -pub mod controller; pub mod api; +pub mod controller; +pub mod proxy; diff --git a/src/services/api.rs b/src/services/api.rs index b8a107a..a3dce19 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -1,16 +1,20 @@ -use std::{hash, net::{IpAddr, SocketAddr}, pin::Pin, sync::Arc}; +use std::{net::IpAddr, pin::Pin, sync::Arc}; use base64::{Engine, prelude::BASE64_STANDARD}; -use bcrypt::DEFAULT_COST; +use bcrypt::bcrypt; use http_body_util::{BodyExt, Full}; use hyper::{ - body::{Bytes, Incoming}, service::Service, Method, Request, Response, StatusCode, Uri + Method, Request, Response, StatusCode, + body::{Bytes, Incoming}, + service::Service, }; -use log::{info, trace}; +use log::{debug, info, warn}; use tokio::{net::TcpStream, sync::Mutex}; use crate::{ - config::{Client, Config}, db::{BoxyDatabase, Endpoint}, types::{GeneralBody, GeneralResponse, TcpIntercept} + config::{Client, Config}, + db::{BoxyDatabase, Endpoint}, + server::{GeneralBody, GeneralResponse, TcpIntercept}, }; #[derive(Debug, Clone)] @@ -20,7 +24,7 @@ pub struct ApiService { pub _address: Option, } -async fn default_response() -> Response>> { +async fn default_response() -> GeneralResponse { Response::builder() .status(404) .body(GeneralBody::Right(Full::from(Bytes::from( @@ -29,7 +33,7 @@ async fn default_response() -> Response Response>> { +async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse { Response::builder() .status(e) .body(GeneralBody::Right(Full::from(Bytes::from(m)))) @@ -37,7 +41,7 @@ async fn custom_resp(e: StatusCode, m: String) -> Response> for ApiService { let database = self.database.clone(); let config = self.config.clone(); let address = self._address.clone().unwrap(); + Box::pin(async move { match *req.method() { Method::POST => match req.uri().path() { "/register" => { - let encoded_header = req.headers().get(hyper::header::AUTHORIZATION).unwrap().to_str().unwrap(); - - let auth_string = String::from_utf8(BASE64_STANDARD.decode(&encoded_header[6..]).unwrap()).unwrap(); - - let auth_string_split: Vec<&str> = auth_string.split(':').collect(); + debug!("new api register request from {}", address); - let name = auth_string_split.first().unwrap(); - let secret = auth_string_split.get(1).unwrap(); + let encoded_header = req + .headers() + .get(hyper::header::AUTHORIZATION) + .unwrap() + .to_str() + .unwrap(); - let matched_clients: Vec<&Client> = config.clients.iter().filter(|x| x.name.eq(name)).collect(); + debug!("authorization header: {}", encoded_header); - let client = matched_clients.first().unwrap(); + let auth_string = String::from_utf8( + BASE64_STANDARD.decode(&encoded_header[6..]).unwrap(), + ) + .unwrap(); - if !bcrypt::verify(secret, client.secret.as_str()).unwrap() { - return Ok(custom_resp(StatusCode::UNAUTHORIZED, "Invalid credentials.".to_string()).await); + debug!("decoded auth string: {}", auth_string); + + if !Client::verify(auth_string.clone(), config).await { + warn!( + "Authentication for string {} from {} failed.", + auth_string, address + ); + + return Ok(custom_resp( + StatusCode::UNAUTHORIZED, + "Invalid credentials.", + ) + .await); } - let body = String::from_utf8(req.collect().await.unwrap().to_bytes().iter().cloned().collect::>()).unwrap(); + let body = String::from_utf8( + req.collect() + .await + .unwrap() + .to_bytes() + .iter() + .cloned() + .collect::>(), + ) + .unwrap(); let json = json::parse(body.as_str()).unwrap(); - info!("body: {}", body); + debug!("body: {}", body); - let mut endpoint = Endpoint::new(None, address, json["port"].as_u16().unwrap(), json["callback"].as_str().unwrap_or("/").to_string()).await; + let mut endpoint = Endpoint::new( + None, + address, + json["port"].as_u16().unwrap(), + json["callback"].as_str().unwrap_or("/").to_string(), + ) + .await; - endpoint.register(*database.lock().await, json["hostname"].as_str().unwrap().to_string()).await.unwrap(); + endpoint + .register( + *database.lock().await, + json["hostname"].as_str().unwrap().to_string(), + ) + .await + .unwrap(); - Ok(custom_resp(StatusCode::OK, "yay".to_string()).await) + Ok(custom_resp(StatusCode::OK, "").await) } _ => Ok(default_response().await), }, diff --git a/src/services/controller.rs b/src/services/controller.rs index eee4b1c..b892b20 100644 --- a/src/services/controller.rs +++ b/src/services/controller.rs @@ -12,7 +12,7 @@ use tokio::sync::Mutex; use crate::{ config::{self, Client, Config, Host}, db::{BoxyDatabase, Endpoint}, - types::{GeneralBody, GeneralResponse, TcpIntercept}, + server::{GeneralBody, GeneralResponse, TcpIntercept}, }; use super::proxy::ProxyService; @@ -23,8 +23,7 @@ pub struct ControllerService { } impl TcpIntercept for ControllerService { - fn handle(&mut self, stream: &tokio::net::TcpStream) { - } + fn stream(&mut self, _: &tokio::net::TcpStream) {} } impl Service> for ControllerService { diff --git a/src/services/proxy.rs b/src/services/proxy.rs index c0e7e7d..e4641e1 100644 --- a/src/services/proxy.rs +++ b/src/services/proxy.rs @@ -5,7 +5,7 @@ use hyper_util::rt::TokioIo; use log::error; use tokio::net::TcpStream; -use crate::types::{GeneralResponse, to_general_response}; +use crate::server::{GeneralResponse, to_general_response}; #[derive(Debug, Clone)] pub struct ProxyService { From a6b2127b0c0e46b457487f360bb8c4be36388d66 Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 12:35:23 +0200 Subject: [PATCH 03/19] chore: remove unused imports --- src/db.rs | 4 ++-- src/main.rs | 8 +++----- src/services/api.rs | 3 +-- src/services/controller.rs | 9 +++------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/db.rs b/src/db.rs index 86c691d..0fdccba 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,9 +1,9 @@ use std::{ error::Error, - net::{IpAddr, SocketAddr}, + net::IpAddr, }; -use tokio_postgres::{Client, Socket, tls::MakeTlsConnect}; +use tokio_postgres::Client; const ENDPOINT_TABLE: &str = "endpoints"; const HOSTS_RELATION_TABLE: &str = "hosts"; diff --git a/src/main.rs b/src/main.rs index 42844c7..8ded716 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,16 +5,14 @@ mod services; use std::{env, sync::Arc}; -use bcrypt::{DEFAULT_COST, bcrypt}; +use bcrypt::DEFAULT_COST; use config::Config; use db::BoxyDatabase; use log::{error, info}; -use nanoid::nanoid; -use ring::rand::SystemRandom; use server::Server; use services::{api::ApiService, controller::ControllerService}; -use tokio::{fs::File, io::AsyncReadExt, sync::Mutex}; -use tokio_postgres::{NoTls, tls::NoTlsError}; +use tokio::sync::Mutex; +use tokio_postgres::NoTls; const VERSION: &str = "v0.1a"; diff --git a/src/services/api.rs b/src/services/api.rs index a3dce19..cab3cac 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -1,14 +1,13 @@ use std::{net::IpAddr, pin::Pin, sync::Arc}; use base64::{Engine, prelude::BASE64_STANDARD}; -use bcrypt::bcrypt; use http_body_util::{BodyExt, Full}; use hyper::{ Method, Request, Response, StatusCode, body::{Bytes, Incoming}, service::Service, }; -use log::{debug, info, warn}; +use log::{debug, warn}; use tokio::{net::TcpStream, sync::Mutex}; use crate::{ diff --git a/src/services/controller.rs b/src/services/controller.rs index b892b20..7665ac7 100644 --- a/src/services/controller.rs +++ b/src/services/controller.rs @@ -1,18 +1,15 @@ use std::{pin::Pin, sync::Arc}; -use http_body_util::Full; use hyper::{ - Request, Response, - body::{Bytes, Incoming}, + Request, + body::Incoming, service::Service, }; -use log::error; use tokio::sync::Mutex; use crate::{ - config::{self, Client, Config, Host}, db::{BoxyDatabase, Endpoint}, - server::{GeneralBody, GeneralResponse, TcpIntercept}, + server::{GeneralResponse, TcpIntercept}, }; use super::proxy::ProxyService; From e2d9789f9a7e2b0d827508bece5a55f35a582b50 Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 12:53:21 +0200 Subject: [PATCH 04/19] feat: extra debug logging and chore: fix unused --- Cargo.lock | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ config.yaml | 9 +------- src/config.rs | 33 ++--------------------------- src/main.rs | 15 ++++++++------ src/server.rs | 11 ++++++++-- 6 files changed, 80 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e73c9b..cff25dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_colours" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14eec43e0298190790f41679fe69ef7a829d2a2ddd78c8c00339e84710e435fe" +dependencies = [ + "rgb", +] + [[package]] name = "anyhow" version = "1.0.98" @@ -118,9 +127,11 @@ dependencies = [ name = "boxy" version = "0.1.0" dependencies = [ + "ansi_colours", "anyhow", "base64", "bcrypt", + "colour", "http-body-util", "hyper", "hyper-util", @@ -143,6 +154,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + [[package]] name = "byteorder" version = "1.5.0" @@ -180,6 +197,15 @@ dependencies = [ "inout", ] +[[package]] +name = "colour" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b536eebcabe54980476d120a182f7da2268fe02d22575cca99cee5fdda178280" +dependencies = [ + "winapi", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -830,6 +856,15 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" +dependencies = [ + "bytemuck", +] + [[package]] name = "ring" version = "0.17.14" @@ -1286,6 +1321,22 @@ dependencies = [ "web-sys", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -1295,6 +1346,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 0c511d3..e6bf1d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,6 @@ serde = "1.0.219" base64 = "0.22.1" string-builder = "0.2.0" json = "0.12.4" +ansi_colours = "1.2.3" +colour = "2.1.0" diff --git a/config.yaml b/config.yaml index 602b3e2..fa4c12b 100644 --- a/config.yaml +++ b/config.yaml @@ -1,7 +1,4 @@ -db: - host: '127.0.0.1' - user: 'postgres' - password: 'trust' +database: 'postgresql://postgres:trust@127.0.0.1' proxy: listen: 127.0.0.1 @@ -11,10 +8,6 @@ api: listen: 127.0.0.1 port: 8006 -hosts: # ignore this it doesn't function - - hostname: localhost:8005 - address: localhost:8000 - clients: - name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend) hashed_secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 diff --git a/src/config.rs b/src/config.rs index 719f3c9..a15575f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,45 +45,16 @@ impl Client { .nth(0) .unwrap(); - return bcrypt::verify(secret, client.hashed_secret.as_str()).unwrap(); + bcrypt::verify(secret, client.hashed_secret.as_str()).unwrap() } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] -pub struct Host { - pub hostname: String, - pub address: String, -} - #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Config { - pub db: Db, + pub database: String, pub proxy: Proxy, pub api: Api, pub clients: Vec, - pub hosts: Vec, -} - -impl Db { - pub async fn to_string(&self) -> String { - let mut builder = String::new(); - - builder += format!( - "host={} port={} user={} dbname={}", - self.host, - self.port.unwrap_or(5432), - self.user, - self.database.clone().unwrap_or(self.user.clone()), - ) - .as_str(); - - match &self.password { - Some(x) => builder += format!(" password={}", x).as_str(), - None => {} - } - - builder - } } impl Config { diff --git a/src/main.rs b/src/main.rs index 8ded716..8fd2d2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,12 +3,12 @@ mod db; mod server; mod services; -use std::{env, sync::Arc}; +use std::{env, process::exit, sync::Arc}; use bcrypt::DEFAULT_COST; use config::Config; use db::BoxyDatabase; -use log::{error, info}; +use log::{debug, error, info}; use server::Server; use services::{api::ApiService, controller::ControllerService}; use tokio::sync::Mutex; @@ -49,20 +49,21 @@ async fn main() -> Result<(), Box> { let config = Config::get().await.unwrap(); - let db_string = config.db.to_string().await; + debug!("Database URI: {}", config.database); - info!("Database string: {}", db_string); - - let (client, conn) = tokio_postgres::connect(db_string.as_str(), NoTls) + let (client, conn) = tokio_postgres::connect(config.database.as_str(), NoTls) .await .unwrap(); tokio::spawn(async move { if let Err(e) = conn.await { error!("Error while connecting to database: {}", e); + exit(1); } }); + info!("Connected to database."); + let database = Box::new(BoxyDatabase::new(client).await.unwrap()); let database_shared = Arc::new(Mutex::new(Box::leak(database))); @@ -86,10 +87,12 @@ async fn main() -> Result<(), Box> { .unwrap(); tokio::task::spawn(async move { + info!("Starting API server..."); api_server.handle().await; }); // We don't put this on a separate thread because we'd be wasting the main thread. + info!("Starting proxy server..."); proxy_server.handle().await; Ok(()) diff --git a/src/server.rs b/src/server.rs index f35f836..0eb7c63 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use std::error::Error; +use std::{any::type_name_of_val, error::Error}; use http_body_util::{Either, Full}; use hyper::{ @@ -8,7 +8,7 @@ use hyper::{ service::{HttpService, Service}, }; use hyper_util::rt::TokioIo; -use log::error; +use log::{error, info}; use tokio::net::{TcpListener, TcpStream}; pub type GeneralResponse = Response; @@ -39,6 +39,12 @@ where >::Future: Send, { pub async fn handle(&self) { + info!( + "Server started at http://{} for service: {}", + self.listener.local_addr().unwrap(), + type_name_of_val(&self.service) + ); + loop { let (stream, _) = self.listener.accept().await.unwrap(); @@ -46,6 +52,7 @@ where svc_clone.stream(&stream); let io = TokioIo::new(stream); + tokio::task::spawn(async move { if let Err(err) = http1::Builder::new() .writev(false) From 3c4f3b75337eb40ac514cc9e10b7bbfc858014b8 Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 13:02:48 +0200 Subject: [PATCH 05/19] add todo --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 696ba9e..6a67b22 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ -# boxy +# Boxy + +The reverse reverse proxy. + +## Todo + +- [ ] Automatic SSL certificates (LE) From 17c802bab8c2efec04d819583f8106f39aa5548a Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 20:38:43 +0200 Subject: [PATCH 06/19] feat: error handling --- src/db.rs | 2 +- src/main.rs | 6 +- src/server.rs | 21 +++++-- src/services/api.rs | 119 +++++++++++++++++++++++++++---------- src/services/controller.rs | 38 +++++++----- src/services/proxy.rs | 18 +++++- 6 files changed, 145 insertions(+), 59 deletions(-) diff --git a/src/db.rs b/src/db.rs index 0fdccba..734ab00 100644 --- a/src/db.rs +++ b/src/db.rs @@ -65,7 +65,7 @@ impl Endpoint { &mut self, db: &mut BoxyDatabase, hostname: String, - ) -> Result<(), Box> { + ) -> Result<(), tokio_postgres::Error> { let tx = db.client.transaction().await?; let endpoint_id: i32 = tx diff --git a/src/main.rs b/src/main.rs index 8fd2d2c..666d87a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,11 +68,7 @@ async fn main() -> Result<(), Box> { let database_shared = Arc::new(Mutex::new(Box::leak(database))); - let api_svc = ApiService { - database: database_shared.clone(), - config: config.clone(), - _address: None, - }; + let api_svc = ApiService::new(database_shared.clone(), config.clone()).await; let svc = ControllerService { database: database_shared, diff --git a/src/server.rs b/src/server.rs index 0eb7c63..52cad1d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,10 +2,7 @@ use std::{any::type_name_of_val, error::Error}; use http_body_util::{Either, Full}; use hyper::{ - Request, Response, - body::{Body, Bytes, Incoming}, - server::conn::http1, - service::{HttpService, Service}, + body::{Body, Bytes, Incoming}, server::conn::http1, service::{HttpService, Service}, Request, Response, StatusCode }; use hyper_util::rt::TokioIo; use log::{error, info}; @@ -28,6 +25,22 @@ pub trait TcpIntercept { fn stream(&mut self, stream: &TcpStream); } +pub async fn default_response() -> GeneralResponse { + Response::builder() + .status(404) + .body(GeneralBody::Right(Full::from(Bytes::from( + "That route doesn't exist.", + )))) + .unwrap() +} + +pub async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse { + Response::builder() + .status(e) + .body(GeneralBody::Right(Full::from(Bytes::from(m)))) + .unwrap() +} + impl Server where S: TcpIntercept, diff --git a/src/services/api.rs b/src/services/api.rs index cab3cac..a6ece5d 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -7,13 +7,13 @@ use hyper::{ body::{Bytes, Incoming}, service::Service, }; -use log::{debug, warn}; +use log::{debug, error, warn}; use tokio::{net::TcpStream, sync::Mutex}; use crate::{ config::{Client, Config}, db::{BoxyDatabase, Endpoint}, - server::{GeneralBody, GeneralResponse, TcpIntercept}, + server::{custom_resp, default_response, GeneralBody, GeneralResponse, TcpIntercept}, }; #[derive(Debug, Clone)] @@ -23,21 +23,6 @@ pub struct ApiService { pub _address: Option, } -async fn default_response() -> GeneralResponse { - Response::builder() - .status(404) - .body(GeneralBody::Right(Full::from(Bytes::from( - "That route doesn't exist.", - )))) - .unwrap() -} - -async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse { - Response::builder() - .status(e) - .body(GeneralBody::Right(Full::from(Bytes::from(m)))) - .unwrap() -} impl TcpIntercept for ApiService { fn stream(&mut self, stream: &TcpStream) { @@ -45,6 +30,16 @@ impl TcpIntercept for ApiService { } } +impl ApiService { + pub async fn new(database: Arc>, config: Config) -> Self { + Self { + database, + config, + _address: None, + } + } +} + impl Service> for ApiService { type Response = GeneralResponse; type Error = hyper::Error; @@ -53,7 +48,7 @@ impl Service> for ApiService { fn call(&self, req: Request) -> Self::Future { let database = self.database.clone(); let config = self.config.clone(); - let address = self._address.clone().unwrap(); + let address = self._address.unwrap(); Box::pin(async move { match *req.method() { @@ -61,19 +56,55 @@ impl Service> for ApiService { "/register" => { debug!("new api register request from {}", address); - let encoded_header = req - .headers() - .get(hyper::header::AUTHORIZATION) - .unwrap() + let encoded_header = + match req.headers().get(hyper::header::AUTHORIZATION) { + None => { + error!( + "Authorization header not given for request from {address}", + ); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid credentials.", + ) + .await); + } + Some(x) => x, + } .to_str() .unwrap(); debug!("authorization header: {}", encoded_header); - let auth_string = String::from_utf8( - BASE64_STANDARD.decode(&encoded_header[6..]).unwrap(), - ) - .unwrap(); + let auth_bytes = match BASE64_STANDARD.decode(&encoded_header[6..]) { + Ok(x) => x, + Err(e) => { + error!( + "Error while decoding authorization header from {address}: {e}", + ); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid base64 string given.", + ) + .await); + } + }; + + let auth_string = match String::from_utf8(auth_bytes) { + Ok(x) => x, + Err(e) => { + error!( + "Error while decoding authorization header from {address}: {e}", + ); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid UTF-8 in authentication string.", + ) + .await); + } + }; debug!("decoded auth string: {}", auth_string); @@ -90,7 +121,7 @@ impl Service> for ApiService { .await); } - let body = String::from_utf8( + let body = match String::from_utf8( req.collect() .await .unwrap() @@ -98,16 +129,40 @@ impl Service> for ApiService { .iter() .cloned() .collect::>(), - ) - .unwrap(); - let json = json::parse(body.as_str()).unwrap(); + ) { + Ok(x) => x, + Err(e) => { + error!( + "Error while inferring UTF-8 string from {address}'s request body: {e}", + ); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid UTF-8 in body.", + ) + .await); + } + }; + + let json = match json::parse(body.as_str()) { + Ok(x) => x, + Err(e) => { + error!("Error while parsing JSON body from {address}: {e}",); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid JSON in body.", + ) + .await); + } + }; debug!("body: {}", body); let mut endpoint = Endpoint::new( None, address, - json["port"].as_u16().unwrap(), + json["port"].as_u16().unwrap_or(8080), json["callback"].as_str().unwrap_or("/").to_string(), ) .await; @@ -120,7 +175,7 @@ impl Service> for ApiService { .await .unwrap(); - Ok(custom_resp(StatusCode::OK, "").await) + Ok(custom_resp(StatusCode::OK, "Success").await) } _ => Ok(default_response().await), }, diff --git a/src/services/controller.rs b/src/services/controller.rs index 7665ac7..2ae7ccc 100644 --- a/src/services/controller.rs +++ b/src/services/controller.rs @@ -1,15 +1,12 @@ use std::{pin::Pin, sync::Arc}; -use hyper::{ - Request, - body::Incoming, - service::Service, -}; +use hyper::{Request, StatusCode, body::Incoming, service::Service}; +use log::error; use tokio::sync::Mutex; use crate::{ db::{BoxyDatabase, Endpoint}, - server::{GeneralResponse, TcpIntercept}, + server::{GeneralResponse, TcpIntercept, custom_resp}, }; use super::proxy::ProxyService; @@ -31,19 +28,32 @@ impl Service> for ControllerService { fn call(&self, req: Request) -> Self::Future { let database = self.database.clone(); Box::pin(async move { - let hostname = req - .headers() - .get(hyper::header::HOST) - .unwrap() - .to_str() - .unwrap() - .to_string(); + let hostname = match req.headers().get(hyper::header::HOST) { + Some(x) => x, + None => { + error!("No host header given."); + + return Ok(custom_resp(StatusCode::BAD_REQUEST, "No host header given.").await); + } + } + .to_str() + .unwrap() + .to_string(); let endpoints = Endpoint::get_by_hostname(*database.lock().await, hostname.clone()) .await .unwrap(); - let endpoint = endpoints.first().unwrap(); + let endpoint = match endpoints.first() { + Some(x) => x, + None => { + error!("No endpoint found for request."); + + return Ok( + custom_resp(StatusCode::NOT_FOUND, "No endpoint found for host.").await, + ); + } + }; let proxy = ProxyService { address: format!("{}:{}", endpoint.address.clone(), endpoint.port), diff --git a/src/services/proxy.rs b/src/services/proxy.rs index e4641e1..47b0a5e 100644 --- a/src/services/proxy.rs +++ b/src/services/proxy.rs @@ -1,11 +1,11 @@ use std::pin::Pin; -use hyper::{Request, body::Incoming, service::Service}; +use hyper::{Request, StatusCode, body::Incoming, service::Service}; use hyper_util::rt::TokioIo; use log::error; use tokio::net::TcpStream; -use crate::server::{GeneralResponse, to_general_response}; +use crate::server::{GeneralResponse, custom_resp, to_general_response}; #[derive(Debug, Clone)] pub struct ProxyService { @@ -22,7 +22,19 @@ impl Service> for ProxyService { let address = self.address.clone(); let hostname = self.hostname.clone(); Box::pin(async move { - let stream = TcpStream::connect(address).await.unwrap(); + let stream = match TcpStream::connect(address).await { + Ok(x) => x, + Err(e) => { + error!("Could not open connection to endpoint: {e}"); + + return Ok(custom_resp( + StatusCode::BAD_GATEWAY, + "Unable to open connection to endpoint.", + ) + .await); + } + }; + let io = TokioIo::new(stream); let (mut sender, conn) = hyper::client::conn::http1::Builder::new() From 5dda53333885fe9053b4a177554e5c25c750e7b6 Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 20:39:23 +0200 Subject: [PATCH 07/19] chore: remove unused imports --- src/services/api.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/api.rs b/src/services/api.rs index a6ece5d..ee86312 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -1,10 +1,10 @@ use std::{net::IpAddr, pin::Pin, sync::Arc}; use base64::{Engine, prelude::BASE64_STANDARD}; -use http_body_util::{BodyExt, Full}; +use http_body_util::BodyExt; use hyper::{ - Method, Request, Response, StatusCode, - body::{Bytes, Incoming}, + Method, Request, StatusCode, + body::Incoming, service::Service, }; use log::{debug, error, warn}; @@ -13,7 +13,7 @@ use tokio::{net::TcpStream, sync::Mutex}; use crate::{ config::{Client, Config}, db::{BoxyDatabase, Endpoint}, - server::{custom_resp, default_response, GeneralBody, GeneralResponse, TcpIntercept}, + server::{custom_resp, default_response, GeneralResponse, TcpIntercept}, }; #[derive(Debug, Clone)] From 0a35a6425cc93cbb537510e7ac0060a2a0c908a5 Mon Sep 17 00:00:00 2001 From: hex Date: Wed, 30 Jul 2025 18:41:47 +0200 Subject: [PATCH 08/19] test --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test diff --git a/test b/test new file mode 100644 index 0000000..e69de29 From f305cb5a85f7bad21010144e7a30a3f1a3e23cdf Mon Sep 17 00:00:00 2001 From: hex Date: Sat, 2 Aug 2025 20:39:13 +0200 Subject: [PATCH 09/19] feat: health checker --- src/health.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/health.rs diff --git a/src/health.rs b/src/health.rs new file mode 100644 index 0000000..83cfbc3 --- /dev/null +++ b/src/health.rs @@ -0,0 +1,60 @@ +use http_body_util::Empty; +use hyper::{Request, body::Bytes}; +use hyper_util::rt::TokioIo; +use log::error; +use tokio::net::TcpStream; + +use crate::db::{BoxyDatabase, Endpoint}; + +pub async fn check(db: &mut BoxyDatabase) { + let endpoints = Endpoint::get_all(db).await.unwrap(); + + for endpoint in endpoints { + let address = format!("{}:{}", endpoint.address, endpoint.port); + + let url = format!("http://{}{}", address, endpoint.callback) + .parse::() + .unwrap(); + + let stream = match TcpStream::connect(address).await { + Ok(x) => x, + Err(e) => { + error!("Could not reach endpoint {}: {e}", endpoint.id.unwrap()); + + endpoint.delete(db).await.unwrap(); + + continue; + } + }; + + let io = TokioIo::new(stream); + + let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await.unwrap(); + + tokio::task::spawn(async move { + if let Err(err) = conn.await { + println!("Connection failed: {:?}", err); + } + }); + + let req = Request::builder() + .uri(url) + .body(Empty::::new()) + .unwrap(); + + let res = match sender.send_request(req).await { + Ok(x) => x, + Err(e) => { + error!("Could not reach endpoint {}: {e}", endpoint.id.unwrap()); + + endpoint.delete(db).await.unwrap(); + + continue; + } + }; + + if !res.status().is_success() { + endpoint.delete(db).await.unwrap(); + } + } +} From 638b0376d827ce3a1c7bc423dba915c6124dc628 Mon Sep 17 00:00:00 2001 From: hex Date: Sat, 2 Aug 2025 20:40:44 +0200 Subject: [PATCH 10/19] feat: new matcher system instead of manually 'match'ing in servcie --- Cargo.lock | 2 + Cargo.toml | 2 + examples/example-server/src/main.rs | 21 +++- src/db.rs | 123 ++++++++++++++---- src/main.rs | 31 ++++- src/matchers.rs | 1 + src/matchers/api.rs | 180 +++++++++++++++++++++++++++ src/routes.rs | 1 + src/routes/api.rs | 157 +++++++++++++++++++++++ src/server.rs | 20 ++- src/services.rs | 2 +- src/services/api.rs | 186 ---------------------------- src/services/controller.rs | 14 ++- src/services/matcher.rs | 129 +++++++++++++++++++ src/services/proxy.rs | 2 +- 15 files changed, 646 insertions(+), 225 deletions(-) create mode 100644 src/matchers.rs create mode 100644 src/matchers/api.rs create mode 100644 src/routes.rs create mode 100644 src/routes/api.rs delete mode 100644 src/services/api.rs create mode 100644 src/services/matcher.rs diff --git a/Cargo.lock b/Cargo.lock index cff25dd..d81bd87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,9 +129,11 @@ version = "0.1.0" dependencies = [ "ansi_colours", "anyhow", + "async-trait", "base64", "bcrypt", "colour", + "http", "http-body-util", "hyper", "hyper-util", diff --git a/Cargo.toml b/Cargo.toml index e6bf1d9..229a6f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,6 @@ string-builder = "0.2.0" json = "0.12.4" ansi_colours = "1.2.3" colour = "2.1.0" +async-trait = "0.1.88" +http = "1.3.1" diff --git a/examples/example-server/src/main.rs b/examples/example-server/src/main.rs index b19cced..52638b7 100644 --- a/examples/example-server/src/main.rs +++ b/examples/example-server/src/main.rs @@ -24,7 +24,7 @@ fn rocket() -> _ { // We define the port of the server running locally and the hostname we want to route to it. let body = json!({ "port": 8000, - "hostname": "localhost:8005", + "hosts": ["localhost:8005"], }); // Send it to Boxy's API @@ -35,7 +35,24 @@ fn rocket() -> _ { .send() .unwrap(); - println!("{}", res.text().unwrap()); + let id = res.text().unwrap(); + + println!("{}", id); + + let body2 = json!({}); + + // Send it to Boxy's API + let res2 = client + .delete(format!( + "http://{}:{}/endpoint/{}", + BOXY_ADDRESS, BOXY_PORT, id + )) + .basic_auth(CLIENT_NAME, Some(CLIENT_SECRET)) + .json(&body2) + .send() + .unwrap(); + + println!("{}", res2.text().unwrap()); build().mount("/", routes![index]) } diff --git a/src/db.rs b/src/db.rs index 734ab00..e0eb17d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,9 +1,8 @@ -use std::{ - error::Error, - net::IpAddr, -}; +use std::{error::Error, net::IpAddr}; -use tokio_postgres::Client; +use json::JsonValue; +use log::warn; +use tokio_postgres::{Client, Row, Statement}; const ENDPOINT_TABLE: &str = "endpoints"; const HOSTS_RELATION_TABLE: &str = "hosts"; @@ -14,14 +13,14 @@ pub struct BoxyDatabase { } pub struct Endpoint { - pub id: Option, + pub id: Option, pub address: IpAddr, pub port: u16, pub callback: String, } impl Endpoint { - pub async fn new(id: Option, address: IpAddr, port: u16, callback: String) -> Self { + pub async fn new(id: Option, address: IpAddr, port: u16, callback: String) -> Self { Self { id, address, @@ -48,23 +47,97 @@ impl Endpoint { .await?; for row in rows { - result.push(Self { - id: row.get("id"), - address: row.get("address"), - port: row.get::<&str, i32>("port") as u16, - callback: row.get("callback"), - }); + result.push(row.into()); } Ok(result) } + pub async fn get_all(db: &BoxyDatabase) -> Result, Box> { + let mut result: Vec = Vec::new(); + + let rows = db + .client + .query(format!("SELECT * FROM {ENDPOINT_TABLE}").as_str(), &[]) + .await?; + + for row in rows { + result.push(row.into()); + } + + Ok(result) + } + pub async fn get_by_id(db: &BoxyDatabase, id: u32) -> Result, Box> { + let endpoint = db + .client + .query_one( + format!("SELECT * FROM {ENDPOINT_TABLE} WHERE id = $1").as_str(), + &[&(id as i32)], + ) + .await?; + + Ok(Some(endpoint.into())) + } +} + +impl From for Endpoint { + fn from(value: Row) -> Self { + Self { + id: Some(value.get::<&str, i32>("id") as u32), + address: value.get("address"), + port: value.get::<&str, i32>("port") as u16, + callback: value.get("callback"), + } + } } impl Endpoint { + pub async fn host( + &self, + db: &mut BoxyDatabase, + hostnames: Vec, + ) -> Result<(), tokio_postgres::Error> { + let tx = db.client.transaction().await?; + + let statement = tx + .prepare( + format!("INSERT INTO {HOSTS_RELATION_TABLE} (endpoint_id,hostname) VALUES ($1,$2)") + .as_str(), + ) + .await?; + + for host in hostnames { + tx.execute(&statement, &[&(self.id.unwrap() as i32), &host]) + .await?; + } + + tx.commit().await?; + + Ok(()) + } + pub async fn delete(self, db: &mut BoxyDatabase) -> Result<(), tokio_postgres::Error> { + let tx = db.client.transaction().await?; + + let id = self.id.unwrap() as i32; + + tx.execute( + format!("DELETE FROM {ENDPOINT_TABLE} where id = $1").as_str(), + &[&id], + ) + .await?; + + tx.commit().await?; + + warn!( + "Removed endpoint with ID: {}, address: {}:{}", + id, self.address, self.port + ); + + Ok(()) + } pub async fn register( &mut self, db: &mut BoxyDatabase, - hostname: String, + hostnames: Vec, ) -> Result<(), tokio_postgres::Error> { let tx = db.client.transaction().await?; @@ -81,16 +154,20 @@ impl Endpoint { .await? .get("id"); - tx.execute( - format!("INSERT INTO {HOSTS_RELATION_TABLE} (endpoint_id,hostname) VALUES ($1,$2)") - .as_str(), - &[&endpoint_id, &hostname], - ) - .await?; + let statement = tx + .prepare( + format!("INSERT INTO {HOSTS_RELATION_TABLE} (endpoint_id,hostname) VALUES ($1,$2)") + .as_str(), + ) + .await?; + + for host in hostnames { + tx.execute(&statement, &[&endpoint_id, &host]).await?; + } tx.commit().await?; - self.id = Some(endpoint_id); + self.id = Some(endpoint_id as u32); Ok(()) } @@ -118,8 +195,8 @@ impl BoxyDatabase { format!( "CREATE TABLE IF NOT EXISTS {HOSTS_RELATION_TABLE} ( - id SERIAL PRIMARY KEY, - endpoint_id int REFERENCES {HOSTS_RELATION_TABLE}(id), + id serial PRIMARY KEY, + endpoint_id int REFERENCES {ENDPOINT_TABLE}(id) ON DELETE CASCADE, hostname text ) " diff --git a/src/main.rs b/src/main.rs index 666d87a..671a19f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,27 @@ mod config; mod db; +mod health; +mod matchers; +mod routes; mod server; mod services; -use std::{env, process::exit, sync::Arc}; +use std::{env, process::exit, sync::Arc, time::Duration}; use bcrypt::DEFAULT_COST; use config::Config; use db::BoxyDatabase; use log::{debug, error, info}; +use matchers::api::ApiMatcher; use server::Server; -use services::{api::ApiService, controller::ControllerService}; -use tokio::sync::Mutex; +use services::{ + controller::ControllerService, + matcher::{Matcher, MatcherService}, +}; +use tokio::{ + sync::Mutex, + time::{self, interval}, +}; use tokio_postgres::NoTls; const VERSION: &str = "v0.1a"; @@ -68,13 +78,13 @@ async fn main() -> Result<(), Box> { let database_shared = Arc::new(Mutex::new(Box::leak(database))); - let api_svc = ApiService::new(database_shared.clone(), config.clone()).await; + let api_matcher = ApiMatcher::new(database_shared.clone(), config.clone()).await; let svc = ControllerService { - database: database_shared, + database: database_shared.clone(), }; - let api_server = Server::new(api_svc, (config.api.listen, config.api.port)) + let api_server = Server::new(api_matcher.service(), (config.api.listen, config.api.port)) .await .unwrap(); @@ -87,6 +97,15 @@ async fn main() -> Result<(), Box> { api_server.handle().await; }); + tokio::task::spawn(async move { + let mut interval = time::interval(Duration::from_secs(30)); + + loop { + health::check(*database_shared.lock().await).await; + interval.tick().await; + } + }); + // We don't put this on a separate thread because we'd be wasting the main thread. info!("Starting proxy server..."); proxy_server.handle().await; diff --git a/src/matchers.rs b/src/matchers.rs new file mode 100644 index 0000000..e5fdf85 --- /dev/null +++ b/src/matchers.rs @@ -0,0 +1 @@ +pub mod api; diff --git a/src/matchers/api.rs b/src/matchers/api.rs new file mode 100644 index 0000000..c8c108a --- /dev/null +++ b/src/matchers/api.rs @@ -0,0 +1,180 @@ +use std::{net::IpAddr, pin::Pin, sync::Arc}; + +use async_trait::async_trait; +use base64::{Engine, prelude::BASE64_STANDARD}; +use http::request::Parts; +use http_body_util::BodyExt; +use hyper::{ + Method, Request, StatusCode, + body::{self, Incoming}, + service::Service, +}; +use json::JsonValue; +use log::{debug, error, warn}; +use tokio::{net::TcpStream, sync::Mutex}; + +use crate::{ + config::{Client, Config}, + db::{BoxyDatabase, Endpoint}, + routes::api::{AddHost, RegisterEndpoint, RemoveHost}, + server::{GeneralResponse, TcpIntercept, custom_resp, default_response, json_to_vec}, + services::matcher::{Matcher, MatcherService}, +}; + +#[derive(Debug, Clone)] +pub struct ApiMatcher { + pub database: Arc>, + pub config: Config, + pub _address: Option, + pub body: Option, +} + +impl ApiMatcher { + pub async fn new(database: Arc>, config: Config) -> Self { + Self { + database, + config, + _address: None, + body: None, + } + } +} + +#[async_trait] +impl Matcher for ApiMatcher { + async fn unimatch( + &mut self, + req: &Request, + ) -> (bool, Option>) { + let address = self._address.unwrap(); + + let encoded_header = match req.headers().get(hyper::header::AUTHORIZATION) { + None => { + error!("Authorization header not given for request from {address}",); + + return ( + false, + Some(Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid credentials.".to_string(), + ) + .await)), + ); + } + Some(x) => x, + } + .to_str() + .unwrap(); + + debug!("authorization header: {}", encoded_header); + + let auth_bytes = match BASE64_STANDARD.decode(&encoded_header[6..]) { + Ok(x) => x, + Err(e) => { + error!("Error while decoding authorization header from {address}: {e}",); + + return ( + false, + Some(Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid base64 string given.".to_string(), + ) + .await)), + ); + } + }; + + let auth_string = match String::from_utf8(auth_bytes) { + Ok(x) => x, + Err(e) => { + error!("Error while decoding authorization header from {address}: {e}",); + + return ( + false, + Some(Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid UTF-8 in body.".to_string(), + ) + .await)), + ); + } + }; + + debug!("decoded auth string: {}", auth_string); + + if !Client::verify(auth_string.clone(), self.config.clone()).await { + warn!( + "Authentication for string {} from {} failed.", + auth_string, address + ); + + return ( + false, + Some(Ok(custom_resp( + StatusCode::UNAUTHORIZED, + "Invalid credentials.".to_string(), + ) + .await)), + ); + } + + return (true, None); + } + + fn retrieve(&self) -> Vec + Sync + Send>> { + vec![ + Arc::new(RegisterEndpoint {}), + Arc::new(AddHost {}), + Arc::new(RemoveHost {}), + ] + } + + fn stream(&mut self, stream: &TcpStream) { + self._address = Some(stream.peer_addr().unwrap().ip()); + } + + async fn body(&mut self, body: Incoming) -> Option> { + let address = self._address.unwrap(); + + let body_string = match String::from_utf8( + body.collect() + .await + .unwrap() + .to_bytes() + .iter() + .cloned() + .collect::>() + .clone(), + ) { + Ok(x) => x, + Err(e) => { + error!("Error while inferring UTF-8 string from {address}'s request body: {e}",); + + return Some(Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid UTF-8 in body.".to_string(), + ) + .await)); + } + }; + + debug!("body: {}", body_string); + + let json = match json::parse(body_string.as_str()) { + Ok(x) => x, + Err(e) => { + error!("Error while parsing JSON body from {address}: {e}",); + + return Some(Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Invalid JSON in body.".to_string(), + ) + .await)); + } + }; + + self.body = Some(json); + + None + } +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..e5fdf85 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1 @@ +pub mod api; diff --git a/src/routes/api.rs b/src/routes/api.rs new file mode 100644 index 0000000..d137093 --- /dev/null +++ b/src/routes/api.rs @@ -0,0 +1,157 @@ +use async_trait::async_trait; +use base64::{Engine, prelude::BASE64_STANDARD}; +use http::request::Parts; +use http_body_util::BodyExt; +use hyper::{Method, StatusCode}; +use log::{debug, error, warn}; + +use crate::{ + config::Client, + db::Endpoint, + matchers::api::ApiMatcher, + server::{custom_resp, json_to_vec}, + services::matcher::Route, +}; + +pub struct AddHost {} + +#[async_trait] +impl Route for AddHost { + fn matcher(&self, _: &ApiMatcher, req: &hyper::Request) -> bool { + req.uri().path().starts_with("/endpoint/") && req.method() == Method::POST + } + + async fn call( + &self, + m: &ApiMatcher, + parts: Parts, + ) -> Result { + let database = m.database.clone(); + let address = m._address.unwrap(); + let body = m.body.clone().unwrap(); + + let endpoint_id: u32 = parts.uri.path().replace("/endpoint/", "").parse().unwrap(); + + if !body["hosts"].is_array() { + error!("Hosts parameter is not an array.",); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Hosts parameter is not an array.".to_string(), + ) + .await); + } + + let endpoint = match Endpoint::get_by_id(*database.lock().await, endpoint_id) + .await + .unwrap() + { + Some(x) => x, + None => { + error!("No endpoint found by id {endpoint_id} from {address}",); + + return Ok(custom_resp( + StatusCode::NOT_FOUND, + "No endpoint by that ID.".to_string(), + ) + .await); + } + }; + + let hosts = json_to_vec(body["hosts"].clone()).await.unwrap(); + + endpoint.host(*database.lock().await, hosts).await.unwrap(); + + Ok(custom_resp(StatusCode::OK, "Success".to_string()).await) + } +} + +pub struct RegisterEndpoint {} + +#[async_trait] +impl Route for RegisterEndpoint { + fn matcher(&self, _: &ApiMatcher, req: &hyper::Request) -> bool { + req.uri().path() == "/register" && req.method() == Method::POST + } + + async fn call( + &self, + m: &ApiMatcher, + _: Parts, + ) -> Result { + let address = m._address.unwrap(); + let database = m.database.clone(); + let body = m.body.clone().unwrap(); + + let mut endpoint = Endpoint::new( + None, + address, + body["port"].as_u16().unwrap_or(8080), + body["callback"].as_str().unwrap_or("/").to_string(), + ) + .await; + + if !body["hosts"].is_array() { + error!("Hosts parameter is not an array.",); + + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "Hosts parameter is not an array.".to_string(), + ) + .await); + }; + + let hosts = json_to_vec(body["hosts"].clone()).await.unwrap(); + + endpoint + .register(*database.lock().await, hosts) + .await + .unwrap(); + + let endpoint_id = endpoint.id.unwrap().to_string(); + + let response = custom_resp(StatusCode::OK, endpoint_id).await; + + Ok(response) + } +} + +pub struct RemoveHost {} + +#[async_trait] +impl Route for RemoveHost { + fn matcher(&self, _: &ApiMatcher, req: &hyper::Request) -> bool { + req.uri().path().starts_with("/endpoint/") && req.method() == Method::DELETE + } + + async fn call( + &self, + m: &ApiMatcher, + parts: Parts, + ) -> Result { + let database = m.database.clone(); + let address = m._address.unwrap(); + + let endpoint_id: u32 = parts.uri.path().replace("/endpoint/", "").parse().unwrap(); + + let endpoint = match Endpoint::get_by_id(*database.lock().await, endpoint_id) + .await + .unwrap() + { + Some(x) => x, + None => { + error!("No endpoint found by id {endpoint_id} from {address}",); + + return Ok(custom_resp( + StatusCode::NOT_FOUND, + "No endpoint by that ID.".to_string(), + ) + .await); + } + }; + + endpoint.delete(*database.lock().await).await.unwrap(); + + Ok(custom_resp(StatusCode::OK, "Success".to_string()).await) + } +} diff --git a/src/server.rs b/src/server.rs index 52cad1d..662bdec 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,9 +2,13 @@ use std::{any::type_name_of_val, error::Error}; use http_body_util::{Either, Full}; use hyper::{ - body::{Body, Bytes, Incoming}, server::conn::http1, service::{HttpService, Service}, Request, Response, StatusCode + Request, Response, StatusCode, + body::{Body, Bytes, Incoming}, + server::conn::http1, + service::{HttpService, Service}, }; use hyper_util::rt::TokioIo; +use json::JsonValue; use log::{error, info}; use tokio::net::{TcpListener, TcpStream}; @@ -34,13 +38,25 @@ pub async fn default_response() -> GeneralResponse { .unwrap() } -pub async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse { +pub async fn custom_resp(e: StatusCode, m: String) -> GeneralResponse { Response::builder() .status(e) .body(GeneralBody::Right(Full::from(Bytes::from(m)))) .unwrap() } +pub async fn json_to_vec(v: JsonValue) -> Option> { + if let JsonValue::Array(arr) = v { + Some( + arr.into_iter() + .map(|val| val.as_str().unwrap().to_string()) + .collect(), + ) + } else { + None + } +} + impl Server where S: TcpIntercept, diff --git a/src/services.rs b/src/services.rs index 168dbf8..381d0dc 100644 --- a/src/services.rs +++ b/src/services.rs @@ -1,3 +1,3 @@ -pub mod api; pub mod controller; pub mod proxy; +pub mod matcher; diff --git a/src/services/api.rs b/src/services/api.rs deleted file mode 100644 index ee86312..0000000 --- a/src/services/api.rs +++ /dev/null @@ -1,186 +0,0 @@ -use std::{net::IpAddr, pin::Pin, sync::Arc}; - -use base64::{Engine, prelude::BASE64_STANDARD}; -use http_body_util::BodyExt; -use hyper::{ - Method, Request, StatusCode, - body::Incoming, - service::Service, -}; -use log::{debug, error, warn}; -use tokio::{net::TcpStream, sync::Mutex}; - -use crate::{ - config::{Client, Config}, - db::{BoxyDatabase, Endpoint}, - server::{custom_resp, default_response, GeneralResponse, TcpIntercept}, -}; - -#[derive(Debug, Clone)] -pub struct ApiService { - pub database: Arc>, - pub config: Config, - pub _address: Option, -} - - -impl TcpIntercept for ApiService { - fn stream(&mut self, stream: &TcpStream) { - self._address = Some(stream.peer_addr().unwrap().ip()); - } -} - -impl ApiService { - pub async fn new(database: Arc>, config: Config) -> Self { - Self { - database, - config, - _address: None, - } - } -} - -impl Service> for ApiService { - type Response = GeneralResponse; - type Error = hyper::Error; - type Future = Pin> + Send>>; - - fn call(&self, req: Request) -> Self::Future { - let database = self.database.clone(); - let config = self.config.clone(); - let address = self._address.unwrap(); - - Box::pin(async move { - match *req.method() { - Method::POST => match req.uri().path() { - "/register" => { - debug!("new api register request from {}", address); - - let encoded_header = - match req.headers().get(hyper::header::AUTHORIZATION) { - None => { - error!( - "Authorization header not given for request from {address}", - ); - - return Ok(custom_resp( - StatusCode::BAD_REQUEST, - "Invalid credentials.", - ) - .await); - } - Some(x) => x, - } - .to_str() - .unwrap(); - - debug!("authorization header: {}", encoded_header); - - let auth_bytes = match BASE64_STANDARD.decode(&encoded_header[6..]) { - Ok(x) => x, - Err(e) => { - error!( - "Error while decoding authorization header from {address}: {e}", - ); - - return Ok(custom_resp( - StatusCode::BAD_REQUEST, - "Invalid base64 string given.", - ) - .await); - } - }; - - let auth_string = match String::from_utf8(auth_bytes) { - Ok(x) => x, - Err(e) => { - error!( - "Error while decoding authorization header from {address}: {e}", - ); - - return Ok(custom_resp( - StatusCode::BAD_REQUEST, - "Invalid UTF-8 in authentication string.", - ) - .await); - } - }; - - debug!("decoded auth string: {}", auth_string); - - if !Client::verify(auth_string.clone(), config).await { - warn!( - "Authentication for string {} from {} failed.", - auth_string, address - ); - - return Ok(custom_resp( - StatusCode::UNAUTHORIZED, - "Invalid credentials.", - ) - .await); - } - - let body = match String::from_utf8( - req.collect() - .await - .unwrap() - .to_bytes() - .iter() - .cloned() - .collect::>(), - ) { - Ok(x) => x, - Err(e) => { - error!( - "Error while inferring UTF-8 string from {address}'s request body: {e}", - ); - - return Ok(custom_resp( - StatusCode::BAD_REQUEST, - "Invalid UTF-8 in body.", - ) - .await); - } - }; - - let json = match json::parse(body.as_str()) { - Ok(x) => x, - Err(e) => { - error!("Error while parsing JSON body from {address}: {e}",); - - return Ok(custom_resp( - StatusCode::BAD_REQUEST, - "Invalid JSON in body.", - ) - .await); - } - }; - - debug!("body: {}", body); - - let mut endpoint = Endpoint::new( - None, - address, - json["port"].as_u16().unwrap_or(8080), - json["callback"].as_str().unwrap_or("/").to_string(), - ) - .await; - - endpoint - .register( - *database.lock().await, - json["hostname"].as_str().unwrap().to_string(), - ) - .await - .unwrap(); - - Ok(custom_resp(StatusCode::OK, "Success").await) - } - _ => Ok(default_response().await), - }, - _ => Ok(default_response().await), - } - }) - } -} diff --git a/src/services/controller.rs b/src/services/controller.rs index 2ae7ccc..628f432 100644 --- a/src/services/controller.rs +++ b/src/services/controller.rs @@ -33,7 +33,11 @@ impl Service> for ControllerService { None => { error!("No host header given."); - return Ok(custom_resp(StatusCode::BAD_REQUEST, "No host header given.").await); + return Ok(custom_resp( + StatusCode::BAD_REQUEST, + "No host header given.".to_string(), + ) + .await); } } .to_str() @@ -49,9 +53,11 @@ impl Service> for ControllerService { None => { error!("No endpoint found for request."); - return Ok( - custom_resp(StatusCode::NOT_FOUND, "No endpoint found for host.").await, - ); + return Ok(custom_resp( + StatusCode::NOT_FOUND, + "No endpoint found for host.".to_string(), + ) + .await); } }; diff --git a/src/services/matcher.rs b/src/services/matcher.rs new file mode 100644 index 0000000..fbcb074 --- /dev/null +++ b/src/services/matcher.rs @@ -0,0 +1,129 @@ +use std::{net::IpAddr, pin::Pin, sync::Arc}; + +use async_trait::async_trait; +use base64::{Engine, prelude::BASE64_STANDARD}; +use http::request::Parts; +use http_body_util::BodyExt; +use hyper::{ + Method, Request, StatusCode, + body::{self, Incoming}, + service::Service, +}; +use log::{debug, error, warn}; +use tokio::{net::TcpStream, sync::Mutex}; + +use crate::{ + config::{Client, Config}, + db::{BoxyDatabase, Endpoint}, + server::{GeneralResponse, TcpIntercept, custom_resp, default_response, json_to_vec}, +}; + +// The routes itself +#[async_trait] +pub trait Route +where + T: Matcher, +{ + fn matcher(&self, m: &T, req: &Request) -> bool; + async fn call(&self, m: &T, parts: Parts) -> Result; +} + +// Matcher, essentially just a router that contains routes and some other features +#[async_trait] +pub trait Matcher: Clone + Send + Sync + 'static { + // Essentially a kind of "middleware", a universal matcher. If it doesn't match, it won't + // route. + async fn unimatch( + &mut self, + req: &Request, + ) -> (bool, Option>); + + // Return list of routes associated with self matcher + fn retrieve(&self) -> Vec + Sync + Send>>; + + // Wrap self into matcher service + fn service(self) -> MatcherService { + MatcherService::new(self) + } + + // Do something with TCP stream + fn stream(&mut self, stream: &TcpStream) {} + + // Body parser - made universal for api server cause lazy + async fn body(&mut self, body: Incoming) -> Option> { + None + } +} + +// Wrapper service, wraps matcher into a service +#[derive(Clone)] +pub struct MatcherService +where + T: Matcher, +{ + inner: T, +} + +impl MatcherService +where + T: Matcher, +{ + pub fn new(inner: T) -> Self { + Self { inner } + } +} + +impl Service> for MatcherService +where + T: Matcher, +{ + type Response = GeneralResponse; + type Error = hyper::Error; + type Future = Pin> + Send>>; + + fn call(&self, req: Request) -> Self::Future { + let mut matcher = self.inner.clone(); + + Box::pin(async move { + let unimatched = matcher.unimatch(&req).await; + + if !unimatched.0 { + match unimatched.1 { + Some(x) => { + return x; + } + None => { + return Ok(custom_resp( + StatusCode::NOT_FOUND, + "Could not match route".to_string(), + ) + .await); + } + } + } + + for r in matcher.retrieve() { + if r.matcher(&matcher, &req) { + let (parts, body) = req.into_parts(); + + if let Some(resp) = matcher.body(body).await { + return resp; + } + + return r.call(&matcher, parts).await; + } + } + + Ok(default_response().await) + }) + } +} + +impl TcpIntercept for MatcherService +where + T: Matcher, +{ + fn stream(&mut self, stream: &TcpStream) { + self.inner.stream(stream); + } +} diff --git a/src/services/proxy.rs b/src/services/proxy.rs index 47b0a5e..0c59f3f 100644 --- a/src/services/proxy.rs +++ b/src/services/proxy.rs @@ -29,7 +29,7 @@ impl Service> for ProxyService { return Ok(custom_resp( StatusCode::BAD_GATEWAY, - "Unable to open connection to endpoint.", + "Unable to open connection to endpoint.".to_string(), ) .await); } From 89df8c684b0782656f6ce0bcdb3e114e21216d07 Mon Sep 17 00:00:00 2001 From: hex Date: Sat, 2 Aug 2025 20:41:28 +0200 Subject: [PATCH 11/19] chore: cargo fmt --- src/health.rs | 2 +- src/services.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/health.rs b/src/health.rs index 83cfbc3..82fc7eb 100644 --- a/src/health.rs +++ b/src/health.rs @@ -26,7 +26,7 @@ pub async fn check(db: &mut BoxyDatabase) { continue; } }; - + let io = TokioIo::new(stream); let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await.unwrap(); diff --git a/src/services.rs b/src/services.rs index 381d0dc..a2b6a6c 100644 --- a/src/services.rs +++ b/src/services.rs @@ -1,3 +1,3 @@ pub mod controller; -pub mod proxy; pub mod matcher; +pub mod proxy; From 8092c07ee6a21fe2c464bb06cf705528079d7949 Mon Sep 17 00:00:00 2001 From: hex Date: Sat, 2 Aug 2025 20:43:23 +0200 Subject: [PATCH 12/19] chore: cargo fix --- src/db.rs | 3 +-- src/main.rs | 4 ++-- src/matchers/api.rs | 14 ++++++-------- src/routes/api.rs | 5 +---- src/services/matcher.rs | 21 ++++++--------------- 5 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/db.rs b/src/db.rs index e0eb17d..3fa8d5d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,8 +1,7 @@ use std::{error::Error, net::IpAddr}; -use json::JsonValue; use log::warn; -use tokio_postgres::{Client, Row, Statement}; +use tokio_postgres::{Client, Row}; const ENDPOINT_TABLE: &str = "endpoints"; const HOSTS_RELATION_TABLE: &str = "hosts"; diff --git a/src/main.rs b/src/main.rs index 671a19f..42b6a58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,11 +16,11 @@ use matchers::api::ApiMatcher; use server::Server; use services::{ controller::ControllerService, - matcher::{Matcher, MatcherService}, + matcher::Matcher, }; use tokio::{ sync::Mutex, - time::{self, interval}, + time::{self}, }; use tokio_postgres::NoTls; diff --git a/src/matchers/api.rs b/src/matchers/api.rs index c8c108a..da62e4b 100644 --- a/src/matchers/api.rs +++ b/src/matchers/api.rs @@ -1,13 +1,11 @@ -use std::{net::IpAddr, pin::Pin, sync::Arc}; +use std::{net::IpAddr, sync::Arc}; use async_trait::async_trait; use base64::{Engine, prelude::BASE64_STANDARD}; -use http::request::Parts; use http_body_util::BodyExt; use hyper::{ - Method, Request, StatusCode, - body::{self, Incoming}, - service::Service, + Request, StatusCode, + body::Incoming, }; use json::JsonValue; use log::{debug, error, warn}; @@ -15,10 +13,10 @@ use tokio::{net::TcpStream, sync::Mutex}; use crate::{ config::{Client, Config}, - db::{BoxyDatabase, Endpoint}, + db::BoxyDatabase, routes::api::{AddHost, RegisterEndpoint, RemoveHost}, - server::{GeneralResponse, TcpIntercept, custom_resp, default_response, json_to_vec}, - services::matcher::{Matcher, MatcherService}, + server::{GeneralResponse, custom_resp}, + services::matcher::Matcher, }; #[derive(Debug, Clone)] diff --git a/src/routes/api.rs b/src/routes/api.rs index d137093..8461fb4 100644 --- a/src/routes/api.rs +++ b/src/routes/api.rs @@ -1,12 +1,9 @@ use async_trait::async_trait; -use base64::{Engine, prelude::BASE64_STANDARD}; use http::request::Parts; -use http_body_util::BodyExt; use hyper::{Method, StatusCode}; -use log::{debug, error, warn}; +use log::error; use crate::{ - config::Client, db::Endpoint, matchers::api::ApiMatcher, server::{custom_resp, json_to_vec}, diff --git a/src/services/matcher.rs b/src/services/matcher.rs index fbcb074..3618f93 100644 --- a/src/services/matcher.rs +++ b/src/services/matcher.rs @@ -1,22 +1,11 @@ -use std::{net::IpAddr, pin::Pin, sync::Arc}; +use std::{pin::Pin, sync::Arc}; use async_trait::async_trait; -use base64::{Engine, prelude::BASE64_STANDARD}; use http::request::Parts; -use http_body_util::BodyExt; -use hyper::{ - Method, Request, StatusCode, - body::{self, Incoming}, - service::Service, -}; -use log::{debug, error, warn}; -use tokio::{net::TcpStream, sync::Mutex}; +use hyper::{Request, StatusCode, body::Incoming, service::Service}; +use tokio::net::TcpStream; -use crate::{ - config::{Client, Config}, - db::{BoxyDatabase, Endpoint}, - server::{GeneralResponse, TcpIntercept, custom_resp, default_response, json_to_vec}, -}; +use crate::server::{GeneralResponse, TcpIntercept, custom_resp, default_response}; // The routes itself #[async_trait] @@ -47,9 +36,11 @@ pub trait Matcher: Clone + Send + Sync + 'static { } // Do something with TCP stream + #[allow(unused_variables)] fn stream(&mut self, stream: &TcpStream) {} // Body parser - made universal for api server cause lazy + #[allow(unused_variables)] async fn body(&mut self, body: Incoming) -> Option> { None } From cfaf03f04acc079607e2c4582168617980cd0289 Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 00:59:26 +0200 Subject: [PATCH 13/19] add: todo checker --- .woodpecker/todo.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .woodpecker/todo.yaml diff --git a/.woodpecker/todo.yaml b/.woodpecker/todo.yaml new file mode 100644 index 0000000..9258955 --- /dev/null +++ b/.woodpecker/todo.yaml @@ -0,0 +1,8 @@ +when: + - event: push + branch: dev +steps: + - name: 'Check TODOs' + image: codeberg.org/epsilon_02/todo-checker + settings: + single_issue_check: true From 16018112786a5af06e5855ca90e598b14806e12e Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:00:36 +0200 Subject: [PATCH 14/19] add todo --- examples/example-server/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/example-server/src/main.rs b/examples/example-server/src/main.rs index 52638b7..0bcf16d 100644 --- a/examples/example-server/src/main.rs +++ b/examples/example-server/src/main.rs @@ -18,6 +18,8 @@ fn index() -> &'static str { #[launch] fn rocket() -> _ { + // TODO: clean up example code + // This is the example backend client. (The stereo.cat backend for example). let client = reqwest::blocking::Client::new(); From 64beaa043a3761b30a08bb24946814716680470a Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:01:38 +0200 Subject: [PATCH 15/19] test --- .test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .test diff --git a/.test b/.test new file mode 100644 index 0000000..e69de29 From 46fb165021322226c79bad1f27f842a214ab551d Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:23:48 +0200 Subject: [PATCH 16/19] f: swap todo for formatter --- .woodpecker/formatter.yaml | 14 ++++++++++++++ .woodpecker/todo.yaml | 8 -------- 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 .woodpecker/formatter.yaml delete mode 100644 .woodpecker/todo.yaml diff --git a/.woodpecker/formatter.yaml b/.woodpecker/formatter.yaml new file mode 100644 index 0000000..1885843 --- /dev/null +++ b/.woodpecker/formatter.yaml @@ -0,0 +1,14 @@ +when: + - event: push + branch: ${CI_REPO_DEFAULT_BRANCH} + - event: pull_request + +steps: + - name: 'Check w/ Prettier' + image: woodpeckerci/plugin-prettier:next + settings: + single_issue_check: true + - name: 'Check w/ Cargo' + image: rust:1.88 + commands: + - cargo check diff --git a/.woodpecker/todo.yaml b/.woodpecker/todo.yaml deleted file mode 100644 index 9258955..0000000 --- a/.woodpecker/todo.yaml +++ /dev/null @@ -1,8 +0,0 @@ -when: - - event: push - branch: dev -steps: - - name: 'Check TODOs' - image: codeberg.org/epsilon_02/todo-checker - settings: - single_issue_check: true From f9cca163ffd56f24db8dfbca3f2aa4faa920e2e3 Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:48:18 +0200 Subject: [PATCH 17/19] add shit --- .woodpecker/audit.yaml | 10 ++++++++++ .woodpecker/check.yaml | 9 +++++++++ .woodpecker/formatter.yaml | 14 +++++++------- src/main.rs | 5 +---- src/matchers/api.rs | 5 +---- 5 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 .woodpecker/audit.yaml create mode 100644 .woodpecker/check.yaml diff --git a/.woodpecker/audit.yaml b/.woodpecker/audit.yaml new file mode 100644 index 0000000..fa19d1e --- /dev/null +++ b/.woodpecker/audit.yaml @@ -0,0 +1,10 @@ +when: + - event: push + branch: ${CI_REPO_DEFAULT_BRANCH} + +steps: + - name: 'Format w/ Carg' + image: rust:1.88 + commands: + - cargo install cargo-audit + - cargo audit diff --git a/.woodpecker/check.yaml b/.woodpecker/check.yaml new file mode 100644 index 0000000..600779b --- /dev/null +++ b/.woodpecker/check.yaml @@ -0,0 +1,9 @@ +when: + - event: push + branch: ${CI_REPO_DEFAULT_BRANCH} + +steps: + - name: 'Format w/ Carg' + image: rust:1.88 + commands: + - cargo check diff --git a/.woodpecker/formatter.yaml b/.woodpecker/formatter.yaml index 1885843..af280c2 100644 --- a/.woodpecker/formatter.yaml +++ b/.woodpecker/formatter.yaml @@ -1,14 +1,14 @@ when: - event: push branch: ${CI_REPO_DEFAULT_BRANCH} - - event: pull_request steps: - - name: 'Check w/ Prettier' - image: woodpeckerci/plugin-prettier:next - settings: - single_issue_check: true - - name: 'Check w/ Cargo' + - name: 'Format w/ Cargo' image: rust:1.88 commands: - - cargo check + - cargo fmt + - name: 'Push formatted' + image: appleboy/drone-git-push + settings: + remote_name: origin + branch: ${CI_COMMIT_BRANCH} diff --git a/src/main.rs b/src/main.rs index 42b6a58..b4ddad3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,7 @@ use db::BoxyDatabase; use log::{debug, error, info}; use matchers::api::ApiMatcher; use server::Server; -use services::{ - controller::ControllerService, - matcher::Matcher, -}; +use services::{controller::ControllerService, matcher::Matcher}; use tokio::{ sync::Mutex, time::{self}, diff --git a/src/matchers/api.rs b/src/matchers/api.rs index da62e4b..10ad87c 100644 --- a/src/matchers/api.rs +++ b/src/matchers/api.rs @@ -3,10 +3,7 @@ use std::{net::IpAddr, sync::Arc}; use async_trait::async_trait; use base64::{Engine, prelude::BASE64_STANDARD}; use http_body_util::BodyExt; -use hyper::{ - Request, StatusCode, - body::Incoming, -}; +use hyper::{Request, StatusCode, body::Incoming}; use json::JsonValue; use log::{debug, error, warn}; use tokio::{net::TcpStream, sync::Mutex}; From 3eeb5fd4b30a999cc3a04cb9d45ebb79ee0edbee Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:49:35 +0200 Subject: [PATCH 18/19] remove .test --- .test | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .test diff --git a/.test b/.test deleted file mode 100644 index e69de29..0000000 From 985b1d3810dc89b3f6a0101ea5b7e0c157891cfe Mon Sep 17 00:00:00 2001 From: hex Date: Sun, 3 Aug 2025 01:56:31 +0200 Subject: [PATCH 19/19] fix formatter ci --- .woodpecker/audit.yaml | 2 +- .woodpecker/check.yaml | 2 +- .woodpecker/formatter.yaml | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.woodpecker/audit.yaml b/.woodpecker/audit.yaml index fa19d1e..78c2915 100644 --- a/.woodpecker/audit.yaml +++ b/.woodpecker/audit.yaml @@ -3,7 +3,7 @@ when: branch: ${CI_REPO_DEFAULT_BRANCH} steps: - - name: 'Format w/ Carg' + - name: 'audit dependencies' image: rust:1.88 commands: - cargo install cargo-audit diff --git a/.woodpecker/check.yaml b/.woodpecker/check.yaml index 600779b..c069e98 100644 --- a/.woodpecker/check.yaml +++ b/.woodpecker/check.yaml @@ -3,7 +3,7 @@ when: branch: ${CI_REPO_DEFAULT_BRANCH} steps: - - name: 'Format w/ Carg' + - name: 'Check code' image: rust:1.88 commands: - cargo check diff --git a/.woodpecker/formatter.yaml b/.woodpecker/formatter.yaml index af280c2..25d4d5d 100644 --- a/.woodpecker/formatter.yaml +++ b/.woodpecker/formatter.yaml @@ -6,9 +6,14 @@ steps: - name: 'Format w/ Cargo' image: rust:1.88 commands: + - rustup component add rustfmt - cargo fmt + - name: 'Push formatted' image: appleboy/drone-git-push settings: remote_name: origin branch: ${CI_COMMIT_BRANCH} + commit: true + commit_message: "[skip ci] chore: automated code formatting" + author_name: "Woodpecker CI"