Your locally hosted lumina server for IDAPro

Compare changes

Choose any two refs to compare.

+5
.github/ISSUE_TEMPLATE/config.yml
··· 1 + blank_issues_enabled: false 2 + contact_links: 3 + - name: Community support 4 + url: https://github.com/naim94a/lumen/discussions 5 + about: Please ask questions here
+2
.github/workflows/rust.yml
··· 35 35 toolchain: stable 36 36 override: true 37 37 profile: minimal 38 + - name: Code Formatting 39 + run: cargo fmt --check 38 40 - name: Build 39 41 run: cargo build 40 42 - name: Run tests
+32 -4
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 3 ## [Unreleased] - _TBD_ 4 + 5 + ## [v0.4.0] - 2024-03-19 6 + 7 + ### Added 8 + 9 + - Implemented the function histories command. 10 + - Configurable time limits. 11 + 12 + ### Fixed 13 + 14 + - RPC HelloResult will now report if deletes are enabled. 15 + 16 + ### Changes 17 + 18 + - Applied code formatting using `cargo fmt` 19 + 20 + ## [v0.3.0] - 2023-08-22 21 + 4 22 ### Added 23 + 5 24 - This changelog. 6 25 - Support for IDA 8.1+ delete command. 7 26 - Pooling for connections to database. 8 27 - Attempt to cancel immutable database queries if client leaves. 9 28 - Database migrations via Diesel ORM. 29 + - Support for IDA 8.3+ hello response. 30 + - Add Metrics for prometheus. 10 31 11 32 ### Fixed 33 + 12 34 - 8K stack size is too small for debug builds. 13 35 14 36 ## [v0.2.0] - 2022-10-12 37 + 15 38 ### Added 39 + 16 40 - Protocol: support for IDA 8.1+ user authentication. 17 41 - Client connection duration limitations. 42 + 18 43 ### Changed 44 + 19 45 - Tokio's thread size is reduced from 4M to 8K. 20 46 21 - ## [v0.1.0] - 2021-01-21 47 + ## [v0.1.0] - 2021-01-21 48 + 22 49 This is Lumen's first tagged release. It contains a few fixes and dependency updates since the initial commit (2020-12-17). 23 50 24 - 25 - [Unreleased]: https://github.com/naim94a/lumen/compare/8b78d0a7d5b3ef4e0f221b07903fa5252174b57b...HEAD 26 - [v0.2.0]: https://github.com/naim94a/lumen/compare/v0.1.0...8b78d0a7d5b3ef4e0f221b07903fa5252174b57b 51 + [Unreleased]: https://github.com/naim94a/lumen/compare/v0.4.0...HEAD 52 + [v0.4.0]: https://github.com/naim94a/lumen/compare/v0.3.0...v0.4.0 53 + [v0.3.0]: https://github.com/naim94a/lumen/compare/v0.2.0...v0.3.0 54 + [v0.2.0]: https://github.com/naim94a/lumen/compare/v0.1.0...v0.2.0 27 55 [v0.1.0]: https://github.com/naim94a/lumen/releases/tag/v0.1.0
+830 -539
Cargo.lock
··· 1 1 # This file is automatically @generated by Cargo. 2 2 # It is not intended for manual editing. 3 - version = 3 3 + version = 4 4 4 5 5 [[package]] 6 6 name = "addr2line" 7 - version = "0.21.0" 7 + version = "0.24.2" 8 8 source = "registry+https://github.com/rust-lang/crates.io-index" 9 - checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 9 + checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 10 dependencies = [ 11 11 "gimli", 12 12 ] 13 13 14 14 [[package]] 15 - name = "adler" 16 - version = "1.0.2" 15 + name = "adler2" 16 + version = "2.0.0" 17 17 source = "registry+https://github.com/rust-lang/crates.io-index" 18 - checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 18 + checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 19 20 20 [[package]] 21 21 name = "aho-corasick" 22 - version = "1.1.2" 22 + version = "1.1.3" 23 23 source = "registry+https://github.com/rust-lang/crates.io-index" 24 - checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 24 + checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 25 dependencies = [ 26 26 "memchr", 27 27 ] 28 28 29 29 [[package]] 30 30 name = "anstream" 31 - version = "0.6.5" 31 + version = "0.6.19" 32 32 source = "registry+https://github.com/rust-lang/crates.io-index" 33 - checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" 33 + checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" 34 34 dependencies = [ 35 35 "anstyle", 36 36 "anstyle-parse", 37 37 "anstyle-query", 38 38 "anstyle-wincon", 39 39 "colorchoice", 40 + "is_terminal_polyfill", 40 41 "utf8parse", 41 42 ] 42 43 43 44 [[package]] 44 45 name = "anstyle" 45 - version = "1.0.4" 46 + version = "1.0.11" 46 47 source = "registry+https://github.com/rust-lang/crates.io-index" 47 - checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" 48 + checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 48 49 49 50 [[package]] 50 51 name = "anstyle-parse" 51 - version = "0.2.3" 52 + version = "0.2.7" 52 53 source = "registry+https://github.com/rust-lang/crates.io-index" 53 - checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 54 + checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 54 55 dependencies = [ 55 56 "utf8parse", 56 57 ] 57 58 58 59 [[package]] 59 60 name = "anstyle-query" 60 - version = "1.0.2" 61 + version = "1.1.3" 61 62 source = "registry+https://github.com/rust-lang/crates.io-index" 62 - checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 63 + checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 63 64 dependencies = [ 64 - "windows-sys 0.52.0", 65 + "windows-sys 0.59.0", 65 66 ] 66 67 67 68 [[package]] 68 69 name = "anstyle-wincon" 69 - version = "3.0.2" 70 + version = "3.0.9" 70 71 source = "registry+https://github.com/rust-lang/crates.io-index" 71 - checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 72 + checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 72 73 dependencies = [ 73 74 "anstyle", 74 - "windows-sys 0.52.0", 75 + "once_cell_polyfill", 76 + "windows-sys 0.59.0", 75 77 ] 76 78 77 79 [[package]] 78 80 name = "anyhow" 79 - version = "1.0.75" 81 + version = "1.0.98" 80 82 source = "registry+https://github.com/rust-lang/crates.io-index" 81 - checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 83 + checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 82 84 83 85 [[package]] 84 86 name = "async-trait" 85 - version = "0.1.74" 87 + version = "0.1.88" 86 88 source = "registry+https://github.com/rust-lang/crates.io-index" 87 - checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" 89 + checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 88 90 dependencies = [ 89 91 "proc-macro2", 90 92 "quote", ··· 93 95 94 96 [[package]] 95 97 name = "autocfg" 96 - version = "1.1.0" 98 + version = "1.4.0" 97 99 source = "registry+https://github.com/rust-lang/crates.io-index" 98 - checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 100 + checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 99 101 100 102 [[package]] 101 103 name = "backtrace" 102 - version = "0.3.69" 104 + version = "0.3.75" 103 105 source = "registry+https://github.com/rust-lang/crates.io-index" 104 - checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 106 + checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 105 107 dependencies = [ 106 108 "addr2line", 107 - "cc", 108 109 "cfg-if", 109 110 "libc", 110 111 "miniz_oxide", 111 112 "object", 112 113 "rustc-demangle", 114 + "windows-targets", 113 115 ] 114 116 115 117 [[package]] 116 118 name = "base64" 117 - version = "0.21.5" 119 + version = "0.21.7" 120 + source = "registry+https://github.com/rust-lang/crates.io-index" 121 + checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 122 + 123 + [[package]] 124 + name = "base64" 125 + version = "0.22.1" 118 126 source = "registry+https://github.com/rust-lang/crates.io-index" 119 - checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" 127 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 120 128 121 129 [[package]] 122 130 name = "bb8" 123 - version = "0.8.1" 131 + version = "0.8.6" 124 132 source = "registry+https://github.com/rust-lang/crates.io-index" 125 - checksum = "98b4b0f25f18bcdc3ac72bdb486ed0acf7e185221fd4dc985bc15db5800b0ba2" 133 + checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" 126 134 dependencies = [ 127 135 "async-trait", 128 - "futures-channel", 129 136 "futures-util", 130 137 "parking_lot", 131 138 "tokio", ··· 139 146 140 147 [[package]] 141 148 name = "bitflags" 142 - version = "1.3.2" 149 + version = "2.9.1" 143 150 source = "registry+https://github.com/rust-lang/crates.io-index" 144 - checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 145 - 146 - [[package]] 147 - name = "bitflags" 148 - version = "2.4.1" 149 - source = "registry+https://github.com/rust-lang/crates.io-index" 150 - checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 151 + checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 151 152 152 153 [[package]] 153 154 name = "block-buffer" ··· 160 161 161 162 [[package]] 162 163 name = "bumpalo" 163 - version = "3.14.0" 164 + version = "3.18.1" 164 165 source = "registry+https://github.com/rust-lang/crates.io-index" 165 - checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 166 + checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" 166 167 167 168 [[package]] 168 169 name = "byteorder" ··· 172 173 173 174 [[package]] 174 175 name = "bytes" 175 - version = "1.5.0" 176 + version = "1.10.1" 176 177 source = "registry+https://github.com/rust-lang/crates.io-index" 177 - checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 178 + checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 178 179 179 180 [[package]] 180 181 name = "cc" 181 - version = "1.0.83" 182 + version = "1.2.26" 182 183 source = "registry+https://github.com/rust-lang/crates.io-index" 183 - checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 184 + checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" 184 185 dependencies = [ 185 - "libc", 186 + "shlex", 186 187 ] 187 188 188 189 [[package]] ··· 193 194 194 195 [[package]] 195 196 name = "clap" 196 - version = "4.4.11" 197 + version = "4.5.39" 197 198 source = "registry+https://github.com/rust-lang/crates.io-index" 198 - checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" 199 + checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" 199 200 dependencies = [ 200 201 "clap_builder", 201 202 ] 202 203 203 204 [[package]] 204 205 name = "clap_builder" 205 - version = "4.4.11" 206 + version = "4.5.39" 206 207 source = "registry+https://github.com/rust-lang/crates.io-index" 207 - checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" 208 + checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" 208 209 dependencies = [ 209 210 "anstream", 210 211 "anstyle", ··· 214 215 215 216 [[package]] 216 217 name = "clap_lex" 217 - version = "0.6.0" 218 + version = "0.7.4" 218 219 source = "registry+https://github.com/rust-lang/crates.io-index" 219 - checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" 220 + checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 220 221 221 222 [[package]] 222 223 name = "colorchoice" 223 - version = "1.0.0" 224 + version = "1.0.4" 224 225 source = "registry+https://github.com/rust-lang/crates.io-index" 225 - checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 226 + checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 226 227 227 228 [[package]] 228 229 name = "common" ··· 238 239 "postgres-native-tls", 239 240 "prometheus-client", 240 241 "serde", 242 + "time", 241 243 "tokio", 242 244 "tokio-postgres", 243 245 "toml", ··· 256 258 257 259 [[package]] 258 260 name = "core-foundation-sys" 259 - version = "0.8.6" 261 + version = "0.8.7" 260 262 source = "registry+https://github.com/rust-lang/crates.io-index" 261 - checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 263 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 262 264 263 265 [[package]] 264 266 name = "cpufeatures" 265 - version = "0.2.11" 267 + version = "0.2.17" 266 268 source = "registry+https://github.com/rust-lang/crates.io-index" 267 - checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" 269 + checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 268 270 dependencies = [ 269 271 "libc", 270 272 ] ··· 280 282 ] 281 283 282 284 [[package]] 285 + name = "darling" 286 + version = "0.20.11" 287 + source = "registry+https://github.com/rust-lang/crates.io-index" 288 + checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 289 + dependencies = [ 290 + "darling_core", 291 + "darling_macro", 292 + ] 293 + 294 + [[package]] 295 + name = "darling_core" 296 + version = "0.20.11" 297 + source = "registry+https://github.com/rust-lang/crates.io-index" 298 + checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 299 + dependencies = [ 300 + "fnv", 301 + "ident_case", 302 + "proc-macro2", 303 + "quote", 304 + "strsim", 305 + "syn", 306 + ] 307 + 308 + [[package]] 309 + name = "darling_macro" 310 + version = "0.20.11" 311 + source = "registry+https://github.com/rust-lang/crates.io-index" 312 + checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 313 + dependencies = [ 314 + "darling_core", 315 + "quote", 316 + "syn", 317 + ] 318 + 319 + [[package]] 283 320 name = "data-encoding" 284 - version = "2.5.0" 321 + version = "2.9.0" 285 322 source = "registry+https://github.com/rust-lang/crates.io-index" 286 - checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" 323 + checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 287 324 288 325 [[package]] 289 326 name = "deranged" 290 - version = "0.3.10" 327 + version = "0.4.0" 291 328 source = "registry+https://github.com/rust-lang/crates.io-index" 292 - checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" 329 + checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 293 330 dependencies = [ 294 331 "powerfmt", 295 332 ] 296 333 297 334 [[package]] 298 335 name = "diesel" 299 - version = "2.1.4" 336 + version = "2.2.10" 300 337 source = "registry+https://github.com/rust-lang/crates.io-index" 301 - checksum = "62c6fcf842f17f8c78ecf7c81d75c5ce84436b41ee07e03f490fbb5f5a8731d8" 338 + checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506" 302 339 dependencies = [ 303 - "bitflags 2.4.1", 340 + "bitflags", 304 341 "byteorder", 305 342 "diesel_derives", 306 343 "itoa", ··· 309 346 310 347 [[package]] 311 348 name = "diesel-async" 312 - version = "0.3.2" 349 + version = "0.5.2" 313 350 source = "registry+https://github.com/rust-lang/crates.io-index" 314 - checksum = "c7e7974099f0d9bde0e010dd3a673555276a474f3362a7a52ab535a57b7c5056" 351 + checksum = "51a307ac00f7c23f526a04a77761a0519b9f0eb2838ebf5b905a58580095bdcb" 315 352 dependencies = [ 316 353 "async-trait", 317 354 "bb8", ··· 324 361 325 362 [[package]] 326 363 name = "diesel_derives" 327 - version = "2.1.2" 364 + version = "2.2.5" 328 365 source = "registry+https://github.com/rust-lang/crates.io-index" 329 - checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" 366 + checksum = "68d4216021b3ea446fd2047f5c8f8fe6e98af34508a254a01e4d6bc1e844f84d" 330 367 dependencies = [ 331 368 "diesel_table_macro_syntax", 369 + "dsl_auto_type", 332 370 "proc-macro2", 333 371 "quote", 334 372 "syn", ··· 336 374 337 375 [[package]] 338 376 name = "diesel_table_macro_syntax" 339 - version = "0.1.0" 377 + version = "0.2.0" 340 378 source = "registry+https://github.com/rust-lang/crates.io-index" 341 - checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" 379 + checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" 342 380 dependencies = [ 343 381 "syn", 344 382 ] ··· 355 393 ] 356 394 357 395 [[package]] 396 + name = "displaydoc" 397 + version = "0.2.5" 398 + source = "registry+https://github.com/rust-lang/crates.io-index" 399 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 400 + dependencies = [ 401 + "proc-macro2", 402 + "quote", 403 + "syn", 404 + ] 405 + 406 + [[package]] 407 + name = "dsl_auto_type" 408 + version = "0.1.3" 409 + source = "registry+https://github.com/rust-lang/crates.io-index" 410 + checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b" 411 + dependencies = [ 412 + "darling", 413 + "either", 414 + "heck", 415 + "proc-macro2", 416 + "quote", 417 + "syn", 418 + ] 419 + 420 + [[package]] 358 421 name = "dtoa" 359 - version = "1.0.9" 422 + version = "1.0.10" 360 423 source = "registry+https://github.com/rust-lang/crates.io-index" 361 - checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" 424 + checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" 425 + 426 + [[package]] 427 + name = "either" 428 + version = "1.15.0" 429 + source = "registry+https://github.com/rust-lang/crates.io-index" 430 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 362 431 363 432 [[package]] 364 433 name = "encoding_rs" 365 - version = "0.8.33" 434 + version = "0.8.35" 366 435 source = "registry+https://github.com/rust-lang/crates.io-index" 367 - checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" 436 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 368 437 dependencies = [ 369 438 "cfg-if", 370 439 ] 371 440 372 441 [[package]] 373 442 name = "env_logger" 374 - version = "0.10.1" 443 + version = "0.10.2" 375 444 source = "registry+https://github.com/rust-lang/crates.io-index" 376 - checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" 445 + checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" 377 446 dependencies = [ 378 447 "humantime", 379 448 "is-terminal", ··· 384 453 385 454 [[package]] 386 455 name = "equivalent" 387 - version = "1.0.1" 456 + version = "1.0.2" 388 457 source = "registry+https://github.com/rust-lang/crates.io-index" 389 - checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 458 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 390 459 391 460 [[package]] 392 461 name = "errno" 393 - version = "0.3.8" 462 + version = "0.3.12" 394 463 source = "registry+https://github.com/rust-lang/crates.io-index" 395 - checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 464 + checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" 396 465 dependencies = [ 397 466 "libc", 398 - "windows-sys 0.52.0", 467 + "windows-sys 0.59.0", 399 468 ] 400 469 401 470 [[package]] ··· 406 475 407 476 [[package]] 408 477 name = "fastrand" 409 - version = "2.0.1" 410 - source = "registry+https://github.com/rust-lang/crates.io-index" 411 - checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 412 - 413 - [[package]] 414 - name = "finl_unicode" 415 - version = "1.2.0" 478 + version = "2.3.0" 416 479 source = "registry+https://github.com/rust-lang/crates.io-index" 417 - checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" 480 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 418 481 419 482 [[package]] 420 483 name = "fnv" ··· 447 510 ] 448 511 449 512 [[package]] 450 - name = "futures" 451 - version = "0.3.29" 452 - source = "registry+https://github.com/rust-lang/crates.io-index" 453 - checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" 454 - dependencies = [ 455 - "futures-channel", 456 - "futures-core", 457 - "futures-executor", 458 - "futures-io", 459 - "futures-sink", 460 - "futures-task", 461 - "futures-util", 462 - ] 463 - 464 - [[package]] 465 513 name = "futures-channel" 466 - version = "0.3.29" 514 + version = "0.3.31" 467 515 source = "registry+https://github.com/rust-lang/crates.io-index" 468 - checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" 516 + checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 469 517 dependencies = [ 470 518 "futures-core", 471 519 "futures-sink", ··· 473 521 474 522 [[package]] 475 523 name = "futures-core" 476 - version = "0.3.29" 524 + version = "0.3.31" 477 525 source = "registry+https://github.com/rust-lang/crates.io-index" 478 - checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" 479 - 480 - [[package]] 481 - name = "futures-executor" 482 - version = "0.3.29" 483 - source = "registry+https://github.com/rust-lang/crates.io-index" 484 - checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" 485 - dependencies = [ 486 - "futures-core", 487 - "futures-task", 488 - "futures-util", 489 - ] 490 - 491 - [[package]] 492 - name = "futures-io" 493 - version = "0.3.29" 494 - source = "registry+https://github.com/rust-lang/crates.io-index" 495 - checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" 526 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 496 527 497 528 [[package]] 498 529 name = "futures-macro" 499 - version = "0.3.29" 530 + version = "0.3.31" 500 531 source = "registry+https://github.com/rust-lang/crates.io-index" 501 - checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" 532 + checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 502 533 dependencies = [ 503 534 "proc-macro2", 504 535 "quote", ··· 507 538 508 539 [[package]] 509 540 name = "futures-sink" 510 - version = "0.3.29" 541 + version = "0.3.31" 511 542 source = "registry+https://github.com/rust-lang/crates.io-index" 512 - checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" 543 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 513 544 514 545 [[package]] 515 546 name = "futures-task" 516 - version = "0.3.29" 547 + version = "0.3.31" 517 548 source = "registry+https://github.com/rust-lang/crates.io-index" 518 - checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" 549 + checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 519 550 520 551 [[package]] 521 552 name = "futures-util" 522 - version = "0.3.29" 553 + version = "0.3.31" 523 554 source = "registry+https://github.com/rust-lang/crates.io-index" 524 - checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" 555 + checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 525 556 dependencies = [ 526 - "futures-channel", 527 557 "futures-core", 528 - "futures-io", 529 558 "futures-macro", 530 559 "futures-sink", 531 560 "futures-task", 532 - "memchr", 533 561 "pin-project-lite", 534 562 "pin-utils", 535 563 "slab", ··· 547 575 548 576 [[package]] 549 577 name = "getrandom" 550 - version = "0.2.11" 578 + version = "0.2.16" 551 579 source = "registry+https://github.com/rust-lang/crates.io-index" 552 - checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" 580 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 553 581 dependencies = [ 554 582 "cfg-if", 555 583 "libc", 556 - "wasi", 584 + "wasi 0.11.0+wasi-snapshot-preview1", 585 + ] 586 + 587 + [[package]] 588 + name = "getrandom" 589 + version = "0.3.3" 590 + source = "registry+https://github.com/rust-lang/crates.io-index" 591 + checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 592 + dependencies = [ 593 + "cfg-if", 594 + "libc", 595 + "r-efi", 596 + "wasi 0.14.2+wasi-0.2.4", 557 597 ] 558 598 559 599 [[package]] 560 600 name = "gimli" 561 - version = "0.28.1" 601 + version = "0.31.1" 562 602 source = "registry+https://github.com/rust-lang/crates.io-index" 563 - checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 603 + checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 564 604 565 605 [[package]] 566 606 name = "h2" 567 - version = "0.3.22" 607 + version = "0.3.26" 568 608 source = "registry+https://github.com/rust-lang/crates.io-index" 569 - checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" 609 + checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 570 610 dependencies = [ 571 611 "bytes", 572 612 "fnv", 573 613 "futures-core", 574 614 "futures-sink", 575 615 "futures-util", 576 - "http", 616 + "http 0.2.12", 577 617 "indexmap", 578 618 "slab", 579 619 "tokio", ··· 583 623 584 624 [[package]] 585 625 name = "hashbrown" 586 - version = "0.14.3" 626 + version = "0.15.4" 587 627 source = "registry+https://github.com/rust-lang/crates.io-index" 588 - checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 628 + checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" 589 629 590 630 [[package]] 591 631 name = "headers" ··· 593 633 source = "registry+https://github.com/rust-lang/crates.io-index" 594 634 checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" 595 635 dependencies = [ 596 - "base64", 636 + "base64 0.21.7", 597 637 "bytes", 598 638 "headers-core", 599 - "http", 639 + "http 0.2.12", 600 640 "httpdate", 601 641 "mime", 602 642 "sha1", ··· 608 648 source = "registry+https://github.com/rust-lang/crates.io-index" 609 649 checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 610 650 dependencies = [ 611 - "http", 651 + "http 0.2.12", 612 652 ] 613 653 614 654 [[package]] 655 + name = "heck" 656 + version = "0.5.0" 657 + source = "registry+https://github.com/rust-lang/crates.io-index" 658 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 659 + 660 + [[package]] 615 661 name = "hermit-abi" 616 - version = "0.3.3" 662 + version = "0.5.1" 617 663 source = "registry+https://github.com/rust-lang/crates.io-index" 618 - checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 664 + checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" 619 665 620 666 [[package]] 621 667 name = "hmac" ··· 628 674 629 675 [[package]] 630 676 name = "http" 631 - version = "0.2.11" 677 + version = "0.2.12" 678 + source = "registry+https://github.com/rust-lang/crates.io-index" 679 + checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 680 + dependencies = [ 681 + "bytes", 682 + "fnv", 683 + "itoa", 684 + ] 685 + 686 + [[package]] 687 + name = "http" 688 + version = "1.3.1" 632 689 source = "registry+https://github.com/rust-lang/crates.io-index" 633 - checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" 690 + checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 634 691 dependencies = [ 635 692 "bytes", 636 693 "fnv", ··· 644 701 checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 645 702 dependencies = [ 646 703 "bytes", 647 - "http", 704 + "http 0.2.12", 648 705 "pin-project-lite", 649 706 ] 650 707 651 708 [[package]] 652 709 name = "httparse" 653 - version = "1.8.0" 710 + version = "1.10.1" 654 711 source = "registry+https://github.com/rust-lang/crates.io-index" 655 - checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 712 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 656 713 657 714 [[package]] 658 715 name = "httpdate" ··· 662 719 663 720 [[package]] 664 721 name = "humantime" 665 - version = "2.1.0" 722 + version = "2.2.0" 666 723 source = "registry+https://github.com/rust-lang/crates.io-index" 667 - checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 724 + checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" 668 725 669 726 [[package]] 670 727 name = "hyper" 671 - version = "0.14.27" 728 + version = "0.14.32" 672 729 source = "registry+https://github.com/rust-lang/crates.io-index" 673 - checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 730 + checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 674 731 dependencies = [ 675 732 "bytes", 676 733 "futures-channel", 677 734 "futures-core", 678 735 "futures-util", 679 736 "h2", 680 - "http", 737 + "http 0.2.12", 681 738 "http-body", 682 739 "httparse", 683 740 "httpdate", 684 741 "itoa", 685 742 "pin-project-lite", 686 - "socket2 0.4.10", 743 + "socket2", 687 744 "tokio", 688 745 "tower-service", 689 746 "tracing", ··· 691 748 ] 692 749 693 750 [[package]] 751 + name = "icu_collections" 752 + version = "2.0.0" 753 + source = "registry+https://github.com/rust-lang/crates.io-index" 754 + checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 755 + dependencies = [ 756 + "displaydoc", 757 + "potential_utf", 758 + "yoke", 759 + "zerofrom", 760 + "zerovec", 761 + ] 762 + 763 + [[package]] 764 + name = "icu_locale_core" 765 + version = "2.0.0" 766 + source = "registry+https://github.com/rust-lang/crates.io-index" 767 + checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 768 + dependencies = [ 769 + "displaydoc", 770 + "litemap", 771 + "tinystr", 772 + "writeable", 773 + "zerovec", 774 + ] 775 + 776 + [[package]] 777 + name = "icu_normalizer" 778 + version = "2.0.0" 779 + source = "registry+https://github.com/rust-lang/crates.io-index" 780 + checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 781 + dependencies = [ 782 + "displaydoc", 783 + "icu_collections", 784 + "icu_normalizer_data", 785 + "icu_properties", 786 + "icu_provider", 787 + "smallvec", 788 + "zerovec", 789 + ] 790 + 791 + [[package]] 792 + name = "icu_normalizer_data" 793 + version = "2.0.0" 794 + source = "registry+https://github.com/rust-lang/crates.io-index" 795 + checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 796 + 797 + [[package]] 798 + name = "icu_properties" 799 + version = "2.0.1" 800 + source = "registry+https://github.com/rust-lang/crates.io-index" 801 + checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 802 + dependencies = [ 803 + "displaydoc", 804 + "icu_collections", 805 + "icu_locale_core", 806 + "icu_properties_data", 807 + "icu_provider", 808 + "potential_utf", 809 + "zerotrie", 810 + "zerovec", 811 + ] 812 + 813 + [[package]] 814 + name = "icu_properties_data" 815 + version = "2.0.1" 816 + source = "registry+https://github.com/rust-lang/crates.io-index" 817 + checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 818 + 819 + [[package]] 820 + name = "icu_provider" 821 + version = "2.0.0" 822 + source = "registry+https://github.com/rust-lang/crates.io-index" 823 + checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 824 + dependencies = [ 825 + "displaydoc", 826 + "icu_locale_core", 827 + "stable_deref_trait", 828 + "tinystr", 829 + "writeable", 830 + "yoke", 831 + "zerofrom", 832 + "zerotrie", 833 + "zerovec", 834 + ] 835 + 836 + [[package]] 837 + name = "ident_case" 838 + version = "1.0.1" 839 + source = "registry+https://github.com/rust-lang/crates.io-index" 840 + checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 841 + 842 + [[package]] 694 843 name = "idna" 695 - version = "0.5.0" 844 + version = "1.0.3" 696 845 source = "registry+https://github.com/rust-lang/crates.io-index" 697 - checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 846 + checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 698 847 dependencies = [ 699 - "unicode-bidi", 700 - "unicode-normalization", 848 + "idna_adapter", 849 + "smallvec", 850 + "utf8_iter", 851 + ] 852 + 853 + [[package]] 854 + name = "idna_adapter" 855 + version = "1.2.1" 856 + source = "registry+https://github.com/rust-lang/crates.io-index" 857 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 858 + dependencies = [ 859 + "icu_normalizer", 860 + "icu_properties", 701 861 ] 702 862 703 863 [[package]] 704 864 name = "indexmap" 705 - version = "2.1.0" 865 + version = "2.9.0" 706 866 source = "registry+https://github.com/rust-lang/crates.io-index" 707 - checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" 867 + checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 708 868 dependencies = [ 709 869 "equivalent", 710 870 "hashbrown", ··· 712 872 713 873 [[package]] 714 874 name = "is-terminal" 715 - version = "0.4.9" 875 + version = "0.4.16" 716 876 source = "registry+https://github.com/rust-lang/crates.io-index" 717 - checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 877 + checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" 718 878 dependencies = [ 719 879 "hermit-abi", 720 - "rustix", 721 - "windows-sys 0.48.0", 880 + "libc", 881 + "windows-sys 0.59.0", 722 882 ] 723 883 724 884 [[package]] 885 + name = "is_terminal_polyfill" 886 + version = "1.70.1" 887 + source = "registry+https://github.com/rust-lang/crates.io-index" 888 + checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 889 + 890 + [[package]] 725 891 name = "itoa" 726 - version = "1.0.10" 892 + version = "1.0.15" 727 893 source = "registry+https://github.com/rust-lang/crates.io-index" 728 - checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 894 + checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 729 895 730 896 [[package]] 731 897 name = "js-sys" 732 - version = "0.3.66" 898 + version = "0.3.77" 733 899 source = "registry+https://github.com/rust-lang/crates.io-index" 734 - checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" 900 + checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 735 901 dependencies = [ 902 + "once_cell", 736 903 "wasm-bindgen", 737 904 ] 738 905 739 906 [[package]] 740 - name = "lazy_static" 741 - version = "1.4.0" 907 + name = "libc" 908 + version = "0.2.172" 742 909 source = "registry+https://github.com/rust-lang/crates.io-index" 743 - checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 910 + checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 744 911 745 912 [[package]] 746 - name = "libc" 747 - version = "0.2.151" 913 + name = "linux-raw-sys" 914 + version = "0.9.4" 748 915 source = "registry+https://github.com/rust-lang/crates.io-index" 749 - checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 916 + checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 750 917 751 918 [[package]] 752 - name = "linux-raw-sys" 753 - version = "0.4.12" 919 + name = "litemap" 920 + version = "0.8.0" 754 921 source = "registry+https://github.com/rust-lang/crates.io-index" 755 - checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" 922 + checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 756 923 757 924 [[package]] 758 925 name = "lock_api" 759 - version = "0.4.11" 926 + version = "0.4.13" 760 927 source = "registry+https://github.com/rust-lang/crates.io-index" 761 - checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 928 + checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 762 929 dependencies = [ 763 930 "autocfg", 764 931 "scopeguard", ··· 766 933 767 934 [[package]] 768 935 name = "log" 769 - version = "0.4.20" 936 + version = "0.4.27" 770 937 source = "registry+https://github.com/rust-lang/crates.io-index" 771 - checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 938 + checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 772 939 773 940 [[package]] 774 941 name = "lumen" ··· 797 964 798 965 [[package]] 799 966 name = "memchr" 800 - version = "2.6.4" 967 + version = "2.7.4" 801 968 source = "registry+https://github.com/rust-lang/crates.io-index" 802 - checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 969 + checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 803 970 804 971 [[package]] 805 972 name = "mime" ··· 809 976 810 977 [[package]] 811 978 name = "mime_guess" 812 - version = "2.0.4" 979 + version = "2.0.5" 813 980 source = "registry+https://github.com/rust-lang/crates.io-index" 814 - checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 981 + checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 815 982 dependencies = [ 816 983 "mime", 817 984 "unicase", ··· 819 986 820 987 [[package]] 821 988 name = "miniz_oxide" 822 - version = "0.7.1" 989 + version = "0.8.8" 823 990 source = "registry+https://github.com/rust-lang/crates.io-index" 824 - checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 991 + checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 825 992 dependencies = [ 826 - "adler", 993 + "adler2", 827 994 ] 828 995 829 996 [[package]] 830 997 name = "mio" 831 - version = "0.8.10" 998 + version = "1.0.4" 832 999 source = "registry+https://github.com/rust-lang/crates.io-index" 833 - checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" 1000 + checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 834 1001 dependencies = [ 835 1002 "libc", 836 - "wasi", 837 - "windows-sys 0.48.0", 1003 + "wasi 0.11.0+wasi-snapshot-preview1", 1004 + "windows-sys 0.59.0", 838 1005 ] 839 1006 840 1007 [[package]] ··· 846 1013 "bytes", 847 1014 "encoding_rs", 848 1015 "futures-util", 849 - "http", 1016 + "http 0.2.12", 850 1017 "httparse", 851 1018 "log", 852 1019 "memchr", ··· 857 1024 858 1025 [[package]] 859 1026 name = "native-tls" 860 - version = "0.2.11" 1027 + version = "0.2.14" 861 1028 source = "registry+https://github.com/rust-lang/crates.io-index" 862 - checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 1029 + checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 863 1030 dependencies = [ 864 - "lazy_static", 865 1031 "libc", 866 1032 "log", 867 1033 "openssl", ··· 874 1040 ] 875 1041 876 1042 [[package]] 877 - name = "num_cpus" 878 - version = "1.16.0" 1043 + name = "num-conv" 1044 + version = "0.1.0" 879 1045 source = "registry+https://github.com/rust-lang/crates.io-index" 880 - checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 881 - dependencies = [ 882 - "hermit-abi", 883 - "libc", 884 - ] 1046 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 885 1047 886 1048 [[package]] 887 1049 name = "object" 888 - version = "0.32.1" 1050 + version = "0.36.7" 889 1051 source = "registry+https://github.com/rust-lang/crates.io-index" 890 - checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 1052 + checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 891 1053 dependencies = [ 892 1054 "memchr", 893 1055 ] 894 1056 895 1057 [[package]] 896 1058 name = "once_cell" 897 - version = "1.19.0" 1059 + version = "1.21.3" 1060 + source = "registry+https://github.com/rust-lang/crates.io-index" 1061 + checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1062 + 1063 + [[package]] 1064 + name = "once_cell_polyfill" 1065 + version = "1.70.1" 898 1066 source = "registry+https://github.com/rust-lang/crates.io-index" 899 - checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1067 + checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 900 1068 901 1069 [[package]] 902 1070 name = "openssl" 903 - version = "0.10.61" 1071 + version = "0.10.73" 904 1072 source = "registry+https://github.com/rust-lang/crates.io-index" 905 - checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" 1073 + checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" 906 1074 dependencies = [ 907 - "bitflags 2.4.1", 1075 + "bitflags", 908 1076 "cfg-if", 909 1077 "foreign-types", 910 1078 "libc", ··· 926 1094 927 1095 [[package]] 928 1096 name = "openssl-probe" 929 - version = "0.1.5" 1097 + version = "0.1.6" 930 1098 source = "registry+https://github.com/rust-lang/crates.io-index" 931 - checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1099 + checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 932 1100 933 1101 [[package]] 934 1102 name = "openssl-sys" 935 - version = "0.9.97" 1103 + version = "0.9.109" 936 1104 source = "registry+https://github.com/rust-lang/crates.io-index" 937 - checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" 1105 + checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" 938 1106 dependencies = [ 939 1107 "cc", 940 1108 "libc", ··· 944 1112 945 1113 [[package]] 946 1114 name = "parking_lot" 947 - version = "0.12.1" 1115 + version = "0.12.4" 948 1116 source = "registry+https://github.com/rust-lang/crates.io-index" 949 - checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1117 + checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 950 1118 dependencies = [ 951 1119 "lock_api", 952 1120 "parking_lot_core", ··· 954 1122 955 1123 [[package]] 956 1124 name = "parking_lot_core" 957 - version = "0.9.9" 1125 + version = "0.9.11" 958 1126 source = "registry+https://github.com/rust-lang/crates.io-index" 959 - checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" 1127 + checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 960 1128 dependencies = [ 961 1129 "cfg-if", 962 1130 "libc", 963 1131 "redox_syscall", 964 1132 "smallvec", 965 - "windows-targets 0.48.5", 1133 + "windows-targets", 966 1134 ] 967 1135 968 1136 [[package]] ··· 973 1141 974 1142 [[package]] 975 1143 name = "phf" 976 - version = "0.11.2" 1144 + version = "0.11.3" 977 1145 source = "registry+https://github.com/rust-lang/crates.io-index" 978 - checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 1146 + checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 979 1147 dependencies = [ 980 1148 "phf_shared", 981 1149 ] 982 1150 983 1151 [[package]] 984 1152 name = "phf_shared" 985 - version = "0.11.2" 1153 + version = "0.11.3" 986 1154 source = "registry+https://github.com/rust-lang/crates.io-index" 987 - checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 1155 + checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 988 1156 dependencies = [ 989 1157 "siphasher", 990 1158 ] 991 1159 992 1160 [[package]] 993 1161 name = "pin-project" 994 - version = "1.1.3" 1162 + version = "1.1.10" 995 1163 source = "registry+https://github.com/rust-lang/crates.io-index" 996 - checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" 1164 + checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" 997 1165 dependencies = [ 998 1166 "pin-project-internal", 999 1167 ] 1000 1168 1001 1169 [[package]] 1002 1170 name = "pin-project-internal" 1003 - version = "1.1.3" 1171 + version = "1.1.10" 1004 1172 source = "registry+https://github.com/rust-lang/crates.io-index" 1005 - checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" 1173 + checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" 1006 1174 dependencies = [ 1007 1175 "proc-macro2", 1008 1176 "quote", ··· 1011 1179 1012 1180 [[package]] 1013 1181 name = "pin-project-lite" 1014 - version = "0.2.13" 1182 + version = "0.2.16" 1015 1183 source = "registry+https://github.com/rust-lang/crates.io-index" 1016 - checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 1184 + checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1017 1185 1018 1186 [[package]] 1019 1187 name = "pin-utils" ··· 1023 1191 1024 1192 [[package]] 1025 1193 name = "pkg-config" 1026 - version = "0.3.27" 1194 + version = "0.3.32" 1027 1195 source = "registry+https://github.com/rust-lang/crates.io-index" 1028 - checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 1196 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1029 1197 1030 1198 [[package]] 1031 1199 name = "postgres-native-tls" 1032 - version = "0.5.0" 1200 + version = "0.5.1" 1033 1201 source = "registry+https://github.com/rust-lang/crates.io-index" 1034 - checksum = "2d442770e2b1e244bb5eb03b31c79b65bb2568f413b899eaba850fa945a65954" 1202 + checksum = "a1f39498473c92f7b6820ae970382c1d83178a3454c618161cb772e8598d9f6f" 1035 1203 dependencies = [ 1036 - "futures", 1037 1204 "native-tls", 1038 1205 "tokio", 1039 1206 "tokio-native-tls", ··· 1042 1209 1043 1210 [[package]] 1044 1211 name = "postgres-protocol" 1045 - version = "0.6.6" 1212 + version = "0.6.8" 1046 1213 source = "registry+https://github.com/rust-lang/crates.io-index" 1047 - checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" 1214 + checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" 1048 1215 dependencies = [ 1049 - "base64", 1216 + "base64 0.22.1", 1050 1217 "byteorder", 1051 1218 "bytes", 1052 1219 "fallible-iterator", 1053 1220 "hmac", 1054 1221 "md-5", 1055 1222 "memchr", 1056 - "rand", 1223 + "rand 0.9.1", 1057 1224 "sha2", 1058 1225 "stringprep", 1059 1226 ] 1060 1227 1061 1228 [[package]] 1062 1229 name = "postgres-types" 1063 - version = "0.2.6" 1230 + version = "0.2.9" 1064 1231 source = "registry+https://github.com/rust-lang/crates.io-index" 1065 - checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" 1232 + checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" 1066 1233 dependencies = [ 1067 1234 "bytes", 1068 1235 "fallible-iterator", ··· 1070 1237 ] 1071 1238 1072 1239 [[package]] 1240 + name = "potential_utf" 1241 + version = "0.1.2" 1242 + source = "registry+https://github.com/rust-lang/crates.io-index" 1243 + checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 1244 + dependencies = [ 1245 + "zerovec", 1246 + ] 1247 + 1248 + [[package]] 1073 1249 name = "powerfmt" 1074 1250 version = "0.2.0" 1075 1251 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1077 1253 1078 1254 [[package]] 1079 1255 name = "ppv-lite86" 1080 - version = "0.2.17" 1256 + version = "0.2.21" 1081 1257 source = "registry+https://github.com/rust-lang/crates.io-index" 1082 - checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1258 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1259 + dependencies = [ 1260 + "zerocopy", 1261 + ] 1083 1262 1084 1263 [[package]] 1085 1264 name = "pretty_env_logger" ··· 1093 1272 1094 1273 [[package]] 1095 1274 name = "proc-macro2" 1096 - version = "1.0.70" 1275 + version = "1.0.95" 1097 1276 source = "registry+https://github.com/rust-lang/crates.io-index" 1098 - checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" 1277 + checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 1099 1278 dependencies = [ 1100 1279 "unicode-ident", 1101 1280 ] 1102 1281 1103 1282 [[package]] 1104 1283 name = "prometheus-client" 1105 - version = "0.21.2" 1284 + version = "0.22.3" 1106 1285 source = "registry+https://github.com/rust-lang/crates.io-index" 1107 - checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" 1286 + checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" 1108 1287 dependencies = [ 1109 1288 "dtoa", 1110 1289 "itoa", ··· 1125 1304 1126 1305 [[package]] 1127 1306 name = "quote" 1128 - version = "1.0.33" 1307 + version = "1.0.40" 1129 1308 source = "registry+https://github.com/rust-lang/crates.io-index" 1130 - checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1309 + checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1131 1310 dependencies = [ 1132 1311 "proc-macro2", 1133 1312 ] 1134 1313 1135 1314 [[package]] 1315 + name = "r-efi" 1316 + version = "5.2.0" 1317 + source = "registry+https://github.com/rust-lang/crates.io-index" 1318 + checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 1319 + 1320 + [[package]] 1136 1321 name = "rand" 1137 1322 version = "0.8.5" 1138 1323 source = "registry+https://github.com/rust-lang/crates.io-index" 1139 1324 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1140 1325 dependencies = [ 1141 1326 "libc", 1142 - "rand_chacha", 1143 - "rand_core", 1327 + "rand_chacha 0.3.1", 1328 + "rand_core 0.6.4", 1329 + ] 1330 + 1331 + [[package]] 1332 + name = "rand" 1333 + version = "0.9.1" 1334 + source = "registry+https://github.com/rust-lang/crates.io-index" 1335 + checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 1336 + dependencies = [ 1337 + "rand_chacha 0.9.0", 1338 + "rand_core 0.9.3", 1144 1339 ] 1145 1340 1146 1341 [[package]] ··· 1150 1345 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1151 1346 dependencies = [ 1152 1347 "ppv-lite86", 1153 - "rand_core", 1348 + "rand_core 0.6.4", 1349 + ] 1350 + 1351 + [[package]] 1352 + name = "rand_chacha" 1353 + version = "0.9.0" 1354 + source = "registry+https://github.com/rust-lang/crates.io-index" 1355 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1356 + dependencies = [ 1357 + "ppv-lite86", 1358 + "rand_core 0.9.3", 1154 1359 ] 1155 1360 1156 1361 [[package]] ··· 1159 1364 source = "registry+https://github.com/rust-lang/crates.io-index" 1160 1365 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1161 1366 dependencies = [ 1162 - "getrandom", 1367 + "getrandom 0.2.16", 1368 + ] 1369 + 1370 + [[package]] 1371 + name = "rand_core" 1372 + version = "0.9.3" 1373 + source = "registry+https://github.com/rust-lang/crates.io-index" 1374 + checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1375 + dependencies = [ 1376 + "getrandom 0.3.3", 1163 1377 ] 1164 1378 1165 1379 [[package]] 1166 1380 name = "redox_syscall" 1167 - version = "0.4.1" 1381 + version = "0.5.12" 1168 1382 source = "registry+https://github.com/rust-lang/crates.io-index" 1169 - checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1383 + checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 1170 1384 dependencies = [ 1171 - "bitflags 1.3.2", 1385 + "bitflags", 1172 1386 ] 1173 1387 1174 1388 [[package]] 1175 1389 name = "regex" 1176 - version = "1.10.2" 1390 + version = "1.11.1" 1177 1391 source = "registry+https://github.com/rust-lang/crates.io-index" 1178 - checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" 1392 + checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1179 1393 dependencies = [ 1180 1394 "aho-corasick", 1181 1395 "memchr", ··· 1185 1399 1186 1400 [[package]] 1187 1401 name = "regex-automata" 1188 - version = "0.4.3" 1402 + version = "0.4.9" 1189 1403 source = "registry+https://github.com/rust-lang/crates.io-index" 1190 - checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" 1404 + checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1191 1405 dependencies = [ 1192 1406 "aho-corasick", 1193 1407 "memchr", ··· 1196 1410 1197 1411 [[package]] 1198 1412 name = "regex-syntax" 1199 - version = "0.8.2" 1413 + version = "0.8.5" 1200 1414 source = "registry+https://github.com/rust-lang/crates.io-index" 1201 - checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 1415 + checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1202 1416 1203 1417 [[package]] 1204 1418 name = "rustc-demangle" 1205 - version = "0.1.23" 1419 + version = "0.1.24" 1206 1420 source = "registry+https://github.com/rust-lang/crates.io-index" 1207 - checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1421 + checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1208 1422 1209 1423 [[package]] 1210 1424 name = "rustix" 1211 - version = "0.38.28" 1425 + version = "1.0.7" 1212 1426 source = "registry+https://github.com/rust-lang/crates.io-index" 1213 - checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" 1427 + checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 1214 1428 dependencies = [ 1215 - "bitflags 2.4.1", 1429 + "bitflags", 1216 1430 "errno", 1217 1431 "libc", 1218 1432 "linux-raw-sys", 1219 - "windows-sys 0.52.0", 1220 - ] 1221 - 1222 - [[package]] 1223 - name = "rustls-pemfile" 1224 - version = "1.0.4" 1225 - source = "registry+https://github.com/rust-lang/crates.io-index" 1226 - checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1227 - dependencies = [ 1228 - "base64", 1433 + "windows-sys 0.59.0", 1229 1434 ] 1230 1435 1231 1436 [[package]] 1232 1437 name = "ryu" 1233 - version = "1.0.16" 1438 + version = "1.0.20" 1234 1439 source = "registry+https://github.com/rust-lang/crates.io-index" 1235 - checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" 1440 + checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1236 1441 1237 1442 [[package]] 1238 1443 name = "schannel" 1239 - version = "0.1.22" 1444 + version = "0.1.27" 1240 1445 source = "registry+https://github.com/rust-lang/crates.io-index" 1241 - checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" 1446 + checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1242 1447 dependencies = [ 1243 - "windows-sys 0.48.0", 1448 + "windows-sys 0.59.0", 1244 1449 ] 1245 1450 1246 1451 [[package]] 1247 1452 name = "scoped-futures" 1248 - version = "0.1.3" 1453 + version = "0.1.4" 1249 1454 source = "registry+https://github.com/rust-lang/crates.io-index" 1250 - checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" 1455 + checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091" 1251 1456 dependencies = [ 1252 - "cfg-if", 1253 - "pin-utils", 1457 + "pin-project-lite", 1254 1458 ] 1255 1459 1256 1460 [[package]] ··· 1267 1471 1268 1472 [[package]] 1269 1473 name = "security-framework" 1270 - version = "2.9.2" 1474 + version = "2.11.1" 1271 1475 source = "registry+https://github.com/rust-lang/crates.io-index" 1272 - checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" 1476 + checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1273 1477 dependencies = [ 1274 - "bitflags 1.3.2", 1478 + "bitflags", 1275 1479 "core-foundation", 1276 1480 "core-foundation-sys", 1277 1481 "libc", ··· 1280 1484 1281 1485 [[package]] 1282 1486 name = "security-framework-sys" 1283 - version = "2.9.1" 1487 + version = "2.14.0" 1284 1488 source = "registry+https://github.com/rust-lang/crates.io-index" 1285 - checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" 1489 + checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1286 1490 dependencies = [ 1287 1491 "core-foundation-sys", 1288 1492 "libc", ··· 1290 1494 1291 1495 [[package]] 1292 1496 name = "serde" 1293 - version = "1.0.193" 1497 + version = "1.0.219" 1294 1498 source = "registry+https://github.com/rust-lang/crates.io-index" 1295 - checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" 1499 + checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1296 1500 dependencies = [ 1297 1501 "serde_derive", 1298 1502 ] 1299 1503 1300 1504 [[package]] 1301 1505 name = "serde_derive" 1302 - version = "1.0.193" 1506 + version = "1.0.219" 1303 1507 source = "registry+https://github.com/rust-lang/crates.io-index" 1304 - checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" 1508 + checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1305 1509 dependencies = [ 1306 1510 "proc-macro2", 1307 1511 "quote", ··· 1310 1514 1311 1515 [[package]] 1312 1516 name = "serde_json" 1313 - version = "1.0.108" 1517 + version = "1.0.140" 1314 1518 source = "registry+https://github.com/rust-lang/crates.io-index" 1315 - checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 1519 + checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1316 1520 dependencies = [ 1317 1521 "itoa", 1522 + "memchr", 1318 1523 "ryu", 1319 1524 "serde", 1320 1525 ] 1321 1526 1322 1527 [[package]] 1323 1528 name = "serde_spanned" 1324 - version = "0.6.4" 1529 + version = "0.6.9" 1325 1530 source = "registry+https://github.com/rust-lang/crates.io-index" 1326 - checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" 1531 + checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" 1327 1532 dependencies = [ 1328 1533 "serde", 1329 1534 ] ··· 1353 1558 1354 1559 [[package]] 1355 1560 name = "sha2" 1356 - version = "0.10.8" 1561 + version = "0.10.9" 1357 1562 source = "registry+https://github.com/rust-lang/crates.io-index" 1358 - checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1563 + checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1359 1564 dependencies = [ 1360 1565 "cfg-if", 1361 1566 "cpufeatures", 1362 1567 "digest", 1363 1568 ] 1569 + 1570 + [[package]] 1571 + name = "shlex" 1572 + version = "1.3.0" 1573 + source = "registry+https://github.com/rust-lang/crates.io-index" 1574 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1364 1575 1365 1576 [[package]] 1366 1577 name = "signal-hook-registry" 1367 - version = "1.4.1" 1578 + version = "1.4.5" 1368 1579 source = "registry+https://github.com/rust-lang/crates.io-index" 1369 - checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 1580 + checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 1370 1581 dependencies = [ 1371 1582 "libc", 1372 1583 ] 1373 1584 1374 1585 [[package]] 1375 1586 name = "siphasher" 1376 - version = "0.3.11" 1587 + version = "1.0.1" 1377 1588 source = "registry+https://github.com/rust-lang/crates.io-index" 1378 - checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1589 + checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 1379 1590 1380 1591 [[package]] 1381 1592 name = "slab" ··· 1388 1599 1389 1600 [[package]] 1390 1601 name = "smallvec" 1391 - version = "1.11.2" 1602 + version = "1.15.1" 1392 1603 source = "registry+https://github.com/rust-lang/crates.io-index" 1393 - checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" 1394 - 1395 - [[package]] 1396 - name = "socket2" 1397 - version = "0.4.10" 1398 - source = "registry+https://github.com/rust-lang/crates.io-index" 1399 - checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" 1400 - dependencies = [ 1401 - "libc", 1402 - "winapi", 1403 - ] 1604 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1404 1605 1405 1606 [[package]] 1406 1607 name = "socket2" 1407 - version = "0.5.5" 1608 + version = "0.5.10" 1408 1609 source = "registry+https://github.com/rust-lang/crates.io-index" 1409 - checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" 1610 + checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 1410 1611 dependencies = [ 1411 1612 "libc", 1412 - "windows-sys 0.48.0", 1613 + "windows-sys 0.52.0", 1413 1614 ] 1414 1615 1415 1616 [[package]] ··· 1419 1620 checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1420 1621 1421 1622 [[package]] 1623 + name = "stable_deref_trait" 1624 + version = "1.2.0" 1625 + source = "registry+https://github.com/rust-lang/crates.io-index" 1626 + checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1627 + 1628 + [[package]] 1422 1629 name = "stringprep" 1423 - version = "0.1.4" 1630 + version = "0.1.5" 1424 1631 source = "registry+https://github.com/rust-lang/crates.io-index" 1425 - checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" 1632 + checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 1426 1633 dependencies = [ 1427 - "finl_unicode", 1428 1634 "unicode-bidi", 1429 1635 "unicode-normalization", 1636 + "unicode-properties", 1430 1637 ] 1431 1638 1432 1639 [[package]] 1433 1640 name = "strsim" 1434 - version = "0.10.0" 1641 + version = "0.11.1" 1435 1642 source = "registry+https://github.com/rust-lang/crates.io-index" 1436 - checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1643 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1437 1644 1438 1645 [[package]] 1439 1646 name = "subtle" 1440 - version = "2.5.0" 1647 + version = "2.6.1" 1441 1648 source = "registry+https://github.com/rust-lang/crates.io-index" 1442 - checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1649 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1443 1650 1444 1651 [[package]] 1445 1652 name = "syn" 1446 - version = "2.0.41" 1653 + version = "2.0.101" 1447 1654 source = "registry+https://github.com/rust-lang/crates.io-index" 1448 - checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" 1655 + checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 1449 1656 dependencies = [ 1450 1657 "proc-macro2", 1451 1658 "quote", ··· 1453 1660 ] 1454 1661 1455 1662 [[package]] 1663 + name = "synstructure" 1664 + version = "0.13.2" 1665 + source = "registry+https://github.com/rust-lang/crates.io-index" 1666 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1667 + dependencies = [ 1668 + "proc-macro2", 1669 + "quote", 1670 + "syn", 1671 + ] 1672 + 1673 + [[package]] 1456 1674 name = "tempfile" 1457 - version = "3.8.1" 1675 + version = "3.20.0" 1458 1676 source = "registry+https://github.com/rust-lang/crates.io-index" 1459 - checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" 1677 + checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" 1460 1678 dependencies = [ 1461 - "cfg-if", 1462 1679 "fastrand", 1463 - "redox_syscall", 1680 + "getrandom 0.3.3", 1681 + "once_cell", 1464 1682 "rustix", 1465 - "windows-sys 0.48.0", 1683 + "windows-sys 0.59.0", 1466 1684 ] 1467 1685 1468 1686 [[package]] 1469 1687 name = "termcolor" 1470 - version = "1.4.0" 1688 + version = "1.4.1" 1471 1689 source = "registry+https://github.com/rust-lang/crates.io-index" 1472 - checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" 1690 + checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1473 1691 dependencies = [ 1474 1692 "winapi-util", 1475 1693 ] 1476 1694 1477 1695 [[package]] 1478 1696 name = "thiserror" 1479 - version = "1.0.50" 1697 + version = "1.0.69" 1480 1698 source = "registry+https://github.com/rust-lang/crates.io-index" 1481 - checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 1699 + checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1482 1700 dependencies = [ 1483 1701 "thiserror-impl", 1484 1702 ] 1485 1703 1486 1704 [[package]] 1487 1705 name = "thiserror-impl" 1488 - version = "1.0.50" 1706 + version = "1.0.69" 1489 1707 source = "registry+https://github.com/rust-lang/crates.io-index" 1490 - checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 1708 + checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1491 1709 dependencies = [ 1492 1710 "proc-macro2", 1493 1711 "quote", ··· 1496 1714 1497 1715 [[package]] 1498 1716 name = "time" 1499 - version = "0.3.30" 1717 + version = "0.3.41" 1500 1718 source = "registry+https://github.com/rust-lang/crates.io-index" 1501 - checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" 1719 + checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 1502 1720 dependencies = [ 1503 1721 "deranged", 1722 + "num-conv", 1504 1723 "powerfmt", 1505 1724 "serde", 1506 1725 "time-core", ··· 1509 1728 1510 1729 [[package]] 1511 1730 name = "time-core" 1512 - version = "0.1.2" 1731 + version = "0.1.4" 1513 1732 source = "registry+https://github.com/rust-lang/crates.io-index" 1514 - checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1733 + checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 1515 1734 1516 1735 [[package]] 1517 1736 name = "time-macros" 1518 - version = "0.2.15" 1737 + version = "0.2.22" 1519 1738 source = "registry+https://github.com/rust-lang/crates.io-index" 1520 - checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" 1739 + checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 1521 1740 dependencies = [ 1741 + "num-conv", 1522 1742 "time-core", 1523 1743 ] 1524 1744 1525 1745 [[package]] 1746 + name = "tinystr" 1747 + version = "0.8.1" 1748 + source = "registry+https://github.com/rust-lang/crates.io-index" 1749 + checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 1750 + dependencies = [ 1751 + "displaydoc", 1752 + "zerovec", 1753 + ] 1754 + 1755 + [[package]] 1526 1756 name = "tinyvec" 1527 - version = "1.6.0" 1757 + version = "1.9.0" 1528 1758 source = "registry+https://github.com/rust-lang/crates.io-index" 1529 - checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1759 + checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" 1530 1760 dependencies = [ 1531 1761 "tinyvec_macros", 1532 1762 ] ··· 1539 1769 1540 1770 [[package]] 1541 1771 name = "tokio" 1542 - version = "1.35.0" 1772 + version = "1.45.1" 1543 1773 source = "registry+https://github.com/rust-lang/crates.io-index" 1544 - checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" 1774 + checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 1545 1775 dependencies = [ 1546 1776 "backtrace", 1547 1777 "bytes", 1548 1778 "libc", 1549 1779 "mio", 1550 - "num_cpus", 1551 1780 "parking_lot", 1552 1781 "pin-project-lite", 1553 1782 "signal-hook-registry", 1554 - "socket2 0.5.5", 1783 + "socket2", 1555 1784 "tokio-macros", 1556 - "windows-sys 0.48.0", 1785 + "windows-sys 0.52.0", 1557 1786 ] 1558 1787 1559 1788 [[package]] 1560 1789 name = "tokio-macros" 1561 - version = "2.2.0" 1790 + version = "2.5.0" 1562 1791 source = "registry+https://github.com/rust-lang/crates.io-index" 1563 - checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 1792 + checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1564 1793 dependencies = [ 1565 1794 "proc-macro2", 1566 1795 "quote", ··· 1579 1808 1580 1809 [[package]] 1581 1810 name = "tokio-postgres" 1582 - version = "0.7.10" 1811 + version = "0.7.13" 1583 1812 source = "registry+https://github.com/rust-lang/crates.io-index" 1584 - checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" 1813 + checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" 1585 1814 dependencies = [ 1586 1815 "async-trait", 1587 1816 "byteorder", ··· 1596 1825 "pin-project-lite", 1597 1826 "postgres-protocol", 1598 1827 "postgres-types", 1599 - "rand", 1600 - "socket2 0.5.5", 1828 + "rand 0.9.1", 1829 + "socket2", 1601 1830 "tokio", 1602 1831 "tokio-util", 1603 1832 "whoami", 1604 1833 ] 1605 1834 1606 1835 [[package]] 1607 - name = "tokio-stream" 1608 - version = "0.1.14" 1609 - source = "registry+https://github.com/rust-lang/crates.io-index" 1610 - checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" 1611 - dependencies = [ 1612 - "futures-core", 1613 - "pin-project-lite", 1614 - "tokio", 1615 - ] 1616 - 1617 - [[package]] 1618 1836 name = "tokio-tungstenite" 1619 - version = "0.20.1" 1837 + version = "0.21.0" 1620 1838 source = "registry+https://github.com/rust-lang/crates.io-index" 1621 - checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" 1839 + checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 1622 1840 dependencies = [ 1623 1841 "futures-util", 1624 1842 "log", ··· 1628 1846 1629 1847 [[package]] 1630 1848 name = "tokio-util" 1631 - version = "0.7.10" 1849 + version = "0.7.15" 1632 1850 source = "registry+https://github.com/rust-lang/crates.io-index" 1633 - checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" 1851 + checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" 1634 1852 dependencies = [ 1635 1853 "bytes", 1636 1854 "futures-core", 1637 1855 "futures-sink", 1638 1856 "pin-project-lite", 1639 1857 "tokio", 1640 - "tracing", 1641 1858 ] 1642 1859 1643 1860 [[package]] 1644 1861 name = "toml" 1645 - version = "0.7.8" 1862 + version = "0.8.23" 1646 1863 source = "registry+https://github.com/rust-lang/crates.io-index" 1647 - checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" 1864 + checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" 1648 1865 dependencies = [ 1649 1866 "serde", 1650 1867 "serde_spanned", ··· 1654 1871 1655 1872 [[package]] 1656 1873 name = "toml_datetime" 1657 - version = "0.6.5" 1874 + version = "0.6.11" 1658 1875 source = "registry+https://github.com/rust-lang/crates.io-index" 1659 - checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" 1876 + checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 1660 1877 dependencies = [ 1661 1878 "serde", 1662 1879 ] 1663 1880 1664 1881 [[package]] 1665 1882 name = "toml_edit" 1666 - version = "0.19.15" 1883 + version = "0.22.27" 1667 1884 source = "registry+https://github.com/rust-lang/crates.io-index" 1668 - checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" 1885 + checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 1669 1886 dependencies = [ 1670 1887 "indexmap", 1671 1888 "serde", 1672 1889 "serde_spanned", 1673 1890 "toml_datetime", 1891 + "toml_write", 1674 1892 "winnow", 1675 1893 ] 1676 1894 1677 1895 [[package]] 1896 + name = "toml_write" 1897 + version = "0.1.2" 1898 + source = "registry+https://github.com/rust-lang/crates.io-index" 1899 + checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" 1900 + 1901 + [[package]] 1678 1902 name = "tower-service" 1679 - version = "0.3.2" 1903 + version = "0.3.3" 1680 1904 source = "registry+https://github.com/rust-lang/crates.io-index" 1681 - checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1905 + checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1682 1906 1683 1907 [[package]] 1684 1908 name = "tracing" 1685 - version = "0.1.40" 1909 + version = "0.1.41" 1686 1910 source = "registry+https://github.com/rust-lang/crates.io-index" 1687 - checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1911 + checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1688 1912 dependencies = [ 1689 1913 "log", 1690 1914 "pin-project-lite", ··· 1693 1917 1694 1918 [[package]] 1695 1919 name = "tracing-core" 1696 - version = "0.1.32" 1920 + version = "0.1.34" 1697 1921 source = "registry+https://github.com/rust-lang/crates.io-index" 1698 - checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1922 + checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 1699 1923 dependencies = [ 1700 1924 "once_cell", 1701 1925 ] ··· 1708 1932 1709 1933 [[package]] 1710 1934 name = "tungstenite" 1711 - version = "0.20.1" 1935 + version = "0.21.0" 1712 1936 source = "registry+https://github.com/rust-lang/crates.io-index" 1713 - checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" 1937 + checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 1714 1938 dependencies = [ 1715 1939 "byteorder", 1716 1940 "bytes", 1717 1941 "data-encoding", 1718 - "http", 1942 + "http 1.3.1", 1719 1943 "httparse", 1720 1944 "log", 1721 - "rand", 1945 + "rand 0.8.5", 1722 1946 "sha1", 1723 1947 "thiserror", 1724 1948 "url", ··· 1727 1951 1728 1952 [[package]] 1729 1953 name = "typenum" 1730 - version = "1.17.0" 1954 + version = "1.18.0" 1731 1955 source = "registry+https://github.com/rust-lang/crates.io-index" 1732 - checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1956 + checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 1733 1957 1734 1958 [[package]] 1735 1959 name = "unicase" 1736 - version = "2.7.0" 1960 + version = "2.8.1" 1737 1961 source = "registry+https://github.com/rust-lang/crates.io-index" 1738 - checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" 1739 - dependencies = [ 1740 - "version_check", 1741 - ] 1962 + checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 1742 1963 1743 1964 [[package]] 1744 1965 name = "unicode-bidi" 1745 - version = "0.3.14" 1966 + version = "0.3.18" 1746 1967 source = "registry+https://github.com/rust-lang/crates.io-index" 1747 - checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" 1968 + checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" 1748 1969 1749 1970 [[package]] 1750 1971 name = "unicode-ident" 1751 - version = "1.0.12" 1972 + version = "1.0.18" 1752 1973 source = "registry+https://github.com/rust-lang/crates.io-index" 1753 - checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1974 + checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1754 1975 1755 1976 [[package]] 1756 1977 name = "unicode-normalization" 1757 - version = "0.1.22" 1978 + version = "0.1.24" 1758 1979 source = "registry+https://github.com/rust-lang/crates.io-index" 1759 - checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1980 + checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 1760 1981 dependencies = [ 1761 1982 "tinyvec", 1762 1983 ] 1763 1984 1764 1985 [[package]] 1986 + name = "unicode-properties" 1987 + version = "0.1.3" 1988 + source = "registry+https://github.com/rust-lang/crates.io-index" 1989 + checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" 1990 + 1991 + [[package]] 1765 1992 name = "url" 1766 - version = "2.5.0" 1993 + version = "2.5.4" 1767 1994 source = "registry+https://github.com/rust-lang/crates.io-index" 1768 - checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 1995 + checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1769 1996 dependencies = [ 1770 1997 "form_urlencoded", 1771 1998 "idna", ··· 1779 2006 checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1780 2007 1781 2008 [[package]] 2009 + name = "utf8_iter" 2010 + version = "1.0.4" 2011 + source = "registry+https://github.com/rust-lang/crates.io-index" 2012 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2013 + 2014 + [[package]] 1782 2015 name = "utf8parse" 1783 - version = "0.2.1" 2016 + version = "0.2.2" 1784 2017 source = "registry+https://github.com/rust-lang/crates.io-index" 1785 - checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 2018 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1786 2019 1787 2020 [[package]] 1788 2021 name = "vcpkg" ··· 1792 2025 1793 2026 [[package]] 1794 2027 name = "version_check" 1795 - version = "0.9.4" 2028 + version = "0.9.5" 1796 2029 source = "registry+https://github.com/rust-lang/crates.io-index" 1797 - checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2030 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1798 2031 1799 2032 [[package]] 1800 2033 name = "want" ··· 1807 2040 1808 2041 [[package]] 1809 2042 name = "warp" 1810 - version = "0.3.6" 2043 + version = "0.3.7" 1811 2044 source = "registry+https://github.com/rust-lang/crates.io-index" 1812 - checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" 2045 + checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" 1813 2046 dependencies = [ 1814 2047 "bytes", 1815 2048 "futures-channel", 1816 2049 "futures-util", 1817 2050 "headers", 1818 - "http", 2051 + "http 0.2.12", 1819 2052 "hyper", 1820 2053 "log", 1821 2054 "mime", ··· 1823 2056 "multer", 1824 2057 "percent-encoding", 1825 2058 "pin-project", 1826 - "rustls-pemfile", 1827 2059 "scoped-tls", 1828 2060 "serde", 1829 2061 "serde_json", 1830 2062 "serde_urlencoded", 1831 2063 "tokio", 1832 - "tokio-stream", 1833 2064 "tokio-tungstenite", 1834 2065 "tokio-util", 1835 2066 "tower-service", ··· 1843 2074 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1844 2075 1845 2076 [[package]] 2077 + name = "wasi" 2078 + version = "0.14.2+wasi-0.2.4" 2079 + source = "registry+https://github.com/rust-lang/crates.io-index" 2080 + checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 2081 + dependencies = [ 2082 + "wit-bindgen-rt", 2083 + ] 2084 + 2085 + [[package]] 2086 + name = "wasite" 2087 + version = "0.1.0" 2088 + source = "registry+https://github.com/rust-lang/crates.io-index" 2089 + checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" 2090 + 2091 + [[package]] 1846 2092 name = "wasm-bindgen" 1847 - version = "0.2.89" 2093 + version = "0.2.100" 1848 2094 source = "registry+https://github.com/rust-lang/crates.io-index" 1849 - checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" 2095 + checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1850 2096 dependencies = [ 1851 2097 "cfg-if", 2098 + "once_cell", 1852 2099 "wasm-bindgen-macro", 1853 2100 ] 1854 2101 1855 2102 [[package]] 1856 2103 name = "wasm-bindgen-backend" 1857 - version = "0.2.89" 2104 + version = "0.2.100" 1858 2105 source = "registry+https://github.com/rust-lang/crates.io-index" 1859 - checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" 2106 + checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1860 2107 dependencies = [ 1861 2108 "bumpalo", 1862 2109 "log", 1863 - "once_cell", 1864 2110 "proc-macro2", 1865 2111 "quote", 1866 2112 "syn", ··· 1869 2115 1870 2116 [[package]] 1871 2117 name = "wasm-bindgen-macro" 1872 - version = "0.2.89" 2118 + version = "0.2.100" 1873 2119 source = "registry+https://github.com/rust-lang/crates.io-index" 1874 - checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" 2120 + checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1875 2121 dependencies = [ 1876 2122 "quote", 1877 2123 "wasm-bindgen-macro-support", ··· 1879 2125 1880 2126 [[package]] 1881 2127 name = "wasm-bindgen-macro-support" 1882 - version = "0.2.89" 2128 + version = "0.2.100" 1883 2129 source = "registry+https://github.com/rust-lang/crates.io-index" 1884 - checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" 2130 + checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1885 2131 dependencies = [ 1886 2132 "proc-macro2", 1887 2133 "quote", ··· 1892 2138 1893 2139 [[package]] 1894 2140 name = "wasm-bindgen-shared" 1895 - version = "0.2.89" 2141 + version = "0.2.100" 1896 2142 source = "registry+https://github.com/rust-lang/crates.io-index" 1897 - checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" 2143 + checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2144 + dependencies = [ 2145 + "unicode-ident", 2146 + ] 1898 2147 1899 2148 [[package]] 1900 2149 name = "web-sys" 1901 - version = "0.3.66" 2150 + version = "0.3.77" 1902 2151 source = "registry+https://github.com/rust-lang/crates.io-index" 1903 - checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" 2152 + checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 1904 2153 dependencies = [ 1905 2154 "js-sys", 1906 2155 "wasm-bindgen", ··· 1908 2157 1909 2158 [[package]] 1910 2159 name = "whoami" 1911 - version = "1.4.1" 2160 + version = "1.6.0" 1912 2161 source = "registry+https://github.com/rust-lang/crates.io-index" 1913 - checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" 2162 + checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" 1914 2163 dependencies = [ 1915 - "wasm-bindgen", 2164 + "redox_syscall", 2165 + "wasite", 1916 2166 "web-sys", 1917 2167 ] 1918 2168 1919 2169 [[package]] 1920 - name = "winapi" 1921 - version = "0.3.9" 2170 + name = "winapi-util" 2171 + version = "0.1.9" 1922 2172 source = "registry+https://github.com/rust-lang/crates.io-index" 1923 - checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2173 + checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1924 2174 dependencies = [ 1925 - "winapi-i686-pc-windows-gnu", 1926 - "winapi-x86_64-pc-windows-gnu", 2175 + "windows-sys 0.59.0", 1927 2176 ] 1928 2177 1929 2178 [[package]] 1930 - name = "winapi-i686-pc-windows-gnu" 1931 - version = "0.4.0" 2179 + name = "windows-sys" 2180 + version = "0.52.0" 1932 2181 source = "registry+https://github.com/rust-lang/crates.io-index" 1933 - checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2182 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2183 + dependencies = [ 2184 + "windows-targets", 2185 + ] 1934 2186 1935 2187 [[package]] 1936 - name = "winapi-util" 1937 - version = "0.1.6" 2188 + name = "windows-sys" 2189 + version = "0.59.0" 1938 2190 source = "registry+https://github.com/rust-lang/crates.io-index" 1939 - checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 2191 + checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1940 2192 dependencies = [ 1941 - "winapi", 2193 + "windows-targets", 1942 2194 ] 1943 2195 1944 2196 [[package]] 1945 - name = "winapi-x86_64-pc-windows-gnu" 1946 - version = "0.4.0" 2197 + name = "windows-targets" 2198 + version = "0.52.6" 1947 2199 source = "registry+https://github.com/rust-lang/crates.io-index" 1948 - checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2200 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2201 + dependencies = [ 2202 + "windows_aarch64_gnullvm", 2203 + "windows_aarch64_msvc", 2204 + "windows_i686_gnu", 2205 + "windows_i686_gnullvm", 2206 + "windows_i686_msvc", 2207 + "windows_x86_64_gnu", 2208 + "windows_x86_64_gnullvm", 2209 + "windows_x86_64_msvc", 2210 + ] 1949 2211 1950 2212 [[package]] 1951 - name = "windows-sys" 1952 - version = "0.48.0" 2213 + name = "windows_aarch64_gnullvm" 2214 + version = "0.52.6" 1953 2215 source = "registry+https://github.com/rust-lang/crates.io-index" 1954 - checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1955 - dependencies = [ 1956 - "windows-targets 0.48.5", 1957 - ] 2216 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1958 2217 1959 2218 [[package]] 1960 - name = "windows-sys" 1961 - version = "0.52.0" 2219 + name = "windows_aarch64_msvc" 2220 + version = "0.52.6" 1962 2221 source = "registry+https://github.com/rust-lang/crates.io-index" 1963 - checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1964 - dependencies = [ 1965 - "windows-targets 0.52.0", 1966 - ] 2222 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1967 2223 1968 2224 [[package]] 1969 - name = "windows-targets" 1970 - version = "0.48.5" 2225 + name = "windows_i686_gnu" 2226 + version = "0.52.6" 1971 2227 source = "registry+https://github.com/rust-lang/crates.io-index" 1972 - checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1973 - dependencies = [ 1974 - "windows_aarch64_gnullvm 0.48.5", 1975 - "windows_aarch64_msvc 0.48.5", 1976 - "windows_i686_gnu 0.48.5", 1977 - "windows_i686_msvc 0.48.5", 1978 - "windows_x86_64_gnu 0.48.5", 1979 - "windows_x86_64_gnullvm 0.48.5", 1980 - "windows_x86_64_msvc 0.48.5", 1981 - ] 2228 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1982 2229 1983 2230 [[package]] 1984 - name = "windows-targets" 1985 - version = "0.52.0" 2231 + name = "windows_i686_gnullvm" 2232 + version = "0.52.6" 1986 2233 source = "registry+https://github.com/rust-lang/crates.io-index" 1987 - checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 1988 - dependencies = [ 1989 - "windows_aarch64_gnullvm 0.52.0", 1990 - "windows_aarch64_msvc 0.52.0", 1991 - "windows_i686_gnu 0.52.0", 1992 - "windows_i686_msvc 0.52.0", 1993 - "windows_x86_64_gnu 0.52.0", 1994 - "windows_x86_64_gnullvm 0.52.0", 1995 - "windows_x86_64_msvc 0.52.0", 1996 - ] 2234 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1997 2235 1998 2236 [[package]] 1999 - name = "windows_aarch64_gnullvm" 2000 - version = "0.48.5" 2237 + name = "windows_i686_msvc" 2238 + version = "0.52.6" 2001 2239 source = "registry+https://github.com/rust-lang/crates.io-index" 2002 - checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2240 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2003 2241 2004 2242 [[package]] 2005 - name = "windows_aarch64_gnullvm" 2006 - version = "0.52.0" 2243 + name = "windows_x86_64_gnu" 2244 + version = "0.52.6" 2007 2245 source = "registry+https://github.com/rust-lang/crates.io-index" 2008 - checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 2246 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2009 2247 2010 2248 [[package]] 2011 - name = "windows_aarch64_msvc" 2012 - version = "0.48.5" 2249 + name = "windows_x86_64_gnullvm" 2250 + version = "0.52.6" 2013 2251 source = "registry+https://github.com/rust-lang/crates.io-index" 2014 - checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2252 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2015 2253 2016 2254 [[package]] 2017 - name = "windows_aarch64_msvc" 2018 - version = "0.52.0" 2255 + name = "windows_x86_64_msvc" 2256 + version = "0.52.6" 2019 2257 source = "registry+https://github.com/rust-lang/crates.io-index" 2020 - checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 2258 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2021 2259 2022 2260 [[package]] 2023 - name = "windows_i686_gnu" 2024 - version = "0.48.5" 2261 + name = "winnow" 2262 + version = "0.7.10" 2025 2263 source = "registry+https://github.com/rust-lang/crates.io-index" 2026 - checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2264 + checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" 2265 + dependencies = [ 2266 + "memchr", 2267 + ] 2268 + 2269 + [[package]] 2270 + name = "wit-bindgen-rt" 2271 + version = "0.39.0" 2272 + source = "registry+https://github.com/rust-lang/crates.io-index" 2273 + checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 2274 + dependencies = [ 2275 + "bitflags", 2276 + ] 2027 2277 2028 2278 [[package]] 2029 - name = "windows_i686_gnu" 2030 - version = "0.52.0" 2279 + name = "writeable" 2280 + version = "0.6.1" 2031 2281 source = "registry+https://github.com/rust-lang/crates.io-index" 2032 - checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 2282 + checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 2033 2283 2034 2284 [[package]] 2035 - name = "windows_i686_msvc" 2036 - version = "0.48.5" 2285 + name = "yoke" 2286 + version = "0.8.0" 2037 2287 source = "registry+https://github.com/rust-lang/crates.io-index" 2038 - checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2288 + checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 2289 + dependencies = [ 2290 + "serde", 2291 + "stable_deref_trait", 2292 + "yoke-derive", 2293 + "zerofrom", 2294 + ] 2039 2295 2040 2296 [[package]] 2041 - name = "windows_i686_msvc" 2042 - version = "0.52.0" 2297 + name = "yoke-derive" 2298 + version = "0.8.0" 2043 2299 source = "registry+https://github.com/rust-lang/crates.io-index" 2044 - checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 2300 + checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 2301 + dependencies = [ 2302 + "proc-macro2", 2303 + "quote", 2304 + "syn", 2305 + "synstructure", 2306 + ] 2045 2307 2046 2308 [[package]] 2047 - name = "windows_x86_64_gnu" 2048 - version = "0.48.5" 2309 + name = "zerocopy" 2310 + version = "0.8.25" 2049 2311 source = "registry+https://github.com/rust-lang/crates.io-index" 2050 - checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2312 + checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" 2313 + dependencies = [ 2314 + "zerocopy-derive", 2315 + ] 2051 2316 2052 2317 [[package]] 2053 - name = "windows_x86_64_gnu" 2054 - version = "0.52.0" 2318 + name = "zerocopy-derive" 2319 + version = "0.8.25" 2055 2320 source = "registry+https://github.com/rust-lang/crates.io-index" 2056 - checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 2321 + checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" 2322 + dependencies = [ 2323 + "proc-macro2", 2324 + "quote", 2325 + "syn", 2326 + ] 2057 2327 2058 2328 [[package]] 2059 - name = "windows_x86_64_gnullvm" 2060 - version = "0.48.5" 2329 + name = "zerofrom" 2330 + version = "0.1.6" 2061 2331 source = "registry+https://github.com/rust-lang/crates.io-index" 2062 - checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2332 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2333 + dependencies = [ 2334 + "zerofrom-derive", 2335 + ] 2063 2336 2064 2337 [[package]] 2065 - name = "windows_x86_64_gnullvm" 2066 - version = "0.52.0" 2338 + name = "zerofrom-derive" 2339 + version = "0.1.6" 2067 2340 source = "registry+https://github.com/rust-lang/crates.io-index" 2068 - checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 2341 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2342 + dependencies = [ 2343 + "proc-macro2", 2344 + "quote", 2345 + "syn", 2346 + "synstructure", 2347 + ] 2069 2348 2070 2349 [[package]] 2071 - name = "windows_x86_64_msvc" 2072 - version = "0.48.5" 2350 + name = "zerotrie" 2351 + version = "0.2.2" 2073 2352 source = "registry+https://github.com/rust-lang/crates.io-index" 2074 - checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2353 + checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 2354 + dependencies = [ 2355 + "displaydoc", 2356 + "yoke", 2357 + "zerofrom", 2358 + ] 2075 2359 2076 2360 [[package]] 2077 - name = "windows_x86_64_msvc" 2078 - version = "0.52.0" 2361 + name = "zerovec" 2362 + version = "0.11.2" 2079 2363 source = "registry+https://github.com/rust-lang/crates.io-index" 2080 - checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 2364 + checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 2365 + dependencies = [ 2366 + "yoke", 2367 + "zerofrom", 2368 + "zerovec-derive", 2369 + ] 2081 2370 2082 2371 [[package]] 2083 - name = "winnow" 2084 - version = "0.5.28" 2372 + name = "zerovec-derive" 2373 + version = "0.11.1" 2085 2374 source = "registry+https://github.com/rust-lang/crates.io-index" 2086 - checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" 2375 + checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 2087 2376 dependencies = [ 2088 - "memchr", 2377 + "proc-macro2", 2378 + "quote", 2379 + "syn", 2089 2380 ]
+1
Cargo.toml
··· 1 1 [workspace] 2 + resolver = "2" 2 3 members = [ 3 4 "common", 4 5 "lumen",
+5 -6
Dockerfile
··· 1 - FROM rust:1.74.1-slim-buster 1 + FROM rust:1.87.0-slim-bookworm 2 2 ARG DEBIAN_FRONTEND=noninteractive 3 3 RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests ca-certificates pkg-config libssl-dev libpq-dev 4 4 ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse 5 5 6 6 RUN --mount=type=cache,target=$CARGO_HOME/registry \ 7 - cargo install diesel_cli --version 2.1.1 --no-default-features --features postgres 7 + cargo install diesel_cli --version 2.2.10 --no-default-features --features postgres 8 8 9 9 COPY common /lumen/common 10 10 COPY lumen /lumen/lumen 11 11 COPY Cargo.toml /lumen/ 12 12 RUN --mount=type=cache,target=$CARGO_HOME/registry,target=/lumen/target \ 13 - cd /lumen && cargo build --release && cp /lumen/target/release/lumen /root/ 13 + cd /lumen && cargo build --release && cp /lumen/target/release/lumen /root/ 14 14 15 - FROM debian:buster-slim 15 + FROM debian:bookworm-slim 16 16 ARG DEBIAN_FRONTEND=noninteractive 17 17 RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests openssl libpq5 && \ 18 - sed -i -e 's,\[ v3_req \],\[ v3_req \]\nextendedKeyUsage = serverAuth,' /etc/ssl/openssl.cnf 18 + sed -i -e 's,\[ v3_req \],\[ v3_req \]\nextendedKeyUsage = serverAuth,' /etc/ssl/openssl.cnf 19 19 RUN mkdir /usr/lib/lumen/ 20 20 21 21 COPY --from=0 /usr/local/cargo/bin/diesel /usr/bin/diesel ··· 26 26 COPY config-example.toml docker-init.sh /lumen/ 27 27 RUN chmod a+x /lumen/docker-init.sh && chmod a+x /usr/bin/lumen 28 28 WORKDIR /lumen 29 - STOPSIGNAL SIGINT 30 29 CMD /lumen/docker-init.sh
+125 -100
README.md
··· 1 - # Lumen 2 - A private Lumina server that can be used with IDA Pro 7.2+. 3 - 4 - [lumen.abda.nl](https://lumen.abda.nl/) runs this server. 5 - 6 - You can read about the protocol research [here](https://abda.nl/posts/introducing-lumen/). 7 - 8 - ## Features 9 - - Stores function signatures so you (and your team) can quickly identify functions that you found in the past using IDA's built-in Lumina features. 10 - - Backed by PostgreSQL 11 - - Experimental HTTP API that allows querying the database for comments by file or function hash. 12 - 13 - ## Getting Started 14 - 15 - ### Docker Method (Recommended) 16 - In this method precompiled docker images will be downloaded, All you need is [docker-compose.yml](./docker-compose.yml). 17 - 18 - 1. Install `docker-engine` and `docker-compose`. 19 - 2. If using a custom TLS certificate, copy the private key (`.p12`/`.pfx` extension) to `./dockershare` and set the key password in `.env` as `PKCSPASSWD`. 20 - 3. If using a custom Lumen config, copy it to `./dockershare/config.toml`. 21 - 4. Otherwise, or if you have finished these steps, just run `docker-compose up`. 22 - 5. Regardless, if TLS is enabled in the `config.toml`, a `hexrays.crt` will be generated in `./dockershare` to be copied to the IDA install directory. 23 - 24 - ### Building from source with Rust 25 - 1. `git clone https://github.com/naim94a/lumen.git` 26 - 2. Get a rust toolchain: https://rustup.rs/ 27 - 3. `cd lumen` 28 - 4. Setup a Postgres database and execute src/schema.sql on it 29 - 5. `cargo build --release` 30 - 31 - ### Usage 32 - ``` 33 - ./lumen -c config.toml 34 - ``` 35 - 36 - ### Configuring IDA 37 - 38 - #### IDA Pro >= 8.1 39 - If you used LUMEN in the past, remove the LUMINA settings in the ida.cfg or idauser.cfg files, otherwise you will get a warning about 40 - bad config parameters. 41 - 42 - ##### Setup under Linux : 43 - ``` 44 - #!/bin/sh 45 - export LUMINA_TLS=false 46 - $1 47 - ``` 48 - - save as ida_lumen.sh, "chmod +x ida_lumen.sh", now you can run IDA using "./ida_lumen.sh ./ida" or "./ida_lumen ./ida64" 49 - 50 - ##### Setup under Windows : 51 - ``` 52 - set LUMINA_TLS=false 53 - %1 54 - ``` 55 - - save as ida_lumen.bat, now you can run IDA using "./ida_lumen.bat ida.exe" or "./ida_lumen.bat ida64.exe" 56 - 57 - ##### Setup IDA 58 - - Go to Options, General, Lumina. Select "Use a private server", then set your host and port and "guest" as username and password. Click on ok. 59 - 60 - #### IDA Pro < 8.1 61 - You will need IDA Pro 7.2 or above in order to use _lumen_. 62 - 63 - > The following information may get sent to _lumen_ server: IDA key, Hostname, IDB path, original file path, file MD5, function signature, stack frames & comments. 64 - 65 - - In your IDA's installation directory open "cfg\ida.cfg" with your favorite text editor _(Example: C:\Program Files\IDA Pro 7.5\cfg\ida.cfg)_ 66 - - Locate the commented out `LUMINA_HOST`, `LUMINA_PORT`, and change their values to the address of your _lumen_ server. 67 - - If you didn't configure TLS, Add "LUMINA_TLS = NO" after the line with `LUMINA_PORT`. 68 - 69 - Example: 70 - ```C 71 - LUMINA_HOST = "192.168.1.1"; 72 - LUMINA_PORT = 1234 73 - 74 - // Only if TLS isn't used: 75 - LUMINA_TLS = NO 76 - ``` 77 - 78 - ### Configuring TLS 79 - IDA Pro uses a pinned certificate for Lumina's communcation, so adding a self-signed certificate to your root certificates won't work. 80 - Luckily, we can override the hard-coded public key by writing a DER-base64 encoded certificate to "hexrays.crt" in IDA's install directory. 81 - 82 - You may find the following commands useful: 83 - ```bash 84 - # create a certificate 85 - openssl req -x509 -newkey rsa:4096 -keyout lumen_key.pem -out lumen_crt.pem -days 365 -nodes 86 - 87 - # convert to pkcs12 for lumen; used for `lumen.tls` in config 88 - openssl pkcs12 -export -out lumen.p12 -inkey lumen_key.pem -in lumen_crt.pem 89 - 90 - # export public-key for IDA; Copy hexrays.crt to IDA installation folder 91 - openssl x509 -in lumen_crt.pem -out hexrays.crt 92 - ``` 93 - 94 - No attempt is made to merge function data - this may casuse a situation where metadata is inconsistent. 95 - Instead, the metadata with the highest calculated score is returned to the user. 96 - 97 - 98 - --- 99 - 100 - Developed by [Naim A.](https://github.com/naim94a); License: MIT. 1 + # Lumen 2 + 3 + A private Lumina server that can be used with IDA Pro 7.2+. 4 + 5 + [lumen.abda.nl](https://lumen.abda.nl/) runs this server. 6 + 7 + You can read about the protocol research [here](https://abda.nl/posts/introducing-lumen/). 8 + 9 + ## Features 10 + 11 + - Stores function signatures so you (and your team) can quickly identify functions that you found in the past using IDA's built-in Lumina features. 12 + - Backed by PostgreSQL 13 + - Experimental HTTP API that allows querying the database for comments by file or function hash. 14 + 15 + ## Getting Started 16 + 17 + ### Docker Method (Recommended) 18 + 19 + In this method precompiled docker images will be downloaded, All you need is [docker-compose.yml](./docker-compose.yml). 20 + 21 + 1. Install `docker-engine` and `docker-compose`. 22 + 2. If using a custom TLS certificate, copy the private key (`.p12`/`.pfx` extension) to `./dockershare` and set the key password in `.env` as `PKCSPASSWD`. 23 + 3. If using a custom Lumen config, copy it to `./dockershare/config.toml`. 24 + 4. Otherwise, or if you have finished these steps, just run `docker-compose up`. 25 + 5. Regardless, if TLS is enabled in the `config.toml`, a `hexrays.crt` will be generated in `./dockershare` to be copied to the IDA install directory. 26 + 27 + ### Building from source with Rust 28 + 29 + 1. `git clone https://github.com/naim94a/lumen.git` 30 + 2. Get a rust toolchain: https://rustup.rs/ 31 + 3. `cd lumen` 32 + 4. Setup a the database 33 + 34 + - install postgres 35 + - install diesel-cli and run migrations: 36 + 37 + ```bash 38 + cargo install diesel_cli --no-default-features -Fpostgres 39 + diesel --config-file common/diesel.toml \ 40 + --database-url postgres://postgres:password@localhost/lumen \ 41 + migration run 42 + ``` 43 + 44 + 5. `cargo build --release` 45 + 46 + ### Usage 47 + 48 + ```bash 49 + ./lumen -c config.toml 50 + ``` 51 + 52 + ### Configuring IDA 53 + 54 + #### IDA Pro >= 8.1 55 + 56 + If you used LUMEN in the past, remove the LUMINA settings in the ida.cfg or idauser.cfg files, otherwise you will get a warning about 57 + bad config parameters. 58 + 59 + ##### Setup under Linux : 60 + 61 + ```bash 62 + #!/bin/sh 63 + export LUMINA_TLS=false 64 + $1 65 + ``` 66 + 67 + - save as ida_lumen.sh, "chmod +x ida_lumen.sh", now you can run IDA using "./ida_lumen.sh ./ida" or "./ida_lumen ./ida64" 68 + 69 + ##### Setup under Windows : 70 + 71 + ```batch 72 + set LUMINA_TLS=false 73 + %1 74 + ``` 75 + 76 + - save as ida_lumen.bat, now you can run IDA using "./ida_lumen.bat ida.exe" or "./ida_lumen.bat ida64.exe" 77 + 78 + ##### Setup IDA 79 + 80 + - Go to Options, General, Lumina. Select "Use a private server", then set your host and port and "guest" as username and password. Click on ok. 81 + 82 + #### IDA Pro < 8.1 83 + 84 + You will need IDA Pro 7.2 or above in order to use _lumen_. 85 + 86 + > The following information may get sent to _lumen_ server: IDA key, Hostname, IDB path, original file path, file MD5, function signature, stack frames & comments. 87 + 88 + - In your IDA's installation directory open "cfg\ida.cfg" with your favorite text editor _(Example: C:\Program Files\IDA Pro 7.5\cfg\ida.cfg)_ 89 + - Locate the commented out `LUMINA_HOST`, `LUMINA_PORT`, and change their values to the address of your _lumen_ server. 90 + - If you didn't configure TLS, Add "LUMINA_TLS = NO" after the line with `LUMINA_PORT`. 91 + 92 + Example: 93 + 94 + ```C 95 + LUMINA_HOST = "192.168.1.1"; 96 + LUMINA_PORT = 1234 97 + 98 + // Only if TLS isn't used: 99 + LUMINA_TLS = NO 100 + ``` 101 + 102 + ### Configuring TLS 103 + 104 + IDA Pro uses a pinned certificate for Lumina's communcation, so adding a self-signed certificate to your root certificates won't work. 105 + Luckily, we can override the hard-coded public key by writing a DER-base64 encoded certificate to "hexrays.crt" in IDA's install directory. 106 + 107 + You may find the following commands useful: 108 + 109 + ```bash 110 + # create a certificate 111 + openssl req -x509 -newkey rsa:4096 -keyout lumen_key.pem -out lumen_crt.pem -days 365 -nodes 112 + 113 + # convert to pkcs12 for lumen; used for `lumen.tls` in config 114 + openssl pkcs12 -export -out lumen.p12 -inkey lumen_key.pem -in lumen_crt.pem 115 + 116 + # export public-key for IDA; Copy hexrays.crt to IDA installation folder 117 + openssl x509 -in lumen_crt.pem -out hexrays.crt 118 + ``` 119 + 120 + No attempt is made to merge function data - this may cause a situation where metadata is inconsistent. 121 + Instead, the metadata with the highest calculated score is returned to the user. 122 + 123 + --- 124 + 125 + Developed by [Naim A.](https://github.com/naim94a); License: MIT.
+27 -12
common/Cargo.toml
··· 7 7 publish = false 8 8 9 9 [dependencies] 10 - tokio = {version = "1.32", features = ["full"], optional = true} 11 - log = {version = "0.4", features = ["release_max_level_debug"]} 12 - serde = {version = "1.0", features = ["derive"]} 13 - postgres-native-tls = {version = "0.5", optional = true} 14 - native-tls = {version = "0.2", optional = true} 10 + tokio = { version = "1.39", features = ["full"], optional = true } 11 + log = { version = "0.4", features = ["release_max_level_debug"] } 12 + serde = { version = "1.0", features = ["derive"] } 13 + postgres-native-tls = { version = "0.5", optional = true } 14 + native-tls = { version = "0.2", optional = true } 15 15 futures-util = "0.3" 16 - toml = "0.7" 17 - warp = {version = "0.3", optional = true} 16 + toml = "0.8" 17 + warp = { version = "0.3", optional = true } 18 18 binascii = "0.1" 19 19 20 - tokio-postgres = {version = "0.7", default-features = false, optional = true} 21 - diesel = {version = "2.1", optional = true, default-features = false, features = ["postgres_backend", "time"]} 22 - diesel-async = {version = "0.3", optional = true, features = ["postgres", "bb8"]} 20 + tokio-postgres = { version = "0.7", default-features = false, optional = true } 21 + diesel = { version = "2.2", optional = true, default-features = false, features = [ 22 + "postgres_backend", 23 + "time", 24 + ] } 25 + time = { version = "0.3.36", optional = true } 26 + diesel-async = { version = "0.5", optional = true, features = [ 27 + "postgres", 28 + "bb8", 29 + ] } 23 30 anyhow = "1.0" 24 - prometheus-client = "0.21.2" 31 + prometheus-client = "0.22" 25 32 26 33 [features] 27 34 default = ["web", "db"] 28 35 web = ["warp"] 29 - db = ["tokio", "postgres-native-tls", "native-tls", "diesel", "diesel-async", "tokio-postgres"] 36 + db = [ 37 + "tokio", 38 + "postgres-native-tls", 39 + "native-tls", 40 + "diesel", 41 + "diesel-async", 42 + "tokio-postgres", 43 + "time", 44 + ]
+3 -6
common/src/async_drop.rs
··· 1 1 use futures_util::{future::BoxFuture, Future}; 2 2 use log::trace; 3 - use tokio::{sync::mpsc::{UnboundedSender, unbounded_channel, WeakUnboundedSender}}; 3 + use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, WeakUnboundedSender}; 4 4 5 5 enum AsyncDropperMsg { 6 6 Future(BoxFuture<'static, ()>), ··· 29 29 AsyncDropperMsg::Termination => { 30 30 trace!("term received for '{orig}'..."); 31 31 break; 32 - } 32 + }, 33 33 } 34 34 } 35 35 trace!("dropper '{orig}' exited."); ··· 41 41 /// Defers execution of a future to when the returned `AsyncDropGuard` is dropped 42 42 pub fn defer<F: Future<Output = ()> + Send + 'static>(&self, fut: F) -> AsyncDropGuard { 43 43 let tx = self.tx.downgrade(); 44 - AsyncDropGuard { 45 - tx, 46 - run: Some(Box::pin(fut)) 47 - } 44 + AsyncDropGuard { tx, run: Some(Box::pin(fut)) } 48 45 } 49 46 } 50 47 impl Drop for AsyncDropper {
+92 -57
common/src/config.rs
··· 1 - use serde::Deserialize; 2 - use toml::from_str; 3 - use std::{net::SocketAddr, path::PathBuf}; 4 - 5 - #[derive(Deserialize)] 6 - pub struct TlsIdentity { 7 - pub server_cert: PathBuf, 8 - } 9 - 10 - #[derive(Deserialize)] 11 - pub struct LuminaServer { 12 - pub bind_addr: SocketAddr, 13 - pub use_tls: Option<bool>, 14 - pub tls: Option<TlsIdentity>, 15 - pub server_name: Option<String>, 16 - pub allow_deletes: Option<bool>, 17 - } 18 - 19 - #[derive(Deserialize)] 20 - pub struct WebServer { 21 - pub bind_addr: SocketAddr, 22 - } 23 - 24 - #[derive(Deserialize)] 25 - pub struct Database { 26 - pub connection_info: String, 27 - 28 - pub use_tls: bool, 29 - pub server_ca: Option<PathBuf>, 30 - pub client_id: Option<PathBuf>, 31 - } 32 - 33 - #[derive(Deserialize)] 34 - pub struct Config { 35 - pub lumina: LuminaServer, 36 - pub api_server: Option<WebServer>, 37 - pub database: Database, 38 - } 39 - 40 - pub trait HasConfig { 41 - fn get_config(&self) -> &Config; 42 - } 43 - 44 - impl HasConfig for Config { 45 - fn get_config(&self) -> &Config { 46 - self 47 - } 48 - } 49 - 50 - pub fn load_config<R: std::io::Read>(mut fd: R) -> Config { 51 - let mut buf = vec![]; 52 - fd.read_to_end(&mut buf).expect("failed to read config"); 53 - 54 - let buf = std::str::from_utf8(&buf).expect("file contains invalid utf-8"); 55 - 56 - from_str(buf).expect("failed to parse configuration") 57 - } 1 + use serde::Deserialize; 2 + use std::time::Duration; 3 + use std::{net::SocketAddr, path::PathBuf}; 4 + use toml::from_str; 5 + 6 + #[derive(Deserialize)] 7 + pub struct TlsIdentity { 8 + pub server_cert: PathBuf, 9 + } 10 + 11 + #[derive(Deserialize)] 12 + pub struct LuminaServer { 13 + pub bind_addr: SocketAddr, 14 + pub use_tls: Option<bool>, 15 + pub tls: Option<TlsIdentity>, 16 + pub server_name: Option<String>, 17 + pub allow_deletes: Option<bool>, 18 + 19 + /// limit of function histories to return per function. 20 + /// `None`, or `Some(0)` will disable the feature on the server. 21 + pub get_history_limit: Option<u32>, 22 + } 23 + 24 + #[derive(Deserialize)] 25 + pub struct WebServer { 26 + pub bind_addr: SocketAddr, 27 + } 28 + 29 + #[derive(Deserialize)] 30 + pub struct Database { 31 + pub connection_info: String, 32 + 33 + pub use_tls: bool, 34 + pub server_ca: Option<PathBuf>, 35 + pub client_id: Option<PathBuf>, 36 + } 37 + 38 + #[derive(Deserialize, Debug)] 39 + #[serde(default)] 40 + pub struct Limits { 41 + /// Maximum time to wait on an idle connection between commands. 42 + pub command_timeout: Duration, 43 + 44 + /// Maximum time to all `PULL_MD` queries. 45 + pub pull_md_timeout: Duration, 46 + 47 + /// Maximum time to wait for `HELO` message. 48 + pub hello_timeout: Duration, 49 + 50 + /// Maximum time allowed until TLS handshake completes. 51 + pub tls_handshake_timeout: Duration, 52 + } 53 + 54 + impl Default for Limits { 55 + fn default() -> Self { 56 + Self { 57 + command_timeout: Duration::from_secs(3600), 58 + pull_md_timeout: Duration::from_secs(4 * 60), 59 + hello_timeout: Duration::from_secs(15), 60 + tls_handshake_timeout: Duration::from_secs(10), 61 + } 62 + } 63 + } 64 + 65 + #[derive(Deserialize)] 66 + pub struct Config { 67 + pub lumina: LuminaServer, 68 + pub api_server: Option<WebServer>, 69 + pub database: Database, 70 + 71 + #[serde(default)] 72 + pub limits: Limits, 73 + } 74 + 75 + pub trait HasConfig { 76 + fn get_config(&self) -> &Config; 77 + } 78 + 79 + impl HasConfig for Config { 80 + fn get_config(&self) -> &Config { 81 + self 82 + } 83 + } 84 + 85 + pub fn load_config<R: std::io::Read>(mut fd: R) -> Config { 86 + let mut buf = vec![]; 87 + fd.read_to_end(&mut buf).expect("failed to read config"); 88 + 89 + let buf = std::str::from_utf8(&buf).expect("file contains invalid utf-8"); 90 + 91 + from_str(buf).expect("failed to parse configuration") 92 + }
+478 -406
common/src/db/mod.rs
··· 1 - use log::*; 2 - use postgres_native_tls::MakeTlsConnector; 3 - use serde::Serialize; 4 - use tokio_postgres::{tls::MakeTlsConnect, Socket, NoTls}; 5 - use std::{collections::HashMap}; 6 - use crate::async_drop::{AsyncDropper, AsyncDropGuard}; 7 - mod schema_auto; 8 - pub mod schema; 9 - 10 - use diesel::{upsert::excluded, ExpressionMethods, QueryDsl, NullableExpressionMethods, sql_types::{Array, Binary, VarChar, Integer}, query_builder::{QueryFragment, Query}}; 11 - use diesel_async::RunQueryDsl; 12 - 13 - pub type DynConfig = dyn crate::config::HasConfig + Send + Sync; 14 - 15 - pub struct Database { 16 - tls_connector: Option<MakeTlsConnector>, 17 - diesel: diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>, 18 - dropper: AsyncDropper, 19 - } 20 - 21 - pub struct FunctionInfo { 22 - pub name: String, 23 - pub len: u32, 24 - pub data: Vec<u8>, 25 - pub popularity: u32, 26 - } 27 - 28 - #[derive(Debug, Serialize)] 29 - pub struct DbStats { 30 - unique_lics: i32, 31 - unique_hosts_per_lic: i32, 32 - 33 - unique_funcs: i32, 34 - total_funcs: i32, 35 - 36 - dbs: i32, 37 - unique_files: i32, 38 - } 39 - 40 - impl Database { 41 - pub async fn open(config: &crate::config::Database) -> Result<Self, anyhow::Error> { 42 - let connection_string = config.connection_info.as_str(); 43 - let tls_connector = if config.use_tls { 44 - Some(Self::make_tls(config).await) 45 - } else { 46 - None 47 - }; 48 - 49 - let (dropper, worker) = AsyncDropper::new(); 50 - tokio::task::spawn(worker); 51 - 52 - let diesel = Self::make_bb8_pool(connection_string, tls_connector.clone()).await?; 53 - 54 - Ok(Database{ 55 - tls_connector, 56 - dropper, 57 - diesel, 58 - }) 59 - } 60 - 61 - async fn make_pg_client<T>(db_url: &str, tls: T) -> diesel::result::ConnectionResult<diesel_async::AsyncPgConnection> 62 - where T: MakeTlsConnect<Socket>, 63 - T::Stream: Send + 'static { 64 - let (cli, conn) = tokio_postgres::connect(db_url, tls) 65 - .await 66 - .map_err(|e| { 67 - error!("failed to connect db: {e}"); 68 - diesel::result::ConnectionError::BadConnection(format!("{e}")) 69 - })?; 70 - 71 - tokio::spawn(async move { 72 - if let Err(e) = conn.await { 73 - error!("connection task error: {e}"); 74 - } 75 - }); 76 - 77 - diesel_async::AsyncPgConnection::try_from(cli).await 78 - } 79 - 80 - async fn make_bb8_pool(db_url: &str, tls: Option<MakeTlsConnector>) -> Result<diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>, anyhow::Error> { 81 - let cfg = diesel_async::pooled_connection::AsyncDieselConnectionManager::<diesel_async::AsyncPgConnection>::new_with_setup(db_url, move |db_url| { 82 - let tls = tls.clone(); 83 - Box::pin( async move { 84 - if let Some(tls) = tls { 85 - Self::make_pg_client(db_url, tls).await 86 - } else { 87 - Self::make_pg_client(db_url, NoTls).await 88 - } 89 - }) 90 - }); 91 - 92 - let pool = diesel_async::pooled_connection::bb8::Pool::builder() 93 - .min_idle(Some(1)) 94 - .build(cfg) 95 - .await?; 96 - Ok(pool) 97 - } 98 - 99 - async fn make_tls(database: &crate::config::Database) -> MakeTlsConnector { 100 - use native_tls::{TlsConnector, Certificate, Identity}; 101 - 102 - let mut tls_connector = TlsConnector::builder(); 103 - 104 - if let Some(ref client_identity) = database.client_id { 105 - let client_identity = tokio::fs::read(client_identity).await.expect("failed to read db's client id"); 106 - let client_identity = Identity::from_pkcs12(&client_identity, "").expect("failed to load db's client identity (PKCS12)"); 107 - tls_connector.identity(client_identity); 108 - } 109 - 110 - if let Some(ref server_ca) = database.server_ca { 111 - let server_ca = tokio::fs::read(server_ca).await.expect("failed to read db's server ca"); 112 - let server_ca = Certificate::from_pem(&server_ca).expect("failed to load db's server ca (PEM)"); 113 - tls_connector.add_root_certificate(server_ca); 114 - } 115 - 116 - let tls_connector = tls_connector 117 - .danger_accept_invalid_hostnames(true) 118 - .build() 119 - .expect("failed to build TlsConnector"); 120 - 121 - MakeTlsConnector::new(tls_connector) 122 - } 123 - 124 - pub async fn get_funcs(&self, funcs: &[crate::rpc::PullMetadataFunc<'_>]) -> Result<Vec<Option<FunctionInfo>>, anyhow::Error> { 125 - let chksums: Vec<&[u8]> = funcs.iter().map(|v| v.mb_hash).collect(); 126 - 127 - let rows: Vec<(String, i32, Vec<u8>, Vec<u8>)> = { 128 - let conn = &mut self.diesel.get().await?; 129 - 130 - let ct = self.cancel_guard(&*conn); 131 - 132 - let res: Vec<_> = BestMds(chksums.as_slice()) 133 - .get_results::<_>(conn).await?; 134 - ct.consume(); 135 - res 136 - }; 137 - 138 - let mut partial: HashMap<Vec<u8>, FunctionInfo> = rows 139 - .into_iter() 140 - .map(|row| { 141 - let v = FunctionInfo { 142 - name: row.0, 143 - len: row.1 as u32, 144 - data: row.2, 145 - popularity: 0, 146 - }; 147 - 148 - (row.3, v) 149 - }) 150 - .collect(); 151 - 152 - let results = partial.len(); 153 - 154 - let res: Vec<Option<FunctionInfo>> = chksums.iter().map(|&chksum| { 155 - partial.remove(chksum) 156 - }).collect(); 157 - 158 - trace!("found {}/{} results", results, chksums.len()); 159 - debug_assert_eq!(chksums.len(), res.len()); 160 - Ok(res) 161 - } 162 - 163 - pub async fn get_or_create_user<'a>(&self, user: &'a crate::rpc::RpcHello<'a>, hostname: &str) -> Result<i32, anyhow::Error> { 164 - use schema::users; 165 - 166 - let conn = &mut self.diesel.get().await?; 167 - 168 - let lic_id = &user.lic_number[..]; 169 - let lic_data = user.license_data; 170 - 171 - let get_user = || users::table.select(users::id) 172 - .filter(users::lic_data.eq(lic_data)) 173 - .filter(users::lic_id.eq(lic_id)) 174 - .filter(users::hostname.eq(hostname)); 175 - 176 - match get_user().get_result::<i32>(conn).await { 177 - Ok(v) => return Ok(v), 178 - Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 179 - _ => {}, 180 - }; 181 - 182 - match diesel::insert_into(users::table) 183 - .values(vec![ 184 - ( 185 - users::lic_id.eq(lic_id), 186 - users::lic_data.eq(lic_data), 187 - users::hostname.eq(hostname), 188 - ) 189 - ]) 190 - .returning(users::id) // xmax = 0 if the row is new 191 - .get_result::<i32>(conn) 192 - .await { 193 - Ok(v) => return Ok(v), 194 - Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {}, 195 - Err(e) => return Err(e.into()), 196 - } 197 - 198 - Ok(get_user().get_result::<i32>(conn).await?) 199 - } 200 - 201 - async fn get_or_create_file<'a>(&self, funcs: &'a crate::rpc::PushMetadata<'a>) -> Result<i32, anyhow::Error> { 202 - use schema::files::{table as files, chksum, id}; 203 - 204 - let hash = &funcs.md5[..]; 205 - 206 - let conn = &mut self.diesel.get().await?; 207 - 208 - let get_file = || files.filter(chksum.eq(hash)).select(id); 209 - 210 - match get_file().get_result::<i32>(conn).await { 211 - Ok(v) => return Ok(v), 212 - Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 213 - _ => {}, 214 - } 215 - 216 - match diesel::insert_into(files) 217 - .values(vec![(chksum.eq(hash),)]) 218 - .returning(id) 219 - .get_result::<i32>(conn) 220 - .await { 221 - Ok(v) => return Ok(v), 222 - Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {}, 223 - Err(e) => return Err(e.into()), 224 - } 225 - Ok(get_file().get_result::<i32>(conn).await?) 226 - } 227 - 228 - async fn get_or_create_db<'a>(&self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>) -> Result<i32, anyhow::Error> { 229 - use schema::dbs::{table as dbs, id as db_id, user_id as db_user, file_id as db_file_id, file_path, idb_path}; 230 - 231 - let file_id = self.get_or_create_file(funcs); 232 - let user_id = self.get_or_create_user(user, funcs.hostname); 233 - 234 - let (file_id, user_id): (i32, i32) = futures_util::try_join!(file_id, user_id)?; 235 - 236 - let conn = &mut self.diesel.get().await?; 237 - 238 - let get_db = || { 239 - dbs.select(db_id) 240 - .filter(db_user.eq(user_id)) 241 - .filter(db_file_id.eq(file_id)) 242 - .filter(file_path.eq(funcs.file_path)) 243 - .filter(idb_path.eq(funcs.idb_path)) 244 - }; 245 - 246 - match get_db().get_result::<i32>(conn).await { 247 - Ok(v) => return Ok(v), 248 - Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 249 - _ => {}, 250 - }; 251 - 252 - match diesel::insert_into(dbs) 253 - .values(vec![( 254 - db_user.eq(user_id), 255 - db_file_id.eq(file_id), 256 - file_path.eq(funcs.file_path), 257 - idb_path.eq(funcs.idb_path), 258 - )]) 259 - .returning(db_id) 260 - .get_result::<i32>(conn) 261 - .await { 262 - Ok(id) => return Ok(id), 263 - Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {}, 264 - Err(e) => return Err(e.into()), 265 - }; 266 - Ok(get_db().get_result::<i32>(conn).await?) 267 - } 268 - 269 - pub async fn push_funcs<'a, 'b>(&'b self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>, scores: &[u32]) -> Result<Vec<bool>, anyhow::Error> { 270 - use futures_util::TryStreamExt; 271 - 272 - // postgres has a limitation of binding per statement (i16::MAX). Split large push requests into smaller chunks. 273 - const PUSH_FUNC_CHUNK_SIZE: usize = 3000; 274 - 275 - let db_id = self.get_or_create_db(user, funcs).await?; 276 - 277 - let mut rows = Vec::with_capacity(funcs.funcs.len().min(PUSH_FUNC_CHUNK_SIZE)); 278 - let mut is_new = Vec::with_capacity(funcs.funcs.len()); 279 - let conn = &mut self.diesel.get().await?; 280 - let f2 = diesel::alias!(schema::funcs as f2); 281 - 282 - for (idx, (func, &score)) in funcs.funcs.iter().zip(scores.iter()).enumerate() { 283 - let name = func.name; 284 - let len = func.func_len as i32; 285 - let chksum = func.hash; 286 - let md = func.func_data; 287 - let score = score as i32; 288 - 289 - rows.push(( 290 - schema::funcs::name.eq(name), 291 - schema::funcs::len.eq(len), 292 - schema::funcs::chksum.eq(chksum), 293 - schema::funcs::metadata.eq(md), 294 - schema::funcs::rank.eq(score), 295 - schema::funcs::db_id.eq(db_id), 296 - )); 297 - 298 - if rows.len() < PUSH_FUNC_CHUNK_SIZE && idx < funcs.funcs.len() - 1 { 299 - continue; 300 - } 301 - 302 - let mut current_rows = Vec::with_capacity((funcs.funcs.len() - (idx + 1)).max(PUSH_FUNC_CHUNK_SIZE)); 303 - std::mem::swap(&mut current_rows, &mut rows); 304 - 305 - diesel::insert_into(schema::funcs::table) 306 - .values(current_rows) 307 - .on_conflict((schema::funcs::chksum, schema::funcs::db_id)) 308 - .do_update() 309 - .set(( 310 - schema::funcs::name.eq(excluded(schema::funcs::name)), 311 - schema::funcs::metadata.eq(excluded(schema::funcs::metadata)), 312 - schema::funcs::rank.eq(excluded(schema::funcs::rank)), 313 - schema::funcs::update_dt.eq(diesel::dsl::now) 314 - )) 315 - .returning(diesel::dsl::not(diesel::dsl::exists(f2.filter(f2.field(schema::funcs::chksum).eq(schema::funcs::chksum))))) // xmax=0 when a new row is created. 316 - .load_stream::<bool>(conn) 317 - .await? 318 - .try_fold(&mut is_new, |acc, item: bool| { 319 - acc.push(item); 320 - futures_util::future::ready(Ok(acc)) 321 - }) 322 - .await?; 323 - } 324 - 325 - Ok(is_new) 326 - } 327 - 328 - pub async fn get_file_funcs(&self, md5: &[u8], offset: i64, limit: i64) -> Result<Vec<(String, i32, Vec<u8>)>, anyhow::Error> { 329 - let conn = &mut self.diesel.get().await?; 330 - let results = schema::funcs::table 331 - .left_join(schema::dbs::table.left_join(schema::files::table)) 332 - .select((schema::funcs::name.assume_not_null(), schema::funcs::len.assume_not_null(), schema::funcs::chksum.assume_not_null())) 333 - .filter(schema::files::chksum.eq(md5)) 334 - .offset(offset) 335 - .limit(limit) 336 - .get_results::<(String, i32, Vec<u8>)>(conn).await?; 337 - Ok(results) 338 - } 339 - 340 - pub async fn get_files_with_func(&self, func: &[u8]) -> Result<Vec<Vec<u8>>, anyhow::Error> { 341 - let conn = &mut self.diesel.get().await?; 342 - 343 - let res = schema::files::table 344 - .left_join(schema::dbs::table.left_join(schema::funcs::table)) 345 - .select(schema::files::chksum.assume_not_null()) 346 - .distinct() 347 - .filter(schema::funcs::chksum.eq(func)) 348 - .get_results::<Vec<u8>>(conn) 349 - .await?; 350 - Ok(res) 351 - } 352 - 353 - fn cancel_guard(&self, conn: &diesel_async::pooled_connection::bb8::PooledConnection<'_, diesel_async::AsyncPgConnection>) -> AsyncDropGuard { 354 - let token = conn.cancel_token(); 355 - let tls_connector = self.tls_connector.clone(); 356 - self.dropper.defer(async move { 357 - debug!("cancelling query..."); 358 - 359 - if let Some(tls) = tls_connector { 360 - let _ = token.cancel_query(tls).await; 361 - } else { 362 - let _ = token.cancel_query(NoTls).await; 363 - } 364 - }) 365 - } 366 - 367 - pub async fn delete_metadata(&self, req: &crate::rpc::DelHistory<'_>) -> Result<(), anyhow::Error> { 368 - use schema::funcs::{table as funcs, chksum}; 369 - 370 - let chksums = req.funcs.iter() 371 - .map(|v| v.as_slice()) 372 - .collect::<Vec<_>>(); 373 - 374 - let conn = &mut self.diesel.get().await?; 375 - let rows_modified = diesel::delete(funcs.filter(chksum.eq_any(&chksums))) 376 - .execute(conn) 377 - .await?; 378 - 379 - debug!("deleted {rows_modified} rows"); 380 - 381 - Ok(()) 382 - } 383 - } 384 - 385 - // This is eww, but it's the fastest. 386 - struct BestMds<'a>(&'a [&'a [u8]]); 387 - impl<'a> QueryFragment<diesel::pg::Pg> for BestMds<'a> { 388 - fn walk_ast<'b>(&'b self, mut pass: diesel::query_builder::AstPass<'_, 'b, diesel::pg::Pg>) -> diesel::QueryResult<()> { 389 - pass.push_sql(r#"WITH best AS ( 390 - select chksum,MAX(rank) as maxrank from funcs f1 391 - WHERE chksum = ANY("#); 392 - pass.push_bind_param::<Array<Binary>, _>(&self.0)?; 393 - pass.push_sql(r#") 394 - GROUP BY chksum 395 - ) 396 - SELECT f2.name,f2.len,f2.metadata,f2.chksum FROM best 397 - LEFT JOIN funcs f2 ON (best.chksum=f2.chksum AND best.maxrank=f2.rank)"#); 398 - Ok(()) 399 - } 400 - } 401 - impl<'a> diesel::query_builder::QueryId for BestMds<'a> { 402 - type QueryId = BestMds<'static>; 403 - } 404 - impl<'a> Query for BestMds<'a> { 405 - type SqlType = (VarChar, Integer, Binary, Binary); 406 - } 1 + use crate::async_drop::{AsyncDropGuard, AsyncDropper}; 2 + use log::*; 3 + use postgres_native_tls::MakeTlsConnector; 4 + use serde::Serialize; 5 + use std::collections::HashMap; 6 + use time::OffsetDateTime; 7 + use tokio_postgres::{tls::MakeTlsConnect, NoTls, Socket}; 8 + pub mod schema; 9 + mod schema_auto; 10 + 11 + use diesel::{ 12 + query_builder::{Query, QueryFragment}, 13 + sql_types::{Array, Binary, Integer, VarChar}, 14 + upsert::excluded, 15 + ExpressionMethods, NullableExpressionMethods, QueryDsl, 16 + }; 17 + use diesel_async::{pooled_connection::ManagerConfig, RunQueryDsl}; 18 + 19 + pub type DynConfig = dyn crate::config::HasConfig + Send + Sync; 20 + 21 + pub struct Database { 22 + tls_connector: Option<MakeTlsConnector>, 23 + diesel: diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>, 24 + dropper: AsyncDropper, 25 + } 26 + 27 + pub struct FunctionInfo { 28 + pub name: String, 29 + pub len: u32, 30 + pub data: Vec<u8>, 31 + pub popularity: u32, 32 + } 33 + 34 + #[derive(Debug, Serialize)] 35 + pub struct DbStats { 36 + unique_lics: i32, 37 + unique_hosts_per_lic: i32, 38 + 39 + unique_funcs: i32, 40 + total_funcs: i32, 41 + 42 + dbs: i32, 43 + unique_files: i32, 44 + } 45 + 46 + impl Database { 47 + pub async fn open(config: &crate::config::Database) -> Result<Self, anyhow::Error> { 48 + let connection_string = config.connection_info.as_str(); 49 + let tls_connector = if config.use_tls { Some(Self::make_tls(config).await) } else { None }; 50 + 51 + let (dropper, worker) = AsyncDropper::new(); 52 + tokio::task::spawn(worker); 53 + 54 + let diesel = Self::make_bb8_pool(connection_string, tls_connector.clone()).await?; 55 + 56 + Ok(Database { tls_connector, dropper, diesel }) 57 + } 58 + 59 + async fn make_pg_client<T>( 60 + db_url: &str, tls: T, 61 + ) -> diesel::result::ConnectionResult<diesel_async::AsyncPgConnection> 62 + where 63 + T: MakeTlsConnect<Socket>, 64 + T::Stream: Send + 'static, 65 + { 66 + let (cli, conn) = tokio_postgres::connect(db_url, tls).await.map_err(|e| { 67 + error!("failed to connect db: {e}"); 68 + diesel::result::ConnectionError::BadConnection(format!("{e}")) 69 + })?; 70 + 71 + tokio::spawn(async move { 72 + if let Err(e) = conn.await { 73 + error!("connection task error: {e}"); 74 + } 75 + }); 76 + 77 + diesel_async::AsyncPgConnection::try_from(cli).await 78 + } 79 + 80 + async fn make_bb8_pool( 81 + db_url: &str, tls: Option<MakeTlsConnector>, 82 + ) -> Result< 83 + diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>, 84 + anyhow::Error, 85 + > { 86 + let mut config = ManagerConfig::default(); 87 + config.custom_setup = Box::new(move |db_url| { 88 + let tls = tls.clone(); 89 + Box::pin(async move { 90 + if let Some(tls) = tls { 91 + Self::make_pg_client(db_url, tls).await 92 + } else { 93 + Self::make_pg_client(db_url, NoTls).await 94 + } 95 + }) 96 + }); 97 + let cfg = diesel_async::pooled_connection::AsyncDieselConnectionManager::< 98 + diesel_async::AsyncPgConnection, 99 + >::new_with_config(db_url, config); 100 + 101 + let pool = diesel_async::pooled_connection::bb8::Pool::builder() 102 + .min_idle(Some(1)) 103 + .build(cfg) 104 + .await?; 105 + Ok(pool) 106 + } 107 + 108 + async fn make_tls(database: &crate::config::Database) -> MakeTlsConnector { 109 + use native_tls::{Certificate, Identity, TlsConnector}; 110 + 111 + let mut tls_connector = TlsConnector::builder(); 112 + 113 + if let Some(ref client_identity) = database.client_id { 114 + let client_identity = 115 + tokio::fs::read(client_identity).await.expect("failed to read db's client id"); 116 + let client_identity = Identity::from_pkcs12(&client_identity, "") 117 + .expect("failed to load db's client identity (PKCS12)"); 118 + tls_connector.identity(client_identity); 119 + } 120 + 121 + if let Some(ref server_ca) = database.server_ca { 122 + let server_ca = 123 + tokio::fs::read(server_ca).await.expect("failed to read db's server ca"); 124 + let server_ca = 125 + Certificate::from_pem(&server_ca).expect("failed to load db's server ca (PEM)"); 126 + tls_connector.add_root_certificate(server_ca); 127 + } 128 + 129 + let tls_connector = tls_connector 130 + .danger_accept_invalid_hostnames(true) 131 + .build() 132 + .expect("failed to build TlsConnector"); 133 + 134 + MakeTlsConnector::new(tls_connector) 135 + } 136 + 137 + pub async fn get_funcs( 138 + &self, funcs: &[crate::rpc::PullMetadataFunc<'_>], 139 + ) -> Result<Vec<Option<FunctionInfo>>, anyhow::Error> { 140 + let chksums: Vec<&[u8]> = funcs.iter().map(|v| v.mb_hash).collect(); 141 + 142 + let rows: Vec<(String, i32, Vec<u8>, Vec<u8>)> = { 143 + let conn = &mut self.diesel.get().await?; 144 + 145 + let ct = self.cancel_guard(&*conn); 146 + 147 + let res: Vec<_> = BestMds(chksums.as_slice()).get_results::<_>(conn).await?; 148 + ct.consume(); 149 + res 150 + }; 151 + 152 + let mut partial: HashMap<Vec<u8>, FunctionInfo> = rows 153 + .into_iter() 154 + .map(|row| { 155 + let v = FunctionInfo { name: row.0, len: row.1 as u32, data: row.2, popularity: 0 }; 156 + 157 + (row.3, v) 158 + }) 159 + .collect(); 160 + 161 + let results = partial.len(); 162 + 163 + let res: Vec<Option<FunctionInfo>> = 164 + chksums.iter().map(|&chksum| partial.remove(chksum)).collect(); 165 + 166 + trace!("found {}/{} results", results, chksums.len()); 167 + debug_assert_eq!(chksums.len(), res.len()); 168 + Ok(res) 169 + } 170 + 171 + pub async fn get_or_create_user<'a>( 172 + &self, user: &'a crate::rpc::RpcHello<'a>, hostname: &str, 173 + ) -> Result<i32, anyhow::Error> { 174 + use schema::users; 175 + 176 + let conn = &mut self.diesel.get().await?; 177 + 178 + let lic_id = &user.lic_number[..]; 179 + let lic_data = user.license_data; 180 + 181 + let get_user = || { 182 + users::table 183 + .select(users::id) 184 + .filter(users::lic_data.eq(lic_data)) 185 + .filter(users::lic_id.eq(lic_id)) 186 + .filter(users::hostname.eq(hostname)) 187 + }; 188 + 189 + match get_user().get_result::<i32>(conn).await { 190 + Ok(v) => return Ok(v), 191 + Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 192 + _ => {}, 193 + }; 194 + 195 + match diesel::insert_into(users::table) 196 + .values(vec![( 197 + users::lic_id.eq(lic_id), 198 + users::lic_data.eq(lic_data), 199 + users::hostname.eq(hostname), 200 + )]) 201 + .returning(users::id) // xmax = 0 if the row is new 202 + .get_result::<i32>(conn) 203 + .await 204 + { 205 + Ok(v) => return Ok(v), 206 + Err(diesel::result::Error::DatabaseError( 207 + diesel::result::DatabaseErrorKind::UniqueViolation, 208 + _, 209 + )) => {}, 210 + Err(e) => return Err(e.into()), 211 + } 212 + 213 + Ok(get_user().get_result::<i32>(conn).await?) 214 + } 215 + 216 + async fn get_or_create_file<'a>( 217 + &self, funcs: &'a crate::rpc::PushMetadata<'a>, 218 + ) -> Result<i32, anyhow::Error> { 219 + use schema::files::{chksum, id, table as files}; 220 + 221 + let hash = &funcs.md5[..]; 222 + 223 + let conn = &mut self.diesel.get().await?; 224 + 225 + let get_file = || files.filter(chksum.eq(hash)).select(id); 226 + 227 + match get_file().get_result::<i32>(conn).await { 228 + Ok(v) => return Ok(v), 229 + Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 230 + _ => {}, 231 + } 232 + 233 + match diesel::insert_into(files) 234 + .values(vec![(chksum.eq(hash),)]) 235 + .returning(id) 236 + .get_result::<i32>(conn) 237 + .await 238 + { 239 + Ok(v) => return Ok(v), 240 + Err(diesel::result::Error::DatabaseError( 241 + diesel::result::DatabaseErrorKind::UniqueViolation, 242 + _, 243 + )) => {}, 244 + Err(e) => return Err(e.into()), 245 + } 246 + Ok(get_file().get_result::<i32>(conn).await?) 247 + } 248 + 249 + async fn get_or_create_db<'a>( 250 + &self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>, 251 + ) -> Result<i32, anyhow::Error> { 252 + use schema::dbs::{ 253 + file_id as db_file_id, file_path, id as db_id, idb_path, table as dbs, 254 + user_id as db_user, 255 + }; 256 + 257 + let file_id = self.get_or_create_file(funcs); 258 + let user_id = self.get_or_create_user(user, funcs.hostname); 259 + 260 + let (file_id, user_id): (i32, i32) = futures_util::try_join!(file_id, user_id)?; 261 + 262 + let conn = &mut self.diesel.get().await?; 263 + 264 + let get_db = || { 265 + dbs.select(db_id) 266 + .filter(db_user.eq(user_id)) 267 + .filter(db_file_id.eq(file_id)) 268 + .filter(file_path.eq(funcs.file_path)) 269 + .filter(idb_path.eq(funcs.idb_path)) 270 + }; 271 + 272 + match get_db().get_result::<i32>(conn).await { 273 + Ok(v) => return Ok(v), 274 + Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()), 275 + _ => {}, 276 + }; 277 + 278 + match diesel::insert_into(dbs) 279 + .values(vec![( 280 + db_user.eq(user_id), 281 + db_file_id.eq(file_id), 282 + file_path.eq(funcs.file_path), 283 + idb_path.eq(funcs.idb_path), 284 + )]) 285 + .returning(db_id) 286 + .get_result::<i32>(conn) 287 + .await 288 + { 289 + Ok(id) => return Ok(id), 290 + Err(diesel::result::Error::DatabaseError( 291 + diesel::result::DatabaseErrorKind::UniqueViolation, 292 + _, 293 + )) => {}, 294 + Err(e) => return Err(e.into()), 295 + }; 296 + Ok(get_db().get_result::<i32>(conn).await?) 297 + } 298 + 299 + pub async fn push_funcs<'a, 'b>( 300 + &'b self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>, 301 + scores: &[u32], 302 + ) -> Result<Vec<bool>, anyhow::Error> { 303 + use futures_util::TryStreamExt; 304 + 305 + // postgres has a limitation of binding per statement (i16::MAX). Split large push requests into smaller chunks. 306 + const PUSH_FUNC_CHUNK_SIZE: usize = 3000; 307 + 308 + let db_id = self.get_or_create_db(user, funcs).await?; 309 + 310 + let mut rows = Vec::with_capacity(funcs.funcs.len().min(PUSH_FUNC_CHUNK_SIZE)); 311 + let mut is_new = Vec::with_capacity(funcs.funcs.len()); 312 + let conn = &mut self.diesel.get().await?; 313 + let f2 = diesel::alias!(schema::funcs as f2); 314 + 315 + for (idx, (func, &score)) in funcs.funcs.iter().zip(scores.iter()).enumerate() { 316 + let name = func.name; 317 + let len = func.func_len as i32; 318 + let chksum = func.hash; 319 + let md = func.func_data; 320 + let score = score as i32; 321 + 322 + rows.push(( 323 + schema::funcs::name.eq(name), 324 + schema::funcs::len.eq(len), 325 + schema::funcs::chksum.eq(chksum), 326 + schema::funcs::metadata.eq(md), 327 + schema::funcs::rank.eq(score), 328 + schema::funcs::db_id.eq(db_id), 329 + )); 330 + 331 + if rows.len() < PUSH_FUNC_CHUNK_SIZE && idx < funcs.funcs.len() - 1 { 332 + continue; 333 + } 334 + 335 + let mut current_rows = 336 + Vec::with_capacity((funcs.funcs.len() - (idx + 1)).max(PUSH_FUNC_CHUNK_SIZE)); 337 + std::mem::swap(&mut current_rows, &mut rows); 338 + 339 + diesel::insert_into(schema::funcs::table) 340 + .values(current_rows) 341 + .on_conflict((schema::funcs::chksum, schema::funcs::db_id)) 342 + .do_update() 343 + .set(( 344 + schema::funcs::name.eq(excluded(schema::funcs::name)), 345 + schema::funcs::metadata.eq(excluded(schema::funcs::metadata)), 346 + schema::funcs::rank.eq(excluded(schema::funcs::rank)), 347 + schema::funcs::update_dt.eq(diesel::dsl::now), 348 + )) 349 + .returning(diesel::dsl::not(diesel::dsl::exists( 350 + f2.filter(f2.field(schema::funcs::chksum).eq(schema::funcs::chksum)), 351 + ))) // xmax=0 when a new row is created. 352 + .load_stream::<bool>(conn) 353 + .await? 354 + .try_fold(&mut is_new, |acc, item: bool| { 355 + acc.push(item); 356 + futures_util::future::ready(Ok(acc)) 357 + }) 358 + .await?; 359 + } 360 + 361 + Ok(is_new) 362 + } 363 + 364 + pub async fn get_file_funcs( 365 + &self, md5: &[u8], offset: i64, limit: i64, 366 + ) -> Result<Vec<(String, i32, Vec<u8>)>, anyhow::Error> { 367 + let conn = &mut self.diesel.get().await?; 368 + let results = schema::funcs::table 369 + .left_join(schema::dbs::table.left_join(schema::files::table)) 370 + .select(( 371 + schema::funcs::name.assume_not_null(), 372 + schema::funcs::len.assume_not_null(), 373 + schema::funcs::chksum.assume_not_null(), 374 + )) 375 + .filter(schema::files::chksum.eq(md5)) 376 + .offset(offset) 377 + .limit(limit) 378 + .get_results::<(String, i32, Vec<u8>)>(conn) 379 + .await?; 380 + Ok(results) 381 + } 382 + 383 + pub async fn get_files_with_func(&self, func: &[u8]) -> Result<Vec<Vec<u8>>, anyhow::Error> { 384 + let conn = &mut self.diesel.get().await?; 385 + 386 + let res = schema::files::table 387 + .left_join(schema::dbs::table.left_join(schema::funcs::table)) 388 + .select(schema::files::chksum.assume_not_null()) 389 + .distinct() 390 + .filter(schema::funcs::chksum.eq(func)) 391 + .get_results::<Vec<u8>>(conn) 392 + .await?; 393 + Ok(res) 394 + } 395 + 396 + fn cancel_guard( 397 + &self, 398 + conn: &diesel_async::pooled_connection::bb8::PooledConnection< 399 + '_, 400 + diesel_async::AsyncPgConnection, 401 + >, 402 + ) -> AsyncDropGuard { 403 + let token = conn.cancel_token(); 404 + let tls_connector = self.tls_connector.clone(); 405 + self.dropper.defer(async move { 406 + debug!("cancelling query..."); 407 + 408 + if let Some(tls) = tls_connector { 409 + let _ = token.cancel_query(tls).await; 410 + } else { 411 + let _ = token.cancel_query(NoTls).await; 412 + } 413 + }) 414 + } 415 + 416 + pub async fn delete_metadata( 417 + &self, req: &crate::rpc::DelHistory<'_>, 418 + ) -> Result<(), anyhow::Error> { 419 + use schema::funcs::{chksum, table as funcs}; 420 + 421 + let chksums = req.funcs.iter().map(|v| v.as_slice()).collect::<Vec<_>>(); 422 + 423 + let conn = &mut self.diesel.get().await?; 424 + let rows_modified = 425 + diesel::delete(funcs.filter(chksum.eq_any(&chksums))).execute(conn).await?; 426 + 427 + debug!("deleted {rows_modified} rows"); 428 + 429 + Ok(()) 430 + } 431 + 432 + pub async fn get_func_histories( 433 + &self, chksum: &[u8], limit: u32, 434 + ) -> Result<Vec<(OffsetDateTime, String, Vec<u8>)>, anyhow::Error> { 435 + let conn = &mut self.diesel.get().await?; 436 + let rows = &schema::funcs::table.select(( 437 + schema::funcs::update_dt.assume_not_null(), 438 + schema::funcs::name, 439 + schema::funcs::metadata.assume_not_null(), 440 + )); 441 + let rows = rows 442 + .limit(limit as i64) 443 + .order_by(schema::funcs::update_dt.desc()) 444 + .filter(schema::funcs::chksum.eq(chksum)) 445 + .get_results::<(time::OffsetDateTime, String, Vec<u8>)>(conn) 446 + .await?; 447 + Ok(rows) 448 + } 449 + } 450 + 451 + // This is eww, but it's the fastest. 452 + struct BestMds<'a>(&'a [&'a [u8]]); 453 + impl<'a> QueryFragment<diesel::pg::Pg> for BestMds<'a> { 454 + fn walk_ast<'b>( 455 + &'b self, mut pass: diesel::query_builder::AstPass<'_, 'b, diesel::pg::Pg>, 456 + ) -> diesel::QueryResult<()> { 457 + pass.push_sql( 458 + r#"WITH best AS ( 459 + select chksum,MAX(rank) as maxrank from funcs f1 460 + WHERE chksum = ANY("#, 461 + ); 462 + pass.push_bind_param::<Array<Binary>, _>(&self.0)?; 463 + pass.push_sql( 464 + r#") 465 + GROUP BY chksum 466 + ) 467 + SELECT f2.name,f2.len,f2.metadata,f2.chksum FROM best 468 + LEFT JOIN funcs f2 ON (best.chksum=f2.chksum AND best.maxrank=f2.rank)"#, 469 + ); 470 + Ok(()) 471 + } 472 + } 473 + impl<'a> diesel::query_builder::QueryId for BestMds<'a> { 474 + type QueryId = BestMds<'static>; 475 + } 476 + impl<'a> Query for BestMds<'a> { 477 + type SqlType = (VarChar, Integer, Binary, Binary); 478 + }
+1 -6
common/src/db/schema_auto.rs
··· 45 45 diesel::joinable!(dbs -> users (user_id)); 46 46 diesel::joinable!(funcs -> dbs (db_id)); 47 47 48 - diesel::allow_tables_to_appear_in_same_query!( 49 - dbs, 50 - files, 51 - funcs, 52 - users, 53 - ); 48 + diesel::allow_tables_to_appear_in_same_query!(dbs, files, funcs, users,);
+8 -4
common/src/lib.rs
··· 3 3 4 4 use std::fmt::Write; 5 5 6 + pub mod async_drop; 7 + pub mod config; 6 8 pub mod db; 7 - pub mod config; 8 9 pub mod md; 10 + pub mod metrics; 9 11 pub mod rpc; 10 12 pub mod web; 11 - pub mod async_drop; 12 - pub mod metrics; 13 13 14 14 pub struct SharedState_ { 15 15 pub db: db::Database, ··· 33 33 } 34 34 35 35 let _ = write!(&mut output, " | "); 36 - for ch in chunk.iter().chain(std::iter::repeat(&b' ').take(padding)).map(|&v| std::char::from_u32(v as u32).unwrap_or('.')) { 36 + for ch in chunk 37 + .iter() 38 + .chain(std::iter::repeat(&b' ').take(padding)) 39 + .map(|&v| std::char::from_u32(v as u32).unwrap_or('.')) 40 + { 37 41 if !ch.is_ascii_graphic() { 38 42 output.push('.'); 39 43 } else {
+218 -214
common/src/md.rs
··· 1 - use std::collections::HashSet; 2 - 3 - use serde::{Serialize, Deserialize}; 4 - use crate::rpc::de::from_slice; 5 - 6 - #[derive(Serialize, Deserialize)] 7 - pub struct MetadataChunk<'a> { 8 - code: u32, 9 - data: &'a [u8], 10 - } 11 - 12 - #[derive(Debug)] 13 - pub enum FunctionMetadata<'a> { 14 - FunctionComment(FunctionComment<'a>), 15 - ByteComment(ByteComment<'a>), 16 - ExtraComment(ExtraComment<'a>), 17 - } 18 - 19 - #[derive(Debug)] 20 - pub struct FunctionComment<'a> { 21 - pub is_repeatable: bool, 22 - pub comment: &'a str, 23 - } 24 - 25 - #[derive(Debug)] 26 - pub struct ByteComment<'a> { 27 - pub is_repeatable: bool, 28 - pub offset: u32, 29 - pub comment: &'a str, 30 - } 31 - 32 - #[derive(Debug)] 33 - pub struct ExtraComment<'a> { 34 - pub offset: u32, 35 - pub anterior: &'a str, 36 - pub posterior: &'a str, 37 - } 38 - 39 - impl<'a> FunctionMetadata<'a> { 40 - fn is_useful(&self) -> bool { 41 - // TODO: rewrite using regex with configurable library names 42 - match self { 43 - FunctionMetadata::ExtraComment(cmt) => { 44 - if cmt.anterior.starts_with("; Exported entry ") // offset=0 45 - { 46 - return false; 47 - } 48 - if cmt.anterior.is_empty() && cmt.posterior.is_empty() { 49 - return false; 50 - } 51 - }, 52 - FunctionMetadata::FunctionComment(cmt) => { 53 - if cmt.comment == "Microsoft VisualC v14 64bit runtime" 54 - || cmt.comment == "Microsoft VisualC 64bit universal runtime" 55 - { 56 - return false; 57 - } 58 - if cmt.comment.is_empty() { 59 - return false; 60 - } 61 - }, 62 - FunctionMetadata::ByteComment(cmt) => { 63 - if cmt.comment == "Trap to Debugger" 64 - || (cmt.comment.starts_with("jumptable ") && cmt.comment.contains(" case")) // repeatable=true 65 - || cmt.comment == "switch jump" 66 - || (cmt.comment.starts_with("switch ") && cmt.comment.ends_with(" cases ")) 67 - || cmt.comment == "jump table for switch statement" 68 - || cmt.comment == "indirect table for switch statement" 69 - || cmt.comment == "Microsoft VisualC v7/14 64bit runtime" 70 - || cmt.comment == "Microsoft VisualC v7/14 64bit runtime\nMicrosoft VisualC v14 64bit runtime" 71 - || cmt.comment == "Microsoft VisualC v14 64bit runtime" { 72 - return false; 73 - } 74 - if cmt.comment.is_empty() { 75 - return false; 76 - } 77 - }, 78 - } 79 - true 80 - } 81 - } 82 - 83 - fn deserialize_seq<'de, T: Deserialize<'de>>(mut data: &'de [u8]) -> Result<Vec<(u32, T)>, crate::rpc::Error> { 84 - let mut res = vec![]; 85 - let mut reset = true; 86 - let (mut offset, used): (u32, usize) = from_slice(data)?; 87 - data = &data[used..]; 88 - if data.is_empty() { 89 - return Err(crate::rpc::Error::UnexpectedEof); 90 - } 91 - 92 - loop { 93 - let (offset_diff, used): (u32, usize) = from_slice(data)?; 94 - data = &data[used..]; 95 - if data.is_empty() { 96 - return Err(crate::rpc::Error::UnexpectedEof); 97 - } 98 - 99 - if (offset_diff > 0) || reset { 100 - offset += offset_diff; 101 - let (e, used): (T, usize) = from_slice(data)?; 102 - data = &data[used..]; 103 - 104 - res.push((offset, e)); 105 - 106 - reset = false; 107 - } else { 108 - let (offset_diff, used): (u32, usize) = from_slice(data)?; 109 - data = &data[used..]; 110 - 111 - offset = offset_diff; 112 - reset = true; 113 - } 114 - 115 - if data.is_empty() { 116 - break; 117 - } 118 - } 119 - 120 - Ok(res) 121 - } 122 - 123 - pub fn parse_metadata(mut data: &[u8]) -> Result<Vec<FunctionMetadata<'_>>, crate::rpc::Error> { 124 - let mut res = vec![]; 125 - let mut bad_codes = HashSet::new(); 126 - 127 - while !data.is_empty() { 128 - let (chunk, used) :(MetadataChunk, _) = from_slice(data)?; 129 - data = &data[used..]; 130 - 131 - let data = chunk.data; 132 - 133 - if data.is_empty() { 134 - continue; 135 - } 136 - 137 - match chunk.code { 138 - 1 => {}, // TODO: parse typeinfo 139 - 2 => {}, // nop 140 - 3 | 4 => { // function comments 141 - let is_repeatable = chunk.code == 4; 142 - let cmt = std::str::from_utf8(data)?; 143 - res.push(FunctionMetadata::FunctionComment(FunctionComment{ 144 - is_repeatable, 145 - comment: cmt, 146 - })); 147 - }, 148 - 5 | 6 => { // comments 149 - let is_repeatable = chunk.code == 6; 150 - let byte_comments: Vec<(_, &[u8])> = match deserialize_seq(data) { 151 - Ok(v) => v, 152 - Err(err) => { 153 - log::error!("err: {}\n{}", err, super::make_pretty_hex(data)); 154 - return Err(err); 155 - }, 156 - }; 157 - 158 - for comment in byte_comments { 159 - let cmt = std::str::from_utf8(comment.1)?; 160 - res.push(FunctionMetadata::ByteComment( 161 - ByteComment{ 162 - is_repeatable, 163 - offset: comment.0, 164 - comment: cmt, 165 - } 166 - )); 167 - } 168 - }, 169 - 7 => { // extra comments 170 - let byte_comments: Vec<(_, (&[u8], &[u8]))> = match deserialize_seq(data) { 171 - Ok(v) => v, 172 - Err(err) => { 173 - log::error!("err: {}\n{}", err, super::make_pretty_hex(data)); 174 - return Err(err); 175 - }, 176 - }; 177 - 178 - for comment in byte_comments { 179 - res.push(FunctionMetadata::ExtraComment(ExtraComment{ 180 - offset: comment.0, 181 - anterior: std::str::from_utf8(comment.1.0)?, 182 - posterior: std::str::from_utf8(comment.1.1)?, 183 - })); 184 - } 185 - }, 186 - 9 | 10 => { /* TODO! */ }, 187 - _ => { 188 - bad_codes.insert(chunk.code); 189 - }, 190 - } 191 - } 192 - 193 - Ok(res) 194 - } 195 - 196 - pub fn get_score(md: &crate::rpc::PushMetadataFunc) -> u32 { 197 - let mut score = 0; 198 - 199 - let md = match parse_metadata(md.func_data) { 200 - Ok(v) => v, 201 - Err(e) => { 202 - log::warn!("failed to parse metadata: {}", e); 203 - return 0; 204 - } 205 - }; 206 - 207 - for md in md { 208 - if md.is_useful() { 209 - score += 10; 210 - } 211 - } 212 - 213 - score 214 - } 1 + use std::collections::HashSet; 2 + 3 + use crate::rpc::de::from_slice; 4 + use serde::{Deserialize, Serialize}; 5 + 6 + #[derive(Serialize, Deserialize)] 7 + pub struct MetadataChunk<'a> { 8 + code: u32, 9 + data: &'a [u8], 10 + } 11 + 12 + #[derive(Debug)] 13 + pub enum FunctionMetadata<'a> { 14 + FunctionComment(FunctionComment<'a>), 15 + ByteComment(ByteComment<'a>), 16 + ExtraComment(ExtraComment<'a>), 17 + } 18 + 19 + #[derive(Debug)] 20 + pub struct FunctionComment<'a> { 21 + pub is_repeatable: bool, 22 + pub comment: &'a str, 23 + } 24 + 25 + #[derive(Debug)] 26 + pub struct ByteComment<'a> { 27 + pub is_repeatable: bool, 28 + pub offset: u32, 29 + pub comment: &'a str, 30 + } 31 + 32 + #[derive(Debug)] 33 + pub struct ExtraComment<'a> { 34 + pub offset: u32, 35 + pub anterior: &'a str, 36 + pub posterior: &'a str, 37 + } 38 + 39 + impl<'a> FunctionMetadata<'a> { 40 + fn is_useful(&self) -> bool { 41 + // TODO: rewrite using regex with configurable library names 42 + match self { 43 + FunctionMetadata::ExtraComment(cmt) => { 44 + if cmt.anterior.starts_with("; Exported entry ") 45 + // offset=0 46 + { 47 + return false; 48 + } 49 + if cmt.anterior.is_empty() && cmt.posterior.is_empty() { 50 + return false; 51 + } 52 + }, 53 + FunctionMetadata::FunctionComment(cmt) => { 54 + if cmt.comment == "Microsoft VisualC v14 64bit runtime" 55 + || cmt.comment == "Microsoft VisualC 64bit universal runtime" 56 + { 57 + return false; 58 + } 59 + if cmt.comment.is_empty() { 60 + return false; 61 + } 62 + }, 63 + FunctionMetadata::ByteComment(cmt) => { 64 + if cmt.comment == "Trap to Debugger" 65 + || (cmt.comment.starts_with("jumptable ") && cmt.comment.contains(" case")) // repeatable=true 66 + || cmt.comment == "switch jump" 67 + || (cmt.comment.starts_with("switch ") && cmt.comment.ends_with(" cases ")) 68 + || cmt.comment == "jump table for switch statement" 69 + || cmt.comment == "indirect table for switch statement" 70 + || cmt.comment == "Microsoft VisualC v7/14 64bit runtime" 71 + || cmt.comment == "Microsoft VisualC v7/14 64bit runtime\nMicrosoft VisualC v14 64bit runtime" 72 + || cmt.comment == "Microsoft VisualC v14 64bit runtime" { 73 + return false; 74 + } 75 + if cmt.comment.is_empty() { 76 + return false; 77 + } 78 + }, 79 + } 80 + true 81 + } 82 + } 83 + 84 + fn deserialize_seq<'de, T: Deserialize<'de>>( 85 + mut data: &'de [u8], 86 + ) -> Result<Vec<(u32, T)>, crate::rpc::Error> { 87 + let mut res = vec![]; 88 + let mut reset = true; 89 + let (mut offset, used): (u32, usize) = from_slice(data)?; 90 + data = &data[used..]; 91 + if data.is_empty() { 92 + return Err(crate::rpc::Error::UnexpectedEof); 93 + } 94 + 95 + loop { 96 + let (offset_diff, used): (u32, usize) = from_slice(data)?; 97 + data = &data[used..]; 98 + if data.is_empty() { 99 + return Err(crate::rpc::Error::UnexpectedEof); 100 + } 101 + 102 + if (offset_diff > 0) || reset { 103 + offset += offset_diff; 104 + let (e, used): (T, usize) = from_slice(data)?; 105 + data = &data[used..]; 106 + 107 + res.push((offset, e)); 108 + 109 + reset = false; 110 + } else { 111 + let (offset_diff, used): (u32, usize) = from_slice(data)?; 112 + data = &data[used..]; 113 + 114 + offset = offset_diff; 115 + reset = true; 116 + } 117 + 118 + if data.is_empty() { 119 + break; 120 + } 121 + } 122 + 123 + Ok(res) 124 + } 125 + 126 + pub fn parse_metadata(mut data: &[u8]) -> Result<Vec<FunctionMetadata<'_>>, crate::rpc::Error> { 127 + let mut res = vec![]; 128 + let mut bad_codes = HashSet::new(); 129 + 130 + while !data.is_empty() { 131 + let (chunk, used): (MetadataChunk, _) = from_slice(data)?; 132 + data = &data[used..]; 133 + 134 + let data = chunk.data; 135 + 136 + if data.is_empty() { 137 + continue; 138 + } 139 + 140 + match chunk.code { 141 + 1 => {}, // TODO: parse typeinfo 142 + 2 => {}, // nop 143 + 3 | 4 => { 144 + // function comments 145 + let is_repeatable = chunk.code == 4; 146 + let cmt = std::str::from_utf8(data)?; 147 + res.push(FunctionMetadata::FunctionComment(FunctionComment { 148 + is_repeatable, 149 + comment: cmt, 150 + })); 151 + }, 152 + 5 | 6 => { 153 + // comments 154 + let is_repeatable = chunk.code == 6; 155 + let byte_comments: Vec<(_, &[u8])> = match deserialize_seq(data) { 156 + Ok(v) => v, 157 + Err(err) => { 158 + log::error!("err: {}\n{}", err, super::make_pretty_hex(data)); 159 + return Err(err); 160 + }, 161 + }; 162 + 163 + for comment in byte_comments { 164 + let cmt = std::str::from_utf8(comment.1)?; 165 + res.push(FunctionMetadata::ByteComment(ByteComment { 166 + is_repeatable, 167 + offset: comment.0, 168 + comment: cmt, 169 + })); 170 + } 171 + }, 172 + 7 => { 173 + // extra comments 174 + let byte_comments: Vec<(_, (&[u8], &[u8]))> = match deserialize_seq(data) { 175 + Ok(v) => v, 176 + Err(err) => { 177 + log::error!("err: {}\n{}", err, super::make_pretty_hex(data)); 178 + return Err(err); 179 + }, 180 + }; 181 + 182 + for comment in byte_comments { 183 + res.push(FunctionMetadata::ExtraComment(ExtraComment { 184 + offset: comment.0, 185 + anterior: std::str::from_utf8(comment.1 .0)?, 186 + posterior: std::str::from_utf8(comment.1 .1)?, 187 + })); 188 + } 189 + }, 190 + 9 | 10 => { /* TODO! */ }, 191 + _ => { 192 + bad_codes.insert(chunk.code); 193 + }, 194 + } 195 + } 196 + 197 + Ok(res) 198 + } 199 + 200 + pub fn get_score(md: &crate::rpc::PushMetadataFunc) -> u32 { 201 + let mut score = 0; 202 + 203 + let md = match parse_metadata(md.func_data) { 204 + Ok(v) => v, 205 + Err(e) => { 206 + log::warn!("failed to parse metadata: {}", e); 207 + return 0; 208 + }, 209 + }; 210 + 211 + for md in md { 212 + if md.is_useful() { 213 + score += 10; 214 + } 215 + } 216 + 217 + score 218 + }
+20 -4
common/src/metrics.rs
··· 1 1 use std::sync::atomic::AtomicI64; 2 2 3 - use prometheus_client::{registry::Registry, metrics::{gauge::Gauge, family::Family, counter::Counter}, encoding::EncodeLabelSet}; 3 + use prometheus_client::{ 4 + encoding::EncodeLabelSet, 5 + metrics::{counter::Counter, family::Family, gauge::Gauge}, 6 + registry::Registry, 7 + }; 4 8 5 9 pub struct Metrics { 6 10 pub registry: Registry, ··· 34 38 let mut registry = Registry::default(); 35 39 36 40 let active_connections = Gauge::default(); 37 - registry.register("lumen_active_connections", "Active Lumina connections", active_connections.clone()); 41 + registry.register( 42 + "lumen_active_connections", 43 + "Active Lumina connections", 44 + active_connections.clone(), 45 + ); 38 46 39 47 let lumina_version = Family::<LuminaVersion, Gauge>::default(); 40 - registry.register("lumen_protocol_version", "Version of Lumina protocol being used", lumina_version.clone()); 48 + registry.register( 49 + "lumen_protocol_version", 50 + "Version of Lumina protocol being used", 51 + lumina_version.clone(), 52 + ); 41 53 42 54 let new_funcs = Counter::default(); 43 - registry.register("lumen_new_funcs", "Pushes previously unknown functions", new_funcs.clone()); 55 + registry.register( 56 + "lumen_new_funcs", 57 + "Pushes previously unknown functions", 58 + new_funcs.clone(), 59 + ); 44 60 45 61 let pushes = Counter::default(); 46 62 registry.register("lumen_pushes_total", "Total pushes functions", pushes.clone());
+163 -159
common/src/rpc/de.rs
··· 1 - use serde::Deserialize; 2 - use serde::de::{self, DeserializeSeed, SeqAccess, Visitor}; 3 - use super::Error; 4 - 5 - struct Deserializer<'de> { 6 - input: &'de [u8], 7 - } 8 - 9 - impl<'de> Deserializer<'de> { 10 - fn from_bytes(b: &'de [u8]) -> Self { 11 - Self { 12 - input: b, 13 - } 14 - } 15 - 16 - fn unpack_dd(&mut self) -> Result<u32, Error> { 17 - let (v, len) = super::packing::unpack_dd(self.input); 18 - if len == 0 { 19 - Err(Error::UnexpectedEof) 20 - } else { 21 - self.input = &self.input[len..]; 22 - Ok(v) 23 - } 24 - } 25 - 26 - fn unpack_dq(&mut self) -> Result<u64, Error> { 27 - let a = self.unpack_dd()? as u64; 28 - let b = self.unpack_dd()? as u64; 29 - Ok((a << 32) | b) 30 - } 31 - 32 - fn unpack_var_bytes(&mut self) -> Result<&'de [u8], Error> { 33 - let bytes = self.unpack_dd()? as usize; 34 - if bytes > self.input.len() { 35 - return Err(Error::UnexpectedEof); 36 - } 37 - 38 - let payload = &self.input[..bytes]; 39 - self.input = &self.input[bytes..]; 40 - assert_eq!(payload.len(), bytes); 41 - 42 - Ok(payload) 43 - } 44 - 45 - fn unpack_cstr(&mut self) -> Result<&'de str, Error> { 46 - let len = self.input.iter().enumerate().find_map(|(idx, &v)| if v == 0 { Some(idx) } else { None }); 47 - let len = match len { 48 - Some(v) => v, 49 - None => return Err(Error::UnexpectedEof), 50 - }; 51 - let res = match std::str::from_utf8(&self.input[..len]) { 52 - Ok(v) => v, 53 - Err(err) => { 54 - return Err(err.into()); 55 - } 56 - }; 57 - self.input = &self.input[len + 1..]; 58 - Ok(res) 59 - } 60 - 61 - fn take_byte(&mut self) -> Result<u8, Error> { 62 - if self.input.is_empty() { 63 - return Err(Error::UnexpectedEof); 64 - } 65 - 66 - let v = self.input[0]; 67 - self.input = &self.input[1..]; 68 - Ok(v) 69 - } 70 - } 71 - 72 - /// Returns: a tuple containing the deserialized struct and the bytes used 73 - pub fn from_slice<'a, T: Deserialize<'a>>(b: &'a [u8]) -> Result<(T, usize), Error> { 74 - let mut de = Deserializer::from_bytes(b); 75 - let v = T::deserialize(&mut de)?; 76 - Ok((v, b.len() - de.input.len())) 77 - } 78 - 79 - impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { 80 - type Error = Error; 81 - 82 - fn deserialize_any<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> { 83 - unimplemented!() 84 - } 85 - 86 - fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 87 - visitor.visit_u8(self.take_byte()?) 88 - } 89 - 90 - fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 91 - visitor.visit_u32(self.unpack_dd()?) 92 - } 93 - 94 - fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 95 - visitor.visit_u64(self.unpack_dq()?) 96 - } 97 - 98 - fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 99 - let len = self.unpack_dd()?; 100 - 101 - visitor.visit_seq(Access { 102 - len: len as usize, 103 - de: &mut *self, 104 - }) 105 - } 106 - 107 - fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 108 - visitor.visit_borrowed_str(self.unpack_cstr()?) 109 - } 110 - 111 - fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 112 - let v = self.unpack_var_bytes()?; 113 - visitor.visit_borrowed_bytes(v) 114 - } 115 - 116 - fn deserialize_tuple<V: Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> { 117 - visitor.visit_seq(Access { 118 - len, 119 - de: &mut *self, 120 - }) 121 - } 122 - 123 - fn deserialize_tuple_struct<V: Visitor<'de>>(self, _name: &'static str, len: usize, visitor: V) -> Result<V::Value, Self::Error> { 124 - self.deserialize_tuple(len, visitor) 125 - } 126 - 127 - fn deserialize_struct<V: Visitor<'de>>(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error> { 128 - self.deserialize_tuple_struct(name, fields.len(), visitor) 129 - } 130 - 131 - serde::forward_to_deserialize_any! { 132 - i8 i16 i32 i64 char u16 bool 133 - f32 f64 string byte_buf option unit unit_struct newtype_struct map enum identifier ignored_any 134 - } 135 - } 136 - 137 - struct Access<'a, 'de> { 138 - de: &'a mut Deserializer<'de>, 139 - len: usize, 140 - } 141 - 142 - impl<'de, 'a> SeqAccess<'a> for Access<'de, 'a> { 143 - type Error = Error; 144 - 145 - fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> { 146 - if self.len > 0 { 147 - self.len -= 1; 148 - 149 - let v = serde::de::DeserializeSeed::deserialize(seed, &mut *self.de)?; 150 - Ok(Some(v)) 151 - } else { 152 - Ok(None) 153 - } 154 - } 155 - 156 - fn size_hint(&self) -> Option<usize> { 157 - Some(self.len) 158 - } 159 - } 1 + use super::Error; 2 + use serde::de::{self, DeserializeSeed, SeqAccess, Visitor}; 3 + use serde::Deserialize; 4 + 5 + struct Deserializer<'de> { 6 + input: &'de [u8], 7 + } 8 + 9 + impl<'de> Deserializer<'de> { 10 + fn from_bytes(b: &'de [u8]) -> Self { 11 + Self { input: b } 12 + } 13 + 14 + fn unpack_dd(&mut self) -> Result<u32, Error> { 15 + let (v, len) = super::packing::unpack_dd(self.input); 16 + if len == 0 { 17 + Err(Error::UnexpectedEof) 18 + } else { 19 + self.input = &self.input[len..]; 20 + Ok(v) 21 + } 22 + } 23 + 24 + fn unpack_dq(&mut self) -> Result<u64, Error> { 25 + let a = self.unpack_dd()? as u64; 26 + let b = self.unpack_dd()? as u64; 27 + Ok((a << 32) | b) 28 + } 29 + 30 + fn unpack_var_bytes(&mut self) -> Result<&'de [u8], Error> { 31 + let bytes = self.unpack_dd()? as usize; 32 + if bytes > self.input.len() { 33 + return Err(Error::UnexpectedEof); 34 + } 35 + 36 + let payload = &self.input[..bytes]; 37 + self.input = &self.input[bytes..]; 38 + assert_eq!(payload.len(), bytes); 39 + 40 + Ok(payload) 41 + } 42 + 43 + fn unpack_cstr(&mut self) -> Result<&'de str, Error> { 44 + let len = self 45 + .input 46 + .iter() 47 + .enumerate() 48 + .find_map(|(idx, &v)| if v == 0 { Some(idx) } else { None }); 49 + let len = match len { 50 + Some(v) => v, 51 + None => return Err(Error::UnexpectedEof), 52 + }; 53 + let res = match std::str::from_utf8(&self.input[..len]) { 54 + Ok(v) => v, 55 + Err(err) => { 56 + return Err(err.into()); 57 + }, 58 + }; 59 + self.input = &self.input[len + 1..]; 60 + Ok(res) 61 + } 62 + 63 + fn take_byte(&mut self) -> Result<u8, Error> { 64 + if self.input.is_empty() { 65 + return Err(Error::UnexpectedEof); 66 + } 67 + 68 + let v = self.input[0]; 69 + self.input = &self.input[1..]; 70 + Ok(v) 71 + } 72 + } 73 + 74 + /// Returns: a tuple containing the deserialized struct and the bytes used 75 + pub fn from_slice<'a, T: Deserialize<'a>>(b: &'a [u8]) -> Result<(T, usize), Error> { 76 + let mut de = Deserializer::from_bytes(b); 77 + let v = T::deserialize(&mut de)?; 78 + Ok((v, b.len() - de.input.len())) 79 + } 80 + 81 + impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { 82 + type Error = Error; 83 + 84 + fn deserialize_any<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> { 85 + unimplemented!() 86 + } 87 + 88 + fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 89 + visitor.visit_u8(self.take_byte()?) 90 + } 91 + 92 + fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 93 + visitor.visit_u32(self.unpack_dd()?) 94 + } 95 + 96 + fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 97 + visitor.visit_u64(self.unpack_dq()?) 98 + } 99 + 100 + fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 101 + let len = self.unpack_dd()?; 102 + 103 + visitor.visit_seq(Access { len: len as usize, de: &mut *self }) 104 + } 105 + 106 + fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 107 + visitor.visit_borrowed_str(self.unpack_cstr()?) 108 + } 109 + 110 + fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { 111 + let v = self.unpack_var_bytes()?; 112 + visitor.visit_borrowed_bytes(v) 113 + } 114 + 115 + fn deserialize_tuple<V: Visitor<'de>>( 116 + self, len: usize, visitor: V, 117 + ) -> Result<V::Value, Self::Error> { 118 + visitor.visit_seq(Access { len, de: &mut *self }) 119 + } 120 + 121 + fn deserialize_tuple_struct<V: Visitor<'de>>( 122 + self, _name: &'static str, len: usize, visitor: V, 123 + ) -> Result<V::Value, Self::Error> { 124 + self.deserialize_tuple(len, visitor) 125 + } 126 + 127 + fn deserialize_struct<V: Visitor<'de>>( 128 + self, name: &'static str, fields: &'static [&'static str], visitor: V, 129 + ) -> Result<V::Value, Self::Error> { 130 + self.deserialize_tuple_struct(name, fields.len(), visitor) 131 + } 132 + 133 + serde::forward_to_deserialize_any! { 134 + i8 i16 i32 i64 char u16 bool 135 + f32 f64 string byte_buf option unit unit_struct newtype_struct map enum identifier ignored_any 136 + } 137 + } 138 + 139 + struct Access<'a, 'de> { 140 + de: &'a mut Deserializer<'de>, 141 + len: usize, 142 + } 143 + 144 + impl<'de, 'a> SeqAccess<'a> for Access<'de, 'a> { 145 + type Error = Error; 146 + 147 + fn next_element_seed<T: DeserializeSeed<'a>>( 148 + &mut self, seed: T, 149 + ) -> Result<Option<T::Value>, Self::Error> { 150 + if self.len > 0 { 151 + self.len -= 1; 152 + 153 + let v = serde::de::DeserializeSeed::deserialize(seed, &mut *self.de)?; 154 + Ok(Some(v)) 155 + } else { 156 + Ok(None) 157 + } 158 + } 159 + 160 + fn size_hint(&self) -> Option<usize> { 161 + Some(self.len) 162 + } 163 + }
+156 -118
common/src/rpc/messages.rs
··· 1 - use serde::{Serialize, Deserialize}; 2 - use std::borrow::Cow; 3 - 4 - #[derive(Deserialize, Serialize)] 5 - pub struct RpcFail<'a> { 6 - pub code: u32, 7 - pub message: &'a str, 8 - } 9 - 10 - #[derive(Serialize, Deserialize)] 11 - pub struct RpcNotify<'a> { 12 - pub code: u32, 13 - pub msg: &'a str, 14 - } 15 - 16 - #[derive(Serialize, Deserialize, Debug)] 17 - pub struct Creds<'a> { 18 - pub username: &'a str, 19 - pub password: &'a str, 20 - } 21 - 22 - #[derive(Serialize, Deserialize)] 23 - pub struct RpcHello<'a> { 24 - pub protocol_version: u32, 25 - pub license_data: &'a [u8], 26 - pub lic_number: [u8; 6], 27 - pub unk2: u32, 28 - } 29 - 30 - #[derive(Deserialize, Serialize, Clone)] 31 - pub struct PullMetadataFunc<'a> { 32 - pub unk0: u32, 33 - pub mb_hash: &'a [u8], 34 - } 35 - 36 - #[derive(Deserialize, Serialize)] 37 - pub struct PullMetadata<'a> { 38 - pub unk0: u32, 39 - pub unk1: Cow<'a, [u32]>, 40 - 41 - #[serde(borrow)] 42 - pub funcs: Cow<'a, [PullMetadataFunc<'a>]>, 43 - } 44 - 45 - #[derive(Deserialize, Serialize, Clone)] 46 - pub struct PullMetadataResultFunc<'a> { 47 - pub name: Cow<'a, str>, 48 - pub len: u32, 49 - pub mb_data: Cow<'a, [u8]>, 50 - pub popularity: u32, 51 - } 52 - 53 - #[derive(Deserialize, Serialize)] 54 - pub struct PullMetadataResult<'a> { 55 - pub unk0: Cow<'a, [u32]>, 56 - #[serde(borrow)] 57 - pub funcs: Cow<'a, [PullMetadataResultFunc<'a>]>, 58 - } 59 - 60 - #[derive(Clone, Deserialize, Serialize)] 61 - pub struct PushMetadataFunc<'a> { 62 - pub name: &'a str, 63 - pub func_len: u32, 64 - pub func_data: &'a [u8], 65 - 66 - // PullMetadata's fields (tuple 'unk2') are similar to these two 67 - pub unk2: u32, 68 - pub hash: &'a [u8], 69 - } 70 - 71 - #[derive(Deserialize, Serialize)] 72 - pub struct PushMetadata<'a> { 73 - pub unk0: u32, 74 - pub idb_path: &'a str, 75 - pub file_path: &'a str, 76 - pub md5: [u8; 16], 77 - pub hostname: &'a str, 78 - pub funcs: Cow<'a, [PushMetadataFunc<'a>]>, 79 - pub unk1: Cow<'a, [u64]>, 80 - } 81 - 82 - #[derive(Deserialize, Serialize)] 83 - pub struct PushMetadataResult<'a> { 84 - // array of 0=exists, 1=NEW 85 - pub status: Cow<'a, [u32]>, 86 - } 87 - 88 - #[derive(Debug, Deserialize, Serialize)] 89 - pub struct DelHistory<'a> { 90 - pub unk0: u32, // =0x08 91 - pub unk1: Cow<'a, [Cow<'a, str>]>, 92 - pub unk2: Cow<'a, [[u64; 2]]>, 93 - pub unk3: Cow<'a, [[u64; 2]]>, 94 - pub unk4: Cow<'a, [Cow<'a, str>]>, 95 - pub unk5: Cow<'a, [Cow<'a, str>]>, 96 - pub unk6: Cow<'a, [Cow<'a, str>]>, 97 - pub unk7: Cow<'a, [Cow<'a, str>]>, 98 - pub unk8: Cow<'a, [Cow<'a, [u8; 16]>]>, 99 - pub funcs: Cow<'a, [Cow<'a, [u8; 16]>]>, 100 - pub unk10: Cow<'a, [[u64; 2]]>, 101 - pub unk11: u64, 102 - } 103 - 104 - #[derive(Deserialize, Serialize)] 105 - pub struct DelHistoryResult { 106 - pub deleted_mds: u32, 107 - } 108 - 109 - #[derive(Debug, Deserialize, Serialize)] 110 - pub struct HelloResult<'a> { 111 - pub unk0: Cow<'a, str>, 112 - pub unk1: Cow<'a, str>, 113 - pub unk2: Cow<'a, str>, 114 - pub unk3: Cow<'a, str>, 115 - pub unk4: u32, 116 - pub unk5: u64, 117 - pub unk6: u32, 118 - } 1 + use serde::{Deserialize, Serialize}; 2 + use std::borrow::Cow; 3 + 4 + #[derive(Deserialize, Serialize)] 5 + pub struct RpcFail<'a> { 6 + pub code: u32, 7 + pub message: &'a str, 8 + } 9 + 10 + #[derive(Serialize, Deserialize)] 11 + pub struct RpcNotify<'a> { 12 + pub code: u32, 13 + pub msg: &'a str, 14 + } 15 + 16 + #[derive(Serialize, Deserialize, Debug)] 17 + pub struct Creds<'a> { 18 + pub username: &'a str, 19 + pub password: &'a str, 20 + } 21 + 22 + #[derive(Serialize, Deserialize)] 23 + pub struct RpcHello<'a> { 24 + pub protocol_version: u32, 25 + pub license_data: &'a [u8], 26 + pub lic_number: [u8; 6], 27 + pub unk2: u32, 28 + } 29 + 30 + #[derive(Debug, Deserialize, Serialize, Clone)] 31 + pub struct PullMetadataFunc<'a> { 32 + pub unk0: u32, 33 + pub mb_hash: &'a [u8], 34 + } 35 + 36 + #[derive(Deserialize, Serialize)] 37 + pub struct PullMetadata<'a> { 38 + pub unk0: u32, 39 + pub unk1: Cow<'a, [u32]>, 40 + 41 + #[serde(borrow)] 42 + pub funcs: Cow<'a, [PullMetadataFunc<'a>]>, 43 + } 44 + 45 + #[derive(Deserialize, Serialize, Clone)] 46 + pub struct PullMetadataResultFunc<'a> { 47 + pub name: Cow<'a, str>, 48 + pub len: u32, 49 + pub mb_data: Cow<'a, [u8]>, 50 + pub popularity: u32, 51 + } 52 + 53 + #[derive(Deserialize, Serialize)] 54 + pub struct PullMetadataResult<'a> { 55 + pub unk0: Cow<'a, [u32]>, 56 + #[serde(borrow)] 57 + pub funcs: Cow<'a, [PullMetadataResultFunc<'a>]>, 58 + } 59 + 60 + #[derive(Clone, Deserialize, Serialize)] 61 + pub struct PushMetadataFunc<'a> { 62 + pub name: &'a str, 63 + pub func_len: u32, 64 + pub func_data: &'a [u8], 65 + 66 + // PullMetadata's fields (tuple 'unk2') are similar to these two 67 + pub unk2: u32, 68 + pub hash: &'a [u8], 69 + } 70 + 71 + #[derive(Deserialize, Serialize)] 72 + pub struct PushMetadata<'a> { 73 + pub unk0: u32, 74 + pub idb_path: &'a str, 75 + pub file_path: &'a str, 76 + pub md5: [u8; 16], 77 + pub hostname: &'a str, 78 + pub funcs: Cow<'a, [PushMetadataFunc<'a>]>, 79 + pub unk1: Cow<'a, [u64]>, 80 + } 81 + 82 + #[derive(Deserialize, Serialize)] 83 + pub struct PushMetadataResult<'a> { 84 + // array of 0=exists, 1=NEW 85 + pub status: Cow<'a, [u32]>, 86 + } 87 + 88 + #[derive(Debug, Deserialize, Serialize)] 89 + pub struct DelHistory<'a> { 90 + pub unk0: u32, // =0x08 91 + pub unk1: Cow<'a, [Cow<'a, str>]>, 92 + pub unk2: Cow<'a, [[u64; 2]]>, 93 + pub unk3: Cow<'a, [[u64; 2]]>, 94 + pub unk4: Cow<'a, [Cow<'a, str>]>, 95 + pub unk5: Cow<'a, [Cow<'a, str>]>, 96 + pub unk6: Cow<'a, [Cow<'a, str>]>, 97 + pub unk7: Cow<'a, [Cow<'a, str>]>, 98 + pub unk8: Cow<'a, [Cow<'a, [u8; 16]>]>, 99 + pub funcs: Cow<'a, [Cow<'a, [u8; 16]>]>, 100 + pub unk10: Cow<'a, [[u64; 2]]>, 101 + pub unk11: u64, 102 + } 103 + 104 + #[derive(Deserialize, Serialize)] 105 + pub struct DelHistoryResult { 106 + pub deleted_mds: u32, 107 + } 108 + 109 + #[derive(Debug, Deserialize, Serialize, Default)] 110 + pub struct LicenseInfo<'a> { 111 + pub id: Cow<'a, str>, 112 + pub name: Cow<'a, str>, 113 + pub email: Cow<'a, str>, 114 + } 115 + 116 + #[derive(Debug, Deserialize, Serialize, Default)] 117 + pub struct HelloResult<'a> { 118 + pub license_info: LicenseInfo<'a>, 119 + pub username: Cow<'a, str>, 120 + pub karma: u32, 121 + pub last_active: u64, 122 + pub features: u32, 123 + } 124 + 125 + #[derive(Debug, Deserialize, Serialize)] 126 + pub struct GetFuncHistories<'a> { 127 + #[serde(borrow)] 128 + pub funcs: Cow<'a, [PullMetadataFunc<'a>]>, 129 + pub unk0: u32, 130 + } 131 + 132 + #[derive(Debug, Deserialize, Serialize, Clone)] 133 + pub struct FunctionHistory<'a> { 134 + pub unk0: u64, 135 + pub unk1: u64, 136 + pub name: Cow<'a, str>, 137 + pub metadata: Cow<'a, [u8]>, 138 + pub timestamp: u64, 139 + pub author_idx: u32, 140 + pub idb_path_idx: u32, 141 + } 142 + 143 + #[derive(Debug, Deserialize, Serialize, Clone)] 144 + pub struct FunctionHistories<'a> { 145 + #[serde(borrow)] 146 + pub log: Cow<'a, [FunctionHistory<'a>]>, 147 + } 148 + 149 + #[derive(Debug, Deserialize, Serialize)] 150 + pub struct GetFuncHistoriesResult<'a> { 151 + pub status: Cow<'a, [u32]>, 152 + #[serde(borrow)] 153 + pub funcs: Cow<'a, [FunctionHistories<'a>]>, 154 + pub users: Cow<'a, [Cow<'a, str>]>, 155 + pub dbs: Cow<'a, [Cow<'a, str>]>, 156 + }
+257 -234
common/src/rpc/mod.rs
··· 1 - use tokio::io::{AsyncWriteExt, AsyncWrite, AsyncRead, AsyncReadExt}; 2 - use log::*; 3 - mod ser; 4 - pub(crate) mod de; 5 - mod messages; 6 - mod packing; 7 - use serde::Serializer; 8 - 9 - pub use messages::*; 10 - 11 - #[derive(Debug)] 12 - pub enum Error { 13 - UnexpectedEof, 14 - Utf8Error(std::str::Utf8Error), 15 - IOError(std::io::Error), 16 - Serde(String), 17 - InvalidData, 18 - OutOfMemory, 19 - Todo, 20 - Timeout, 21 - Eof, 22 - } 23 - 24 - impl std::fmt::Display for Error { 25 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 26 - std::fmt::Debug::fmt(self, f) 27 - } 28 - } 29 - 30 - impl std::error::Error for Error {} 31 - impl serde::ser::Error for Error { 32 - fn custom<T: std::fmt::Display>(msg: T) -> Self { 33 - Error::Serde(msg.to_string()) 34 - } 35 - } 36 - impl serde::de::Error for Error { 37 - fn custom<T: std::fmt::Display>(msg: T) -> Self { 38 - Error::Serde(msg.to_string()) 39 - } 40 - } 41 - impl From<std::io::Error> for Error { 42 - fn from(v: std::io::Error) -> Self { 43 - Error::IOError(v) 44 - } 45 - } 46 - impl From<std::str::Utf8Error> for Error { 47 - fn from(v: std::str::Utf8Error) -> Self { 48 - Error::Utf8Error(v) 49 - } 50 - } 51 - impl From<std::collections::TryReserveError> for Error { 52 - fn from(v: std::collections::TryReserveError) -> Self { 53 - error!("failed to allocate {} bytes", v); 54 - Error::OutOfMemory 55 - } 56 - } 57 - 58 - fn get_code_maxlen(code: u8) -> usize { 59 - match code { 60 - 0x0e => 50 * 1024 * 1024, // PullMD: 50 MiB 61 - 0x10 => 200 * 1024 * 1024, // PushMD: 200 MiB 62 - _ => 1024 * 50, // otherwise 50K 63 - } 64 - } 65 - 66 - pub async fn read_packet<R: AsyncRead + Unpin>(mut reader: R) -> Result<Vec<u8>, Error> { 67 - let mut head = [0u8; 5]; 68 - match reader.read_exact(&mut head).await { 69 - Ok(_) => {}, 70 - Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Err(Error::Eof), // client decided to disconnect... 71 - Err(e) => return Err(e.into()), 72 - } 73 - let code = head[4]; 74 - let mut buf_len = [0u8; 4]; 75 - buf_len.copy_from_slice(&head[..4]); 76 - 77 - let buf_len = u32::from_be_bytes(buf_len) as usize; 78 - if buf_len < 4 { 79 - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "payload size is too small").into()); 80 - } 81 - 82 - let max_len = get_code_maxlen(code); 83 - 84 - if buf_len > max_len { 85 - info!("maxium size exceeded: code={}: max={}; req={}", code, max_len, buf_len); 86 - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "request length exceeded maximum limit").into()); 87 - } 88 - 89 - // the additional byte is for the RPC code 90 - trace!("expecting {} bytes...", buf_len); 91 - let buf_len = buf_len + 1; 92 - 93 - let mut data = Vec::new(); 94 - data.try_reserve_exact(buf_len)?; 95 - data.resize(buf_len, 0); 96 - data[0] = code; 97 - reader.read_exact(&mut data[1..]).await?; 98 - 99 - Ok(data) 100 - } 101 - 102 - async fn write_packet<W: AsyncWrite + Unpin>(mut w: W, data: &[u8]) -> Result<(), std::io::Error> { 103 - let buf_len: u32 = (data.len() - 1) as u32; 104 - let buf_len = buf_len.to_be_bytes(); 105 - w.write_all(&buf_len).await?; 106 - w.write_all(data).await?; 107 - Ok(()) 108 - } 109 - 110 - pub enum RpcMessage<'a> { 111 - Ok(()), 112 - Fail(RpcFail<'a>), 113 - Notify(RpcNotify<'a>), 114 - Hello(RpcHello<'a>, Option<Creds<'a>>), 115 - PullMetadata(PullMetadata<'a>), 116 - PullMetadataResult(PullMetadataResult<'a>), 117 - PushMetadata(PushMetadata<'a>), 118 - PushMetadataResult(PushMetadataResult<'a>), 119 - DelHistory(DelHistory<'a>), 120 - DelHistoryResult(DelHistoryResult), 121 - HelloResult(HelloResult<'a>), 122 - } 123 - 124 - impl<'a> serde::Serialize for RpcMessage<'a> { 125 - fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 126 - use serde::ser::SerializeTuple; 127 - 128 - let code = self.get_code(); 129 - let mut tuple = serializer.serialize_tuple(2)?; 130 - 131 - // u8 is pushed without further encoding... 132 - tuple.serialize_element(&code)?; 133 - 134 - match self { 135 - RpcMessage::Ok(msg) => tuple.serialize_element(msg)?, 136 - RpcMessage::Fail(msg) => tuple.serialize_element(msg)?, 137 - RpcMessage::Notify(msg) => tuple.serialize_element(msg)?, 138 - RpcMessage::Hello(msg, _) => tuple.serialize_element(msg)?, 139 - RpcMessage::PullMetadata(msg) => tuple.serialize_element(msg)?, 140 - RpcMessage::PullMetadataResult(msg) => tuple.serialize_element(msg)?, 141 - RpcMessage::PushMetadata(msg) => tuple.serialize_element(msg)?, 142 - RpcMessage::PushMetadataResult(msg) => tuple.serialize_element(msg)?, 143 - RpcMessage::DelHistory(msg) => tuple.serialize_element(msg)?, 144 - RpcMessage::DelHistoryResult(msg) => tuple.serialize_element(msg)?, 145 - RpcMessage::HelloResult(msg) => tuple.serialize_element(msg)?, 146 - } 147 - 148 - tuple.end() 149 - } 150 - } 151 - 152 - impl<'a> RpcMessage<'a> { 153 - fn deserialize_check<T: serde::Deserialize<'a>>(payload: &'a [u8]) -> Result<T, Error> { 154 - let v = de::from_slice(payload)?; 155 - if v.1 != payload.len() { 156 - let bytes_remaining = crate::make_pretty_hex(&payload[v.1..]); 157 - trace!("{} remaining bytes after deserializing {}\n{bytes_remaining}", payload.len() - v.1, std::any::type_name::<T>()); 158 - } 159 - Ok(v.0) 160 - } 161 - 162 - pub fn deserialize(payload: &'a [u8]) -> Result<RpcMessage<'a>, Error> { 163 - let msg_type = payload[0]; 164 - let payload = &payload[1..]; 165 - 166 - let res = match msg_type { 167 - 0x0a => { 168 - if !payload.is_empty() { 169 - trace!("Ok message with additional data: {} bytes: {payload:02x?}", payload.len()); 170 - } 171 - RpcMessage::Ok(()) 172 - }, 173 - 0x0b => RpcMessage::Fail(Self::deserialize_check(payload)?), 174 - 0x0c => RpcMessage::Notify(Self::deserialize_check(payload)?), 175 - 0x0d => { 176 - let (hello, consumed) = de::from_slice::<messages::RpcHello>(payload)?; 177 - let creds = if payload.len() > consumed && hello.protocol_version > 2 { 178 - let payload = &payload[consumed..]; 179 - let (creds, consumed) = de::from_slice::<Creds>(payload)?; 180 - if payload.len() != consumed { 181 - trace!("bytes remaining after HelloV2: {payload:02x?}"); 182 - } 183 - Some(creds) 184 - } else { 185 - if hello.protocol_version > 2 || payload.len() != consumed { 186 - trace!("Unexpected Hello msg: {payload:02x?}"); 187 - } 188 - None 189 - }; 190 - RpcMessage::Hello(hello, creds) 191 - }, 192 - 0x0e => RpcMessage::PullMetadata(Self::deserialize_check(payload)?), 193 - 0x0f => RpcMessage::PullMetadataResult(Self::deserialize_check(payload)?), 194 - 0x10 => RpcMessage::PushMetadata(Self::deserialize_check(payload)?), 195 - 0x11 => RpcMessage::PushMetadataResult(Self::deserialize_check(payload)?), 196 - 0x18 => RpcMessage::DelHistory(Self::deserialize_check(payload)?), 197 - 0x19 => RpcMessage::DelHistoryResult(Self::deserialize_check(payload)?), 198 - 0x31 => RpcMessage::HelloResult(Self::deserialize_check(payload)?), 199 - _ => { 200 - trace!("got invalid message type '{:02x}'", msg_type); 201 - return Err(Error::InvalidData); 202 - }, 203 - }; 204 - 205 - Ok(res) 206 - } 207 - 208 - pub async fn async_write<W: AsyncWrite + Unpin>(&self, w: W) -> Result<(), Error> { 209 - let mut output = Vec::with_capacity(32); 210 - ser::to_writer(self, &mut output)?; 211 - 212 - write_packet(w, &output).await?; 213 - 214 - Ok(()) 215 - } 216 - 217 - fn get_code(&self) -> u8 { 218 - use RpcMessage::*; 219 - 220 - match self { 221 - Ok(_) => 0x0a, 222 - Fail(_) => 0x0b, 223 - Notify(_) => 0x0c, 224 - Hello(..) => 0x0d, 225 - PullMetadata(_) => 0x0e, 226 - PullMetadataResult(_) => 0x0f, 227 - PushMetadata(_) => 0x10, 228 - PushMetadataResult(_) => 0x11, 229 - DelHistory(_) => 0x18, 230 - DelHistoryResult(_) => 0x19, 231 - HelloResult(_) => 0x31, 232 - } 233 - } 234 - } 1 + use log::*; 2 + use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; 3 + pub(crate) mod de; 4 + mod messages; 5 + mod packing; 6 + mod ser; 7 + use serde::Serializer; 8 + 9 + pub use messages::*; 10 + 11 + #[derive(Debug)] 12 + pub enum Error { 13 + UnexpectedEof, 14 + Utf8Error(std::str::Utf8Error), 15 + IOError(std::io::Error), 16 + Serde(String), 17 + InvalidData, 18 + OutOfMemory, 19 + Todo, 20 + Timeout, 21 + Eof, 22 + } 23 + 24 + impl std::fmt::Display for Error { 25 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 26 + std::fmt::Debug::fmt(self, f) 27 + } 28 + } 29 + 30 + impl std::error::Error for Error {} 31 + impl serde::ser::Error for Error { 32 + fn custom<T: std::fmt::Display>(msg: T) -> Self { 33 + Error::Serde(msg.to_string()) 34 + } 35 + } 36 + impl serde::de::Error for Error { 37 + fn custom<T: std::fmt::Display>(msg: T) -> Self { 38 + Error::Serde(msg.to_string()) 39 + } 40 + } 41 + impl From<std::io::Error> for Error { 42 + fn from(v: std::io::Error) -> Self { 43 + Error::IOError(v) 44 + } 45 + } 46 + impl From<std::str::Utf8Error> for Error { 47 + fn from(v: std::str::Utf8Error) -> Self { 48 + Error::Utf8Error(v) 49 + } 50 + } 51 + impl From<std::collections::TryReserveError> for Error { 52 + fn from(v: std::collections::TryReserveError) -> Self { 53 + error!("failed to allocate {} bytes", v); 54 + Error::OutOfMemory 55 + } 56 + } 57 + 58 + fn get_code_maxlen(code: u8) -> usize { 59 + match code { 60 + 0x0e => 50 * 1024 * 1024, // PullMD: 50 MiB 61 + 0x10 => 200 * 1024 * 1024, // PushMD: 200 MiB 62 + _ => 1024 * 50, // otherwise 50K 63 + } 64 + } 65 + 66 + pub async fn read_packet<R: AsyncRead + Unpin>(mut reader: R) -> Result<Vec<u8>, Error> { 67 + let mut head = [0u8; 5]; 68 + match reader.read_exact(&mut head).await { 69 + Ok(_) => {}, 70 + Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Err(Error::Eof), // client decided to disconnect... 71 + Err(e) => return Err(e.into()), 72 + } 73 + let code = head[4]; 74 + let mut buf_len = [0u8; 4]; 75 + buf_len.copy_from_slice(&head[..4]); 76 + 77 + let buf_len = u32::from_be_bytes(buf_len) as usize; 78 + if buf_len < 4 { 79 + return Err(std::io::Error::new( 80 + std::io::ErrorKind::InvalidData, 81 + "payload size is too small", 82 + ) 83 + .into()); 84 + } 85 + 86 + let max_len = get_code_maxlen(code); 87 + 88 + if buf_len > max_len { 89 + info!("maxium size exceeded: code={}: max={}; req={}", code, max_len, buf_len); 90 + return Err(std::io::Error::new( 91 + std::io::ErrorKind::InvalidData, 92 + "request length exceeded maximum limit", 93 + ) 94 + .into()); 95 + } 96 + 97 + // the additional byte is for the RPC code 98 + trace!("expecting {} bytes...", buf_len); 99 + let buf_len = buf_len + 1; 100 + 101 + let mut data = Vec::new(); 102 + data.try_reserve_exact(buf_len)?; 103 + data.resize(buf_len, 0); 104 + data[0] = code; 105 + reader.read_exact(&mut data[1..]).await?; 106 + 107 + Ok(data) 108 + } 109 + 110 + async fn write_packet<W: AsyncWrite + Unpin>(mut w: W, data: &[u8]) -> Result<(), std::io::Error> { 111 + let buf_len: u32 = (data.len() - 1) as u32; 112 + let buf_len = buf_len.to_be_bytes(); 113 + w.write_all(&buf_len).await?; 114 + w.write_all(data).await?; 115 + Ok(()) 116 + } 117 + 118 + pub enum RpcMessage<'a> { 119 + Ok(()), 120 + Fail(RpcFail<'a>), 121 + Notify(RpcNotify<'a>), 122 + Hello(RpcHello<'a>, Option<Creds<'a>>), 123 + PullMetadata(PullMetadata<'a>), 124 + PullMetadataResult(PullMetadataResult<'a>), 125 + PushMetadata(PushMetadata<'a>), 126 + PushMetadataResult(PushMetadataResult<'a>), 127 + DelHistory(DelHistory<'a>), 128 + DelHistoryResult(DelHistoryResult), 129 + GetFuncHistories(GetFuncHistories<'a>), 130 + GetFuncHistoriesResult(GetFuncHistoriesResult<'a>), 131 + HelloResult(HelloResult<'a>), 132 + } 133 + 134 + impl<'a> serde::Serialize for RpcMessage<'a> { 135 + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 136 + use serde::ser::SerializeTuple; 137 + 138 + let code = self.get_code(); 139 + let mut tuple = serializer.serialize_tuple(2)?; 140 + 141 + // u8 is pushed without further encoding... 142 + tuple.serialize_element(&code)?; 143 + 144 + match self { 145 + RpcMessage::Ok(msg) => tuple.serialize_element(msg)?, 146 + RpcMessage::Fail(msg) => tuple.serialize_element(msg)?, 147 + RpcMessage::Notify(msg) => tuple.serialize_element(msg)?, 148 + RpcMessage::Hello(msg, _) => tuple.serialize_element(msg)?, 149 + RpcMessage::PullMetadata(msg) => tuple.serialize_element(msg)?, 150 + RpcMessage::PullMetadataResult(msg) => tuple.serialize_element(msg)?, 151 + RpcMessage::PushMetadata(msg) => tuple.serialize_element(msg)?, 152 + RpcMessage::PushMetadataResult(msg) => tuple.serialize_element(msg)?, 153 + RpcMessage::DelHistory(msg) => tuple.serialize_element(msg)?, 154 + RpcMessage::DelHistoryResult(msg) => tuple.serialize_element(msg)?, 155 + RpcMessage::GetFuncHistories(msg) => tuple.serialize_element(msg)?, 156 + RpcMessage::GetFuncHistoriesResult(msg) => tuple.serialize_element(msg)?, 157 + RpcMessage::HelloResult(msg) => tuple.serialize_element(msg)?, 158 + } 159 + 160 + tuple.end() 161 + } 162 + } 163 + 164 + impl<'a> RpcMessage<'a> { 165 + fn deserialize_check<T: serde::Deserialize<'a>>(payload: &'a [u8]) -> Result<T, Error> { 166 + let v = de::from_slice(payload)?; 167 + if v.1 != payload.len() { 168 + let bytes_remaining = crate::make_pretty_hex(&payload[v.1..]); 169 + trace!( 170 + "{} remaining bytes after deserializing {}\n{bytes_remaining}", 171 + payload.len() - v.1, 172 + std::any::type_name::<T>() 173 + ); 174 + } 175 + Ok(v.0) 176 + } 177 + 178 + pub fn deserialize(payload: &'a [u8]) -> Result<RpcMessage<'a>, Error> { 179 + let msg_type = payload[0]; 180 + let payload = &payload[1..]; 181 + 182 + let res = match msg_type { 183 + 0x0a => { 184 + if !payload.is_empty() { 185 + trace!( 186 + "Ok message with additional data: {} bytes: {payload:02x?}", 187 + payload.len() 188 + ); 189 + } 190 + RpcMessage::Ok(()) 191 + }, 192 + 0x0b => RpcMessage::Fail(Self::deserialize_check(payload)?), 193 + 0x0c => RpcMessage::Notify(Self::deserialize_check(payload)?), 194 + 0x0d => { 195 + let (hello, consumed) = de::from_slice::<messages::RpcHello>(payload)?; 196 + let creds = if payload.len() > consumed && hello.protocol_version > 2 { 197 + let payload = &payload[consumed..]; 198 + let (creds, consumed) = de::from_slice::<Creds>(payload)?; 199 + if payload.len() != consumed { 200 + trace!("bytes remaining after HelloV2: {payload:02x?}"); 201 + } 202 + Some(creds) 203 + } else { 204 + if hello.protocol_version > 2 || payload.len() != consumed { 205 + trace!("Unexpected Hello msg: {payload:02x?}"); 206 + } 207 + None 208 + }; 209 + RpcMessage::Hello(hello, creds) 210 + }, 211 + 0x0e => RpcMessage::PullMetadata(Self::deserialize_check(payload)?), 212 + 0x0f => RpcMessage::PullMetadataResult(Self::deserialize_check(payload)?), 213 + 0x10 => RpcMessage::PushMetadata(Self::deserialize_check(payload)?), 214 + 0x11 => RpcMessage::PushMetadataResult(Self::deserialize_check(payload)?), 215 + 0x18 => RpcMessage::DelHistory(Self::deserialize_check(payload)?), 216 + 0x19 => RpcMessage::DelHistoryResult(Self::deserialize_check(payload)?), 217 + 0x2f => RpcMessage::GetFuncHistories(Self::deserialize_check(payload)?), 218 + 0x30 => RpcMessage::GetFuncHistoriesResult(Self::deserialize_check(payload)?), 219 + 0x31 => RpcMessage::HelloResult(Self::deserialize_check(payload)?), 220 + _ => { 221 + trace!("got invalid message type '{:02x}'", msg_type); 222 + return Err(Error::InvalidData); 223 + }, 224 + }; 225 + 226 + Ok(res) 227 + } 228 + 229 + pub async fn async_write<W: AsyncWrite + Unpin>(&self, w: W) -> Result<(), Error> { 230 + let mut output = Vec::with_capacity(32); 231 + ser::to_writer(self, &mut output)?; 232 + 233 + write_packet(w, &output).await?; 234 + 235 + Ok(()) 236 + } 237 + 238 + fn get_code(&self) -> u8 { 239 + use RpcMessage::*; 240 + 241 + match self { 242 + Ok(_) => 0x0a, 243 + Fail(_) => 0x0b, 244 + Notify(_) => 0x0c, 245 + Hello(..) => 0x0d, 246 + PullMetadata(_) => 0x0e, 247 + PullMetadataResult(_) => 0x0f, 248 + PushMetadata(_) => 0x10, 249 + PushMetadataResult(_) => 0x11, 250 + DelHistory(_) => 0x18, 251 + DelHistoryResult(_) => 0x19, 252 + GetFuncHistories(_) => 0x2f, 253 + GetFuncHistoriesResult(_) => 0x30, 254 + HelloResult(_) => 0x31, 255 + } 256 + } 257 + }
+111 -104
common/src/rpc/packing.rs
··· 1 - /// packs a dd into `buf` returning amout of bytes written. 2 - /// Returns 0 if buffer is too small 3 - pub fn pack_dd(v: u32, buf: &mut [u8]) -> usize { 4 - let bytes = v.to_le_bytes(); 5 - match v { 6 - 0..=0x7f => { // 0..0XXXXXXX (7 bits) 7 - if buf.is_empty() { 8 - return 0; 9 - } 10 - buf[0] = bytes[0]; 11 - 1 12 - }, 13 - 0x80..=0x3fff => { // 10AAAAAA..BBBBBBBB (14 bits) 14 - if buf.len() < 2 { 15 - return 0; 16 - } 17 - buf[0] = 0x80 | bytes[1]; 18 - buf[1] = bytes[0]; 19 - 2 20 - }, 21 - 0x4000..=0x1fffff => { // 11000000_AAAAAAAA_BBBBBBBB_CCCCCCCC (24 bits) 22 - if buf.len() < 3 { 23 - return 0; 24 - } 25 - buf[0] = 0xc0; 26 - buf[1] = bytes[2]; 27 - buf[2] = bytes[1]; 28 - buf[3] = bytes[0]; 29 - 4 30 - }, 31 - 0x200000..=u32::MAX => { // 11111111_AAAAAAAA_BBBBBBBB_CCCCCCCC_DDDDDDDD (32 bits) 32 - if buf.len() < 5 { 33 - return 0; 34 - } 35 - buf[0] = 0xff; 36 - buf[1] = bytes[3]; 37 - buf[2] = bytes[2]; 38 - buf[3] = bytes[1]; 39 - buf[4] = bytes[0]; 40 - 5 41 - } 42 - } 43 - } 44 - 45 - /// unpacks a dd from `buf`, returning the amount (value, byte consumed) 46 - pub fn unpack_dd(buf: &[u8]) -> (u32, usize) { 47 - if buf.is_empty() { 48 - return (0, 0); 49 - } 50 - 51 - let msb = buf[0]; 52 - let mut val = [0u8; 4]; 53 - 54 - if msb & 0x80 == 0 { // 0...... 55 - val[0] = msb; 56 - return (u32::from_le_bytes(val), 1); 57 - } 58 - if msb & 0x40 == 0 { // 10....../0x80 59 - if buf.len() < 2 { 60 - return (0, 0); 61 - } 62 - val[1] = msb & 0x3f; 63 - val[0] = buf[1]; 64 - return (u32::from_le_bytes(val), 2); 65 - } 66 - if msb & 0x20 == 0 { // 110...../0xC0 67 - if buf.len() < 4 { 68 - return (0, 0); 69 - } 70 - val[3] = msb & 0x1f; 71 - val[2] = buf[1]; 72 - val[1] = buf[2]; 73 - val[0] = buf[3]; 74 - return (u32::from_le_bytes(val), 4); 75 - } 76 - 77 - if buf.len() < 5 { 78 - return (0, 0); 79 - } 80 - 81 - val[3] = buf[1]; 82 - val[2] = buf[2]; 83 - val[1] = buf[3]; 84 - val[0] = buf[4]; 85 - 86 - (u32::from_le_bytes(val), 5) 87 - } 88 - 89 - #[cfg(test)] 90 - mod tests { 91 - #[test] 92 - #[ignore = "this is a very time consuming test, it should be run in release/profiling mode"] 93 - fn pack_all_nums() { 94 - for num in 0..=u32::MAX { 95 - let mut buf = [0u8; 5]; 96 - let rlen = super::pack_dd(num, &mut buf); 97 - assert!(rlen > 0); 98 - 99 - let unpacked = super::unpack_dd(&buf[..rlen]); 100 - assert_eq!(unpacked.1, rlen, "bad unpack size"); 101 - assert_eq!(unpacked.0, num, "values don't match"); 102 - } 103 - } 104 - } 1 + /// packs a dd into `buf` returning amout of bytes written. 2 + /// Returns 0 if buffer is too small 3 + pub fn pack_dd(v: u32, buf: &mut [u8]) -> usize { 4 + let bytes = v.to_le_bytes(); 5 + match v { 6 + 0..=0x7f => { 7 + // 0..0XXXXXXX (7 bits) 8 + if buf.is_empty() { 9 + return 0; 10 + } 11 + buf[0] = bytes[0]; 12 + 1 13 + }, 14 + 0x80..=0x3fff => { 15 + // 10AAAAAA..BBBBBBBB (14 bits) 16 + if buf.len() < 2 { 17 + return 0; 18 + } 19 + buf[0] = 0x80 | bytes[1]; 20 + buf[1] = bytes[0]; 21 + 2 22 + }, 23 + 0x4000..=0x1fffff => { 24 + // 11000000_AAAAAAAA_BBBBBBBB_CCCCCCCC (24 bits) 25 + if buf.len() < 3 { 26 + return 0; 27 + } 28 + buf[0] = 0xc0; 29 + buf[1] = bytes[2]; 30 + buf[2] = bytes[1]; 31 + buf[3] = bytes[0]; 32 + 4 33 + }, 34 + 0x200000..=u32::MAX => { 35 + // 11111111_AAAAAAAA_BBBBBBBB_CCCCCCCC_DDDDDDDD (32 bits) 36 + if buf.len() < 5 { 37 + return 0; 38 + } 39 + buf[0] = 0xff; 40 + buf[1] = bytes[3]; 41 + buf[2] = bytes[2]; 42 + buf[3] = bytes[1]; 43 + buf[4] = bytes[0]; 44 + 5 45 + }, 46 + } 47 + } 48 + 49 + /// unpacks a dd from `buf`, returning the amount (value, byte consumed) 50 + pub fn unpack_dd(buf: &[u8]) -> (u32, usize) { 51 + if buf.is_empty() { 52 + return (0, 0); 53 + } 54 + 55 + let msb = buf[0]; 56 + let mut val = [0u8; 4]; 57 + 58 + if msb & 0x80 == 0 { 59 + // 0...... 60 + val[0] = msb; 61 + return (u32::from_le_bytes(val), 1); 62 + } 63 + if msb & 0x40 == 0 { 64 + // 10....../0x80 65 + if buf.len() < 2 { 66 + return (0, 0); 67 + } 68 + val[1] = msb & 0x3f; 69 + val[0] = buf[1]; 70 + return (u32::from_le_bytes(val), 2); 71 + } 72 + if msb & 0x20 == 0 { 73 + // 110...../0xC0 74 + if buf.len() < 4 { 75 + return (0, 0); 76 + } 77 + val[3] = msb & 0x1f; 78 + val[2] = buf[1]; 79 + val[1] = buf[2]; 80 + val[0] = buf[3]; 81 + return (u32::from_le_bytes(val), 4); 82 + } 83 + 84 + if buf.len() < 5 { 85 + return (0, 0); 86 + } 87 + 88 + val[3] = buf[1]; 89 + val[2] = buf[2]; 90 + val[1] = buf[3]; 91 + val[0] = buf[4]; 92 + 93 + (u32::from_le_bytes(val), 5) 94 + } 95 + 96 + #[cfg(test)] 97 + mod tests { 98 + #[test] 99 + #[ignore = "this is a very time consuming test, it should be run in release/profiling mode"] 100 + fn pack_all_nums() { 101 + for num in 0..=u32::MAX { 102 + let mut buf = [0u8; 5]; 103 + let rlen = super::pack_dd(num, &mut buf); 104 + assert!(rlen > 0); 105 + 106 + let unpacked = super::unpack_dd(&buf[..rlen]); 107 + assert_eq!(unpacked.1, rlen, "bad unpack size"); 108 + assert_eq!(unpacked.0, num, "values don't match"); 109 + } 110 + } 111 + }
+255 -241
common/src/rpc/ser.rs
··· 1 - use std::io::Write; 2 - use serde::{ser, Serialize, ser::Impossible}; 3 - use super::Error; 4 - 5 - struct Serializer<W: Write> { 6 - output: W, 7 - } 8 - 9 - pub fn to_writer<T: Serialize, W: Write>(v: &T, w: W) -> Result<(), Error> { 10 - let mut serializer = Serializer { 11 - output: w, 12 - }; 13 - v.serialize(&mut serializer)?; 14 - Ok(()) 15 - } 16 - 17 - #[allow(dead_code)] 18 - pub fn to_vec<T: Serialize>(v: &T) -> Result<Vec<u8>, Error> { 19 - let mut buf = vec![]; 20 - to_writer(v, &mut buf)?; 21 - Ok(buf) 22 - } 23 - 24 - impl<W: Write> Serializer<W> { 25 - fn pack_dd(&mut self, num: u32) -> Result<(), Error> { 26 - let mut buf = [0u8; 5]; 27 - let bytes = super::packing::pack_dd(num, &mut buf); 28 - self.output.write_all(&buf[..bytes])?; 29 - Ok(()) 30 - } 31 - 32 - fn pack_str(&mut self, s: &str) -> Result<(), Error> { 33 - self.output.write_all(s.as_bytes())?; 34 - self.output.write_all(&[0])?; 35 - Ok(()) 36 - } 37 - 38 - fn pack_bytes(&mut self, b: &[u8]) -> Result<(), Error> { 39 - self.pack_dd(b.len() as u32)?; 40 - self.output.write_all(b)?; 41 - Ok(()) 42 - } 43 - } 44 - 45 - impl<'a, W: Write> ser::Serializer for &'a mut Serializer<W> { 46 - type Ok = (); 47 - type Error = Error; 48 - 49 - type SerializeSeq = Self; 50 - type SerializeTuple = Self; 51 - type SerializeTupleStruct = Impossible<(), Self::Error>; 52 - type SerializeTupleVariant = Impossible<(), Self::Error>; 53 - type SerializeMap = Impossible<(), Self::Error>; 54 - type SerializeStruct = Self; 55 - type SerializeStructVariant = Impossible<(), Self::Error>; 56 - 57 - fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> { 58 - unreachable!() 59 - } 60 - 61 - fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> { 62 - unreachable!() 63 - } 64 - 65 - fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> { 66 - unreachable!() 67 - } 68 - 69 - fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> { 70 - unreachable!() 71 - } 72 - 73 - fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> { 74 - unreachable!() 75 - } 76 - 77 - fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> { 78 - self.output.write_all(&[v])?; 79 - Ok(()) 80 - } 81 - 82 - fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> { 83 - unreachable!() 84 - } 85 - 86 - fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> { 87 - self.pack_dd(v) 88 - } 89 - 90 - fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> { 91 - let high = (v >> 32) & 0xffffffff; 92 - let low = v & 0xffffffff; 93 - self.pack_dd(high as u32)?; 94 - self.pack_dd(low as u32)?; 95 - Ok(()) 96 - } 97 - 98 - fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> { 99 - unreachable!() 100 - } 101 - 102 - fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> { 103 - unreachable!() 104 - } 105 - 106 - fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> { 107 - unreachable!() 108 - } 109 - 110 - fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { 111 - self.pack_str(v) 112 - } 113 - 114 - fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> { 115 - self.pack_bytes(v) 116 - } 117 - 118 - fn serialize_none(self) -> Result<Self::Ok, Self::Error> { 119 - unreachable!() 120 - } 121 - 122 - fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<Self::Ok, Self::Error> { 123 - unreachable!() 124 - } 125 - 126 - fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { 127 - // unit contains no information... 128 - Ok(()) 129 - } 130 - 131 - fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { 132 - unreachable!() 133 - } 134 - 135 - fn serialize_unit_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str) -> Result<Self::Ok, Self::Error> { 136 - unreachable!() 137 - } 138 - 139 - fn serialize_newtype_struct<T: ?Sized + Serialize>(self, _name: &'static str, _value: &T) -> Result<Self::Ok, Self::Error> { 140 - unreachable!() 141 - } 142 - 143 - fn serialize_newtype_variant<T: ?Sized + Serialize>(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T) -> Result<Self::Ok, Self::Error> { 144 - unreachable!() 145 - } 146 - 147 - fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { 148 - let len = len.unwrap(); 149 - self.pack_dd(len as u32)?; 150 - Ok(self) 151 - } 152 - 153 - fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { 154 - Ok(self) 155 - } 156 - 157 - fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct, Self::Error> { 158 - unreachable!(); 159 - } 160 - 161 - fn serialize_tuple_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeTupleVariant, Self::Error> { 162 - unreachable!() 163 - } 164 - 165 - fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { 166 - unreachable!() 167 - } 168 - 169 - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct, Self::Error> { 170 - // structs will simply be flattened 171 - Ok(self) 172 - } 173 - 174 - fn serialize_struct_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeStructVariant, Self::Error> { 175 - unreachable!() 176 - } 177 - } 178 - 179 - impl<'a, W: Write> ser::SerializeSeq for &'a mut Serializer<W> { 180 - type Ok = (); 181 - type Error = Error; 182 - 183 - fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> { 184 - value.serialize(&mut **self) 185 - } 186 - 187 - fn end(self) -> Result<Self::Ok, Self::Error> { 188 - Ok(()) 189 - } 190 - } 191 - 192 - impl<'a, W: Write> ser::SerializeTuple for &'a mut Serializer<W> { 193 - type Ok = (); 194 - type Error = Error; 195 - 196 - fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> { 197 - value.serialize(&mut **self) 198 - } 199 - 200 - fn end(self) -> Result<Self::Ok, Self::Error> { 201 - Ok(()) 202 - } 203 - } 204 - 205 - impl<'a, W: Write> ser::SerializeStruct for &'a mut Serializer<W> { 206 - type Ok = (); 207 - type Error = Error; 208 - 209 - fn serialize_field<T: ?Sized + Serialize>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error> { 210 - // struct names have no meaning 211 - value.serialize(&mut **self) 212 - } 213 - 214 - fn end(self) -> Result<Self::Ok, Self::Error> { 215 - Ok(()) 216 - } 217 - } 218 - 219 - #[cfg(test)] 220 - mod tests { 221 - #[test] 222 - fn ser_hello() { 223 - #[derive(serde::Serialize)] 224 - struct Test<'a> { 225 - arr: [u8; 16], 226 - s: &'a str, 227 - b: &'a [u8], 228 - i: u32, 229 - q: u64, 230 - } 231 - let v = Test { 232 - arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 233 - s: "somestring", 234 - b: b"bytes", 235 - i: 0x20, 236 - q: 0x20, 237 - }; 238 - let v = super::to_vec(&v).expect("failed to serialize dummy"); 239 - assert_eq!(v, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10somestring\x00\x05bytes\x20\x00\x20"); 240 - } 241 - } 1 + use super::Error; 2 + use serde::{ser, ser::Impossible, Serialize}; 3 + use std::io::Write; 4 + 5 + struct Serializer<W: Write> { 6 + output: W, 7 + } 8 + 9 + pub fn to_writer<T: Serialize, W: Write>(v: &T, w: W) -> Result<(), Error> { 10 + let mut serializer = Serializer { output: w }; 11 + v.serialize(&mut serializer)?; 12 + Ok(()) 13 + } 14 + 15 + #[allow(dead_code)] 16 + pub fn to_vec<T: Serialize>(v: &T) -> Result<Vec<u8>, Error> { 17 + let mut buf = vec![]; 18 + to_writer(v, &mut buf)?; 19 + Ok(buf) 20 + } 21 + 22 + impl<W: Write> Serializer<W> { 23 + fn pack_dd(&mut self, num: u32) -> Result<(), Error> { 24 + let mut buf = [0u8; 5]; 25 + let bytes = super::packing::pack_dd(num, &mut buf); 26 + self.output.write_all(&buf[..bytes])?; 27 + Ok(()) 28 + } 29 + 30 + fn pack_str(&mut self, s: &str) -> Result<(), Error> { 31 + self.output.write_all(s.as_bytes())?; 32 + self.output.write_all(&[0])?; 33 + Ok(()) 34 + } 35 + 36 + fn pack_bytes(&mut self, b: &[u8]) -> Result<(), Error> { 37 + self.pack_dd(b.len() as u32)?; 38 + self.output.write_all(b)?; 39 + Ok(()) 40 + } 41 + } 42 + 43 + impl<'a, W: Write> ser::Serializer for &'a mut Serializer<W> { 44 + type Ok = (); 45 + type Error = Error; 46 + 47 + type SerializeSeq = Self; 48 + type SerializeTuple = Self; 49 + type SerializeTupleStruct = Impossible<(), Self::Error>; 50 + type SerializeTupleVariant = Impossible<(), Self::Error>; 51 + type SerializeMap = Impossible<(), Self::Error>; 52 + type SerializeStruct = Self; 53 + type SerializeStructVariant = Impossible<(), Self::Error>; 54 + 55 + fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> { 56 + unreachable!() 57 + } 58 + 59 + fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> { 60 + unreachable!() 61 + } 62 + 63 + fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> { 64 + unreachable!() 65 + } 66 + 67 + fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> { 68 + unreachable!() 69 + } 70 + 71 + fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> { 72 + unreachable!() 73 + } 74 + 75 + fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> { 76 + self.output.write_all(&[v])?; 77 + Ok(()) 78 + } 79 + 80 + fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> { 81 + unreachable!() 82 + } 83 + 84 + fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> { 85 + self.pack_dd(v) 86 + } 87 + 88 + fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> { 89 + let high = (v >> 32) & 0xffffffff; 90 + let low = v & 0xffffffff; 91 + self.pack_dd(high as u32)?; 92 + self.pack_dd(low as u32)?; 93 + Ok(()) 94 + } 95 + 96 + fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> { 97 + unreachable!() 98 + } 99 + 100 + fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> { 101 + unreachable!() 102 + } 103 + 104 + fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> { 105 + unreachable!() 106 + } 107 + 108 + fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { 109 + self.pack_str(v) 110 + } 111 + 112 + fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> { 113 + self.pack_bytes(v) 114 + } 115 + 116 + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { 117 + unreachable!() 118 + } 119 + 120 + fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<Self::Ok, Self::Error> { 121 + unreachable!() 122 + } 123 + 124 + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { 125 + // unit contains no information... 126 + Ok(()) 127 + } 128 + 129 + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { 130 + unreachable!() 131 + } 132 + 133 + fn serialize_unit_variant( 134 + self, _name: &'static str, _variant_index: u32, _variant: &'static str, 135 + ) -> Result<Self::Ok, Self::Error> { 136 + unreachable!() 137 + } 138 + 139 + fn serialize_newtype_struct<T: ?Sized + Serialize>( 140 + self, _name: &'static str, _value: &T, 141 + ) -> Result<Self::Ok, Self::Error> { 142 + unreachable!() 143 + } 144 + 145 + fn serialize_newtype_variant<T: ?Sized + Serialize>( 146 + self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, 147 + ) -> Result<Self::Ok, Self::Error> { 148 + unreachable!() 149 + } 150 + 151 + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { 152 + let len = len.unwrap(); 153 + self.pack_dd(len as u32)?; 154 + Ok(self) 155 + } 156 + 157 + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { 158 + Ok(self) 159 + } 160 + 161 + fn serialize_tuple_struct( 162 + self, _name: &'static str, _len: usize, 163 + ) -> Result<Self::SerializeTupleStruct, Self::Error> { 164 + unreachable!(); 165 + } 166 + 167 + fn serialize_tuple_variant( 168 + self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, 169 + ) -> Result<Self::SerializeTupleVariant, Self::Error> { 170 + unreachable!() 171 + } 172 + 173 + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { 174 + unreachable!() 175 + } 176 + 177 + fn serialize_struct( 178 + self, _name: &'static str, _len: usize, 179 + ) -> Result<Self::SerializeStruct, Self::Error> { 180 + // structs will simply be flattened 181 + Ok(self) 182 + } 183 + 184 + fn serialize_struct_variant( 185 + self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, 186 + ) -> Result<Self::SerializeStructVariant, Self::Error> { 187 + unreachable!() 188 + } 189 + } 190 + 191 + impl<'a, W: Write> ser::SerializeSeq for &'a mut Serializer<W> { 192 + type Ok = (); 193 + type Error = Error; 194 + 195 + fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> { 196 + value.serialize(&mut **self) 197 + } 198 + 199 + fn end(self) -> Result<Self::Ok, Self::Error> { 200 + Ok(()) 201 + } 202 + } 203 + 204 + impl<'a, W: Write> ser::SerializeTuple for &'a mut Serializer<W> { 205 + type Ok = (); 206 + type Error = Error; 207 + 208 + fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> { 209 + value.serialize(&mut **self) 210 + } 211 + 212 + fn end(self) -> Result<Self::Ok, Self::Error> { 213 + Ok(()) 214 + } 215 + } 216 + 217 + impl<'a, W: Write> ser::SerializeStruct for &'a mut Serializer<W> { 218 + type Ok = (); 219 + type Error = Error; 220 + 221 + fn serialize_field<T: ?Sized + Serialize>( 222 + &mut self, _key: &'static str, value: &T, 223 + ) -> Result<(), Self::Error> { 224 + // struct names have no meaning 225 + value.serialize(&mut **self) 226 + } 227 + 228 + fn end(self) -> Result<Self::Ok, Self::Error> { 229 + Ok(()) 230 + } 231 + } 232 + 233 + #[cfg(test)] 234 + mod tests { 235 + #[test] 236 + fn ser_hello() { 237 + #[derive(serde::Serialize)] 238 + struct Test<'a> { 239 + arr: [u8; 16], 240 + s: &'a str, 241 + b: &'a [u8], 242 + i: u32, 243 + q: u64, 244 + } 245 + let v = Test { 246 + arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 247 + s: "somestring", 248 + b: b"bytes", 249 + i: 0x20, 250 + q: 0x20, 251 + }; 252 + let v = super::to_vec(&v).expect("failed to serialize dummy"); 253 + assert_eq!(v, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10somestring\x00\x05bytes\x20\x00\x20"); 254 + } 255 + }
+192 -204
common/src/web/api.rs
··· 1 - use std::borrow::Cow; 2 - use log::*; 3 - use warp::{Filter, Reply, Rejection}; 4 - use serde::Serialize; 5 - 6 - use super::SharedState; 7 - 8 - struct Md5([u8; 16]); 9 - impl std::str::FromStr for Md5 { 10 - type Err = &'static str; 11 - fn from_str(s: &str) -> Result<Md5, Self::Err> { 12 - let mut res = [0u8; 16]; 13 - let s = s.trim(); 14 - if s.len() != 32 { 15 - return Err("bad md5 length"); 16 - } 17 - binascii::hex2bin(s.as_bytes(), &mut res) 18 - .map_err(|_| "bad md5")?; 19 - Ok(Md5(res)) 20 - } 21 - } 22 - 23 - #[derive(Serialize)] 24 - struct Error<'a> { 25 - error: &'a str, 26 - } 27 - 28 - impl std::fmt::Display for Md5 { 29 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 30 - let mut out = [0u8; 32]; 31 - binascii::bin2hex(&self.0, &mut out).unwrap(); 32 - let out = std::str::from_utf8(&out).unwrap(); 33 - write!(f, "{}", &out) 34 - } 35 - } 36 - 37 - impl Serialize for Md5 { 38 - fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 39 - serializer.serialize_str(&format!("{}", &self)) 40 - } 41 - } 42 - 43 - pub fn api_root(state: SharedState) -> impl Filter<Extract = (impl Reply + 'static, ), Error=Rejection> + Clone { 44 - let view_file = warp::get() 45 - .and(warp::path("files")) 46 - .and(super::with_state(state.clone())) 47 - .and(warp::filters::path::param::<Md5>()) 48 - .and_then(view_file_by_hash); 49 - let view_func = warp::get() 50 - .and(warp::path("funcs")) 51 - .and(super::with_state(state)) 52 - .and(warp::filters::path::param::<Md5>()) 53 - .and_then(view_func_by_hash); 54 - 55 - view_file 56 - .or(view_func) 57 - } 58 - 59 - // GET server/api/files/:md5 60 - async fn view_file_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> { 61 - #[derive(Serialize)] 62 - struct FileFunc { 63 - hash: Md5, 64 - len: u32, 65 - name: String, 66 - } 67 - 68 - let v = match state.db.get_file_funcs(&md5.0[..], 0, 10_000).await { 69 - Ok(v) => v, 70 - Err(err) => { 71 - error!("failed to get file's funcs {}: {}", &md5, err); 72 - return Ok(warp::reply::json(&Error{error: "internal server error"})); 73 - }, 74 - }; 75 - let v: Vec<_> = v.into_iter() 76 - .map(|v| { 77 - let mut hash = [0u8; 16]; 78 - hash.copy_from_slice(&v.2); 79 - FileFunc { 80 - name: v.0, 81 - len: v.1 as u32, 82 - hash: Md5(hash), 83 - } 84 - }) 85 - .collect(); 86 - 87 - Result::<_, Rejection>::Ok(warp::reply::json(&v)) 88 - } 89 - 90 - // GET server/api/funcs/:md5 91 - async fn view_func_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> { 92 - #[derive(Serialize)] 93 - enum CommentType { 94 - Posterior, 95 - Anterior, 96 - Function{ repeatable: bool }, 97 - Byte { repeatable: bool }, 98 - } 99 - 100 - #[derive(Serialize)] 101 - struct Comment<'a> { 102 - #[serde(skip_serializing_if = "Option::is_none")] 103 - offset: Option<u32>, 104 - #[serde(rename = "type")] 105 - type_: CommentType, 106 - comment: Cow<'a, str>, 107 - } 108 - 109 - #[derive(Serialize)] 110 - struct FuncInfo<'a> { 111 - name: &'a str, 112 - comments: Vec<Comment<'a>>, 113 - length: u32, 114 - in_files: &'a [Md5], 115 - } 116 - 117 - let funcs = [crate::rpc::PullMetadataFunc { 118 - unk0: 1, 119 - mb_hash: &md5.0 120 - }]; 121 - 122 - let files_with = state.db.get_files_with_func(&md5.0[..]); 123 - let files_info = state.db.get_funcs(&funcs); 124 - 125 - let (files_with, files_info) = match futures_util::try_join!(files_with, files_info) { 126 - Ok(v) => v, 127 - Err(err) => { 128 - error!("failed to execute db queries: {}", err); 129 - return Ok(warp::reply::json(&Error {error: "internal server error"})); 130 - } 131 - }; 132 - 133 - let files_with: Vec<Md5> = files_with.into_iter().map(|v| { 134 - let mut md5 = [0u8; 16]; 135 - md5.copy_from_slice(&v); 136 - Md5(md5) 137 - }).collect(); 138 - 139 - let v = files_info; 140 - let v: Vec<FuncInfo> = v 141 - .iter() 142 - .take(1) 143 - .filter_map(|v| v.as_ref()) 144 - .filter_map(|v| { 145 - let md = match crate::md::parse_metadata(&v.data) { 146 - Ok(v) => v, 147 - Err(e) => { 148 - error!("error parsing metadata for {}: {}", &md5, e); 149 - return None; 150 - } 151 - }; 152 - let comments: Vec<Comment> = md.into_iter() 153 - .filter_map(|md| { 154 - match md { 155 - crate::md::FunctionMetadata::ByteComment(c) => { 156 - Some(vec![Comment { 157 - offset: Some(c.offset), 158 - type_: CommentType::Byte{ repeatable: c.is_repeatable }, 159 - comment: c.comment.into(), 160 - }]) 161 - }, 162 - crate::md::FunctionMetadata::FunctionComment(c) => { 163 - Some(vec![Comment { 164 - offset: None, 165 - type_: CommentType::Function{ repeatable: c.is_repeatable }, 166 - comment: c.comment.into(), 167 - }]) 168 - }, 169 - crate::md::FunctionMetadata::ExtraComment(c) => { 170 - let mut res = vec![]; 171 - if !c.anterior.is_empty() { 172 - res.push(Comment { 173 - offset: Some(c.offset), 174 - type_: CommentType::Anterior, 175 - comment: c.anterior.into(), 176 - }); 177 - } 178 - if !c.posterior.is_empty() { 179 - res.push(Comment { 180 - offset: Some(c.offset), 181 - type_: CommentType::Posterior, 182 - comment: c.posterior.into(), 183 - }); 184 - } 185 - if !res.is_empty() { 186 - Some(res) 187 - } else { 188 - None 189 - } 190 - }, 191 - } 192 - }) 193 - .flatten() 194 - .collect(); 195 - Some(FuncInfo { 196 - name: &v.name, 197 - length: v.len, 198 - comments, 199 - in_files: &files_with, 200 - }) 201 - }).collect(); 202 - 203 - Result::<_, Rejection>::Ok(warp::reply::json(&v)) 204 - } 1 + use log::*; 2 + use serde::Serialize; 3 + use std::borrow::Cow; 4 + use warp::{Filter, Rejection, Reply}; 5 + 6 + use super::SharedState; 7 + 8 + struct Md5([u8; 16]); 9 + impl std::str::FromStr for Md5 { 10 + type Err = &'static str; 11 + fn from_str(s: &str) -> Result<Md5, Self::Err> { 12 + let mut res = [0u8; 16]; 13 + let s = s.trim(); 14 + if s.len() != 32 { 15 + return Err("bad md5 length"); 16 + } 17 + binascii::hex2bin(s.as_bytes(), &mut res).map_err(|_| "bad md5")?; 18 + Ok(Md5(res)) 19 + } 20 + } 21 + 22 + #[derive(Serialize)] 23 + struct Error<'a> { 24 + error: &'a str, 25 + } 26 + 27 + impl std::fmt::Display for Md5 { 28 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 29 + let mut out = [0u8; 32]; 30 + binascii::bin2hex(&self.0, &mut out).unwrap(); 31 + let out = std::str::from_utf8(&out).unwrap(); 32 + write!(f, "{}", &out) 33 + } 34 + } 35 + 36 + impl Serialize for Md5 { 37 + fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 38 + serializer.serialize_str(&format!("{}", &self)) 39 + } 40 + } 41 + 42 + pub fn api_root( 43 + state: SharedState, 44 + ) -> impl Filter<Extract = (impl Reply + 'static,), Error = Rejection> + Clone { 45 + let view_file = warp::get() 46 + .and(warp::path("files")) 47 + .and(super::with_state(state.clone())) 48 + .and(warp::filters::path::param::<Md5>()) 49 + .and_then(view_file_by_hash); 50 + let view_func = warp::get() 51 + .and(warp::path("funcs")) 52 + .and(super::with_state(state)) 53 + .and(warp::filters::path::param::<Md5>()) 54 + .and_then(view_func_by_hash); 55 + 56 + view_file.or(view_func) 57 + } 58 + 59 + // GET server/api/files/:md5 60 + async fn view_file_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> { 61 + #[derive(Serialize)] 62 + struct FileFunc { 63 + hash: Md5, 64 + len: u32, 65 + name: String, 66 + } 67 + 68 + let v = match state.db.get_file_funcs(&md5.0[..], 0, 10_000).await { 69 + Ok(v) => v, 70 + Err(err) => { 71 + error!("failed to get file's funcs {}: {}", &md5, err); 72 + return Ok(warp::reply::json(&Error { error: "internal server error" })); 73 + }, 74 + }; 75 + let v: Vec<_> = v 76 + .into_iter() 77 + .map(|v| { 78 + let mut hash = [0u8; 16]; 79 + hash.copy_from_slice(&v.2); 80 + FileFunc { name: v.0, len: v.1 as u32, hash: Md5(hash) } 81 + }) 82 + .collect(); 83 + 84 + Result::<_, Rejection>::Ok(warp::reply::json(&v)) 85 + } 86 + 87 + // GET server/api/funcs/:md5 88 + async fn view_func_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> { 89 + #[derive(Serialize)] 90 + enum CommentType { 91 + Posterior, 92 + Anterior, 93 + Function { repeatable: bool }, 94 + Byte { repeatable: bool }, 95 + } 96 + 97 + #[derive(Serialize)] 98 + struct Comment<'a> { 99 + #[serde(skip_serializing_if = "Option::is_none")] 100 + offset: Option<u32>, 101 + #[serde(rename = "type")] 102 + type_: CommentType, 103 + comment: Cow<'a, str>, 104 + } 105 + 106 + #[derive(Serialize)] 107 + struct FuncInfo<'a> { 108 + name: &'a str, 109 + comments: Vec<Comment<'a>>, 110 + length: u32, 111 + in_files: &'a [Md5], 112 + } 113 + 114 + let funcs = [crate::rpc::PullMetadataFunc { unk0: 1, mb_hash: &md5.0 }]; 115 + 116 + let files_with = state.db.get_files_with_func(&md5.0[..]); 117 + let files_info = state.db.get_funcs(&funcs); 118 + 119 + let (files_with, files_info) = match futures_util::try_join!(files_with, files_info) { 120 + Ok(v) => v, 121 + Err(err) => { 122 + error!("failed to execute db queries: {}", err); 123 + return Ok(warp::reply::json(&Error { error: "internal server error" })); 124 + }, 125 + }; 126 + 127 + let files_with: Vec<Md5> = files_with 128 + .into_iter() 129 + .map(|v| { 130 + let mut md5 = [0u8; 16]; 131 + md5.copy_from_slice(&v); 132 + Md5(md5) 133 + }) 134 + .collect(); 135 + 136 + let v = files_info; 137 + let v: Vec<FuncInfo> = v 138 + .iter() 139 + .take(1) 140 + .filter_map(|v| v.as_ref()) 141 + .filter_map(|v| { 142 + let md = match crate::md::parse_metadata(&v.data) { 143 + Ok(v) => v, 144 + Err(e) => { 145 + error!("error parsing metadata for {}: {}", &md5, e); 146 + return None; 147 + }, 148 + }; 149 + let comments: Vec<Comment> = md 150 + .into_iter() 151 + .filter_map(|md| match md { 152 + crate::md::FunctionMetadata::ByteComment(c) => Some(vec![Comment { 153 + offset: Some(c.offset), 154 + type_: CommentType::Byte { repeatable: c.is_repeatable }, 155 + comment: c.comment.into(), 156 + }]), 157 + crate::md::FunctionMetadata::FunctionComment(c) => Some(vec![Comment { 158 + offset: None, 159 + type_: CommentType::Function { repeatable: c.is_repeatable }, 160 + comment: c.comment.into(), 161 + }]), 162 + crate::md::FunctionMetadata::ExtraComment(c) => { 163 + let mut res = vec![]; 164 + if !c.anterior.is_empty() { 165 + res.push(Comment { 166 + offset: Some(c.offset), 167 + type_: CommentType::Anterior, 168 + comment: c.anterior.into(), 169 + }); 170 + } 171 + if !c.posterior.is_empty() { 172 + res.push(Comment { 173 + offset: Some(c.offset), 174 + type_: CommentType::Posterior, 175 + comment: c.posterior.into(), 176 + }); 177 + } 178 + if !res.is_empty() { 179 + Some(res) 180 + } else { 181 + None 182 + } 183 + }, 184 + }) 185 + .flatten() 186 + .collect(); 187 + Some(FuncInfo { name: &v.name, length: v.len, comments, in_files: &files_with }) 188 + }) 189 + .collect(); 190 + 191 + Result::<_, Rejection>::Ok(warp::reply::json(&v)) 192 + }
+10 -8
common/src/web.rs
··· 1 - use crate::SharedState; 2 - use warp::Filter; 3 - 4 - pub mod api; 5 - 6 - pub fn with_state(state: SharedState) -> impl Filter<Extract=(SharedState,), Error= std::convert::Infallible> + Clone { 7 - warp::any().map(move || state.clone()) 8 - } 1 + use crate::SharedState; 2 + use warp::Filter; 3 + 4 + pub mod api; 5 + 6 + pub fn with_state( 7 + state: SharedState, 8 + ) -> impl Filter<Extract = (SharedState,), Error = std::convert::Infallible> + Clone { 9 + warp::any().map(move || state.clone()) 10 + }
+2
config-example.toml
··· 8 8 9 9 # Allow clients to delete metadata from the database? 10 10 allow_deletes = false 11 + # How many function histories should we return? 0=Disabled. 12 + get_history_limit = 50 11 13 12 14 # only required when `use_tls` is set to true. 13 15 [lumina.tls]
+6 -6
lumen/Cargo.toml
··· 7 7 publish = false 8 8 9 9 [dependencies] 10 - common = {path = "../common"} 11 - tokio = {version = "1.32", features = ["full"]} 12 - log = {version = "0.4", features = ["release_max_level_debug"]} 10 + common = { path = "../common" } 11 + tokio = { version = "1.39", features = ["full"] } 12 + log = { version = "0.4", features = ["release_max_level_debug"] } 13 13 pretty_env_logger = "0.5" 14 - clap = "4.3" 14 + clap = "4.5" 15 15 tokio-native-tls = "0.3" 16 - native-tls = {version = "0.2"} 16 + native-tls = { version = "0.2" } 17 17 warp = "0.3" 18 - prometheus-client = "0.21.2" 18 + prometheus-client = "0.22"
+11 -409
lumen/src/main.rs
··· 4 4 #![warn(unused_crate_dependencies)] 5 5 #![deny(clippy::all)] 6 6 7 - use common::async_drop::AsyncDropper; 8 - use common::metrics::LuminaVersion; 9 - use common::rpc::{RpcHello, RpcFail, HelloResult}; 10 - use native_tls::Identity; 11 7 use clap::Arg; 12 8 use log::*; 13 - use tokio::time::timeout; 14 - use std::collections::HashMap; 15 - use std::mem::discriminant; 16 - use std::time::{Duration, Instant}; 17 - use std::{borrow::Cow, sync::Arc}; 18 - use tokio::{net::TcpListener, io::AsyncWrite, io::AsyncRead}; 19 - use std::process::exit; 20 - use common::{SharedState, SharedState_}; 9 + use server::do_lumen; 10 + use std::sync::Arc; 21 11 12 + mod server; 22 13 mod web; 23 14 24 - use common::{config, make_pretty_hex, md, rpc::{self, Error}}; 25 - use common::db::Database; 26 - use rpc::RpcMessage; 15 + use common::config; 27 16 28 17 fn setup_logger() { 29 18 if std::env::var("RUST_LOG").is_err() { ··· 32 21 pretty_env_logger::init_timed(); 33 22 } 34 23 35 - async fn handle_transaction<'a, S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, user: &'a RpcHello<'a>, mut stream: S) -> Result<(), Error> { 36 - let db = &state.db; 37 - let server_name = state.server_name.as_str(); 38 - 39 - trace!("waiting for command.."); 40 - let req = match timeout(Duration::from_secs(3600), rpc::read_packet(&mut stream)).await { 41 - Ok(res) => match res { 42 - Ok(v) => v, 43 - Err(e) => return Err(e), 44 - }, 45 - Err(_) => { 46 - _ = RpcMessage::Fail(RpcFail { 47 - code: 0, 48 - message: &format!("{server_name} client idle for too long.\n"), 49 - }).async_write(&mut stream).await; 50 - return Err(Error::Timeout); 51 - }, 52 - }; 53 - trace!("got command!"); 54 - let req = match RpcMessage::deserialize(&req) { 55 - Ok(v) => v, 56 - Err(err) => { 57 - warn!("bad message: \n{}\n", make_pretty_hex(&req)); 58 - error!("failed to process rpc message: {}", err); 59 - let resp = rpc::RpcFail{ code: 0, message: &format!("{server_name}: error: invalid data.\n")}; 60 - let resp = RpcMessage::Fail(resp); 61 - resp.async_write(&mut stream).await?; 62 - 63 - return Ok(()); 64 - }, 65 - }; 66 - match req { 67 - RpcMessage::PullMetadata(md) => { 68 - let start = Instant::now(); 69 - let funcs = match timeout(Duration::from_secs(4 * 60), db.get_funcs(&md.funcs)).await { 70 - Ok(r) => match r { 71 - Ok(v) => v, 72 - Err(e) => { 73 - error!("pull failed, db: {}", e); 74 - rpc::RpcMessage::Fail(rpc::RpcFail { 75 - code: 0, 76 - message: &format!("{server_name}: db error; please try again later..\n") 77 - }).async_write(&mut stream).await?; 78 - return Ok(()); 79 - }, 80 - }, 81 - Err(_) => { 82 - RpcMessage::Fail(RpcFail { 83 - code: 0, 84 - message: &format!("{server_name}: query took too long to execute.\n"), 85 - }).async_write(&mut stream).await?; 86 - debug!("pull query timeout"); 87 - return Err(Error::Timeout); 88 - } 89 - }; 90 - let pulled_funcs = funcs.iter().filter(|v| v.is_some()).count(); 91 - state.metrics.pulls.inc_by(pulled_funcs as _); 92 - state.metrics.queried_funcs.inc_by(md.funcs.len() as _); 93 - debug!("pull {pulled_funcs}/{} funcs ended after {:?}", md.funcs.len(), start.elapsed()); 94 - 95 - let statuses: Vec<u32> = funcs.iter().map(|v| u32::from(v.is_none())).collect(); 96 - let found = funcs 97 - .into_iter() 98 - .flatten() 99 - .map(|v| { 100 - rpc::PullMetadataResultFunc { 101 - popularity: v.popularity, 102 - len: v.len, 103 - name: Cow::Owned(v.name), 104 - mb_data: Cow::Owned(v.data), 105 - } 106 - }).collect(); 107 - 108 - RpcMessage::PullMetadataResult(rpc::PullMetadataResult{ 109 - unk0: Cow::Owned(statuses), 110 - funcs: Cow::Owned(found), 111 - }).async_write(&mut stream).await?; 112 - }, 113 - RpcMessage::PushMetadata(mds) => { 114 - // parse the function's metadata 115 - let start = Instant::now(); 116 - let scores: Vec<u32> = mds.funcs.iter() 117 - .map(md::get_score) 118 - .collect(); 119 - 120 - let status = match db.push_funcs(user, &mds, &scores).await { 121 - Ok(v) => { 122 - v.into_iter().map(u32::from).collect::<Vec<u32>>() 123 - }, 124 - Err(err) => { 125 - log::error!("push failed, db: {}", err); 126 - rpc::RpcMessage::Fail(rpc::RpcFail { 127 - code: 0, 128 - message: &format!("{server_name}: db error; please try again later.\n") 129 - }).async_write(&mut stream).await?; 130 - return Ok(()); 131 - } 132 - }; 133 - state.metrics.pushes.inc_by(status.len() as _); 134 - let new_funcs = status 135 - .iter() 136 - .fold(0u64, |counter, &v| if v > 0 { counter + 1 } else {counter}); 137 - state.metrics.new_funcs.inc_by(new_funcs); 138 - debug!("push {} funcs ended after {:?} ({new_funcs} new)", status.len(), start.elapsed()); 139 - 140 - RpcMessage::PushMetadataResult(rpc::PushMetadataResult { 141 - status: Cow::Owned(status), 142 - }).async_write(&mut stream).await?; 143 - }, 144 - RpcMessage::DelHistory(req) => { 145 - let is_delete_allowed = state.config.lumina.allow_deletes.unwrap_or(false); 146 - if !is_delete_allowed { 147 - RpcMessage::Fail(rpc::RpcFail { 148 - code: 2, 149 - message: &format!("{server_name}: Delete command is disabled on this server.") 150 - }).async_write(&mut stream).await?; 151 - } else { 152 - if let Err(err) = db.delete_metadata(&req).await { 153 - error!("delete failed. db: {err}"); 154 - RpcMessage::Fail(rpc::RpcFail { 155 - code: 3, 156 - message: &format!("{server_name}: db error, please try again later.") 157 - }).async_write(&mut stream).await?; 158 - return Ok(()); 159 - } 160 - RpcMessage::DelHistoryResult(rpc::DelHistoryResult { 161 - deleted_mds: req.funcs.len() as u32, 162 - }).async_write(&mut stream).await?; 163 - } 164 - }, 165 - _ => { 166 - RpcMessage::Fail(rpc::RpcFail{code: 0, message: &format!("{server_name}: invalid data.\n")}).async_write(&mut stream).await?; 167 - } 168 - } 169 - Ok(()) 170 - } 171 - 172 - async fn handle_client<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, mut stream: S) -> Result<(), rpc::Error> { 173 - let server_name = &state.server_name; 174 - let hello = match timeout(Duration::from_secs(15), rpc::read_packet(&mut stream)).await { 175 - Ok(v) => v?, 176 - Err(_) => { 177 - debug!("didn't get hello in time."); 178 - return Ok(()); 179 - }, 180 - }; 181 - 182 - let (hello, creds) = match RpcMessage::deserialize(&hello) { 183 - Ok(RpcMessage::Hello(v, creds)) => { 184 - debug!("hello protocol={}, login creds: {creds:?}", v.protocol_version); 185 - (v, creds) 186 - }, 187 - _ => { 188 - // send error 189 - error!("got bad hello message"); 190 - 191 - let resp = rpc::RpcFail{ code: 0, message: &format!("{server_name}: bad sequence.") }; 192 - let resp = rpc::RpcMessage::Fail(resp); 193 - resp.async_write(&mut stream).await?; 194 - 195 - return Ok(()); 196 - } 197 - }; 198 - state.metrics.lumina_version.get_or_create(&LuminaVersion { 199 - protocol_version: hello.protocol_version, 200 - }).inc(); 201 - 202 - if let Some(ref creds) = creds { 203 - if creds.username != "guest" { 204 - // Only allow "guest" to connect for now. 205 - rpc::RpcMessage::Fail(rpc::RpcFail { 206 - code: 1, 207 - message: &format!("{server_name}: invalid username or password. Try logging in with `guest` instead."), 208 - }).async_write(&mut stream).await?; 209 - return Ok(()); 210 - } 211 - } 212 - 213 - let resp = match hello.protocol_version { 214 - 0..=4 => rpc::RpcMessage::Ok(()), 215 - 216 - // starting IDA 8.3 217 - 5.. => rpc::RpcMessage::HelloResult(HelloResult { 218 - unk0: "".into(), 219 - unk1: "".into(), 220 - unk2: "".into(), 221 - unk3: "".into(), 222 - unk4: 0, 223 - unk5: 0, 224 - unk6: 0, 225 - }) 226 - }; 227 - resp.async_write(&mut stream).await?; 228 - 229 - loop { 230 - handle_transaction(state, &hello, &mut stream).await?; 231 - } 232 - } 233 - 234 - async fn handle_connection<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, s: S) { 235 - if let Err(err) = handle_client(state, s).await { 236 - if discriminant(&err) != discriminant(&Error::Eof) { 237 - warn!("err: {}", err); 238 - } 239 - } 240 - } 241 - 242 - async fn serve(listener: TcpListener, accpt: Option<tokio_native_tls::TlsAcceptor>, state: SharedState, mut shutdown_signal: tokio::sync::oneshot::Receiver<()>) { 243 - let accpt = accpt.map(Arc::new); 244 - 245 - let (async_drop, worker) = AsyncDropper::new(); 246 - tokio::task::spawn(worker); 247 - 248 - let connections = Arc::new(tokio::sync::Mutex::new(HashMap::<std::net::SocketAddr, tokio::task::JoinHandle<()>>::new())); 249 - 250 - loop { 251 - let (client, addr) = tokio::select! { 252 - _ = &mut shutdown_signal => { 253 - drop(state); 254 - info!("shutting down..."); 255 - let m = connections.lock().await; 256 - m.iter().for_each(|(k, v)| { 257 - debug!("aborting task for {k}..."); 258 - v.abort(); 259 - }); 260 - return; 261 - }, 262 - res = listener.accept() => match res { 263 - Ok(v) => v, 264 - Err(err) => { 265 - warn!("failed to accept(): {}", err); 266 - continue; 267 - } 268 - }, 269 - }; 270 - 271 - let start = Instant::now(); 272 - 273 - let state = state.clone(); 274 - let accpt = accpt.clone(); 275 - 276 - let conns2 = connections.clone(); 277 - let counter = state.metrics.active_connections.clone(); 278 - let guard = async_drop.defer(async move { 279 - let count = counter.dec() - 1; 280 - debug!("connection with {:?} ended after {:?}; {} active connections", addr, start.elapsed(), count); 281 - 282 - let mut guard = conns2.lock().await; 283 - if guard.remove(&addr).is_none() { 284 - error!("Couldn't remove connection from set {addr}"); 285 - } 286 - }); 287 - 288 - let counter = state.metrics.active_connections.clone(); 289 - let handle = tokio::spawn(async move { 290 - let _guard = guard; 291 - let count = { 292 - counter.inc() + 1 293 - }; 294 - let protocol = if accpt.is_some() {" [TLS]"} else {""}; 295 - debug!("Connection from {:?}{}: {} active connections", &addr, protocol, count); 296 - match accpt { 297 - Some(accpt) => { 298 - match timeout(Duration::from_secs(10), accpt.accept(client)).await { 299 - Ok(r) => match r { 300 - Ok(s) => { 301 - handle_connection(&state, s).await; 302 - }, 303 - Err(err) => debug!("tls accept ({}): {}", &addr, err), 304 - }, 305 - Err(_) => { 306 - debug!("client {} didn't complete ssl handshake in time.", &addr); 307 - }, 308 - }; 309 - }, 310 - None => handle_connection(&state, client).await, 311 - } 312 - }); 313 - 314 - let mut guard = connections.lock().await; 315 - guard.insert(addr, handle); 316 - } 317 - } 318 - 319 - fn main() { 24 + #[tokio::main] 25 + async fn main() { 320 26 setup_logger(); 321 27 let matches = clap::Command::new("lumen") 322 28 .version(env!("CARGO_PKG_VERSION")) ··· 325 31 .arg( 326 32 Arg::new("config") 327 33 .short('c') 328 - .required(true) 329 34 .default_value("config.toml") 330 35 .help("Configuration file path") 331 36 ) 332 37 .get_matches(); 333 38 334 39 let config = { 335 - config::load_config(std::fs::File::open(matches.get_one::<String>("config").unwrap()).expect("failed to read config")) 40 + config::load_config( 41 + std::fs::File::open(matches.get_one::<String>("config").unwrap()) 42 + .expect("failed to read config"), 43 + ) 336 44 }; 337 45 let config = Arc::new(config); 338 46 339 - info!("starting private lumen server..."); 340 - 341 - let rt = match tokio::runtime::Builder::new_multi_thread() 342 - .enable_all() 343 - .build() { 344 - Ok(v) => v, 345 - Err(err) => { 346 - error!("failed to create tokio runtime: {}", err); 347 - exit(1); 348 - }, 349 - }; 350 - 351 - let db = rt.block_on(async { 352 - match Database::open(&config.database).await { 353 - Ok(v) => v, 354 - Err(err) => { 355 - error!("failed to open database: {}", err); 356 - exit(1); 357 - } 358 - } 359 - }); 360 - 361 - let server_name = config.lumina.server_name.clone().unwrap_or_else(|| String::from("lumen")); 362 - 363 - let state = Arc::new(SharedState_{ 364 - db, 365 - config, 366 - server_name, 367 - metrics: common::metrics::Metrics::default(), 368 - }); 369 - 370 - let tls_acceptor; 371 - 372 - if state.config.lumina.use_tls.unwrap_or_default() { 373 - let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; 374 - let mut crt = match std::fs::read(cert_path) { 375 - Ok(v) => v, 376 - Err(err) => { 377 - error!("failed to read certificate file: {}", err); 378 - exit(1); 379 - } 380 - }; 381 - let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); 382 - let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { 383 - Ok(v) => v, 384 - Err(err) => { 385 - error!("failed to parse tls certificate: {}", err); 386 - exit(1); 387 - } 388 - }; 389 - let _ = pkcs_passwd; 390 - crt.iter_mut().for_each(|v| *v = 0); 391 - let _ = crt; 392 - let mut accpt = native_tls::TlsAcceptor::builder(id); 393 - accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); 394 - let accpt = match accpt.build() { 395 - Ok(v) => v, 396 - Err(err) => { 397 - error!("failed to build tls acceptor: {}", err); 398 - exit(1); 399 - }, 400 - }; 401 - let accpt = tokio_native_tls::TlsAcceptor::from(accpt); 402 - tls_acceptor = Some(accpt); 403 - } else { 404 - tls_acceptor = None; 405 - } 406 - 407 - let web_handle = if let Some(ref webcfg) = state.config.api_server { 408 - let bind_addr = webcfg.bind_addr; 409 - let state = state.clone(); 410 - info!("starting http api server on {:?}", &bind_addr); 411 - Some(rt.spawn(async move { 412 - web::start_webserver(bind_addr, state).await; 413 - })) 414 - } else { 415 - None 416 - }; 417 - 418 - let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); 419 - 420 - let async_server = async move { 421 - let server = match TcpListener::bind(state.config.lumina.bind_addr).await { 422 - Ok(v) => v, 423 - Err(err) => { 424 - error!("failed to bind server port: {}", err); 425 - exit(1); 426 - }, 427 - }; 428 - 429 - info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); 430 - 431 - serve(server, tls_acceptor, state, exit_signal_rx).await; 432 - }; 433 - 434 - rt.block_on(async { 435 - let server_handle = tokio::task::spawn(async_server); 436 - tokio::signal::ctrl_c().await.unwrap(); 437 - debug!("CTRL-C; exiting..."); 438 - if let Some(handle) = web_handle { 439 - handle.abort(); 440 - } 441 - exit_signal_tx.send(()).unwrap(); 442 - server_handle.await.unwrap(); 443 - }); 444 - drop(rt); 445 - info!("Goodbye."); 47 + do_lumen(config).await; 446 48 }
+513
lumen/src/server.rs
··· 1 + use std::{ 2 + borrow::Cow, collections::HashMap, mem::discriminant, process::exit, sync::Arc, time::Instant, 3 + }; 4 + 5 + use common::{ 6 + async_drop::AsyncDropper, 7 + config::Config, 8 + db::Database, 9 + make_pretty_hex, md, 10 + metrics::LuminaVersion, 11 + rpc::{self, Error, HelloResult, RpcFail, RpcHello, RpcMessage}, 12 + SharedState, SharedState_, 13 + }; 14 + use log::{debug, error, info, trace, warn}; 15 + use native_tls::Identity; 16 + use tokio::{ 17 + io::{AsyncRead, AsyncWrite}, 18 + net::TcpListener, 19 + time::timeout, 20 + }; 21 + 22 + use crate::web; 23 + 24 + async fn handle_transaction<'a, S: AsyncRead + AsyncWrite + Unpin>( 25 + state: &SharedState, user: &'a RpcHello<'a>, mut stream: S, 26 + ) -> Result<(), Error> { 27 + let db = &state.db; 28 + let server_name = state.server_name.as_str(); 29 + 30 + trace!("waiting for command.."); 31 + let req = 32 + match timeout(state.config.limits.command_timeout, rpc::read_packet(&mut stream)).await { 33 + Ok(res) => match res { 34 + Ok(v) => v, 35 + Err(e) => return Err(e), 36 + }, 37 + Err(_) => { 38 + _ = RpcMessage::Fail(RpcFail { 39 + code: 0, 40 + message: &format!("{server_name} client idle for too long.\n"), 41 + }) 42 + .async_write(&mut stream) 43 + .await; 44 + return Err(Error::Timeout); 45 + }, 46 + }; 47 + trace!("got command!"); 48 + let req = match RpcMessage::deserialize(&req) { 49 + Ok(v) => v, 50 + Err(err) => { 51 + warn!("bad message: \n{}\n", make_pretty_hex(&req)); 52 + error!("failed to process rpc message: {}", err); 53 + let resp = rpc::RpcFail { 54 + code: 0, 55 + message: &format!("{server_name}: error: invalid data.\n"), 56 + }; 57 + let resp = RpcMessage::Fail(resp); 58 + resp.async_write(&mut stream).await?; 59 + 60 + return Ok(()); 61 + }, 62 + }; 63 + match req { 64 + RpcMessage::PullMetadata(md) => { 65 + let start = Instant::now(); 66 + let funcs = 67 + match timeout(state.config.limits.pull_md_timeout, db.get_funcs(&md.funcs)).await { 68 + Ok(r) => match r { 69 + Ok(v) => v, 70 + Err(e) => { 71 + error!("pull failed, db: {}", e); 72 + rpc::RpcMessage::Fail(rpc::RpcFail { 73 + code: 0, 74 + message: &format!( 75 + "{server_name}: db error; please try again later..\n" 76 + ), 77 + }) 78 + .async_write(&mut stream) 79 + .await?; 80 + return Ok(()); 81 + }, 82 + }, 83 + Err(_) => { 84 + RpcMessage::Fail(RpcFail { 85 + code: 0, 86 + message: &format!("{server_name}: query took too long to execute.\n"), 87 + }) 88 + .async_write(&mut stream) 89 + .await?; 90 + debug!("pull query timeout"); 91 + return Err(Error::Timeout); 92 + }, 93 + }; 94 + let pulled_funcs = funcs.iter().filter(|v| v.is_some()).count(); 95 + state.metrics.pulls.inc_by(pulled_funcs as _); 96 + state.metrics.queried_funcs.inc_by(md.funcs.len() as _); 97 + debug!( 98 + "pull {pulled_funcs}/{} funcs ended after {:?}", 99 + md.funcs.len(), 100 + start.elapsed() 101 + ); 102 + 103 + let statuses: Vec<u32> = funcs.iter().map(|v| u32::from(v.is_none())).collect(); 104 + let found = funcs 105 + .into_iter() 106 + .flatten() 107 + .map(|v| rpc::PullMetadataResultFunc { 108 + popularity: v.popularity, 109 + len: v.len, 110 + name: Cow::Owned(v.name), 111 + mb_data: Cow::Owned(v.data), 112 + }) 113 + .collect(); 114 + 115 + RpcMessage::PullMetadataResult(rpc::PullMetadataResult { 116 + unk0: Cow::Owned(statuses), 117 + funcs: Cow::Owned(found), 118 + }) 119 + .async_write(&mut stream) 120 + .await?; 121 + }, 122 + RpcMessage::PushMetadata(mds) => { 123 + // parse the function's metadata 124 + let start = Instant::now(); 125 + let scores: Vec<u32> = mds.funcs.iter().map(md::get_score).collect(); 126 + 127 + let status = match db.push_funcs(user, &mds, &scores).await { 128 + Ok(v) => v.into_iter().map(u32::from).collect::<Vec<u32>>(), 129 + Err(err) => { 130 + log::error!("push failed, db: {}", err); 131 + rpc::RpcMessage::Fail(rpc::RpcFail { 132 + code: 0, 133 + message: &format!("{server_name}: db error; please try again later.\n"), 134 + }) 135 + .async_write(&mut stream) 136 + .await?; 137 + return Ok(()); 138 + }, 139 + }; 140 + state.metrics.pushes.inc_by(status.len() as _); 141 + let new_funcs = 142 + status.iter().fold(0u64, |counter, &v| if v > 0 { counter + 1 } else { counter }); 143 + state.metrics.new_funcs.inc_by(new_funcs); 144 + debug!( 145 + "push {} funcs ended after {:?} ({new_funcs} new)", 146 + status.len(), 147 + start.elapsed() 148 + ); 149 + 150 + RpcMessage::PushMetadataResult(rpc::PushMetadataResult { status: Cow::Owned(status) }) 151 + .async_write(&mut stream) 152 + .await?; 153 + }, 154 + RpcMessage::DelHistory(req) => { 155 + let is_delete_allowed = state.config.lumina.allow_deletes.unwrap_or(false); 156 + if !is_delete_allowed { 157 + RpcMessage::Fail(rpc::RpcFail { 158 + code: 2, 159 + message: &format!("{server_name}: Delete command is disabled on this server."), 160 + }) 161 + .async_write(&mut stream) 162 + .await?; 163 + } else { 164 + if let Err(err) = db.delete_metadata(&req).await { 165 + error!("delete failed. db: {err}"); 166 + RpcMessage::Fail(rpc::RpcFail { 167 + code: 3, 168 + message: &format!("{server_name}: db error, please try again later."), 169 + }) 170 + .async_write(&mut stream) 171 + .await?; 172 + return Ok(()); 173 + } 174 + RpcMessage::DelHistoryResult(rpc::DelHistoryResult { 175 + deleted_mds: req.funcs.len() as u32, 176 + }) 177 + .async_write(&mut stream) 178 + .await?; 179 + } 180 + }, 181 + RpcMessage::GetFuncHistories(req) => { 182 + let limit = state.config.lumina.get_history_limit.unwrap_or(0); 183 + 184 + if limit == 0 { 185 + RpcMessage::Fail(rpc::RpcFail { 186 + code: 4, 187 + message: &format!( 188 + "{server_name}: function histories are disabled on this server." 189 + ), 190 + }) 191 + .async_write(&mut stream) 192 + .await?; 193 + return Ok(()); 194 + } 195 + 196 + let mut statuses = vec![]; 197 + let mut res = vec![]; 198 + for chksum in req.funcs.iter().map(|v| v.mb_hash) { 199 + let history = match db.get_func_histories(chksum, limit).await { 200 + Ok(v) => v, 201 + Err(err) => { 202 + error!("failed to get function histories: {err:?}"); 203 + RpcMessage::Fail(rpc::RpcFail { 204 + code: 3, 205 + message: &format!("{server_name}: db error, please try again later."), 206 + }) 207 + .async_write(&mut stream) 208 + .await?; 209 + return Ok(()); 210 + }, 211 + }; 212 + let status = !history.is_empty() as u32; 213 + statuses.push(status); 214 + if history.is_empty() { 215 + continue; 216 + } 217 + let log = history 218 + .into_iter() 219 + .map(|(updated, name, metadata)| rpc::FunctionHistory { 220 + unk0: 0, 221 + unk1: 0, 222 + name: Cow::Owned(name), 223 + metadata: Cow::Owned(metadata), 224 + timestamp: updated.unix_timestamp() as u64, 225 + author_idx: 0, 226 + idb_path_idx: 0, 227 + }) 228 + .collect::<Vec<_>>(); 229 + res.push(rpc::FunctionHistories { log: Cow::Owned(log) }); 230 + } 231 + 232 + trace!("returning {} histories", res.len()); 233 + 234 + RpcMessage::GetFuncHistoriesResult(rpc::GetFuncHistoriesResult { 235 + status: statuses.into(), 236 + funcs: Cow::Owned(res), 237 + users: vec![].into(), 238 + dbs: vec![].into(), 239 + }) 240 + .async_write(&mut stream) 241 + .await?; 242 + }, 243 + _ => { 244 + RpcMessage::Fail(rpc::RpcFail { 245 + code: 0, 246 + message: &format!("{server_name}: invalid data.\n"), 247 + }) 248 + .async_write(&mut stream) 249 + .await?; 250 + }, 251 + } 252 + Ok(()) 253 + } 254 + 255 + async fn handle_client<S: AsyncRead + AsyncWrite + Unpin>( 256 + state: &SharedState, mut stream: S, 257 + ) -> Result<(), rpc::Error> { 258 + let server_name = &state.server_name; 259 + let hello = 260 + match timeout(state.config.limits.hello_timeout, rpc::read_packet(&mut stream)).await { 261 + Ok(v) => v?, 262 + Err(_) => { 263 + debug!("didn't get hello in time."); 264 + return Ok(()); 265 + }, 266 + }; 267 + 268 + let (hello, creds) = match RpcMessage::deserialize(&hello) { 269 + Ok(RpcMessage::Hello(v, creds)) => { 270 + debug!("hello protocol={}, login creds: {creds:?}", v.protocol_version); 271 + (v, creds) 272 + }, 273 + _ => { 274 + // send error 275 + error!("got bad hello message"); 276 + 277 + let resp = rpc::RpcFail { code: 0, message: &format!("{server_name}: bad sequence.") }; 278 + let resp = rpc::RpcMessage::Fail(resp); 279 + resp.async_write(&mut stream).await?; 280 + 281 + return Ok(()); 282 + }, 283 + }; 284 + state 285 + .metrics 286 + .lumina_version 287 + .get_or_create(&LuminaVersion { protocol_version: hello.protocol_version }) 288 + .inc(); 289 + 290 + if let Some(ref creds) = creds { 291 + if creds.username != "guest" { 292 + // Only allow "guest" to connect for now. 293 + rpc::RpcMessage::Fail(rpc::RpcFail { 294 + code: 1, 295 + message: &format!("{server_name}: invalid username or password. Try logging in with `guest` instead."), 296 + }).async_write(&mut stream).await?; 297 + return Ok(()); 298 + } 299 + } 300 + 301 + let resp = match hello.protocol_version { 302 + 0..=4 => rpc::RpcMessage::Ok(()), 303 + 304 + // starting IDA 8.3 305 + 5.. => { 306 + let mut features = 0; 307 + 308 + if state.config.lumina.allow_deletes.unwrap_or(false) { 309 + features |= 0x02; 310 + } 311 + 312 + rpc::RpcMessage::HelloResult(HelloResult { features, ..Default::default() }) 313 + }, 314 + }; 315 + resp.async_write(&mut stream).await?; 316 + 317 + loop { 318 + handle_transaction(state, &hello, &mut stream).await?; 319 + } 320 + } 321 + 322 + async fn handle_connection<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, s: S) { 323 + if let Err(err) = handle_client(state, s).await { 324 + if discriminant(&err) != discriminant(&Error::Eof) { 325 + warn!("err: {}", err); 326 + } 327 + } 328 + } 329 + 330 + async fn serve( 331 + listener: TcpListener, accpt: Option<tokio_native_tls::TlsAcceptor>, state: SharedState, 332 + mut shutdown_signal: tokio::sync::oneshot::Receiver<()>, 333 + ) { 334 + let accpt = accpt.map(Arc::new); 335 + 336 + let (async_drop, worker) = AsyncDropper::new(); 337 + tokio::task::spawn(worker); 338 + 339 + let connections = Arc::new(tokio::sync::Mutex::new(HashMap::< 340 + std::net::SocketAddr, 341 + tokio::task::JoinHandle<()>, 342 + >::new())); 343 + 344 + loop { 345 + let (client, addr) = tokio::select! { 346 + _ = &mut shutdown_signal => { 347 + drop(state); 348 + info!("shutting down..."); 349 + let m = connections.lock().await; 350 + m.iter().for_each(|(k, v)| { 351 + debug!("aborting task for {k}..."); 352 + v.abort(); 353 + }); 354 + return; 355 + }, 356 + res = listener.accept() => match res { 357 + Ok(v) => v, 358 + Err(err) => { 359 + warn!("failed to accept(): {}", err); 360 + continue; 361 + } 362 + }, 363 + }; 364 + 365 + let start = Instant::now(); 366 + 367 + let state = state.clone(); 368 + let accpt = accpt.clone(); 369 + 370 + let conns2 = connections.clone(); 371 + let counter = state.metrics.active_connections.clone(); 372 + let guard = async_drop.defer(async move { 373 + let count = counter.dec() - 1; 374 + debug!( 375 + "connection with {:?} ended after {:?}; {} active connections", 376 + addr, 377 + start.elapsed(), 378 + count 379 + ); 380 + 381 + let mut guard = conns2.lock().await; 382 + if guard.remove(&addr).is_none() { 383 + error!("Couldn't remove connection from set {addr}"); 384 + } 385 + }); 386 + 387 + let counter = state.metrics.active_connections.clone(); 388 + let handle = tokio::spawn(async move { 389 + let _guard = guard; 390 + let count = { counter.inc() + 1 }; 391 + let protocol = if accpt.is_some() { " [TLS]" } else { "" }; 392 + debug!("Connection from {:?}{}: {} active connections", &addr, protocol, count); 393 + match accpt { 394 + Some(accpt) => { 395 + match timeout(state.config.limits.tls_handshake_timeout, accpt.accept(client)) 396 + .await 397 + { 398 + Ok(r) => match r { 399 + Ok(s) => { 400 + handle_connection(&state, s).await; 401 + }, 402 + Err(err) => debug!("tls accept ({}): {}", &addr, err), 403 + }, 404 + Err(_) => { 405 + debug!("client {} didn't complete ssl handshake in time.", &addr); 406 + }, 407 + }; 408 + }, 409 + None => handle_connection(&state, client).await, 410 + } 411 + }); 412 + 413 + let mut guard = connections.lock().await; 414 + guard.insert(addr, handle); 415 + } 416 + } 417 + 418 + pub(crate) async fn do_lumen(config: Arc<Config>) { 419 + info!("starting private lumen server..."); 420 + 421 + let db = match Database::open(&config.database).await { 422 + Ok(v) => v, 423 + Err(err) => { 424 + error!("failed to open database: {}", err); 425 + exit(1); 426 + }, 427 + }; 428 + 429 + let server_name = config.lumina.server_name.clone().unwrap_or_else(|| String::from("lumen")); 430 + 431 + let state = Arc::new(SharedState_ { 432 + db, 433 + config, 434 + server_name, 435 + metrics: common::metrics::Metrics::default(), 436 + }); 437 + 438 + let tls_acceptor; 439 + 440 + if state.config.lumina.use_tls.unwrap_or_default() { 441 + let cert_path = 442 + &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; 443 + let mut crt = match std::fs::read(cert_path) { 444 + Ok(v) => v, 445 + Err(err) => { 446 + error!("failed to read certificate file: {}", err); 447 + exit(1); 448 + }, 449 + }; 450 + let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); 451 + let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { 452 + Ok(v) => v, 453 + Err(err) => { 454 + error!("failed to parse tls certificate: {}", err); 455 + exit(1); 456 + }, 457 + }; 458 + let _ = pkcs_passwd; 459 + crt.iter_mut().for_each(|v| *v = 0); 460 + let _ = crt; 461 + let mut accpt = native_tls::TlsAcceptor::builder(id); 462 + accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); 463 + let accpt = match accpt.build() { 464 + Ok(v) => v, 465 + Err(err) => { 466 + error!("failed to build tls acceptor: {}", err); 467 + exit(1); 468 + }, 469 + }; 470 + let accpt = tokio_native_tls::TlsAcceptor::from(accpt); 471 + tls_acceptor = Some(accpt); 472 + } else { 473 + tls_acceptor = None; 474 + } 475 + 476 + let web_handle = if let Some(ref webcfg) = state.config.api_server { 477 + let bind_addr = webcfg.bind_addr; 478 + let state = state.clone(); 479 + info!("starting http api server on {:?}", &bind_addr); 480 + Some(tokio::spawn(async move { 481 + web::start_webserver(bind_addr, state).await; 482 + })) 483 + } else { 484 + None 485 + }; 486 + 487 + let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); 488 + 489 + let async_server = async move { 490 + let server = match TcpListener::bind(state.config.lumina.bind_addr).await { 491 + Ok(v) => v, 492 + Err(err) => { 493 + error!("failed to bind server port: {}", err); 494 + exit(1); 495 + }, 496 + }; 497 + 498 + info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); 499 + 500 + serve(server, tls_acceptor, state, exit_signal_rx).await; 501 + }; 502 + 503 + let server_handle = tokio::task::spawn(async_server); 504 + tokio::signal::ctrl_c().await.unwrap(); 505 + debug!("CTRL-C; exiting..."); 506 + if let Some(handle) = web_handle { 507 + handle.abort(); 508 + } 509 + exit_signal_tx.send(()).unwrap(); 510 + server_handle.await.unwrap(); 511 + 512 + info!("Goodbye."); 513 + }
+33 -35
lumen/src/web.rs
··· 1 - use std::net::SocketAddr; 2 - 3 - use log::error; 4 - use warp::{Filter, hyper::StatusCode, reply::Response}; 5 - use common::{SharedState, web::api::api_root}; 6 - 7 - pub async fn start_webserver<A: Into<SocketAddr> + 'static>(bind_addr: A, shared_state: SharedState) { 8 - let root = warp::get() 9 - .and(warp::path::end()) 10 - .map(|| warp::reply::html(include_str!("home.html"))); 11 - 12 - let shared_state1 = shared_state.clone(); 13 - let api = warp::path("api") 14 - .and(api_root(shared_state1)); 15 - 16 - let metrics = warp::get().and(warp::path("metrics")).and(warp::path::end()) 17 - .map(move || { 18 - let mut res = String::new(); 19 - if let Err(err) = prometheus_client::encoding::text::encode(&mut res, &shared_state.metrics.registry) { 20 - error!("failed to encode metrics: {err}"); 21 - let mut r = Response::default(); 22 - *r.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; 23 - r 24 - } else { 25 - warp::reply::Response::new(res.into()) 26 - } 27 - }); 28 - 29 - let routes = root 30 - .or(api) 31 - .or(metrics); 32 - 33 - warp::serve(routes) 34 - .run(bind_addr).await; 35 - } 1 + use std::net::SocketAddr; 2 + 3 + use common::{web::api::api_root, SharedState}; 4 + use log::error; 5 + use warp::{hyper::StatusCode, reply::Response, Filter}; 6 + 7 + pub async fn start_webserver<A: Into<SocketAddr> + 'static>( 8 + bind_addr: A, shared_state: SharedState, 9 + ) { 10 + let root = 11 + warp::get().and(warp::path::end()).map(|| warp::reply::html(include_str!("home.html"))); 12 + 13 + let shared_state1 = shared_state.clone(); 14 + let api = warp::path("api").and(api_root(shared_state1)); 15 + 16 + let metrics = warp::get().and(warp::path("metrics")).and(warp::path::end()).map(move || { 17 + let mut res = String::new(); 18 + if let Err(err) = 19 + prometheus_client::encoding::text::encode(&mut res, &shared_state.metrics.registry) 20 + { 21 + error!("failed to encode metrics: {err}"); 22 + let mut r = Response::default(); 23 + *r.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; 24 + r 25 + } else { 26 + warp::reply::Response::new(res.into()) 27 + } 28 + }); 29 + 30 + let routes = root.or(api).or(metrics); 31 + 32 + warp::serve(routes).run(bind_addr).await; 33 + }
+5
rustfmt.toml
··· 1 + edition = "2021" 2 + fn_params_layout = "Compressed" 3 + match_block_trailing_comma = true 4 + newline_style = "Unix" 5 + use_small_heuristics = "Max"