diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ff21ab..805daf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Build run: cargo build --verbose diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml index 89aa8c6..9418a95 100644 --- a/.github/workflows/manual-release.yml +++ b/.github/workflows/manual-release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Ruby and FPM run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c84f670..84444ca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Ruby and FPM run: | diff --git a/.github/workflows/update-openapi-docs.yml b/.github/workflows/update-openapi-docs.yml index 4ee633d..2b244c0 100644 --- a/.github/workflows/update-openapi-docs.yml +++ b/.github/workflows/update-openapi-docs.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/Cargo.lock b/Cargo.lock index 2b25d3e..3e2fee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # 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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "allocator-api2" version = "0.2.21" @@ -34,9 +19,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -49,9 +34,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -64,22 +49,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -108,17 +93,23 @@ dependencies = [ "num-traits", ] +[[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.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.8.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "bytes", @@ -135,8 +126,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -150,9 +140,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", @@ -161,7 +151,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -179,27 +168,6 @@ dependencies = [ "syn", ] -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -208,9 +176,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bindizr" @@ -225,13 +193,14 @@ dependencies = [ "hex", "log", "once_cell", - "rand 0.9.1", + "rand 0.9.2", "rndc", "serde", "serde_json", "sha2", "sqlx", "tempfile", + "thiserror", "tokio", "tower", "tower-http", @@ -240,11 +209,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -258,9 +227,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "byteorder" @@ -270,30 +239,31 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", "js-sys", @@ -305,9 +275,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -315,9 +285,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -327,9 +297,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -339,9 +309,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "colorchoice" @@ -360,9 +330,9 @@ dependencies = [ [[package]] name = "config" -version = "0.15.11" +version = "0.15.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" dependencies = [ "async-trait", "convert_case", @@ -370,7 +340,8 @@ dependencies = [ "pathdiff", "ron", "rust-ini", - "serde", + "serde-untagged", + "serde_core", "serde_json", "toml", "winnow", @@ -398,7 +369,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "tiny-keccak", ] @@ -429,9 +400,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -459,15 +430,15 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -546,14 +517,25 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -569,9 +551,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -584,6 +566,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + [[package]] name = "flume" version = "0.11.1" @@ -595,12 +583,6 @@ dependencies = [ "spin", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -609,9 +591,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -700,33 +682,27 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "hashbrown" version = "0.14.5" @@ -735,22 +711,28 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + [[package]] name = "hashlink" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.3", + "hashbrown 0.15.5", ] [[package]] @@ -785,21 +767,20 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -840,31 +821,33 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", ] [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "hyper", @@ -899,21 +882,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -922,104 +906,66 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", + "icu_locale_core", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1028,9 +974,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1038,42 +984,31 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.3", -] - -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags", - "cfg-if", - "libc", + "hashbrown 0.16.1", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -1101,9 +1036,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" @@ -1111,6 +1046,17 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall 0.7.0", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -1124,31 +1070,30 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "matchit" @@ -1168,9 +1113,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1178,33 +1123,23 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -1245,15 +1180,6 @@ dependencies = [ "libm", ] -[[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" @@ -1262,9 +1188,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "ordered-multimap" @@ -1284,9 +1210,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1294,15 +1220,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1322,26 +1248,25 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" dependencies = [ "memchr", - "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" dependencies = [ "pest", "pest_generator", @@ -1349,9 +1274,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" dependencies = [ "pest", "pest_meta", @@ -1362,11 +1287,10 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -1410,6 +1334,15 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1421,27 +1354,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -1456,12 +1389,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1481,7 +1414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1490,60 +1423,71 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ "bitflags", ] [[package]] name = "rndc" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500451c106871c925a9262f242010511f1696cce6767e7a01efede87c3277f42" +checksum = "e721e804da6ec80c1142f5e0d46d65937babcc8bd20630664ad7098db3c05762" dependencies = [ - "base64 0.22.1", + "base64", "byteorder", "hmac", "indexmap", "md-5", - "rand 0.9.1", + "rand 0.9.2", "sha1", "sha2", ] [[package]] name = "ron" -version = "0.8.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" dependencies = [ - "base64 0.21.7", "bitflags", + "once_cell", "serde", "serde_derive", + "typeid", + "unicode-ident", ] [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -1561,45 +1505,38 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.21.1" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" dependencies = [ "cfg-if", "ordered-multimap", - "trim-in-place", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "scopeguard" @@ -1609,18 +1546,40 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -1629,33 +1588,35 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1700,10 +1661,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -1719,27 +1681,27 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] [[package]] name = "socket2" -version = "0.5.9" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -1780,7 +1742,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "chrono", "crc", @@ -1791,7 +1753,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "hashlink", "indexmap", "log", @@ -1854,7 +1816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64 0.22.1", + "base64", "bitflags", "byteorder", "bytes", @@ -1897,7 +1859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64 0.22.1", + "base64", "bitflags", "byteorder", "chrono", @@ -1955,9 +1917,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stringprep" @@ -1984,9 +1946,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -2012,31 +1974,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.21.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2054,9 +2016,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2064,9 +2026,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -2079,29 +2041,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.46.1" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -2110,9 +2069,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -2121,43 +2080,40 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ - "serde", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "toml_edit" -version = "0.22.26" +name = "toml_parser" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", "winnow", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -2171,9 +2127,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", @@ -2197,9 +2153,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -2209,9 +2165,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -2220,24 +2176,24 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] [[package]] -name = "trim-in-place" -version = "0.1.7" +name = "typeid" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -2253,24 +2209,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" @@ -2280,21 +2236,16 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2321,17 +2272,17 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -2342,9 +2293,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -2353,25 +2304,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2379,41 +2316,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", ] [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -2424,9 +2361,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -2435,9 +2372,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -2446,24 +2383,24 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -2479,20 +2416,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2512,18 +2449,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", "windows_i686_gnullvm", - "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", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2534,9 +2472,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -2546,9 +2484,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -2558,15 +2496,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -2576,9 +2514,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -2588,9 +2526,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -2600,9 +2538,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -2612,45 +2550,36 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" 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 = "write16" -version = "1.0.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yaml-rust2" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b783b2c2789414f8bb84ca3318fc9c2d7e7be1c22907d37839a58dedb369d3" +checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9" dependencies = [ "arraydeque", "encoding_rs", @@ -2659,11 +2588,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -2671,9 +2599,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -2683,18 +2611,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", @@ -2724,15 +2652,26 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2741,11 +2680,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" diff --git a/Cargo.toml b/Cargo.toml index 3cbb4c8..9683453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,10 +39,11 @@ sqlx = { version = "0.8", features = [ "sqlite", "chrono", ] } -rndc = "0.1.3" +rndc = "0.1.4" rand = "0.9" sha2 = "0.10" hex = "0.4" +thiserror = "2.0.17" [dev-dependencies] tempfile = "3.21.0" diff --git a/renovate.json b/renovate.json index 9789b7e..5ab33b5 100644 --- a/renovate.json +++ b/renovate.json @@ -6,6 +6,7 @@ "baseBranches": [ "develop" ], + "automerge": true, "packageRules": [ { "matchPackagePatterns": [ diff --git a/src/api/controller/dns.rs b/src/api/controller/dns.rs index 11a7f72..f1e319b 100644 --- a/src/api/controller/dns.rs +++ b/src/api/controller/dns.rs @@ -15,39 +15,30 @@ impl DnsController { async fn get_dns_status() -> impl IntoResponse { let status = match DnsService::get_dns_status() { Ok(status) => status, - Err(err) => { - let json_body = json!({ "error": format!("Failed to get DNS status: {}", err) }); - return (StatusCode::INTERNAL_SERVER_ERROR, Json(json_body)); - } + Err(err) => return err.into_response(), }; let json_body = json!({ "status": status }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn reload_dns() -> impl IntoResponse { let msg = match DnsService::reload_dns() { Ok(msg) => msg, - Err(err) => { - let json_body = json!({ "error": format!("Failed to reload DNS: {}", err) }); - return (StatusCode::INTERNAL_SERVER_ERROR, Json(json_body)); - } + Err(err) => return err.into_response(), }; let json_body = json!({ "msg": msg }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn write_dns_config() -> impl IntoResponse { match DnsService::write_dns_config().await { Ok(msg) => { let json_body = json!({ "msg": msg }); - (StatusCode::OK, Json(json_body)) - } - Err(err) => { - let json_body = json!({ "error": format!("Failed to write DNS config: {}", err) }); - (StatusCode::INTERNAL_SERVER_ERROR, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } + Err(err) => err.into_response(), } } } diff --git a/src/api/controller/middleware/body_parser.rs b/src/api/controller/middleware/body_parser.rs index 3121e6a..f195606 100644 --- a/src/api/controller/middleware/body_parser.rs +++ b/src/api/controller/middleware/body_parser.rs @@ -4,19 +4,19 @@ use serde_json::json; use crate::log_error; -// create an extractor that internally uses `axum::Json` but has a custom rejection +// Custom extractor for JSON body with error handling #[derive(FromRequest)] #[from_request(via(axum::Json), rejection(ApiError))] pub struct JsonBody(pub T); -// We create our own rejection type +// Custom API error type for handling JSON extraction errors #[derive(Debug)] pub struct ApiError { code: StatusCode, message: String, } -// We implement `From for ApiError` +// Implement conversion from JsonRejection to ApiError impl From for ApiError { fn from(rejection: JsonRejection) -> Self { let code = match rejection { @@ -35,7 +35,6 @@ impl From for ApiError { } } -// We implement `IntoResponse` so `ApiError` can be used as a response impl IntoResponse for ApiError { fn into_response(self) -> axum::response::Response { let payload = json!({ diff --git a/src/api/controller/record.rs b/src/api/controller/record.rs index 64f6e9b..c45f35c 100644 --- a/src/api/controller/record.rs +++ b/src/api/controller/record.rs @@ -30,10 +30,7 @@ impl RecordController { let raw_records = match RecordService::get_records(zone_id).await { Ok(records) => records, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let records = raw_records @@ -42,7 +39,7 @@ impl RecordController { .collect::>(); let json_body = json!({ "records": records }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn get_record(Path(params): Path) -> impl IntoResponse { @@ -50,31 +47,25 @@ impl RecordController { let raw_record = match RecordService::get_record(record_id).await { Ok(record) => record, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let record = GetRecordResponse::from_record(&raw_record); let json_body = json!({ "record": record }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn create_record(JsonBody(body): JsonBody) -> impl IntoResponse { let raw_record = match RecordService::create_record(&body).await { Ok(record) => record, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let record = GetRecordResponse::from_record(&raw_record); let json_body = json!({ "record": record }); - (StatusCode::CREATED, Json(json_body)) + (StatusCode::CREATED, Json(json_body)).into_response() } async fn update_record( @@ -85,16 +76,13 @@ impl RecordController { let raw_record = match RecordService::update_record(record_id, &body).await { Ok(record) => record, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let record = GetRecordResponse::from_record(&raw_record); let json_body = json!({ "record": record }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn delete_record(Path(params): Path) -> impl IntoResponse { @@ -103,12 +91,9 @@ impl RecordController { match RecordService::delete_record(record_id).await { Ok(_) => { let json_body = json!({ "message": "Record deleted successfully" }); - (StatusCode::OK, Json(json_body)) - } - Err(err) => { - let json_body = json!({ "error": err }); - (StatusCode::BAD_REQUEST, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } + Err(err) => err.into_response(), } } } diff --git a/src/api/controller/record_history.rs b/src/api/controller/record_history.rs index caa508f..a42c756 100644 --- a/src/api/controller/record_history.rs +++ b/src/api/controller/record_history.rs @@ -27,10 +27,7 @@ impl RecordHistoryController { let raw_record_histories = match RecordHistoryService::get_record_histories(record_id).await { Ok(record_histories) => record_histories, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let record_histories = raw_record_histories @@ -39,7 +36,7 @@ impl RecordHistoryController { .collect::>(); let json_body = json!({ "record_histories": record_histories }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn delete_record_history( @@ -50,12 +47,9 @@ impl RecordHistoryController { match RecordHistoryService::delete_record_history(history_id).await { Ok(_) => { let json_body = json!({ "message": "Record history deleted successfully" }); - (StatusCode::OK, Json(json_body)) - } - Err(err) => { - let json_body = json!({ "error": err }); - (StatusCode::BAD_REQUEST, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } + Err(err) => err.into_response(), } } } diff --git a/src/api/controller/zone.rs b/src/api/controller/zone.rs index 15383aa..ac158b2 100644 --- a/src/api/controller/zone.rs +++ b/src/api/controller/zone.rs @@ -34,21 +34,17 @@ impl ZoneController { } async fn get_zones() -> impl IntoResponse { - let raw_zones = match ZoneService::get_zones().await { - Ok(zones) => zones, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); + match ZoneService::get_zones().await { + Ok(zones) => { + let zones = zones + .iter() + .map(GetZoneResponse::from_zone) + .collect::>(); + let json_body = json!({ "zones": zones }); + (StatusCode::OK, Json(json_body)).into_response() } - }; - - let zones = raw_zones - .iter() - .map(GetZoneResponse::from_zone) - .collect::>(); - - let json_body = json!({ "zones": zones }); - (StatusCode::OK, Json(json_body)) + Err(err) => err.into_response(), + } } async fn get_zone( @@ -60,19 +56,13 @@ impl ZoneController { let raw_zone = match ZoneService::get_zone(zone_id).await { Ok(zone) => zone, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let raw_records = match records_query { Some(true) => match RecordService::get_records(Some(zone_id)).await { Ok(records) => records, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }, _ => vec![], }; @@ -83,7 +73,7 @@ impl ZoneController { let zone = GetZoneResponse::from_zone(&raw_zone); let json_body = json!({ "zone": zone, "records": records }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn get_zone_rendered(Path(params): Path) -> impl IntoResponse { @@ -91,18 +81,12 @@ impl ZoneController { let raw_zone = match ZoneService::get_zone(zone_id).await { Ok(zone) => zone, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)).into_response(); - } + Err(err) => return err.into_response(), }; let raw_records = match RecordService::get_records(Some(zone_id)).await { Ok(records) => records, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)).into_response(); - } + Err(err) => return err.into_response(), }; let zone_str = Serializer::serialize_zone(&raw_zone, &raw_records); @@ -115,18 +99,14 @@ impl ZoneController { } async fn create_zone(JsonBody(body): JsonBody) -> impl IntoResponse { - let raw_zone = match ZoneService::create_zone(&body).await { - Ok(zone) => zone, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); + match ZoneService::create_zone(&body).await { + Ok(zone) => { + let zone = GetZoneResponse::from_zone(&zone); + let json_body = json!({ "zone": zone }); + (StatusCode::CREATED, Json(json_body)).into_response() } - }; - - let zone = GetZoneResponse::from_zone(&raw_zone); - - let json_body = json!({ "zone": zone }); - (StatusCode::CREATED, Json(json_body)) + Err(err) => err.into_response(), + } } async fn update_zone( @@ -135,18 +115,14 @@ impl ZoneController { ) -> impl IntoResponse { let zone_id = params.id; - let raw_zone = match ZoneService::update_zone(zone_id, &body).await { - Ok(zone) => zone, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); + match ZoneService::update_zone(zone_id, &body).await { + Ok(zone) => { + let zone = GetZoneResponse::from_zone(&zone); + let json_body = json!({ "zone": zone }); + (StatusCode::OK, Json(json_body)).into_response() } - }; - - let zone = GetZoneResponse::from_zone(&raw_zone); - - let json_body = json!({ "zone": zone }); - (StatusCode::OK, Json(json_body)) + Err(err) => err.into_response(), + } } async fn delete_zone(Path(params): Path) -> impl IntoResponse { @@ -155,12 +131,9 @@ impl ZoneController { match ZoneService::delete_zone(zone_id).await { Ok(_) => { let json_body = json!({ "message": "Zone deleted successfully" }); - (StatusCode::OK, Json(json_body)) - } - Err(err) => { - let json_body = json!({ "error": format!("Failed to delete zone: {}", err) }); - (StatusCode::BAD_REQUEST, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } + Err(err) => err.into_response(), } } } diff --git a/src/api/controller/zone_history.rs b/src/api/controller/zone_history.rs index 114a644..9e5df50 100644 --- a/src/api/controller/zone_history.rs +++ b/src/api/controller/zone_history.rs @@ -24,10 +24,7 @@ impl ZoneHistoryController { let raw_zone_histories = match ZoneHistoryService::get_zone_histories(zone_id).await { Ok(zone_histories) => zone_histories, - Err(err) => { - let json_body = json!({ "error": err }); - return (StatusCode::BAD_REQUEST, Json(json_body)); - } + Err(err) => return err.into_response(), }; let zone_histories = raw_zone_histories @@ -36,7 +33,7 @@ impl ZoneHistoryController { .collect::>(); let json_body = json!({ "zone_histories": zone_histories }); - (StatusCode::OK, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } async fn delete_zone_history(Path(params): Path) -> impl IntoResponse { @@ -45,12 +42,9 @@ impl ZoneHistoryController { match ZoneHistoryService::delete_zone_history(history_id).await { Ok(_) => { let json_body = json!({ "message": "Zone history deleted successfully" }); - (StatusCode::OK, Json(json_body)) - } - Err(err) => { - let json_body = json!({ "error": err }); - (StatusCode::BAD_REQUEST, Json(json_body)) + (StatusCode::OK, Json(json_body)).into_response() } + Err(err) => err.into_response(), } } } diff --git a/src/api/error.rs b/src/api/error.rs new file mode 100644 index 0000000..eb9a160 --- /dev/null +++ b/src/api/error.rs @@ -0,0 +1,48 @@ +use axum::{ + Json, + http::StatusCode, + response::{IntoResponse, Response}, +}; +use serde_json::json; +use thiserror::Error; + +/// API-specific error type that can be converted to HTTP responses +#[derive(Debug, Error)] +pub enum ApiError { + #[error("Bad request: {0}")] + BadRequest(String), + + #[error("Not found: {0}")] + NotFound(String), + + #[error("Unauthorized: {0}")] + Unauthorized(String), + + #[error("Internal server error: {0}")] + InternalServerError(String), +} + +impl ApiError { + fn status_code(&self) -> StatusCode { + match self { + ApiError::BadRequest(_) => StatusCode::BAD_REQUEST, + ApiError::NotFound(_) => StatusCode::NOT_FOUND, + ApiError::Unauthorized(_) => StatusCode::UNAUTHORIZED, + ApiError::InternalServerError(_) => StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_message(&self) -> String { + self.to_string() + } +} + +impl IntoResponse for ApiError { + fn into_response(self) -> Response { + let status = self.status_code(); + let body = Json(json!({ + "error": self.error_message() + })); + (status, body).into_response() + } +} \ No newline at end of file diff --git a/src/api/mod.rs b/src/api/mod.rs index d178a89..65edb7c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,5 +1,7 @@ pub mod controller; +pub mod error; pub mod service; +pub mod validation; mod dto; diff --git a/src/api/service/auth.rs b/src/api/service/auth.rs index 305aad3..2b0d2f8 100644 --- a/src/api/service/auth.rs +++ b/src/api/service/auth.rs @@ -1,4 +1,5 @@ use crate::{ + api::error::ApiError, database::{get_api_token_repository, model::api_token::ApiToken}, log_error, }; @@ -7,15 +8,15 @@ use chrono::Utc; pub struct AuthService; impl AuthService { - pub async fn validate_token(token_str: &str) -> Result { + pub async fn validate_token(token_str: &str) -> Result { let api_token_repository = get_api_token_repository(); let stored_token = match api_token_repository.get_by_token(token_str).await { Ok(Some(token)) => token, - Ok(None) => return Err("Invalid or expired token".to_string()), + Ok(None) => return Err(ApiError::Unauthorized("Invalid or expired token".to_string())), Err(e) => { log_error!("Failed to validate token: {}", e); - return Err("Failed to validate token".to_string()); + return Err(ApiError::InternalServerError("Failed to validate token".to_string())); } }; @@ -23,7 +24,7 @@ impl AuthService { if let Some(expires_at) = &stored_token.expires_at && Utc::now() > *expires_at { - return Err("Token has expired".to_string()); + return Err(ApiError::Unauthorized("Token has expired".to_string())); } // Update last_used_at to current time @@ -39,7 +40,7 @@ impl AuthService { .await .map_err(|e| { log_error!("Failed to update last_used_at: {}", e); - "Failed to update last_used_at".to_string() + ApiError::InternalServerError("Failed to update last_used_at".to_string()) })?; Ok(updated_token) diff --git a/src/api/service/dns.rs b/src/api/service/dns.rs index 94f58db..d682491 100644 --- a/src/api/service/dns.rs +++ b/src/api/service/dns.rs @@ -1,20 +1,20 @@ -use crate::{log_error, rndc::get_rndc_client, serializer::get_serializer}; +use crate::{api::error::ApiError, log_error, rndc::get_rndc_client, serializer::get_serializer}; #[derive(Clone)] pub struct DnsService; impl DnsService { - pub fn get_dns_status() -> Result { + pub fn get_dns_status() -> Result { let res = match get_rndc_client().command("status") { Ok(response) => response, Err(e) => { log_error!("Failed to get DNS status: {}", e); - return Err("Failed to get DNS status".to_string()); + return Err(ApiError::InternalServerError("Failed to get DNS status".to_string())); } }; if !res.result { - return Err("Failed to get DNS status".to_string()); + return Err(ApiError::InternalServerError("Failed to get DNS status".to_string())); } match res.text { @@ -23,17 +23,17 @@ impl DnsService { } } - pub fn reload_dns() -> Result { + pub fn reload_dns() -> Result { let res = match get_rndc_client().command("reload") { Ok(response) => response, Err(e) => { log_error!("Failed to reload DNS: {}", e); - return Err("Failed to reload DNS".to_string()); + return Err(ApiError::InternalServerError("Failed to reload DNS".to_string())); } }; if !res.result { - return Err("Failed to reload DNS".to_string()); + return Err(ApiError::InternalServerError("Failed to reload DNS".to_string())); } match res.text { @@ -42,12 +42,15 @@ impl DnsService { } } - pub async fn write_dns_config() -> Result { + pub async fn write_dns_config() -> Result { match get_serializer().write_config_sync().await { Ok(_) => Ok("DNS configuration written successfully.".to_string()), Err(e) => { log_error!("Failed to write DNS configuration: {}", e); - Err(format!("Failed to write DNS configuration: {}", e)) + Err(ApiError::InternalServerError(format!( + "Failed to write DNS configuration: {}", + e + ))) } } } diff --git a/src/api/service/record.rs b/src/api/service/record.rs index 7f7c4af..ab64602 100644 --- a/src/api/service/record.rs +++ b/src/api/service/record.rs @@ -1,5 +1,5 @@ use crate::{ - api::dto::CreateRecordRequest, + api::{dto::CreateRecordRequest, error::ApiError}, database::{ get_record_history_repository, get_record_repository, get_zone_repository, model::{ @@ -7,8 +7,8 @@ use crate::{ record_history::RecordHistory, }, }, - serializer::utils::{to_relative_domain, to_fqdn}, log_error, + serializer::utils::{to_fqdn, to_relative_domain}, }; use chrono::Utc; @@ -16,7 +16,7 @@ use chrono::Utc; pub struct RecordService; impl RecordService { - pub async fn get_records(zone_id: Option) -> Result, String> { + pub async fn get_records(zone_id: Option) -> Result, ApiError> { let zone_repository = get_zone_repository(); let record_repository = get_record_repository(); @@ -26,11 +26,11 @@ impl RecordService { match zone_repository.get_by_id(id).await { Ok(Some(_)) => {} Ok(None) => { - return Err("Zone not found".to_string()); + return Err(ApiError::BadRequest("Zone not found".to_string())); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to fetch zone".to_string()); + return Err(ApiError::InternalServerError("Failed to fetch zone".to_string())); } } @@ -39,7 +39,10 @@ impl RecordService { Ok(records) => Ok(records), Err(e) => { log_error!("Failed to fetch records for zone {}: {}", id, e); - Err(format!("Failed to fetch records for zone {}", id)) + Err(ApiError::InternalServerError(format!( + "Failed to fetch records for zone {}", + id + ))) } } } @@ -49,46 +52,60 @@ impl RecordService { Ok(records) => Ok(records), Err(e) => { log_error!("Failed to fetch all records: {}", e); - Err("Failed to fetch all records".to_string()) + Err(ApiError::InternalServerError( + "Failed to fetch all records".to_string(), + )) } } } } } - pub async fn get_record(record_id: i32) -> Result { + pub async fn get_record(record_id: i32) -> Result { let record_repository = get_record_repository(); match record_repository.get_by_id(record_id).await { Ok(Some(record)) => Ok(record), - Ok(None) => Err(format!("Record with id {} not found", record_id)), + Ok(None) => Err(ApiError::NotFound(format!( + "Record with id {} not found", + record_id + ))), Err(e) => { log_error!("Failed to fetch record: {}", e); - Err("Failed to fetch record".to_string()) + Err(ApiError::InternalServerError("Failed to fetch record".to_string())) } } } pub async fn create_record( create_record_request: &CreateRecordRequest, - ) -> Result { + ) -> Result { let zone_repository = get_zone_repository(); let record_repository = get_record_repository(); let record_history_repository = get_record_history_repository(); // Validate record type - let record_type = RecordType::from_str(&create_record_request.record_type) - .map_err(|_| format!("Invalid record type: {}", create_record_request.record_type))?; + let record_type = + RecordType::from_str(&create_record_request.record_type).map_err(|_| { + ApiError::BadRequest(format!( + "Invalid record type: {}", + create_record_request.record_type + )) + })?; // CNAME validation for '@' name if record_type == RecordType::CNAME && create_record_request.name == "@" { - return Err("CNAME record cannot have '@' as name".to_string()); + return Err(ApiError::BadRequest( + "CNAME record cannot have '@' as name".to_string(), + )); } // SOA validation if record_type == RecordType::SOA { log_error!("Cannot create SOA record manually"); - return Err("Cannot create SOA record manually".to_string()); + return Err(ApiError::BadRequest( + "Cannot create SOA record manually".to_string(), + )); } // Check if zone exists @@ -98,27 +115,29 @@ impl RecordService { { Ok(Some(zone)) => zone, Ok(None) => { - return Err(format!( + return Err(ApiError::NotFound(format!( "Zone with id {} not found", create_record_request.zone_id - )); + ))); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to create record".to_string()); + return Err(ApiError::InternalServerError("Failed to create record".to_string())); } }; // Prevent manual creation of records related to primary_ns let primary_ns_relative_name = to_relative_domain(&to_fqdn(&zone.primary_ns), &zone.name); if (record_type == RecordType::NS && create_record_request.name == "@") - || (record_type == RecordType::A && create_record_request.name == primary_ns_relative_name) - || (record_type == RecordType::AAAA && create_record_request.name == primary_ns_relative_name) + || (record_type == RecordType::A + && create_record_request.name == primary_ns_relative_name) + || (record_type == RecordType::AAAA + && create_record_request.name == primary_ns_relative_name) { - return Err( + return Err(ApiError::BadRequest( "Cannot manually create records that are automatically generated for the primary NS" .to_string(), - ); + )); } // CNAME validation @@ -129,7 +148,7 @@ impl RecordService { Ok(records) => records, Err(e) => { log_error!("Failed to check existing records: {}", e); - return Err("Failed to create record".to_string()); + return Err(ApiError::InternalServerError("Failed to create record".to_string())); } }; @@ -140,19 +159,19 @@ impl RecordService { if !existing_records_with_name.is_empty() { if record_type == RecordType::CNAME { - return Err(format!( + return Err(ApiError::BadRequest(format!( "A record with name '{}' already exists in this zone, so CNAME cannot be used", create_record_request.name - )); + ))); } if existing_records_with_name .iter() .any(|r| r.record_type == RecordType::CNAME) { - return Err(format!( + return Err(ApiError::BadRequest(format!( "A CNAME record with name '{}' already exists in this zone", create_record_request.name - )); + ))); } } @@ -171,7 +190,7 @@ impl RecordService { .await .map_err(|e| { log_error!("Failed to create record: {}", e); - "Failed to create record".to_string() + ApiError::InternalServerError("Failed to create record".to_string()) })?; // Create record history @@ -193,7 +212,7 @@ impl RecordService { .await .map_err(|e| { log_error!("Failed to create record history: {}", e); - "Failed to create record history".to_string() + ApiError::InternalServerError("Failed to create record history".to_string()) })?; Ok(created_record) @@ -202,7 +221,7 @@ impl RecordService { pub async fn update_record( record_id: i32, update_record_request: &CreateRecordRequest, - ) -> Result { + ) -> Result { let zone_repository = get_zone_repository(); let record_repository = get_record_repository(); let record_history_repository = get_record_history_repository(); @@ -210,10 +229,13 @@ impl RecordService { // Check if record exists match record_repository.get_by_id(record_id).await { Ok(Some(record)) => Ok(record), - Ok(None) => Err(format!("Record with id {} not found", record_id)), + Ok(None) => Err(ApiError::NotFound(format!( + "Record with id {} not found", + record_id + ))), Err(e) => { log_error!("Failed to fetch record: {}", e); - Err("Failed to fetch record".to_string()) + Err(ApiError::InternalServerError("Failed to fetch record".to_string())) } }?; @@ -224,39 +246,50 @@ impl RecordService { { Ok(Some(zone)) => zone, Ok(None) => { - return Err("Zone not found".to_string()); + return Err(ApiError::BadRequest("Zone not found".to_string())); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to fetch zone".to_string()); + return Err(ApiError::InternalServerError("Failed to fetch zone".to_string())); } }; // Validate record type - let record_type = RecordType::from_str(&update_record_request.record_type) - .map_err(|_| format!("Invalid record type: {}", update_record_request.record_type))?; + let record_type = + RecordType::from_str(&update_record_request.record_type).map_err(|_| { + ApiError::BadRequest(format!( + "Invalid record type: {}", + update_record_request.record_type + )) + })?; // CNAME validation for '@' name if record_type == RecordType::CNAME && update_record_request.name == "@" { - return Err("CNAME record cannot have '@' as name".to_string()); + return Err(ApiError::BadRequest( + "CNAME record cannot have '@' as name".to_string(), + )); } // SOA validation if record_type == RecordType::SOA { log_error!("Cannot update to SOA record type"); - return Err("Cannot update to SOA record type".to_string()); + return Err(ApiError::BadRequest( + "Cannot update to SOA record type".to_string(), + )); } // Prevent manual update of records related to primary_ns let primary_ns_relative_name = to_relative_domain(&to_fqdn(&zone.primary_ns), &zone.name); if (record_type == RecordType::NS && update_record_request.name == "@") - || (record_type == RecordType::A && update_record_request.name == primary_ns_relative_name) - || (record_type == RecordType::AAAA && update_record_request.name == primary_ns_relative_name) + || (record_type == RecordType::A + && update_record_request.name == primary_ns_relative_name) + || (record_type == RecordType::AAAA + && update_record_request.name == primary_ns_relative_name) { - return Err( + return Err(ApiError::BadRequest( "Cannot manually update records that are automatically generated for the primary NS" .to_string(), - ); + )); } // CNAME validation @@ -267,7 +300,7 @@ impl RecordService { Ok(records) => records, Err(e) => { log_error!("Failed to check existing record: {}", e); - return Err("Failed to update record".to_string()); + return Err(ApiError::InternalServerError("Failed to update record".to_string())); } }; @@ -278,19 +311,19 @@ impl RecordService { if !other_records_in_zone.is_empty() { if record_type == RecordType::CNAME { - return Err(format!( + return Err(ApiError::BadRequest(format!( "A record with name '{}' already exists in this zone, so CNAME cannot be used", update_record_request.name - )); + ))); } if other_records_in_zone .iter() .any(|r| r.record_type == RecordType::CNAME) { - return Err(format!( + return Err(ApiError::BadRequest(format!( "A CNAME record with name '{}' already exists in this zone", update_record_request.name - )); + ))); } } @@ -309,7 +342,7 @@ impl RecordService { .await .map_err(|e| { log_error!("Failed to update record: {}", e); - "Failed to update record".to_string() + ApiError::InternalServerError("Failed to update record".to_string()) })?; // Create record history @@ -331,56 +364,41 @@ impl RecordService { .await .map_err(|e| { log_error!("Failed to create record history: {}", e); - "Failed to create record history".to_string() + ApiError::InternalServerError("Failed to create record history".to_string()) })?; Ok(updated_record) } - pub async fn delete_record(record_id: i32) -> Result<(), String> { + pub async fn delete_record(record_id: i32) -> Result<(), ApiError> { let record_repository = get_record_repository(); // let record_history_repository = get_record_history_repository(); // Check if record exists let existing_record = match record_repository.get_by_id(record_id).await { Ok(Some(record)) => Ok(record), - Ok(None) => Err(format!("Record with id {} not found", record_id)), + Ok(None) => Err(ApiError::NotFound(format!( + "Record with id {} not found", + record_id + ))), Err(e) => { log_error!("Failed to fetch record: {}", e); - Err("Failed to fetch record".to_string()) + Err(ApiError::InternalServerError("Failed to fetch record".to_string())) } }?; // Prevent deletion of SOA records if existing_record.record_type == RecordType::SOA { log_error!("Cannot delete SOA record"); - return Err("Cannot delete SOA record".to_string()); + return Err(ApiError::BadRequest("Cannot delete SOA record".to_string())); } // Delete record record_repository.delete(record_id).await.map_err(|e| { log_error!("Failed to delete record: {}", e); - "Failed to delete record".to_string() + ApiError::InternalServerError("Failed to delete record".to_string()) })?; - // Create record history - // record_history_repository - // .create(RecordHistory { - // id: 0, // Will be set by the database - // record_id, - // log: format!( - // "[{}] Record deleted: id={}", - // Utc::now().format("%Y-%m-%d %H:%M:%S"), - // record_id, - // ), - // created_at: Utc::now(), // Will be set by the database - // }) - // .await - // .map_err(|e| { - // log_error!("Failed to create record history: {}", e); - // "Failed to create record history".to_string() - // })?; - Ok(()) } } diff --git a/src/api/service/record_history.rs b/src/api/service/record_history.rs index f5af242..c26ef25 100644 --- a/src/api/service/record_history.rs +++ b/src/api/service/record_history.rs @@ -1,4 +1,5 @@ use crate::{ + api::error::ApiError, database::{ get_record_history_repository, get_record_repository, model::record_history::RecordHistory, }, @@ -9,7 +10,7 @@ use crate::{ pub struct RecordHistoryService; impl RecordHistoryService { - pub async fn get_record_histories(record_id: i32) -> Result, String> { + pub async fn get_record_histories(record_id: i32) -> Result, ApiError> { let record_repository = get_record_repository(); let record_history_repository = get_record_history_repository(); @@ -17,11 +18,11 @@ impl RecordHistoryService { match record_repository.get_by_id(record_id).await { Ok(Some(_)) => {} Ok(None) => { - return Err("Record not found".to_string()); + return Err(ApiError::NotFound("Record not found".to_string())); } Err(e) => { log_error!("Failed to fetch record: {}", e); - return Err("Failed to fetch record".to_string()); + return Err(ApiError::InternalServerError("Failed to fetch record".to_string())); } }; @@ -30,31 +31,35 @@ impl RecordHistoryService { .await .map_err(|e| { log_error!("Failed to fetch record histories: {}", e); - "Failed to fetch record histories".to_string() + ApiError::InternalServerError("Failed to fetch record histories".to_string()) })?; Ok(record_histories) } - pub async fn delete_record_history(record_history_id: i32) -> Result<(), String> { + pub async fn delete_record_history(record_history_id: i32) -> Result<(), ApiError> { let record_history_repository = get_record_history_repository(); // Check if the record history exists match record_history_repository.get_by_id(record_history_id).await { Ok(Some(_)) => {} Ok(None) => { - return Err("Record history not found".to_string()); + return Err(ApiError::NotFound("Record history not found".to_string())); } Err(e) => { log_error!("Failed to fetch record history: {}", e); - return Err("Failed to fetch record history".to_string()); + return Err(ApiError::InternalServerError( + "Failed to fetch record history".to_string(), + )); } }; // Delete the record history if let Err(e) = record_history_repository.delete(record_history_id).await { log_error!("Failed to delete record history: {}", e); - return Err("Failed to delete record history".to_string()); + return Err(ApiError::InternalServerError( + "Failed to delete record history".to_string(), + )); }; Ok(()) diff --git a/src/api/service/zone.rs b/src/api/service/zone.rs index 21a4b22..e6ae131 100644 --- a/src/api/service/zone.rs +++ b/src/api/service/zone.rs @@ -1,6 +1,7 @@ use crate::{ - api::dto::CreateZoneRequest, + api::{dto::CreateZoneRequest, error::ApiError}, database::{ + error::DatabaseError, get_zone_history_repository, get_zone_repository, model::{zone::Zone, zone_history::ZoneHistory}, }, @@ -12,32 +13,34 @@ use chrono::Utc; pub struct ZoneService; impl ZoneService { - pub async fn get_zones() -> Result, String> { + pub async fn get_zones() -> Result, ApiError> { let zone_repository = get_zone_repository(); - match zone_repository.get_all().await { - Ok(zones) => Ok(zones), - Err(e) => { - log_error!("Failed to fetch zones: {}", e); - Err("Failed to fetch zones".to_string()) - } - } + zone_repository.get_all().await.map_err(|e: DatabaseError| { + log_error!("Failed to fetch zones: {}", e); + ApiError::InternalServerError("Failed to fetch zones".to_string()) + }) } - pub async fn get_zone(zone_id: i32) -> Result { + pub async fn get_zone(zone_id: i32) -> Result { let zone_repository = get_zone_repository(); match zone_repository.get_by_id(zone_id).await { Ok(Some(zone)) => Ok(zone), - Ok(None) => Err(format!("Zone with id {} not found", zone_id)), + Ok(None) => Err(ApiError::NotFound(format!( + "Zone with id {} not found", + zone_id + ))), Err(e) => { log_error!("Failed to fetch zone: {}", e); - Err("Failed to fetch zone".to_string()) + Err(ApiError::InternalServerError( + "Failed to fetch zone".to_string(), + )) } } } - pub async fn create_zone(create_zone_request: &CreateZoneRequest) -> Result { + pub async fn create_zone(create_zone_request: &CreateZoneRequest) -> Result { let zone_repository = get_zone_repository(); let zone_history_repository = get_zone_history_repository(); @@ -45,21 +48,25 @@ impl ZoneService { if create_zone_request.primary_ns_ip.is_none() && create_zone_request.primary_ns_ipv6.is_none() { - return Err( + return Err(ApiError::BadRequest( "At least one of primary_ns_ip or primary_ns_ipv6 must be provided".to_string(), - ); + )); } // Check if zone already exists match zone_repository.get_by_name(&create_zone_request.name).await { Ok(Some(_)) => { log_error!("Zone with name {} already exists", create_zone_request.name); - return Err("Zone with this name already exists".to_string()); + return Err(ApiError::BadRequest( + "Zone with this name already exists".to_string(), + )); } Ok(None) => (), Err(e) => { log_error!("Failed to check existing zone: {}", e); - return Err("Failed to create zone".to_string()); + return Err(ApiError::InternalServerError( + "Failed to create zone".to_string(), + )); } }; @@ -81,9 +88,9 @@ impl ZoneService { created_at: Utc::now(), // Will be set by the database }) .await - .map_err(|e| { + .map_err(|e: DatabaseError| { log_error!("Failed to create zone: {}", e); - "Failed to create zone".to_string() + ApiError::InternalServerError("Failed to create zone".to_string()) })?; // Create zone history @@ -100,9 +107,9 @@ impl ZoneService { created_at: Utc::now(), // Will be set by the database }) .await - .map_err(|e| { + .map_err(|e: DatabaseError| { log_error!("Failed to create zone history: {}", e); - "Failed to create zone history".to_string() + ApiError::InternalServerError("Failed to create zone history".to_string()) })?; Ok(created_zone) @@ -111,7 +118,7 @@ impl ZoneService { pub async fn update_zone( zone_id: i32, update_zone_request: &CreateZoneRequest, - ) -> Result { + ) -> Result { let zone_repository = get_zone_repository(); let zone_history_repository = get_zone_history_repository(); @@ -119,9 +126,9 @@ impl ZoneService { if update_zone_request.primary_ns_ip.is_none() && update_zone_request.primary_ns_ipv6.is_none() { - return Err( + return Err(ApiError::BadRequest( "At least one of primary_ns_ip or primary_ns_ipv6 must be provided".to_string(), - ); + )); } // Check if zone exists @@ -129,11 +136,16 @@ impl ZoneService { Ok(Some(_)) => {} Ok(None) => { log_error!("Zone with id {} not found", zone_id); - return Err(format!("Zone with id {} not found", zone_id)); + return Err(ApiError::NotFound(format!( + "Zone with id {} not found", + zone_id + ))); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to update zone".to_string()); + return Err(ApiError::InternalServerError( + "Failed to update zone".to_string(), + )); } }; @@ -141,13 +153,17 @@ impl ZoneService { match zone_repository.get_by_name(&update_zone_request.name).await { Ok(Some(existing_zone)) if existing_zone.id != zone_id => { log_error!("Zone with name {} already exists", update_zone_request.name); - return Err("Zone with this name already exists".to_string()); + return Err(ApiError::BadRequest( + "Zone with this name already exists".to_string(), + )); } Ok(Some(_)) => (), // The same zone, allow update Ok(None) => (), Err(e) => { log_error!("Failed to check existing zone: {}", e); - return Err("Failed to update zone".to_string()); + return Err(ApiError::InternalServerError( + "Failed to update zone".to_string(), + )); } }; @@ -169,9 +185,9 @@ impl ZoneService { created_at: Utc::now(), // Will be set by the database }) .await - .map_err(|e| { + .map_err(|e: DatabaseError| { log_error!("Failed to update zone: {}", e); - "Failed to update zone".to_string() + ApiError::InternalServerError("Failed to update zone".to_string()) })?; // Create zone history @@ -188,54 +204,43 @@ impl ZoneService { created_at: Utc::now(), // Will be set by the database }) .await - .map_err(|e| { + .map_err(|e: DatabaseError| { log_error!("Failed to create zone history: {}", e); - "Failed to create zone history".to_string() + ApiError::InternalServerError("Failed to create zone history".to_string()) })?; Ok(updated_zone) } - pub async fn delete_zone(zone_id: i32) -> Result<(), String> { + pub async fn delete_zone(zone_id: i32) -> Result<(), ApiError> { let zone_repository = get_zone_repository(); - // let zone_history_repository = get_zone_history_repository(); // Check if zone exists match zone_repository.get_by_id(zone_id).await { Ok(Some(_)) => {} Ok(None) => { log_error!("Zone with id {} not found", zone_id); - return Err(format!("Zone with id {} not found", zone_id)); + return Err(ApiError::NotFound(format!( + "Zone with id {} not found", + zone_id + ))); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to update zone".to_string()); + return Err(ApiError::InternalServerError( + "Failed to delete zone".to_string(), + )); } }; // Delete zone - zone_repository.delete(zone_id).await.map_err(|e| { - log_error!("Failed to delete zone: {}", e); - "Failed to delete zone".to_string() - })?; - - // Create zone history - // zone_history_repository - // .create(ZoneHistory { - // id: 0, // Will be set by the database - // log: format!( - // "[{}] Zone deleted: id={}", - // Utc::now().format("%Y-%m-%d %H:%M:%S"), - // zone_id, - // ), - // zone_id, - // created_at: Utc::now(), // Will be set by the database - // }) - // .await - // .map_err(|e| { - // log_error!("Failed to create zone history: {}", e); - // "Failed to create zone history".to_string() - // })?; + zone_repository + .delete(zone_id) + .await + .map_err(|e: DatabaseError| { + log_error!("Failed to delete zone: {}", e); + ApiError::InternalServerError("Failed to delete zone".to_string()) + })?; Ok(()) } diff --git a/src/api/service/zone_history.rs b/src/api/service/zone_history.rs index e4d0882..7a502bf 100644 --- a/src/api/service/zone_history.rs +++ b/src/api/service/zone_history.rs @@ -1,4 +1,5 @@ use crate::{ + api::error::ApiError, database::{ get_zone_history_repository, get_zone_repository, model::zone_history::ZoneHistory, }, @@ -9,7 +10,7 @@ use crate::{ pub struct ZoneHistoryService; impl ZoneHistoryService { - pub async fn get_zone_histories(zone_id: i32) -> Result, String> { + pub async fn get_zone_histories(zone_id: i32) -> Result, ApiError> { let zone_repository = get_zone_repository(); let zone_history_repository = get_zone_history_repository(); @@ -17,11 +18,11 @@ impl ZoneHistoryService { match zone_repository.get_by_id(zone_id).await { Ok(Some(_)) => {} Ok(None) => { - return Err("Zone not found".to_string()); + return Err(ApiError::NotFound("Zone not found".to_string())); } Err(e) => { log_error!("Failed to fetch zone: {}", e); - return Err("Failed to fetch zone".to_string()); + return Err(ApiError::InternalServerError("Failed to fetch zone".to_string())); } }; @@ -30,31 +31,35 @@ impl ZoneHistoryService { .await .map_err(|e| { log_error!("Failed to fetch zone histories: {}", e); - "Failed to fetch zone histories".to_string() + ApiError::InternalServerError("Failed to fetch zone histories".to_string()) })?; Ok(zone_histories) } - pub async fn delete_zone_history(zone_history_id: i32) -> Result<(), String> { + pub async fn delete_zone_history(zone_history_id: i32) -> Result<(), ApiError> { let zone_history_repository = get_zone_history_repository(); // Check if the zone history exists match zone_history_repository.get_by_id(zone_history_id).await { Ok(Some(_)) => {} Ok(None) => { - return Err("Zone history not found".to_string()); + return Err(ApiError::NotFound("Zone history not found".to_string())); } Err(e) => { log_error!("Failed to fetch zone history: {}", e); - return Err("Failed to fetch zone history".to_string()); + return Err(ApiError::InternalServerError( + "Failed to fetch zone history".to_string(), + )); } }; // Delete the zone history if let Err(e) = zone_history_repository.delete(zone_history_id).await { log_error!("Failed to delete zone history: {}", e); - return Err("Failed to delete zone history".to_string()); + return Err(ApiError::InternalServerError( + "Failed to delete zone history".to_string(), + )); }; Ok(()) diff --git a/src/api/validation.rs b/src/api/validation.rs new file mode 100644 index 0000000..1c4f4f4 --- /dev/null +++ b/src/api/validation.rs @@ -0,0 +1,18 @@ +use thiserror::Error; + +/// TODO: Validation-related errors +#[allow(dead_code)] +#[derive(Debug, Error)] +pub enum ValidationError { + #[error("Invalid input: {0}")] + InvalidInput(String), + + #[error("Missing required field: {0}")] + MissingField(String), + + #[error("Invalid format: {0}")] + InvalidFormat(String), + + #[error("Constraint violation: {0}")] + ConstraintViolation(String), +} diff --git a/src/cli/status.rs b/src/cli/status.rs index e5d768b..ce9a824 100644 --- a/src/cli/status.rs +++ b/src/cli/status.rs @@ -10,9 +10,7 @@ pub async fn handle_command() -> Result<(), String> { let client = DaemonSocketClient::new(); // Create socket request - let res = client - .send_command(DaemonCommandKind::Status, None) - .await?; + let res = client.send_command(DaemonCommandKind::Status, None).await?; log_debug!("Status command result: {:?}", res); diff --git a/src/config/error.rs b/src/config/error.rs new file mode 100644 index 0000000..725cf37 --- /dev/null +++ b/src/config/error.rs @@ -0,0 +1,18 @@ +use thiserror::Error; + +/// TODO: Configuration-related errors +#[allow(dead_code)] +#[derive(Debug, Error)] +pub enum ConfigError { + #[error("Configuration not found: {0}")] + NotFound(String), + + #[error("Invalid configuration value: {0}")] + InvalidValue(String), + + #[error("Parse error: {0}")] + ParseError(String), + + #[error("Missing required configuration: {0}")] + MissingRequired(String), +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 6ed2534..744cdde 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,6 +1,8 @@ #[cfg(test)] mod tests; +pub mod error; + use config::{Config, File, FileFormat, Source, ValueKind}; use once_cell::sync::OnceCell; use std::{any::type_name, collections::HashMap, path::PathBuf, str::FromStr}; diff --git a/src/config/tests.rs b/src/config/tests.rs index 43b587c..6371f47 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -39,7 +39,7 @@ fn test_get_config_string() { #[test] fn test_get_config_numeric() { - let (dir, config_path) = create_temp_config_file("[test]\nint_value = 42\nfloat_value = 3.14"); + let (dir, config_path) = create_temp_config_file("[test]\nint_value = 42\nfloat_value = 3.15"); // Create a config instance directly for testing let config = Config::builder() @@ -53,7 +53,7 @@ fn test_get_config_numeric() { // Test float value retrieval let float_value: f64 = config.get("test.float_value").unwrap(); - assert_eq!(float_value, 3.14); + assert!((float_value - 3.15).abs() < f64::EPSILON); // Keep dir alive until the end of the test drop(dir); @@ -84,7 +84,7 @@ fn test_get_config_boolean() { #[test] fn test_config_value_to_json() { let (dir, config_path) = create_temp_config_file( - "[test]\nstring_value = \"hello\"\nint_value = 42\nfloat_value = 3.14\nbool_value = true", + "[test]\nstring_value = \"hello\"\nint_value = 42\nfloat_value = 3.15\nbool_value = true", ); // Create a config instance directly for testing @@ -106,7 +106,7 @@ fn test_config_value_to_json() { // Check the JSON values assert_eq!(json_map["string_value"], "hello"); assert_eq!(json_map["int_value"], 42); - assert_eq!(json_map["float_value"], 3.14); + assert!((json_map["float_value"].as_f64().unwrap() - 3.15).abs() < f64::EPSILON); assert_eq!(json_map["bool_value"], true); // Keep dir alive until the end of the test diff --git a/src/database/error.rs b/src/database/error.rs new file mode 100644 index 0000000..5b7c01f --- /dev/null +++ b/src/database/error.rs @@ -0,0 +1,37 @@ +use thiserror::Error; + +/// TODO: Database-related errors +#[allow(dead_code)] +#[derive(Debug, Error)] +pub enum DatabaseError { + #[error("Connection failed: {0}")] + ConnectionFailed(String), + + #[error("Query failed: {0}")] + QueryFailed(String), + + #[error("Record not found: {0}")] + NotFound(String), + + #[error("Record already exists: {0}")] + AlreadyExists(String), + + #[error("Transaction failed: {0}")] + TransactionFailed(String), + + #[error("Migration failed: {0}")] + MigrationFailed(String), + + #[error("Pool error: {0}")] + PoolError(String), +} + +impl From for DatabaseError { + fn from(err: sqlx::Error) -> Self { + match err { + sqlx::Error::RowNotFound => DatabaseError::NotFound("Row not found".to_string()), + sqlx::Error::PoolTimedOut => DatabaseError::PoolError("Pool timed out".to_string()), + _ => DatabaseError::QueryFailed(err.to_string()), + } + } +} diff --git a/src/database/mod.rs b/src/database/mod.rs index a338970..9fda701 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -2,6 +2,7 @@ use crate::{config, log_error, log_info}; use sqlx::{MySql, Pool, Postgres, Sqlite, sqlite::SqlitePoolOptions}; use std::sync::OnceLock; +pub mod error; pub mod model; pub mod repository; mod schema; diff --git a/src/database/repository/mod.rs b/src/database/repository/mod.rs index e74ba9f..cbe0c51 100644 --- a/src/database/repository/mod.rs +++ b/src/database/repository/mod.rs @@ -9,68 +9,68 @@ use super::model::{ zone::Zone, zone_history::ZoneHistory, }; -use crate::database::DatabasePool; +use crate::database::{DatabasePool, error::DatabaseError}; use async_trait::async_trait; // Zone Repository Trait #[allow(dead_code)] #[async_trait] pub trait ZoneRepository: Send + Sync { - async fn create(&self, zone: Zone) -> Result; - async fn get_by_id(&self, id: i32) -> Result, String>; - async fn get_by_name(&self, name: &str) -> Result, String>; - async fn get_all(&self) -> Result, String>; - async fn update(&self, zone: Zone) -> Result; - async fn delete(&self, id: i32) -> Result<(), String>; + async fn create(&self, zone: Zone) -> Result; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError>; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError>; + async fn get_all(&self) -> Result, DatabaseError>; + async fn update(&self, zone: Zone) -> Result; + async fn delete(&self, id: i32) -> Result<(), DatabaseError>; } // Record Repository Trait #[allow(dead_code)] #[async_trait] pub trait RecordRepository: Send + Sync { - async fn create(&self, record: Record) -> Result; - async fn get_by_id(&self, id: i32) -> Result, String>; - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String>; + async fn create(&self, record: Record) -> Result; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError>; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError>; async fn get_by_name_and_type( &self, name: &str, record_type: &RecordType, - ) -> Result, String>; - async fn get_by_name(&self, name: &str) -> Result, String>; - async fn get_all(&self) -> Result, String>; - async fn update(&self, record: Record) -> Result; - async fn delete(&self, id: i32) -> Result<(), String>; + ) -> Result, DatabaseError>; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError>; + async fn get_all(&self) -> Result, DatabaseError>; + async fn update(&self, record: Record) -> Result; + async fn delete(&self, id: i32) -> Result<(), DatabaseError>; } // Zone History Repository Trait #[allow(dead_code)] #[async_trait] pub trait ZoneHistoryRepository: Send + Sync { - async fn create(&self, zone_history: ZoneHistory) -> Result; - async fn get_by_id(&self, id: i32) -> Result, String>; - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String>; - async fn delete(&self, id: i32) -> Result<(), String>; + async fn create(&self, zone_history: ZoneHistory) -> Result; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError>; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError>; + async fn delete(&self, id: i32) -> Result<(), DatabaseError>; } // Record History Repository Trait #[allow(dead_code)] #[async_trait] pub trait RecordHistoryRepository: Send + Sync { - async fn create(&self, record_history: RecordHistory) -> Result; - async fn get_by_id(&self, id: i32) -> Result, String>; - async fn get_by_record_id(&self, record_id: i32) -> Result, String>; - async fn delete(&self, id: i32) -> Result<(), String>; + async fn create(&self, record_history: RecordHistory) -> Result; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError>; + async fn get_by_record_id(&self, record_id: i32) -> Result, DatabaseError>; + async fn delete(&self, id: i32) -> Result<(), DatabaseError>; } // API Token Repository Trait #[async_trait] pub trait ApiTokenRepository: Send + Sync { - async fn create(&self, token: ApiToken) -> Result; - async fn get_by_id(&self, id: i32) -> Result, String>; - async fn get_by_token(&self, token: &str) -> Result, String>; - async fn get_all(&self) -> Result, String>; - async fn update(&self, token: ApiToken) -> Result; - async fn delete(&self, id: i32) -> Result<(), String>; + async fn create(&self, token: ApiToken) -> Result; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError>; + async fn get_by_token(&self, token: &str) -> Result, DatabaseError>; + async fn get_all(&self) -> Result, DatabaseError>; + async fn update(&self, token: ApiToken) -> Result; + async fn delete(&self, id: i32) -> Result<(), DatabaseError>; } // Repository Factory diff --git a/src/database/repository/mysql/api_token_repository_impl.rs b/src/database/repository/mysql/api_token_repository_impl.rs index 69e9057..ef220d4 100644 --- a/src/database/repository/mysql/api_token_repository_impl.rs +++ b/src/database/repository/mysql/api_token_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::api_token::ApiToken, repository::ApiTokenRepository}; use async_trait::async_trait; use sqlx::{MySql, Pool}; @@ -14,8 +15,8 @@ impl MySqlApiTokenRepository { #[async_trait] impl ApiTokenRepository for MySqlApiTokenRepository { - async fn create(&self, mut token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -27,16 +28,15 @@ impl ApiTokenRepository for MySqlApiTokenRepository { .bind(&token.description) .bind(token.expires_at) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; token.id = result.last_insert_id() as i32; Ok(token) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let row = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE id = ?" @@ -44,13 +44,13 @@ impl ApiTokenRepository for MySqlApiTokenRepository { .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(row) } - async fn get_by_token(&self, token: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_token(&self, token: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let row = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE token = ?" @@ -58,26 +58,26 @@ impl ApiTokenRepository for MySqlApiTokenRepository { .bind(token) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(row) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let rows = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens ORDER BY created_at DESC" ) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(rows) } - async fn update(&self, token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -91,20 +91,18 @@ impl ApiTokenRepository for MySqlApiTokenRepository { .bind(token.last_used_at) .bind(token.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(token) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM api_tokens WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/mysql/record_history_repository_impl.rs b/src/database/repository/mysql/record_history_repository_impl.rs index 83a3693..08acee3 100644 --- a/src/database/repository/mysql/record_history_repository_impl.rs +++ b/src/database/repository/mysql/record_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::record_history::RecordHistory, repository::RecordHistoryRepository}; use async_trait::async_trait; use sqlx::{MySql, Pool}; @@ -14,37 +15,38 @@ impl MySqlRecordHistoryRepository { #[async_trait] impl RecordHistoryRepository for MySqlRecordHistoryRepository { - async fn create(&self, mut record_history: RecordHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create( + &self, + mut record_history: RecordHistory, + ) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query("INSERT INTO record_history (log, record_id) VALUES (?, ?)") .bind(&record_history.log) .bind(record_history.record_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record_history.id = result.last_insert_id() as i32; Ok(record_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_history = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE id = ?", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record_history) } - async fn get_by_record_id(&self, record_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_record_id(&self, record_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_histories = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE record_id = ? ORDER BY created_at DESC", @@ -52,19 +54,18 @@ impl RecordHistoryRepository for MySqlRecordHistoryRepository { .bind(record_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM record_history WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/mysql/record_repository_impl.rs b/src/database/repository/mysql/record_repository_impl.rs index fdfba12..50c8d1f 100644 --- a/src/database/repository/mysql/record_repository_impl.rs +++ b/src/database/repository/mysql/record_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{ model::record::{Record, RecordType}, repository::RecordRepository, @@ -17,8 +18,8 @@ impl MySqlRecordRepository { #[async_trait] impl RecordRepository for MySqlRecordRepository { - async fn create(&self, mut record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut record: Record) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -33,35 +34,34 @@ impl RecordRepository for MySqlRecordRepository { .bind(record.priority) .bind(record.zone_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record.id = result.last_insert_id() as i32; Ok(record) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE id = ?") .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE zone_id = ? ORDER BY name") .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } @@ -70,8 +70,8 @@ impl RecordRepository for MySqlRecordRepository { &self, name: &str, record_type: &RecordType, - ) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + ) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = ? AND record_type = ?") @@ -79,37 +79,37 @@ impl RecordRepository for MySqlRecordRepository { .bind(record_type.to_string()) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = ?") .bind(name) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records ORDER BY name") .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn update(&self, record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, record: Record) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -126,19 +126,17 @@ impl RecordRepository for MySqlRecordRepository { .bind(record.zone_id) .bind(record.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM records WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } } diff --git a/src/database/repository/mysql/zone_history_repository_impl.rs b/src/database/repository/mysql/zone_history_repository_impl.rs index 15b2b95..a19e6bf 100644 --- a/src/database/repository/mysql/zone_history_repository_impl.rs +++ b/src/database/repository/mysql/zone_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone_history::ZoneHistory, repository::ZoneHistoryRepository}; use async_trait::async_trait; use sqlx::{MySql, Pool}; @@ -14,37 +15,35 @@ impl MySqlZoneHistoryRepository { #[async_trait] impl ZoneHistoryRepository for MySqlZoneHistoryRepository { - async fn create(&self, mut zone_history: ZoneHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone_history: ZoneHistory) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query("INSERT INTO zone_history (log, zone_id) VALUES (?, ?)") .bind(&zone_history.log) .bind(zone_history.zone_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; zone_history.id = result.last_insert_id() as i32; Ok(zone_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_history = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE id = ?", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone_history) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_histories = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE zone_id = ? ORDER BY created_at DESC", @@ -52,19 +51,18 @@ impl ZoneHistoryRepository for MySqlZoneHistoryRepository { .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zone_history WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/mysql/zone_repository_impl.rs b/src/database/repository/mysql/zone_repository_impl.rs index b1824c0..737c0fe 100644 --- a/src/database/repository/mysql/zone_repository_impl.rs +++ b/src/database/repository/mysql/zone_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone::Zone, repository::ZoneRepository}; use async_trait::async_trait; use sqlx::{MySql, Pool}; @@ -14,8 +15,8 @@ impl MySqlZoneRepository { #[async_trait] impl ZoneRepository for MySqlZoneRepository { - async fn create(&self, mut zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -36,50 +37,50 @@ impl ZoneRepository for MySqlZoneRepository { .bind(zone.minimum_ttl) .execute(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; zone.id = result.last_insert_id() as i32; Ok(zone) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE id = ?") .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE name = ?") .bind(name) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zones = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones ORDER BY name") .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zones) } - async fn update(&self, zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -102,20 +103,18 @@ impl ZoneRepository for MySqlZoneRepository { .bind(zone.minimum_ttl) .bind(zone.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zones WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/postgres/api_token_repository_impl.rs b/src/database/repository/postgres/api_token_repository_impl.rs index 04c3b5d..48af8bd 100644 --- a/src/database/repository/postgres/api_token_repository_impl.rs +++ b/src/database/repository/postgres/api_token_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::api_token::ApiToken, repository::ApiTokenRepository}; use async_trait::async_trait; use sqlx::{Pool, Postgres, Row}; @@ -14,8 +15,8 @@ impl PostgresApiTokenRepository { #[async_trait] impl ApiTokenRepository for PostgresApiTokenRepository { - async fn create(&self, mut token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -28,15 +29,14 @@ impl ApiTokenRepository for PostgresApiTokenRepository { .bind(&token.description) .bind(token.expires_at) .fetch_one(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; token.id = result.get("id"); Ok(token) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let token = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE id = $1" @@ -44,13 +44,13 @@ impl ApiTokenRepository for PostgresApiTokenRepository { .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(token) } - async fn get_by_token(&self, token: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_token(&self, token: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let api_token = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE token = $1" @@ -58,26 +58,26 @@ impl ApiTokenRepository for PostgresApiTokenRepository { .bind(token) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(api_token) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let tokens = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens ORDER BY created_at DESC" ) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(tokens) } - async fn update(&self, token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -91,20 +91,18 @@ impl ApiTokenRepository for PostgresApiTokenRepository { .bind(token.last_used_at) .bind(token.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(token) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM api_tokens WHERE id = $1") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/postgres/record_history_repository_impl.rs b/src/database/repository/postgres/record_history_repository_impl.rs index 10de45e..4f73e12 100644 --- a/src/database/repository/postgres/record_history_repository_impl.rs +++ b/src/database/repository/postgres/record_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::record_history::RecordHistory, repository::RecordHistoryRepository}; use async_trait::async_trait; use sqlx::{Pool, Postgres, Row}; @@ -14,8 +15,11 @@ impl PostgresRecordHistoryRepository { #[async_trait] impl RecordHistoryRepository for PostgresRecordHistoryRepository { - async fn create(&self, mut record_history: RecordHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create( + &self, + mut record_history: RecordHistory, + ) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -27,29 +31,27 @@ impl RecordHistoryRepository for PostgresRecordHistoryRepository { .bind(&record_history.log) .bind(record_history.record_id) .fetch_one(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record_history.id = result.get("id"); Ok(record_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_history = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE id = $1", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record_history) } - async fn get_by_record_id(&self, record_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_record_id(&self, record_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_histories = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE record_id = $1 ORDER BY created_at DESC" @@ -57,19 +59,18 @@ impl RecordHistoryRepository for PostgresRecordHistoryRepository { .bind(record_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM record_history WHERE id = $1") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/postgres/record_repository_impl.rs b/src/database/repository/postgres/record_repository_impl.rs index 1d5009d..18a885e 100644 --- a/src/database/repository/postgres/record_repository_impl.rs +++ b/src/database/repository/postgres/record_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{ model::record::{Record, RecordType}, repository::RecordRepository, @@ -17,8 +18,8 @@ impl PostgresRecordRepository { #[async_trait] impl RecordRepository for PostgresRecordRepository { - async fn create(&self, mut record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut record: Record) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -34,15 +35,14 @@ impl RecordRepository for PostgresRecordRepository { .bind(record.priority) .bind(record.zone_id) .fetch_one(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record.id = result.get("id"); Ok(record) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>( "SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE id = $1" @@ -50,13 +50,13 @@ impl RecordRepository for PostgresRecordRepository { .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>( "SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE zone_id = $1 ORDER BY name" @@ -64,7 +64,7 @@ impl RecordRepository for PostgresRecordRepository { .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } @@ -73,8 +73,8 @@ impl RecordRepository for PostgresRecordRepository { &self, name: &str, record_type: &RecordType, - ) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + ) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>( "SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = $1 AND record_type = $2" @@ -83,13 +83,13 @@ impl RecordRepository for PostgresRecordRepository { .bind(record_type.to_string()) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>( "SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = $1" @@ -97,26 +97,26 @@ impl RecordRepository for PostgresRecordRepository { .bind(name) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>( "SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records ORDER BY name" ) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn update(&self, record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, record: Record) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -133,20 +133,18 @@ impl RecordRepository for PostgresRecordRepository { .bind(record.zone_id) .bind(record.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM records WHERE id = $1") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/postgres/zone_history_repository_impl.rs b/src/database/repository/postgres/zone_history_repository_impl.rs index 07aa5c3..923b584 100644 --- a/src/database/repository/postgres/zone_history_repository_impl.rs +++ b/src/database/repository/postgres/zone_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone_history::ZoneHistory, repository::ZoneHistoryRepository}; use async_trait::async_trait; use sqlx::{Pool, Postgres, Row}; @@ -14,8 +15,8 @@ impl PostgresZoneHistoryRepository { #[async_trait] impl ZoneHistoryRepository for PostgresZoneHistoryRepository { - async fn create(&self, mut zone_history: ZoneHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone_history: ZoneHistory) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -27,29 +28,27 @@ impl ZoneHistoryRepository for PostgresZoneHistoryRepository { .bind(&zone_history.log) .bind(zone_history.zone_id) .fetch_one(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; zone_history.id = result.get("id"); Ok(zone_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_history = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE id = $1", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone_history) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_histories = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE zone_id = $1 ORDER BY created_at DESC" @@ -57,19 +56,18 @@ impl ZoneHistoryRepository for PostgresZoneHistoryRepository { .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zone_history WHERE id = $1") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/postgres/zone_repository_impl.rs b/src/database/repository/postgres/zone_repository_impl.rs index 33aabf1..30ac1ad 100644 --- a/src/database/repository/postgres/zone_repository_impl.rs +++ b/src/database/repository/postgres/zone_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone::Zone, repository::ZoneRepository}; use async_trait::async_trait; use sqlx::{Pool, Postgres, Row}; @@ -14,8 +15,8 @@ impl PostgresZoneRepository { #[async_trait] impl ZoneRepository for PostgresZoneRepository { - async fn create(&self, mut zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -37,14 +38,14 @@ impl ZoneRepository for PostgresZoneRepository { .bind(zone.minimum_ttl) .fetch_one(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; zone.id = result.get("id"); Ok(zone) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>( "SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE id = $1" @@ -52,13 +53,13 @@ impl ZoneRepository for PostgresZoneRepository { .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>( "SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE name = $1" @@ -66,26 +67,26 @@ impl ZoneRepository for PostgresZoneRepository { .bind(name) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zones = sqlx::query_as::<_, Zone>( "SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones ORDER BY name" ) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zones) } - async fn update(&self, zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -109,19 +110,18 @@ impl ZoneRepository for PostgresZoneRepository { .bind(zone.id) .execute(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zones WHERE id = $1") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/sqlite/api_token_repository_impl.rs b/src/database/repository/sqlite/api_token_repository_impl.rs index c302417..8293622 100644 --- a/src/database/repository/sqlite/api_token_repository_impl.rs +++ b/src/database/repository/sqlite/api_token_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::api_token::ApiToken, repository::ApiTokenRepository}; use async_trait::async_trait; use sqlx::{Pool, Sqlite}; @@ -14,8 +15,8 @@ impl SqliteApiTokenRepository { #[async_trait] impl ApiTokenRepository for SqliteApiTokenRepository { - async fn create(&self, mut token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -27,15 +28,14 @@ impl ApiTokenRepository for SqliteApiTokenRepository { .bind(&token.description) .bind(token.expires_at) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; token.id = result.last_insert_rowid() as i32; Ok(token) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let token = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE id = ?" @@ -43,13 +43,13 @@ impl ApiTokenRepository for SqliteApiTokenRepository { .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(token) } - async fn get_by_token(&self, token: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_token(&self, token: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let api_token = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE token = ?" @@ -57,26 +57,26 @@ impl ApiTokenRepository for SqliteApiTokenRepository { .bind(token) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(api_token) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let tokens = sqlx::query_as::<_, ApiToken>( "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens ORDER BY created_at DESC" ) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(tokens) } - async fn update(&self, token: ApiToken) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, token: ApiToken) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -90,20 +90,18 @@ impl ApiTokenRepository for SqliteApiTokenRepository { .bind(token.last_used_at) .bind(token.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(token) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM api_tokens WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/sqlite/record_history_repository_impl.rs b/src/database/repository/sqlite/record_history_repository_impl.rs index 6d87660..06c2044 100644 --- a/src/database/repository/sqlite/record_history_repository_impl.rs +++ b/src/database/repository/sqlite/record_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::record_history::RecordHistory, repository::RecordHistoryRepository}; use async_trait::async_trait; use sqlx::{Pool, Sqlite}; @@ -14,36 +15,37 @@ impl SqliteRecordHistoryRepository { #[async_trait] impl RecordHistoryRepository for SqliteRecordHistoryRepository { - async fn create(&self, mut record_history: RecordHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create( + &self, + mut record_history: RecordHistory, + ) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query("INSERT INTO record_history (log, record_id) VALUES (?, ?)") .bind(&record_history.log) .bind(record_history.record_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record_history.id = result.last_insert_rowid() as i32; Ok(record_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_history = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE id = ?", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record_history) } - async fn get_by_record_id(&self, record_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_record_id(&self, record_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record_histories = sqlx::query_as::<_, RecordHistory>( "SELECT id, log, created_at, record_id FROM record_history WHERE record_id = ? ORDER BY created_at DESC", @@ -51,19 +53,18 @@ impl RecordHistoryRepository for SqliteRecordHistoryRepository { .bind(record_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM record_history WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/sqlite/record_repository_impl.rs b/src/database/repository/sqlite/record_repository_impl.rs index 5fcc08d..1e51c5e 100644 --- a/src/database/repository/sqlite/record_repository_impl.rs +++ b/src/database/repository/sqlite/record_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{ model::record::{Record, RecordType}, repository::RecordRepository, @@ -17,8 +18,8 @@ impl SqliteRecordRepository { #[async_trait] impl RecordRepository for SqliteRecordRepository { - async fn create(&self, mut record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut record: Record) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -33,34 +34,33 @@ impl RecordRepository for SqliteRecordRepository { .bind(record.priority) .bind(record.zone_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; record.id = result.last_insert_rowid() as i32; Ok(record) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE id = ?") .bind(id) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE zone_id = ? ORDER BY name") .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } @@ -69,8 +69,8 @@ impl RecordRepository for SqliteRecordRepository { &self, name: &str, record_type: &RecordType, - ) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + ) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let record = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = ? AND record_type = ?") @@ -78,37 +78,37 @@ impl RecordRepository for SqliteRecordRepository { .bind(record_type.to_string()) .fetch_optional(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(record) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records WHERE name = ?") .bind(name) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let records = sqlx::query_as::<_, Record>("SELECT id, name, record_type, value, ttl, priority, created_at, zone_id FROM records ORDER BY name") .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(records) } - async fn update(&self, record: Record) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, record: Record) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -125,20 +125,18 @@ impl RecordRepository for SqliteRecordRepository { .bind(record.zone_id) .bind(record.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(record) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM records WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/sqlite/zone_history_repository_impl.rs b/src/database/repository/sqlite/zone_history_repository_impl.rs index 2990b71..3b96eed 100644 --- a/src/database/repository/sqlite/zone_history_repository_impl.rs +++ b/src/database/repository/sqlite/zone_history_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone_history::ZoneHistory, repository::ZoneHistoryRepository}; use async_trait::async_trait; use sqlx::{Pool, Sqlite}; @@ -14,36 +15,34 @@ impl SqliteZoneHistoryRepository { #[async_trait] impl ZoneHistoryRepository for SqliteZoneHistoryRepository { - async fn create(&self, mut zone_history: ZoneHistory) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone_history: ZoneHistory) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query("INSERT INTO zone_history (log, zone_id) VALUES (?, ?)") .bind(&zone_history.log) .bind(zone_history.zone_id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; zone_history.id = result.last_insert_rowid() as i32; Ok(zone_history) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_history = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE id = ?", ) .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone_history) } - async fn get_by_zone_id(&self, zone_id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_zone_id(&self, zone_id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone_histories = sqlx::query_as::<_, ZoneHistory>( "SELECT id, log, created_at, zone_id FROM zone_history WHERE zone_id = ? ORDER BY created_at DESC", @@ -51,19 +50,18 @@ impl ZoneHistoryRepository for SqliteZoneHistoryRepository { .bind(zone_id) .fetch_all(&mut *conn) .await - .map_err(|e| e.to_string())?; + ?; Ok(zone_histories) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zone_history WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/database/repository/sqlite/zone_repository_impl.rs b/src/database/repository/sqlite/zone_repository_impl.rs index d87bc52..a687fdf 100644 --- a/src/database/repository/sqlite/zone_repository_impl.rs +++ b/src/database/repository/sqlite/zone_repository_impl.rs @@ -1,3 +1,4 @@ +use crate::database::error::DatabaseError; use crate::database::{model::zone::Zone, repository::ZoneRepository}; use async_trait::async_trait; use sqlx::{Pool, Sqlite}; @@ -14,8 +15,8 @@ impl SqliteZoneRepository { #[async_trait] impl ZoneRepository for SqliteZoneRepository { - async fn create(&self, mut zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn create(&self, mut zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; let result = sqlx::query( r#" @@ -35,50 +36,46 @@ impl ZoneRepository for SqliteZoneRepository { .bind(zone.expire) .bind(zone.minimum_ttl) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; zone.id = result.last_insert_rowid() as i32; Ok(zone) } - async fn get_by_id(&self, id: i32) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_id(&self, id: i32) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE id = ?") .bind(id) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone) } - async fn get_by_name(&self, name: &str) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_by_name(&self, name: &str) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zone = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones WHERE name = ?") .bind(name) .fetch_optional(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone) } - async fn get_all(&self) -> Result, String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn get_all(&self) -> Result, DatabaseError> { + let mut conn = self.pool.acquire().await?; let zones = sqlx::query_as::<_, Zone>("SELECT id, name, primary_ns, primary_ns_ip, primary_ns_ipv6, admin_email, ttl, serial, refresh, retry, expire, minimum_ttl, created_at FROM zones ORDER BY name") .fetch_all(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zones) } - async fn update(&self, zone: Zone) -> Result { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn update(&self, zone: Zone) -> Result { + let mut conn = self.pool.acquire().await?; sqlx::query( r#" @@ -101,20 +98,18 @@ impl ZoneRepository for SqliteZoneRepository { .bind(zone.minimum_ttl) .bind(zone.id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(zone) } - async fn delete(&self, id: i32) -> Result<(), String> { - let mut conn = self.pool.acquire().await.map_err(|e| e.to_string())?; + async fn delete(&self, id: i32) -> Result<(), DatabaseError> { + let mut conn = self.pool.acquire().await?; sqlx::query("DELETE FROM zones WHERE id = ?") .bind(id) .execute(&mut *conn) - .await - .map_err(|e| e.to_string())?; + .await?; Ok(()) } diff --git a/src/error/mod.rs b/src/error/mod.rs new file mode 100644 index 0000000..ee8d0f2 --- /dev/null +++ b/src/error/mod.rs @@ -0,0 +1,30 @@ +use thiserror::Error; + +use crate::{ + api::validation::ValidationError, + config::error::ConfigError, + database::error::DatabaseError, + rndc::error::RndcError, +}; + +/// Top-level error type +#[derive(Debug, Error)] +pub enum BindizrError { + #[error("Database error: {0}")] + Database(#[from] DatabaseError), + + #[error("Configuration error: {0}")] + Config(#[from] ConfigError), + + #[error("RNDC error: {0}")] + Rndc(#[from] RndcError), + + #[error("Validation error: {0}")] + Validation(#[from] ValidationError), + + #[error("Internal error: {0}")] + Internal(String), +} + +/// Type alias +pub type Result = std::result::Result; diff --git a/src/lib.rs b/src/lib.rs index 7c7b427..4f4b0f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod api; pub mod cli; pub mod config; pub mod database; +pub mod error; pub mod logger; pub mod rndc; pub mod serializer; diff --git a/src/rndc/error.rs b/src/rndc/error.rs new file mode 100644 index 0000000..dd577a5 --- /dev/null +++ b/src/rndc/error.rs @@ -0,0 +1,18 @@ +use thiserror::Error; + +/// TODO: RNDC-related errors +#[allow(dead_code)] +#[derive(Debug, Error)] +pub enum RndcError { + #[error("Command execution failed: {0}")] + CommandFailed(String), + + #[error("Connection failed: {0}")] + ConnectionFailed(String), + + #[error("Panic occurred: {0}")] + PanicOccurred(String), + + #[error("Invalid response: {0}")] + InvalidResponse(String), +} diff --git a/src/rndc/mod.rs b/src/rndc/mod.rs index e08d167..5ea49ff 100644 --- a/src/rndc/mod.rs +++ b/src/rndc/mod.rs @@ -1,5 +1,7 @@ +pub mod error; + +use self::error::RndcError; use crate::log_info; -use std::panic::{AssertUnwindSafe, catch_unwind}; use std::sync::OnceLock; pub fn initialize() { @@ -18,25 +20,24 @@ impl RndcClient { let secret_key = crate::config::get_config::("bind.rndc_secret_key"); RndcClient { - client: rndc::RndcClient::new(&server_url, &algorithm, &secret_key), + client: rndc::RndcClient::new(&server_url, &algorithm, &secret_key) + .expect("Failed to initialize RNDC client"), } } - pub fn command(&self, command: &str) -> Result { - let result = catch_unwind(AssertUnwindSafe(|| { - let res = self.client.rndc_command(command)?; - - if !res.result { - return Err("Failed to execute RNDC command".to_string()); - } + pub fn command(&self, command: &str) -> Result { + let res = self + .client + .rndc_command(command) + .map_err(|e| RndcError::CommandFailed(e.to_string()))?; - Ok(res) - })); - - match result { - Ok(res) => res, - Err(_) => Err("Panic occurred while accessing RNDC client".to_string()), + if !res.result { + return Err(RndcError::CommandFailed( + "Command execution failed".to_string(), + )); } + + Ok(res) } } diff --git a/src/serializer/mod.rs b/src/serializer/mod.rs index 1a24dd1..d5c2327 100644 --- a/src/serializer/mod.rs +++ b/src/serializer/mod.rs @@ -9,8 +9,8 @@ use crate::database::{ zone::Zone, }, }; -use crate::{log_error, log_info}; use crate::serializer::utils::{to_bind_rname, to_fqdn, to_relative_domain}; +use crate::{log_error, log_info}; use std::collections::HashMap; use std::fmt::Write; @@ -195,12 +195,7 @@ $TTL {} .unwrap(); // Add NS, A, AAAA records for the primary NS - writeln!( - &mut output, - "@ IN NS {}", - to_fqdn(&zone.primary_ns) - ) - .unwrap(); + writeln!(&mut output, "@ IN NS {}", to_fqdn(&zone.primary_ns)).unwrap(); if let Some(ip) = &zone.primary_ns_ip { writeln!( @@ -301,9 +296,9 @@ $TTL {} "{} {} IN SRV {} {} {} {}", name, ttl, - priority, // default priority - parts[0], // weight - parts[1], // port + priority, // default priority + parts[0], // weight + parts[1], // port to_fqdn(parts[2]), // target ) } else { @@ -311,9 +306,9 @@ $TTL {} &mut output, "{} IN SRV {} {} {} {}", name, - priority, // default priority - parts[0], // weight - parts[1], // port + priority, // default priority + parts[0], // weight + parts[1], // port to_fqdn(parts[2]), // target ) } @@ -331,12 +326,7 @@ $TTL {} record.value ) } else { - writeln!( - &mut output, - "{} IN SOA {}", - to_fqdn(name), - record.value - ) + writeln!(&mut output, "{} IN SOA {}", to_fqdn(name), record.value) } .unwrap(); } diff --git a/tests/api/mod.rs b/tests/api/mod.rs index 28d7115..81c6c65 100644 --- a/tests/api/mod.rs +++ b/tests/api/mod.rs @@ -20,13 +20,13 @@ mod test { async fn test_error_handling() { let ctx = TestContext::new().await; - // Test 400 for non-existent zone + // Test 404 for non-existent zone let (status, _) = ctx.make_request("GET", "/zones/99999", None).await; - assert_eq!(status, StatusCode::BAD_REQUEST); + assert_eq!(status, StatusCode::NOT_FOUND); - // Test 400 for non-existent record + // Test 404 for non-existent record let (status, _) = ctx.make_request("GET", "/records/99999", None).await; - assert_eq!(status, StatusCode::BAD_REQUEST); + assert_eq!(status, StatusCode::NOT_FOUND); // Test invalid JSON for zone creation let invalid_json = serde_json::json!({ diff --git a/tests/api/record.rs b/tests/api/record.rs index 0b8708c..4f8b068 100644 --- a/tests/api/record.rs +++ b/tests/api/record.rs @@ -99,7 +99,7 @@ async fn test_record_crud_operations() { let (status, _) = ctx .make_request("GET", &format!("/records/{}", record_id), None) .await; - assert_eq!(status, StatusCode::BAD_REQUEST); + assert_eq!(status, StatusCode::NOT_FOUND); } #[tokio::test] @@ -237,7 +237,6 @@ async fn test_cname_validation() { assert_eq!(status, StatusCode::BAD_REQUEST); } - #[tokio::test] async fn test_prevent_default_records_creation() { let ctx = TestContext::new().await; @@ -309,4 +308,4 @@ async fn test_prevent_updating_to_default_records() { ) .await; assert_eq!(status, StatusCode::BAD_REQUEST); -} \ No newline at end of file +} diff --git a/tests/api/zone.rs b/tests/api/zone.rs index fdad523..7a4ca80 100644 --- a/tests/api/zone.rs +++ b/tests/api/zone.rs @@ -80,7 +80,7 @@ async fn test_zone_crud_operations() { let (status, _) = ctx .make_request("GET", &format!("/zones/{}", zone_id), None) .await; - assert_eq!(status, StatusCode::BAD_REQUEST); + assert_eq!(status, StatusCode::NOT_FOUND); // Test creating a zone with only primary_ns_ip let create_zone_ip_only = serde_json::json!({ diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 33969c0..2189f89 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -92,7 +92,7 @@ impl TestContext { .bind(zone.retry) .bind(zone.expire) .bind(zone.minimum_ttl) - .bind(&zone.created_at) + .bind(zone.created_at) .execute(&self.db_pool) .await .expect("Failed to insert test zone"); @@ -128,7 +128,7 @@ impl TestContext { .bind(&record.value) .bind(record.ttl) .bind(record.priority) - .bind(&record.created_at) + .bind(record.created_at) .bind(record.zone_id) .execute(&self.db_pool) .await