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
+26 -3
CHANGELOG.md
··· 2 2 3 3 ## [Unreleased] - _TBD_ 4 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 + 5 20 ## [v0.3.0] - 2023-08-22 21 + 6 22 ### Added 23 + 7 24 - This changelog. 8 25 - Support for IDA 8.1+ delete command. 9 26 - Pooling for connections to database. ··· 13 30 - Add Metrics for prometheus. 14 31 15 32 ### Fixed 33 + 16 34 - 8K stack size is too small for debug builds. 17 35 18 36 ## [v0.2.0] - 2022-10-12 37 + 19 38 ### Added 39 + 20 40 - Protocol: support for IDA 8.1+ user authentication. 21 41 - Client connection duration limitations. 42 + 22 43 ### Changed 44 + 23 45 - Tokio's thread size is reduced from 4M to 8K. 24 46 25 - ## [v0.1.0] - 2021-01-21 47 + ## [v0.1.0] - 2021-01-21 48 + 26 49 This is Lumen's first tagged release. It contains a few fixes and dependency updates since the initial commit (2020-12-17). 27 50 28 - 29 - [Unreleased]: https://github.com/naim94a/lumen/compare/v0.3.0...HEAD 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 30 53 [v0.3.0]: https://github.com/naim94a/lumen/compare/v0.2.0...v0.3.0 31 54 [v0.2.0]: https://github.com/naim94a/lumen/compare/v0.1.0...v0.2.0 32 55 [v0.1.0]: https://github.com/naim94a/lumen/releases/tag/v0.1.0
+930 -494
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.20.0" 7 + version = "0.24.2" 8 8 source = "registry+https://github.com/rust-lang/crates.io-index" 9 - checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 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.0.4" 22 + version = "1.1.3" 23 23 source = "registry+https://github.com/rust-lang/crates.io-index" 24 - checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" 24 + checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 25 dependencies = [ 26 26 "memchr", 27 27 ] 28 28 29 29 [[package]] 30 30 name = "anstream" 31 - version = "0.3.2" 31 + version = "0.6.19" 32 32 source = "registry+https://github.com/rust-lang/crates.io-index" 33 - checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" 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", 40 + "is_terminal_polyfill", 41 41 "utf8parse", 42 42 ] 43 43 44 44 [[package]] 45 45 name = "anstyle" 46 - version = "1.0.1" 46 + version = "1.0.11" 47 47 source = "registry+https://github.com/rust-lang/crates.io-index" 48 - checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" 48 + checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 49 49 50 50 [[package]] 51 51 name = "anstyle-parse" 52 - version = "0.2.1" 52 + version = "0.2.7" 53 53 source = "registry+https://github.com/rust-lang/crates.io-index" 54 - checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" 54 + checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 55 55 dependencies = [ 56 56 "utf8parse", 57 57 ] 58 58 59 59 [[package]] 60 60 name = "anstyle-query" 61 - version = "1.0.0" 61 + version = "1.1.3" 62 62 source = "registry+https://github.com/rust-lang/crates.io-index" 63 - checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" 63 + checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 64 64 dependencies = [ 65 - "windows-sys", 65 + "windows-sys 0.59.0", 66 66 ] 67 67 68 68 [[package]] 69 69 name = "anstyle-wincon" 70 - version = "1.0.2" 70 + version = "3.0.9" 71 71 source = "registry+https://github.com/rust-lang/crates.io-index" 72 - checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" 72 + checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 73 73 dependencies = [ 74 74 "anstyle", 75 - "windows-sys", 75 + "once_cell_polyfill", 76 + "windows-sys 0.59.0", 76 77 ] 77 78 78 79 [[package]] 79 80 name = "anyhow" 80 - version = "1.0.75" 81 + version = "1.0.98" 81 82 source = "registry+https://github.com/rust-lang/crates.io-index" 82 - checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 83 + checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 83 84 84 85 [[package]] 85 86 name = "async-trait" 86 - version = "0.1.73" 87 + version = "0.1.88" 87 88 source = "registry+https://github.com/rust-lang/crates.io-index" 88 - checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" 89 + checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 89 90 dependencies = [ 90 91 "proc-macro2", 91 92 "quote", ··· 94 95 95 96 [[package]] 96 97 name = "autocfg" 97 - version = "1.1.0" 98 + version = "1.4.0" 98 99 source = "registry+https://github.com/rust-lang/crates.io-index" 99 - checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 100 + checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 100 101 101 102 [[package]] 102 103 name = "backtrace" 103 - version = "0.3.68" 104 + version = "0.3.75" 104 105 source = "registry+https://github.com/rust-lang/crates.io-index" 105 - checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 106 + checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 106 107 dependencies = [ 107 108 "addr2line", 108 - "cc", 109 109 "cfg-if", 110 110 "libc", 111 111 "miniz_oxide", 112 112 "object", 113 113 "rustc-demangle", 114 + "windows-targets", 114 115 ] 115 116 116 117 [[package]] 117 118 name = "base64" 118 - version = "0.13.1" 119 + version = "0.21.7" 119 120 source = "registry+https://github.com/rust-lang/crates.io-index" 120 - checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 121 + checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 121 122 122 123 [[package]] 123 124 name = "base64" 124 - version = "0.21.2" 125 + version = "0.22.1" 125 126 source = "registry+https://github.com/rust-lang/crates.io-index" 126 - checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" 127 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 127 128 128 129 [[package]] 129 130 name = "bb8" 130 - version = "0.8.1" 131 + version = "0.8.6" 131 132 source = "registry+https://github.com/rust-lang/crates.io-index" 132 - checksum = "98b4b0f25f18bcdc3ac72bdb486ed0acf7e185221fd4dc985bc15db5800b0ba2" 133 + checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" 133 134 dependencies = [ 134 135 "async-trait", 135 - "futures-channel", 136 136 "futures-util", 137 137 "parking_lot", 138 138 "tokio", ··· 146 146 147 147 [[package]] 148 148 name = "bitflags" 149 - version = "1.3.2" 150 - source = "registry+https://github.com/rust-lang/crates.io-index" 151 - checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 152 - 153 - [[package]] 154 - name = "bitflags" 155 - version = "2.4.0" 149 + version = "2.9.1" 156 150 source = "registry+https://github.com/rust-lang/crates.io-index" 157 - checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" 151 + checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 158 152 159 153 [[package]] 160 154 name = "block-buffer" ··· 166 160 ] 167 161 168 162 [[package]] 163 + name = "bumpalo" 164 + version = "3.18.1" 165 + source = "registry+https://github.com/rust-lang/crates.io-index" 166 + checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" 167 + 168 + [[package]] 169 169 name = "byteorder" 170 - version = "1.4.3" 170 + version = "1.5.0" 171 171 source = "registry+https://github.com/rust-lang/crates.io-index" 172 - checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 172 + checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 173 173 174 174 [[package]] 175 175 name = "bytes" 176 - version = "1.4.0" 176 + version = "1.10.1" 177 177 source = "registry+https://github.com/rust-lang/crates.io-index" 178 - checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 178 + checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 179 179 180 180 [[package]] 181 181 name = "cc" 182 - version = "1.0.82" 182 + version = "1.2.26" 183 183 source = "registry+https://github.com/rust-lang/crates.io-index" 184 - checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" 184 + checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" 185 185 dependencies = [ 186 - "libc", 186 + "shlex", 187 187 ] 188 188 189 189 [[package]] ··· 194 194 195 195 [[package]] 196 196 name = "clap" 197 - version = "4.3.22" 197 + version = "4.5.39" 198 198 source = "registry+https://github.com/rust-lang/crates.io-index" 199 - checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" 199 + checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" 200 200 dependencies = [ 201 201 "clap_builder", 202 202 ] 203 203 204 204 [[package]] 205 205 name = "clap_builder" 206 - version = "4.3.22" 206 + version = "4.5.39" 207 207 source = "registry+https://github.com/rust-lang/crates.io-index" 208 - checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" 208 + checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" 209 209 dependencies = [ 210 210 "anstream", 211 211 "anstyle", ··· 215 215 216 216 [[package]] 217 217 name = "clap_lex" 218 - version = "0.5.0" 218 + version = "0.7.4" 219 219 source = "registry+https://github.com/rust-lang/crates.io-index" 220 - checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 220 + checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 221 221 222 222 [[package]] 223 223 name = "colorchoice" 224 - version = "1.0.0" 224 + version = "1.0.4" 225 225 source = "registry+https://github.com/rust-lang/crates.io-index" 226 - checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 226 + checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 227 227 228 228 [[package]] 229 229 name = "common" ··· 239 239 "postgres-native-tls", 240 240 "prometheus-client", 241 241 "serde", 242 + "time", 242 243 "tokio", 243 244 "tokio-postgres", 244 245 "toml", ··· 247 248 248 249 [[package]] 249 250 name = "core-foundation" 250 - version = "0.9.3" 251 + version = "0.9.4" 251 252 source = "registry+https://github.com/rust-lang/crates.io-index" 252 - checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 253 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 253 254 dependencies = [ 254 255 "core-foundation-sys", 255 256 "libc", ··· 257 258 258 259 [[package]] 259 260 name = "core-foundation-sys" 260 - version = "0.8.4" 261 + version = "0.8.7" 261 262 source = "registry+https://github.com/rust-lang/crates.io-index" 262 - checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" 263 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 263 264 264 265 [[package]] 265 266 name = "cpufeatures" 266 - version = "0.2.9" 267 + version = "0.2.17" 267 268 source = "registry+https://github.com/rust-lang/crates.io-index" 268 - checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 269 + checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 269 270 dependencies = [ 270 271 "libc", 271 272 ] ··· 281 282 ] 282 283 283 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]] 320 + name = "data-encoding" 321 + version = "2.9.0" 322 + source = "registry+https://github.com/rust-lang/crates.io-index" 323 + checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 324 + 325 + [[package]] 284 326 name = "deranged" 285 - version = "0.3.7" 327 + version = "0.4.0" 286 328 source = "registry+https://github.com/rust-lang/crates.io-index" 287 - checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" 329 + checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 330 + dependencies = [ 331 + "powerfmt", 332 + ] 288 333 289 334 [[package]] 290 335 name = "diesel" 291 - version = "2.1.0" 336 + version = "2.2.10" 292 337 source = "registry+https://github.com/rust-lang/crates.io-index" 293 - checksum = "f7a532c1f99a0f596f6960a60d1e119e91582b24b39e2d83a190e61262c3ef0c" 338 + checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506" 294 339 dependencies = [ 295 - "bitflags 2.4.0", 340 + "bitflags", 296 341 "byteorder", 297 342 "diesel_derives", 298 343 "itoa", ··· 301 346 302 347 [[package]] 303 348 name = "diesel-async" 304 - version = "0.3.2" 349 + version = "0.5.2" 305 350 source = "registry+https://github.com/rust-lang/crates.io-index" 306 - checksum = "c7e7974099f0d9bde0e010dd3a673555276a474f3362a7a52ab535a57b7c5056" 351 + checksum = "51a307ac00f7c23f526a04a77761a0519b9f0eb2838ebf5b905a58580095bdcb" 307 352 dependencies = [ 308 353 "async-trait", 309 354 "bb8", ··· 316 361 317 362 [[package]] 318 363 name = "diesel_derives" 319 - version = "2.1.0" 364 + version = "2.2.5" 320 365 source = "registry+https://github.com/rust-lang/crates.io-index" 321 - checksum = "74398b79d81e52e130d991afeed9c86034bb1b7735f46d2f5bf7deb261d80303" 366 + checksum = "68d4216021b3ea446fd2047f5c8f8fe6e98af34508a254a01e4d6bc1e844f84d" 322 367 dependencies = [ 323 368 "diesel_table_macro_syntax", 369 + "dsl_auto_type", 324 370 "proc-macro2", 325 371 "quote", 326 372 "syn", ··· 328 374 329 375 [[package]] 330 376 name = "diesel_table_macro_syntax" 331 - version = "0.1.0" 377 + version = "0.2.0" 332 378 source = "registry+https://github.com/rust-lang/crates.io-index" 333 - checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" 379 + checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" 334 380 dependencies = [ 335 381 "syn", 336 382 ] ··· 347 393 ] 348 394 349 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]] 350 421 name = "dtoa" 351 - version = "1.0.9" 422 + version = "1.0.10" 352 423 source = "registry+https://github.com/rust-lang/crates.io-index" 353 - 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" 354 431 355 432 [[package]] 356 433 name = "encoding_rs" 357 - version = "0.8.32" 434 + version = "0.8.35" 358 435 source = "registry+https://github.com/rust-lang/crates.io-index" 359 - checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" 436 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 360 437 dependencies = [ 361 438 "cfg-if", 362 439 ] 363 440 364 441 [[package]] 365 442 name = "env_logger" 366 - version = "0.10.0" 443 + version = "0.10.2" 367 444 source = "registry+https://github.com/rust-lang/crates.io-index" 368 - checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" 445 + checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" 369 446 dependencies = [ 370 447 "humantime", 371 448 "is-terminal", ··· 376 453 377 454 [[package]] 378 455 name = "equivalent" 379 - version = "1.0.1" 456 + version = "1.0.2" 380 457 source = "registry+https://github.com/rust-lang/crates.io-index" 381 - checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 458 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 382 459 383 460 [[package]] 384 461 name = "errno" 385 - version = "0.3.2" 386 - source = "registry+https://github.com/rust-lang/crates.io-index" 387 - checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" 388 - dependencies = [ 389 - "errno-dragonfly", 390 - "libc", 391 - "windows-sys", 392 - ] 393 - 394 - [[package]] 395 - name = "errno-dragonfly" 396 - version = "0.1.2" 462 + version = "0.3.12" 397 463 source = "registry+https://github.com/rust-lang/crates.io-index" 398 - checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 464 + checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" 399 465 dependencies = [ 400 - "cc", 401 466 "libc", 467 + "windows-sys 0.59.0", 402 468 ] 403 469 404 470 [[package]] ··· 409 475 410 476 [[package]] 411 477 name = "fastrand" 412 - version = "2.0.0" 478 + version = "2.3.0" 413 479 source = "registry+https://github.com/rust-lang/crates.io-index" 414 - checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" 480 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 415 481 416 482 [[package]] 417 483 name = "fnv" ··· 436 502 437 503 [[package]] 438 504 name = "form_urlencoded" 439 - version = "1.2.0" 505 + version = "1.2.1" 440 506 source = "registry+https://github.com/rust-lang/crates.io-index" 441 - checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 507 + checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 442 508 dependencies = [ 443 509 "percent-encoding", 444 510 ] 445 511 446 512 [[package]] 447 - name = "futures" 448 - version = "0.3.28" 449 - source = "registry+https://github.com/rust-lang/crates.io-index" 450 - checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 451 - dependencies = [ 452 - "futures-channel", 453 - "futures-core", 454 - "futures-executor", 455 - "futures-io", 456 - "futures-sink", 457 - "futures-task", 458 - "futures-util", 459 - ] 460 - 461 - [[package]] 462 513 name = "futures-channel" 463 - version = "0.3.28" 514 + version = "0.3.31" 464 515 source = "registry+https://github.com/rust-lang/crates.io-index" 465 - checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 516 + checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 466 517 dependencies = [ 467 518 "futures-core", 468 519 "futures-sink", ··· 470 521 471 522 [[package]] 472 523 name = "futures-core" 473 - version = "0.3.28" 474 - source = "registry+https://github.com/rust-lang/crates.io-index" 475 - checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 476 - 477 - [[package]] 478 - name = "futures-executor" 479 - version = "0.3.28" 480 - source = "registry+https://github.com/rust-lang/crates.io-index" 481 - checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 482 - dependencies = [ 483 - "futures-core", 484 - "futures-task", 485 - "futures-util", 486 - ] 487 - 488 - [[package]] 489 - name = "futures-io" 490 - version = "0.3.28" 524 + version = "0.3.31" 491 525 source = "registry+https://github.com/rust-lang/crates.io-index" 492 - checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 526 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 493 527 494 528 [[package]] 495 529 name = "futures-macro" 496 - version = "0.3.28" 530 + version = "0.3.31" 497 531 source = "registry+https://github.com/rust-lang/crates.io-index" 498 - checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 532 + checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 499 533 dependencies = [ 500 534 "proc-macro2", 501 535 "quote", ··· 504 538 505 539 [[package]] 506 540 name = "futures-sink" 507 - version = "0.3.28" 541 + version = "0.3.31" 508 542 source = "registry+https://github.com/rust-lang/crates.io-index" 509 - checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 543 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 510 544 511 545 [[package]] 512 546 name = "futures-task" 513 - version = "0.3.28" 547 + version = "0.3.31" 514 548 source = "registry+https://github.com/rust-lang/crates.io-index" 515 - checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 549 + checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 516 550 517 551 [[package]] 518 552 name = "futures-util" 519 - version = "0.3.28" 553 + version = "0.3.31" 520 554 source = "registry+https://github.com/rust-lang/crates.io-index" 521 - checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 555 + checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 522 556 dependencies = [ 523 - "futures-channel", 524 557 "futures-core", 525 - "futures-io", 526 558 "futures-macro", 527 559 "futures-sink", 528 560 "futures-task", 529 - "memchr", 530 561 "pin-project-lite", 531 562 "pin-utils", 532 563 "slab", ··· 544 575 545 576 [[package]] 546 577 name = "getrandom" 547 - version = "0.2.10" 578 + version = "0.2.16" 548 579 source = "registry+https://github.com/rust-lang/crates.io-index" 549 - checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 580 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 550 581 dependencies = [ 551 582 "cfg-if", 552 583 "libc", 553 - "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", 554 597 ] 555 598 556 599 [[package]] 557 600 name = "gimli" 558 - version = "0.27.3" 601 + version = "0.31.1" 559 602 source = "registry+https://github.com/rust-lang/crates.io-index" 560 - checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 603 + checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 561 604 562 605 [[package]] 563 606 name = "h2" 564 - version = "0.3.20" 607 + version = "0.3.26" 565 608 source = "registry+https://github.com/rust-lang/crates.io-index" 566 - checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" 609 + checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 567 610 dependencies = [ 568 611 "bytes", 569 612 "fnv", 570 613 "futures-core", 571 614 "futures-sink", 572 615 "futures-util", 573 - "http", 574 - "indexmap 1.9.3", 616 + "http 0.2.12", 617 + "indexmap", 575 618 "slab", 576 619 "tokio", 577 620 "tokio-util", ··· 580 623 581 624 [[package]] 582 625 name = "hashbrown" 583 - version = "0.12.3" 626 + version = "0.15.4" 584 627 source = "registry+https://github.com/rust-lang/crates.io-index" 585 - checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 586 - 587 - [[package]] 588 - name = "hashbrown" 589 - version = "0.14.0" 590 - source = "registry+https://github.com/rust-lang/crates.io-index" 591 - checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 628 + checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" 592 629 593 630 [[package]] 594 631 name = "headers" 595 - version = "0.3.8" 632 + version = "0.3.9" 596 633 source = "registry+https://github.com/rust-lang/crates.io-index" 597 - checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" 634 + checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" 598 635 dependencies = [ 599 - "base64 0.13.1", 600 - "bitflags 1.3.2", 636 + "base64 0.21.7", 601 637 "bytes", 602 638 "headers-core", 603 - "http", 639 + "http 0.2.12", 604 640 "httpdate", 605 641 "mime", 606 642 "sha1", ··· 612 648 source = "registry+https://github.com/rust-lang/crates.io-index" 613 649 checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 614 650 dependencies = [ 615 - "http", 651 + "http 0.2.12", 616 652 ] 617 653 618 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]] 619 661 name = "hermit-abi" 620 - version = "0.3.2" 662 + version = "0.5.1" 621 663 source = "registry+https://github.com/rust-lang/crates.io-index" 622 - checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 664 + checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" 623 665 624 666 [[package]] 625 667 name = "hmac" ··· 632 674 633 675 [[package]] 634 676 name = "http" 635 - version = "0.2.9" 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" 636 689 source = "registry+https://github.com/rust-lang/crates.io-index" 637 - checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 690 + checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 638 691 dependencies = [ 639 692 "bytes", 640 693 "fnv", ··· 643 696 644 697 [[package]] 645 698 name = "http-body" 646 - version = "0.4.5" 699 + version = "0.4.6" 647 700 source = "registry+https://github.com/rust-lang/crates.io-index" 648 - checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 701 + checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 649 702 dependencies = [ 650 703 "bytes", 651 - "http", 704 + "http 0.2.12", 652 705 "pin-project-lite", 653 706 ] 654 707 655 708 [[package]] 656 709 name = "httparse" 657 - version = "1.8.0" 710 + version = "1.10.1" 658 711 source = "registry+https://github.com/rust-lang/crates.io-index" 659 - checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 712 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 660 713 661 714 [[package]] 662 715 name = "httpdate" ··· 666 719 667 720 [[package]] 668 721 name = "humantime" 669 - version = "2.1.0" 722 + version = "2.2.0" 670 723 source = "registry+https://github.com/rust-lang/crates.io-index" 671 - checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 724 + checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" 672 725 673 726 [[package]] 674 727 name = "hyper" 675 - version = "0.14.27" 728 + version = "0.14.32" 676 729 source = "registry+https://github.com/rust-lang/crates.io-index" 677 - checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 730 + checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 678 731 dependencies = [ 679 732 "bytes", 680 733 "futures-channel", 681 734 "futures-core", 682 735 "futures-util", 683 736 "h2", 684 - "http", 737 + "http 0.2.12", 685 738 "http-body", 686 739 "httparse", 687 740 "httpdate", 688 741 "itoa", 689 742 "pin-project-lite", 690 - "socket2 0.4.9", 743 + "socket2", 691 744 "tokio", 692 745 "tower-service", 693 746 "tracing", ··· 695 748 ] 696 749 697 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]] 698 843 name = "idna" 699 - version = "0.4.0" 844 + version = "1.0.3" 700 845 source = "registry+https://github.com/rust-lang/crates.io-index" 701 - checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 846 + checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 702 847 dependencies = [ 703 - "unicode-bidi", 704 - "unicode-normalization", 848 + "idna_adapter", 849 + "smallvec", 850 + "utf8_iter", 705 851 ] 706 852 707 853 [[package]] 708 - name = "indexmap" 709 - version = "1.9.3" 854 + name = "idna_adapter" 855 + version = "1.2.1" 710 856 source = "registry+https://github.com/rust-lang/crates.io-index" 711 - checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 857 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 712 858 dependencies = [ 713 - "autocfg", 714 - "hashbrown 0.12.3", 859 + "icu_normalizer", 860 + "icu_properties", 715 861 ] 716 862 717 863 [[package]] 718 864 name = "indexmap" 719 - version = "2.0.0" 865 + version = "2.9.0" 720 866 source = "registry+https://github.com/rust-lang/crates.io-index" 721 - checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 867 + checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 722 868 dependencies = [ 723 869 "equivalent", 724 - "hashbrown 0.14.0", 870 + "hashbrown", 725 871 ] 726 872 727 873 [[package]] 728 874 name = "is-terminal" 729 - version = "0.4.9" 875 + version = "0.4.16" 730 876 source = "registry+https://github.com/rust-lang/crates.io-index" 731 - checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 877 + checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" 732 878 dependencies = [ 733 879 "hermit-abi", 734 - "rustix", 735 - "windows-sys", 880 + "libc", 881 + "windows-sys 0.59.0", 736 882 ] 737 883 738 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]] 739 891 name = "itoa" 740 - version = "1.0.9" 892 + version = "1.0.15" 741 893 source = "registry+https://github.com/rust-lang/crates.io-index" 742 - checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 894 + checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 743 895 744 896 [[package]] 745 - name = "lazy_static" 746 - version = "1.4.0" 897 + name = "js-sys" 898 + version = "0.3.77" 747 899 source = "registry+https://github.com/rust-lang/crates.io-index" 748 - checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 900 + checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 901 + dependencies = [ 902 + "once_cell", 903 + "wasm-bindgen", 904 + ] 749 905 750 906 [[package]] 751 907 name = "libc" 752 - version = "0.2.147" 908 + version = "0.2.172" 753 909 source = "registry+https://github.com/rust-lang/crates.io-index" 754 - checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 910 + checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 755 911 756 912 [[package]] 757 913 name = "linux-raw-sys" 758 - version = "0.4.5" 914 + version = "0.9.4" 915 + source = "registry+https://github.com/rust-lang/crates.io-index" 916 + checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 917 + 918 + [[package]] 919 + name = "litemap" 920 + version = "0.8.0" 759 921 source = "registry+https://github.com/rust-lang/crates.io-index" 760 - checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" 922 + checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 761 923 762 924 [[package]] 763 925 name = "lock_api" 764 - version = "0.4.10" 926 + version = "0.4.13" 765 927 source = "registry+https://github.com/rust-lang/crates.io-index" 766 - checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 928 + checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 767 929 dependencies = [ 768 930 "autocfg", 769 931 "scopeguard", ··· 771 933 772 934 [[package]] 773 935 name = "log" 774 - version = "0.4.20" 936 + version = "0.4.27" 775 937 source = "registry+https://github.com/rust-lang/crates.io-index" 776 - checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 938 + checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 777 939 778 940 [[package]] 779 941 name = "lumen" ··· 792 954 793 955 [[package]] 794 956 name = "md-5" 795 - version = "0.10.5" 957 + version = "0.10.6" 796 958 source = "registry+https://github.com/rust-lang/crates.io-index" 797 - checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" 959 + checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 798 960 dependencies = [ 961 + "cfg-if", 799 962 "digest", 800 963 ] 801 964 802 965 [[package]] 803 966 name = "memchr" 804 - version = "2.5.0" 967 + version = "2.7.4" 805 968 source = "registry+https://github.com/rust-lang/crates.io-index" 806 - checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 969 + checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 807 970 808 971 [[package]] 809 972 name = "mime" ··· 813 976 814 977 [[package]] 815 978 name = "mime_guess" 816 - version = "2.0.4" 979 + version = "2.0.5" 817 980 source = "registry+https://github.com/rust-lang/crates.io-index" 818 - checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 981 + checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 819 982 dependencies = [ 820 983 "mime", 821 984 "unicase", ··· 823 986 824 987 [[package]] 825 988 name = "miniz_oxide" 826 - version = "0.7.1" 989 + version = "0.8.8" 827 990 source = "registry+https://github.com/rust-lang/crates.io-index" 828 - checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 991 + checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 829 992 dependencies = [ 830 - "adler", 993 + "adler2", 831 994 ] 832 995 833 996 [[package]] 834 997 name = "mio" 835 - version = "0.8.8" 998 + version = "1.0.4" 836 999 source = "registry+https://github.com/rust-lang/crates.io-index" 837 - checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" 1000 + checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 838 1001 dependencies = [ 839 1002 "libc", 840 - "wasi", 841 - "windows-sys", 1003 + "wasi 0.11.0+wasi-snapshot-preview1", 1004 + "windows-sys 0.59.0", 842 1005 ] 843 1006 844 1007 [[package]] ··· 850 1013 "bytes", 851 1014 "encoding_rs", 852 1015 "futures-util", 853 - "http", 1016 + "http 0.2.12", 854 1017 "httparse", 855 1018 "log", 856 1019 "memchr", ··· 861 1024 862 1025 [[package]] 863 1026 name = "native-tls" 864 - version = "0.2.11" 1027 + version = "0.2.14" 865 1028 source = "registry+https://github.com/rust-lang/crates.io-index" 866 - checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 1029 + checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 867 1030 dependencies = [ 868 - "lazy_static", 869 1031 "libc", 870 1032 "log", 871 1033 "openssl", ··· 878 1040 ] 879 1041 880 1042 [[package]] 881 - name = "num_cpus" 882 - version = "1.16.0" 1043 + name = "num-conv" 1044 + version = "0.1.0" 883 1045 source = "registry+https://github.com/rust-lang/crates.io-index" 884 - checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 885 - dependencies = [ 886 - "hermit-abi", 887 - "libc", 888 - ] 1046 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 889 1047 890 1048 [[package]] 891 1049 name = "object" 892 - version = "0.31.1" 1050 + version = "0.36.7" 893 1051 source = "registry+https://github.com/rust-lang/crates.io-index" 894 - checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 1052 + checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 895 1053 dependencies = [ 896 1054 "memchr", 897 1055 ] 898 1056 899 1057 [[package]] 900 1058 name = "once_cell" 901 - version = "1.18.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" 902 1066 source = "registry+https://github.com/rust-lang/crates.io-index" 903 - checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 1067 + checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 904 1068 905 1069 [[package]] 906 1070 name = "openssl" 907 - version = "0.10.56" 1071 + version = "0.10.73" 908 1072 source = "registry+https://github.com/rust-lang/crates.io-index" 909 - checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" 1073 + checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" 910 1074 dependencies = [ 911 - "bitflags 1.3.2", 1075 + "bitflags", 912 1076 "cfg-if", 913 1077 "foreign-types", 914 1078 "libc", ··· 930 1094 931 1095 [[package]] 932 1096 name = "openssl-probe" 933 - version = "0.1.5" 1097 + version = "0.1.6" 934 1098 source = "registry+https://github.com/rust-lang/crates.io-index" 935 - checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1099 + checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 936 1100 937 1101 [[package]] 938 1102 name = "openssl-sys" 939 - version = "0.9.91" 1103 + version = "0.9.109" 940 1104 source = "registry+https://github.com/rust-lang/crates.io-index" 941 - checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" 1105 + checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" 942 1106 dependencies = [ 943 1107 "cc", 944 1108 "libc", ··· 948 1112 949 1113 [[package]] 950 1114 name = "parking_lot" 951 - version = "0.12.1" 1115 + version = "0.12.4" 952 1116 source = "registry+https://github.com/rust-lang/crates.io-index" 953 - checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1117 + checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 954 1118 dependencies = [ 955 1119 "lock_api", 956 1120 "parking_lot_core", ··· 958 1122 959 1123 [[package]] 960 1124 name = "parking_lot_core" 961 - version = "0.9.8" 1125 + version = "0.9.11" 962 1126 source = "registry+https://github.com/rust-lang/crates.io-index" 963 - checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 1127 + checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 964 1128 dependencies = [ 965 1129 "cfg-if", 966 1130 "libc", ··· 971 1135 972 1136 [[package]] 973 1137 name = "percent-encoding" 974 - version = "2.3.0" 1138 + version = "2.3.1" 975 1139 source = "registry+https://github.com/rust-lang/crates.io-index" 976 - checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 1140 + checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 977 1141 978 1142 [[package]] 979 1143 name = "phf" 980 - version = "0.11.2" 1144 + version = "0.11.3" 981 1145 source = "registry+https://github.com/rust-lang/crates.io-index" 982 - checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 1146 + checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 983 1147 dependencies = [ 984 1148 "phf_shared", 985 1149 ] 986 1150 987 1151 [[package]] 988 1152 name = "phf_shared" 989 - version = "0.11.2" 1153 + version = "0.11.3" 990 1154 source = "registry+https://github.com/rust-lang/crates.io-index" 991 - checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 1155 + checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 992 1156 dependencies = [ 993 1157 "siphasher", 994 1158 ] 995 1159 996 1160 [[package]] 997 1161 name = "pin-project" 998 - version = "1.1.3" 1162 + version = "1.1.10" 999 1163 source = "registry+https://github.com/rust-lang/crates.io-index" 1000 - checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" 1164 + checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" 1001 1165 dependencies = [ 1002 1166 "pin-project-internal", 1003 1167 ] 1004 1168 1005 1169 [[package]] 1006 1170 name = "pin-project-internal" 1007 - version = "1.1.3" 1171 + version = "1.1.10" 1008 1172 source = "registry+https://github.com/rust-lang/crates.io-index" 1009 - checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" 1173 + checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" 1010 1174 dependencies = [ 1011 1175 "proc-macro2", 1012 1176 "quote", ··· 1015 1179 1016 1180 [[package]] 1017 1181 name = "pin-project-lite" 1018 - version = "0.2.12" 1182 + version = "0.2.16" 1019 1183 source = "registry+https://github.com/rust-lang/crates.io-index" 1020 - checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" 1184 + checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1021 1185 1022 1186 [[package]] 1023 1187 name = "pin-utils" ··· 1027 1191 1028 1192 [[package]] 1029 1193 name = "pkg-config" 1030 - version = "0.3.27" 1194 + version = "0.3.32" 1031 1195 source = "registry+https://github.com/rust-lang/crates.io-index" 1032 - checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 1196 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1033 1197 1034 1198 [[package]] 1035 1199 name = "postgres-native-tls" 1036 - version = "0.5.0" 1200 + version = "0.5.1" 1037 1201 source = "registry+https://github.com/rust-lang/crates.io-index" 1038 - checksum = "2d442770e2b1e244bb5eb03b31c79b65bb2568f413b899eaba850fa945a65954" 1202 + checksum = "a1f39498473c92f7b6820ae970382c1d83178a3454c618161cb772e8598d9f6f" 1039 1203 dependencies = [ 1040 - "futures", 1041 1204 "native-tls", 1042 1205 "tokio", 1043 1206 "tokio-native-tls", ··· 1046 1209 1047 1210 [[package]] 1048 1211 name = "postgres-protocol" 1049 - version = "0.6.5" 1212 + version = "0.6.8" 1050 1213 source = "registry+https://github.com/rust-lang/crates.io-index" 1051 - checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d" 1214 + checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" 1052 1215 dependencies = [ 1053 - "base64 0.21.2", 1216 + "base64 0.22.1", 1054 1217 "byteorder", 1055 1218 "bytes", 1056 1219 "fallible-iterator", 1057 1220 "hmac", 1058 1221 "md-5", 1059 1222 "memchr", 1060 - "rand", 1223 + "rand 0.9.1", 1061 1224 "sha2", 1062 1225 "stringprep", 1063 1226 ] 1064 1227 1065 1228 [[package]] 1066 1229 name = "postgres-types" 1067 - version = "0.2.5" 1230 + version = "0.2.9" 1068 1231 source = "registry+https://github.com/rust-lang/crates.io-index" 1069 - checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6" 1232 + checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" 1070 1233 dependencies = [ 1071 1234 "bytes", 1072 1235 "fallible-iterator", ··· 1074 1237 ] 1075 1238 1076 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]] 1249 + name = "powerfmt" 1250 + version = "0.2.0" 1251 + source = "registry+https://github.com/rust-lang/crates.io-index" 1252 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1253 + 1254 + [[package]] 1077 1255 name = "ppv-lite86" 1078 - version = "0.2.17" 1256 + version = "0.2.21" 1079 1257 source = "registry+https://github.com/rust-lang/crates.io-index" 1080 - checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1258 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1259 + dependencies = [ 1260 + "zerocopy", 1261 + ] 1081 1262 1082 1263 [[package]] 1083 1264 name = "pretty_env_logger" ··· 1091 1272 1092 1273 [[package]] 1093 1274 name = "proc-macro2" 1094 - version = "1.0.66" 1275 + version = "1.0.95" 1095 1276 source = "registry+https://github.com/rust-lang/crates.io-index" 1096 - checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 1277 + checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 1097 1278 dependencies = [ 1098 1279 "unicode-ident", 1099 1280 ] 1100 1281 1101 1282 [[package]] 1102 1283 name = "prometheus-client" 1103 - version = "0.21.2" 1284 + version = "0.22.3" 1104 1285 source = "registry+https://github.com/rust-lang/crates.io-index" 1105 - checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" 1286 + checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" 1106 1287 dependencies = [ 1107 1288 "dtoa", 1108 1289 "itoa", ··· 1123 1304 1124 1305 [[package]] 1125 1306 name = "quote" 1126 - version = "1.0.33" 1307 + version = "1.0.40" 1127 1308 source = "registry+https://github.com/rust-lang/crates.io-index" 1128 - checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1309 + checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1129 1310 dependencies = [ 1130 1311 "proc-macro2", 1131 1312 ] 1132 1313 1133 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]] 1134 1321 name = "rand" 1135 1322 version = "0.8.5" 1136 1323 source = "registry+https://github.com/rust-lang/crates.io-index" 1137 1324 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1138 1325 dependencies = [ 1139 1326 "libc", 1140 - "rand_chacha", 1141 - "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", 1142 1339 ] 1143 1340 1144 1341 [[package]] ··· 1148 1345 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1149 1346 dependencies = [ 1150 1347 "ppv-lite86", 1151 - "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", 1152 1359 ] 1153 1360 1154 1361 [[package]] ··· 1157 1364 source = "registry+https://github.com/rust-lang/crates.io-index" 1158 1365 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1159 1366 dependencies = [ 1160 - "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", 1161 1377 ] 1162 1378 1163 1379 [[package]] 1164 1380 name = "redox_syscall" 1165 - version = "0.3.5" 1381 + version = "0.5.12" 1166 1382 source = "registry+https://github.com/rust-lang/crates.io-index" 1167 - checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1383 + checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 1168 1384 dependencies = [ 1169 - "bitflags 1.3.2", 1385 + "bitflags", 1170 1386 ] 1171 1387 1172 1388 [[package]] 1173 1389 name = "regex" 1174 - version = "1.9.3" 1390 + version = "1.11.1" 1175 1391 source = "registry+https://github.com/rust-lang/crates.io-index" 1176 - checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" 1392 + checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1177 1393 dependencies = [ 1178 1394 "aho-corasick", 1179 1395 "memchr", ··· 1183 1399 1184 1400 [[package]] 1185 1401 name = "regex-automata" 1186 - version = "0.3.6" 1402 + version = "0.4.9" 1187 1403 source = "registry+https://github.com/rust-lang/crates.io-index" 1188 - checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" 1404 + checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1189 1405 dependencies = [ 1190 1406 "aho-corasick", 1191 1407 "memchr", ··· 1194 1410 1195 1411 [[package]] 1196 1412 name = "regex-syntax" 1197 - version = "0.7.4" 1413 + version = "0.8.5" 1198 1414 source = "registry+https://github.com/rust-lang/crates.io-index" 1199 - checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 1415 + checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1200 1416 1201 1417 [[package]] 1202 1418 name = "rustc-demangle" 1203 - version = "0.1.23" 1419 + version = "0.1.24" 1204 1420 source = "registry+https://github.com/rust-lang/crates.io-index" 1205 - checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1421 + checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1206 1422 1207 1423 [[package]] 1208 1424 name = "rustix" 1209 - version = "0.38.8" 1425 + version = "1.0.7" 1210 1426 source = "registry+https://github.com/rust-lang/crates.io-index" 1211 - checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" 1427 + checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 1212 1428 dependencies = [ 1213 - "bitflags 2.4.0", 1429 + "bitflags", 1214 1430 "errno", 1215 1431 "libc", 1216 1432 "linux-raw-sys", 1217 - "windows-sys", 1218 - ] 1219 - 1220 - [[package]] 1221 - name = "rustls-pemfile" 1222 - version = "1.0.3" 1223 - source = "registry+https://github.com/rust-lang/crates.io-index" 1224 - checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" 1225 - dependencies = [ 1226 - "base64 0.21.2", 1433 + "windows-sys 0.59.0", 1227 1434 ] 1228 1435 1229 1436 [[package]] 1230 1437 name = "ryu" 1231 - version = "1.0.15" 1438 + version = "1.0.20" 1232 1439 source = "registry+https://github.com/rust-lang/crates.io-index" 1233 - checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1440 + checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1234 1441 1235 1442 [[package]] 1236 1443 name = "schannel" 1237 - version = "0.1.22" 1444 + version = "0.1.27" 1238 1445 source = "registry+https://github.com/rust-lang/crates.io-index" 1239 - checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" 1446 + checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1240 1447 dependencies = [ 1241 - "windows-sys", 1448 + "windows-sys 0.59.0", 1242 1449 ] 1243 1450 1244 1451 [[package]] 1245 1452 name = "scoped-futures" 1246 - version = "0.1.3" 1453 + version = "0.1.4" 1247 1454 source = "registry+https://github.com/rust-lang/crates.io-index" 1248 - checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" 1455 + checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091" 1249 1456 dependencies = [ 1250 - "cfg-if", 1251 - "pin-utils", 1457 + "pin-project-lite", 1252 1458 ] 1253 1459 1254 1460 [[package]] ··· 1265 1471 1266 1472 [[package]] 1267 1473 name = "security-framework" 1268 - version = "2.9.2" 1474 + version = "2.11.1" 1269 1475 source = "registry+https://github.com/rust-lang/crates.io-index" 1270 - checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" 1476 + checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1271 1477 dependencies = [ 1272 - "bitflags 1.3.2", 1478 + "bitflags", 1273 1479 "core-foundation", 1274 1480 "core-foundation-sys", 1275 1481 "libc", ··· 1278 1484 1279 1485 [[package]] 1280 1486 name = "security-framework-sys" 1281 - version = "2.9.1" 1487 + version = "2.14.0" 1282 1488 source = "registry+https://github.com/rust-lang/crates.io-index" 1283 - checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" 1489 + checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1284 1490 dependencies = [ 1285 1491 "core-foundation-sys", 1286 1492 "libc", ··· 1288 1494 1289 1495 [[package]] 1290 1496 name = "serde" 1291 - version = "1.0.183" 1497 + version = "1.0.219" 1292 1498 source = "registry+https://github.com/rust-lang/crates.io-index" 1293 - checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" 1499 + checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1294 1500 dependencies = [ 1295 1501 "serde_derive", 1296 1502 ] 1297 1503 1298 1504 [[package]] 1299 1505 name = "serde_derive" 1300 - version = "1.0.183" 1506 + version = "1.0.219" 1301 1507 source = "registry+https://github.com/rust-lang/crates.io-index" 1302 - checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" 1508 + checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1303 1509 dependencies = [ 1304 1510 "proc-macro2", 1305 1511 "quote", ··· 1308 1514 1309 1515 [[package]] 1310 1516 name = "serde_json" 1311 - version = "1.0.105" 1517 + version = "1.0.140" 1312 1518 source = "registry+https://github.com/rust-lang/crates.io-index" 1313 - checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" 1519 + checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1314 1520 dependencies = [ 1315 1521 "itoa", 1522 + "memchr", 1316 1523 "ryu", 1317 1524 "serde", 1318 1525 ] 1319 1526 1320 1527 [[package]] 1321 1528 name = "serde_spanned" 1322 - version = "0.6.3" 1529 + version = "0.6.9" 1323 1530 source = "registry+https://github.com/rust-lang/crates.io-index" 1324 - checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" 1531 + checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" 1325 1532 dependencies = [ 1326 1533 "serde", 1327 1534 ] ··· 1340 1547 1341 1548 [[package]] 1342 1549 name = "sha1" 1343 - version = "0.10.5" 1550 + version = "0.10.6" 1344 1551 source = "registry+https://github.com/rust-lang/crates.io-index" 1345 - checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 1552 + checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1346 1553 dependencies = [ 1347 1554 "cfg-if", 1348 1555 "cpufeatures", ··· 1351 1558 1352 1559 [[package]] 1353 1560 name = "sha2" 1354 - version = "0.10.7" 1561 + version = "0.10.9" 1355 1562 source = "registry+https://github.com/rust-lang/crates.io-index" 1356 - checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 1563 + checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1357 1564 dependencies = [ 1358 1565 "cfg-if", 1359 1566 "cpufeatures", ··· 1361 1568 ] 1362 1569 1363 1570 [[package]] 1571 + name = "shlex" 1572 + version = "1.3.0" 1573 + source = "registry+https://github.com/rust-lang/crates.io-index" 1574 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1575 + 1576 + [[package]] 1364 1577 name = "signal-hook-registry" 1365 - version = "1.4.1" 1578 + version = "1.4.5" 1366 1579 source = "registry+https://github.com/rust-lang/crates.io-index" 1367 - checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 1580 + checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 1368 1581 dependencies = [ 1369 1582 "libc", 1370 1583 ] 1371 1584 1372 1585 [[package]] 1373 1586 name = "siphasher" 1374 - version = "0.3.10" 1587 + version = "1.0.1" 1375 1588 source = "registry+https://github.com/rust-lang/crates.io-index" 1376 - checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" 1589 + checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 1377 1590 1378 1591 [[package]] 1379 1592 name = "slab" 1380 - version = "0.4.8" 1593 + version = "0.4.9" 1381 1594 source = "registry+https://github.com/rust-lang/crates.io-index" 1382 - checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 1595 + checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1383 1596 dependencies = [ 1384 1597 "autocfg", 1385 1598 ] 1386 1599 1387 1600 [[package]] 1388 1601 name = "smallvec" 1389 - version = "1.11.0" 1602 + version = "1.15.1" 1390 1603 source = "registry+https://github.com/rust-lang/crates.io-index" 1391 - checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 1604 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1392 1605 1393 1606 [[package]] 1394 1607 name = "socket2" 1395 - version = "0.4.9" 1608 + version = "0.5.10" 1396 1609 source = "registry+https://github.com/rust-lang/crates.io-index" 1397 - checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 1398 - dependencies = [ 1399 - "libc", 1400 - "winapi", 1401 - ] 1402 - 1403 - [[package]] 1404 - name = "socket2" 1405 - version = "0.5.3" 1406 - source = "registry+https://github.com/rust-lang/crates.io-index" 1407 - checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" 1610 + checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 1408 1611 dependencies = [ 1409 1612 "libc", 1410 - "windows-sys", 1613 + "windows-sys 0.52.0", 1411 1614 ] 1412 1615 1413 1616 [[package]] ··· 1417 1620 checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1418 1621 1419 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]] 1420 1629 name = "stringprep" 1421 - version = "0.1.3" 1630 + version = "0.1.5" 1422 1631 source = "registry+https://github.com/rust-lang/crates.io-index" 1423 - checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" 1632 + checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 1424 1633 dependencies = [ 1425 1634 "unicode-bidi", 1426 1635 "unicode-normalization", 1636 + "unicode-properties", 1427 1637 ] 1428 1638 1429 1639 [[package]] 1430 1640 name = "strsim" 1431 - version = "0.10.0" 1641 + version = "0.11.1" 1432 1642 source = "registry+https://github.com/rust-lang/crates.io-index" 1433 - checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1643 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1434 1644 1435 1645 [[package]] 1436 1646 name = "subtle" 1437 - version = "2.5.0" 1647 + version = "2.6.1" 1438 1648 source = "registry+https://github.com/rust-lang/crates.io-index" 1439 - checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1649 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1440 1650 1441 1651 [[package]] 1442 1652 name = "syn" 1443 - version = "2.0.29" 1653 + version = "2.0.101" 1444 1654 source = "registry+https://github.com/rust-lang/crates.io-index" 1445 - checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" 1655 + checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 1446 1656 dependencies = [ 1447 1657 "proc-macro2", 1448 1658 "quote", ··· 1450 1660 ] 1451 1661 1452 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]] 1453 1674 name = "tempfile" 1454 - version = "3.7.1" 1675 + version = "3.20.0" 1455 1676 source = "registry+https://github.com/rust-lang/crates.io-index" 1456 - checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" 1677 + checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" 1457 1678 dependencies = [ 1458 - "cfg-if", 1459 1679 "fastrand", 1460 - "redox_syscall", 1680 + "getrandom 0.3.3", 1681 + "once_cell", 1461 1682 "rustix", 1462 - "windows-sys", 1683 + "windows-sys 0.59.0", 1463 1684 ] 1464 1685 1465 1686 [[package]] 1466 1687 name = "termcolor" 1467 - version = "1.2.0" 1688 + version = "1.4.1" 1468 1689 source = "registry+https://github.com/rust-lang/crates.io-index" 1469 - checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 1690 + checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1470 1691 dependencies = [ 1471 1692 "winapi-util", 1472 1693 ] 1473 1694 1474 1695 [[package]] 1475 1696 name = "thiserror" 1476 - version = "1.0.47" 1697 + version = "1.0.69" 1477 1698 source = "registry+https://github.com/rust-lang/crates.io-index" 1478 - checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" 1699 + checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1479 1700 dependencies = [ 1480 1701 "thiserror-impl", 1481 1702 ] 1482 1703 1483 1704 [[package]] 1484 1705 name = "thiserror-impl" 1485 - version = "1.0.47" 1706 + version = "1.0.69" 1486 1707 source = "registry+https://github.com/rust-lang/crates.io-index" 1487 - checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" 1708 + checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1488 1709 dependencies = [ 1489 1710 "proc-macro2", 1490 1711 "quote", ··· 1493 1714 1494 1715 [[package]] 1495 1716 name = "time" 1496 - version = "0.3.25" 1717 + version = "0.3.41" 1497 1718 source = "registry+https://github.com/rust-lang/crates.io-index" 1498 - checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" 1719 + checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 1499 1720 dependencies = [ 1500 1721 "deranged", 1722 + "num-conv", 1723 + "powerfmt", 1501 1724 "serde", 1502 1725 "time-core", 1503 1726 "time-macros", ··· 1505 1728 1506 1729 [[package]] 1507 1730 name = "time-core" 1508 - version = "0.1.1" 1731 + version = "0.1.4" 1509 1732 source = "registry+https://github.com/rust-lang/crates.io-index" 1510 - checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" 1733 + checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 1511 1734 1512 1735 [[package]] 1513 1736 name = "time-macros" 1514 - version = "0.2.11" 1737 + version = "0.2.22" 1515 1738 source = "registry+https://github.com/rust-lang/crates.io-index" 1516 - checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" 1739 + checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 1517 1740 dependencies = [ 1741 + "num-conv", 1518 1742 "time-core", 1519 1743 ] 1520 1744 1521 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]] 1522 1756 name = "tinyvec" 1523 - version = "1.6.0" 1757 + version = "1.9.0" 1524 1758 source = "registry+https://github.com/rust-lang/crates.io-index" 1525 - checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1759 + checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" 1526 1760 dependencies = [ 1527 1761 "tinyvec_macros", 1528 1762 ] ··· 1535 1769 1536 1770 [[package]] 1537 1771 name = "tokio" 1538 - version = "1.32.0" 1772 + version = "1.45.1" 1539 1773 source = "registry+https://github.com/rust-lang/crates.io-index" 1540 - checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" 1774 + checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 1541 1775 dependencies = [ 1542 1776 "backtrace", 1543 1777 "bytes", 1544 1778 "libc", 1545 1779 "mio", 1546 - "num_cpus", 1547 1780 "parking_lot", 1548 1781 "pin-project-lite", 1549 1782 "signal-hook-registry", 1550 - "socket2 0.5.3", 1783 + "socket2", 1551 1784 "tokio-macros", 1552 - "windows-sys", 1785 + "windows-sys 0.52.0", 1553 1786 ] 1554 1787 1555 1788 [[package]] 1556 1789 name = "tokio-macros" 1557 - version = "2.1.0" 1790 + version = "2.5.0" 1558 1791 source = "registry+https://github.com/rust-lang/crates.io-index" 1559 - checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 1792 + checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1560 1793 dependencies = [ 1561 1794 "proc-macro2", 1562 1795 "quote", ··· 1575 1808 1576 1809 [[package]] 1577 1810 name = "tokio-postgres" 1578 - version = "0.7.8" 1811 + version = "0.7.13" 1579 1812 source = "registry+https://github.com/rust-lang/crates.io-index" 1580 - checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1" 1813 + checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" 1581 1814 dependencies = [ 1582 1815 "async-trait", 1583 1816 "byteorder", ··· 1592 1825 "pin-project-lite", 1593 1826 "postgres-protocol", 1594 1827 "postgres-types", 1595 - "socket2 0.5.3", 1828 + "rand 0.9.1", 1829 + "socket2", 1596 1830 "tokio", 1597 1831 "tokio-util", 1598 - ] 1599 - 1600 - [[package]] 1601 - name = "tokio-stream" 1602 - version = "0.1.14" 1603 - source = "registry+https://github.com/rust-lang/crates.io-index" 1604 - checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" 1605 - dependencies = [ 1606 - "futures-core", 1607 - "pin-project-lite", 1608 - "tokio", 1832 + "whoami", 1609 1833 ] 1610 1834 1611 1835 [[package]] 1612 1836 name = "tokio-tungstenite" 1613 - version = "0.18.0" 1837 + version = "0.21.0" 1614 1838 source = "registry+https://github.com/rust-lang/crates.io-index" 1615 - checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" 1839 + checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 1616 1840 dependencies = [ 1617 1841 "futures-util", 1618 1842 "log", ··· 1622 1846 1623 1847 [[package]] 1624 1848 name = "tokio-util" 1625 - version = "0.7.8" 1849 + version = "0.7.15" 1626 1850 source = "registry+https://github.com/rust-lang/crates.io-index" 1627 - checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" 1851 + checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" 1628 1852 dependencies = [ 1629 1853 "bytes", 1630 1854 "futures-core", 1631 1855 "futures-sink", 1632 1856 "pin-project-lite", 1633 1857 "tokio", 1634 - "tracing", 1635 1858 ] 1636 1859 1637 1860 [[package]] 1638 1861 name = "toml" 1639 - version = "0.7.6" 1862 + version = "0.8.23" 1640 1863 source = "registry+https://github.com/rust-lang/crates.io-index" 1641 - checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" 1864 + checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" 1642 1865 dependencies = [ 1643 1866 "serde", 1644 1867 "serde_spanned", ··· 1648 1871 1649 1872 [[package]] 1650 1873 name = "toml_datetime" 1651 - version = "0.6.3" 1874 + version = "0.6.11" 1652 1875 source = "registry+https://github.com/rust-lang/crates.io-index" 1653 - checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 1876 + checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 1654 1877 dependencies = [ 1655 1878 "serde", 1656 1879 ] 1657 1880 1658 1881 [[package]] 1659 1882 name = "toml_edit" 1660 - version = "0.19.14" 1883 + version = "0.22.27" 1661 1884 source = "registry+https://github.com/rust-lang/crates.io-index" 1662 - checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" 1885 + checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 1663 1886 dependencies = [ 1664 - "indexmap 2.0.0", 1887 + "indexmap", 1665 1888 "serde", 1666 1889 "serde_spanned", 1667 1890 "toml_datetime", 1891 + "toml_write", 1668 1892 "winnow", 1669 1893 ] 1670 1894 1671 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]] 1672 1902 name = "tower-service" 1673 - version = "0.3.2" 1903 + version = "0.3.3" 1674 1904 source = "registry+https://github.com/rust-lang/crates.io-index" 1675 - checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1905 + checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1676 1906 1677 1907 [[package]] 1678 1908 name = "tracing" 1679 - version = "0.1.37" 1909 + version = "0.1.41" 1680 1910 source = "registry+https://github.com/rust-lang/crates.io-index" 1681 - checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1911 + checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1682 1912 dependencies = [ 1683 - "cfg-if", 1684 1913 "log", 1685 1914 "pin-project-lite", 1686 1915 "tracing-core", ··· 1688 1917 1689 1918 [[package]] 1690 1919 name = "tracing-core" 1691 - version = "0.1.31" 1920 + version = "0.1.34" 1692 1921 source = "registry+https://github.com/rust-lang/crates.io-index" 1693 - checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 1922 + checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 1694 1923 dependencies = [ 1695 1924 "once_cell", 1696 1925 ] 1697 1926 1698 1927 [[package]] 1699 1928 name = "try-lock" 1700 - version = "0.2.4" 1929 + version = "0.2.5" 1701 1930 source = "registry+https://github.com/rust-lang/crates.io-index" 1702 - checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1931 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1703 1932 1704 1933 [[package]] 1705 1934 name = "tungstenite" 1706 - version = "0.18.0" 1935 + version = "0.21.0" 1707 1936 source = "registry+https://github.com/rust-lang/crates.io-index" 1708 - checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" 1937 + checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 1709 1938 dependencies = [ 1710 - "base64 0.13.1", 1711 1939 "byteorder", 1712 1940 "bytes", 1713 - "http", 1941 + "data-encoding", 1942 + "http 1.3.1", 1714 1943 "httparse", 1715 1944 "log", 1716 - "rand", 1945 + "rand 0.8.5", 1717 1946 "sha1", 1718 1947 "thiserror", 1719 1948 "url", ··· 1722 1951 1723 1952 [[package]] 1724 1953 name = "typenum" 1725 - version = "1.16.0" 1954 + version = "1.18.0" 1726 1955 source = "registry+https://github.com/rust-lang/crates.io-index" 1727 - checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1956 + checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 1728 1957 1729 1958 [[package]] 1730 1959 name = "unicase" 1731 - version = "2.6.0" 1960 + version = "2.8.1" 1732 1961 source = "registry+https://github.com/rust-lang/crates.io-index" 1733 - checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1734 - dependencies = [ 1735 - "version_check", 1736 - ] 1962 + checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 1737 1963 1738 1964 [[package]] 1739 1965 name = "unicode-bidi" 1740 - version = "0.3.13" 1966 + version = "0.3.18" 1741 1967 source = "registry+https://github.com/rust-lang/crates.io-index" 1742 - checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1968 + checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" 1743 1969 1744 1970 [[package]] 1745 1971 name = "unicode-ident" 1746 - version = "1.0.11" 1972 + version = "1.0.18" 1747 1973 source = "registry+https://github.com/rust-lang/crates.io-index" 1748 - checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 1974 + checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1749 1975 1750 1976 [[package]] 1751 1977 name = "unicode-normalization" 1752 - version = "0.1.22" 1978 + version = "0.1.24" 1753 1979 source = "registry+https://github.com/rust-lang/crates.io-index" 1754 - checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1980 + checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 1755 1981 dependencies = [ 1756 1982 "tinyvec", 1757 1983 ] 1758 1984 1759 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]] 1760 1992 name = "url" 1761 - version = "2.4.0" 1993 + version = "2.5.4" 1762 1994 source = "registry+https://github.com/rust-lang/crates.io-index" 1763 - checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" 1995 + checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1764 1996 dependencies = [ 1765 1997 "form_urlencoded", 1766 1998 "idna", ··· 1774 2006 checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1775 2007 1776 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]] 1777 2015 name = "utf8parse" 1778 - version = "0.2.1" 2016 + version = "0.2.2" 1779 2017 source = "registry+https://github.com/rust-lang/crates.io-index" 1780 - checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 2018 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1781 2019 1782 2020 [[package]] 1783 2021 name = "vcpkg" ··· 1787 2025 1788 2026 [[package]] 1789 2027 name = "version_check" 1790 - version = "0.9.4" 2028 + version = "0.9.5" 1791 2029 source = "registry+https://github.com/rust-lang/crates.io-index" 1792 - checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2030 + checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1793 2031 1794 2032 [[package]] 1795 2033 name = "want" ··· 1802 2040 1803 2041 [[package]] 1804 2042 name = "warp" 1805 - version = "0.3.5" 2043 + version = "0.3.7" 1806 2044 source = "registry+https://github.com/rust-lang/crates.io-index" 1807 - checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69" 2045 + checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" 1808 2046 dependencies = [ 1809 2047 "bytes", 1810 2048 "futures-channel", 1811 2049 "futures-util", 1812 2050 "headers", 1813 - "http", 2051 + "http 0.2.12", 1814 2052 "hyper", 1815 2053 "log", 1816 2054 "mime", ··· 1818 2056 "multer", 1819 2057 "percent-encoding", 1820 2058 "pin-project", 1821 - "rustls-pemfile", 1822 2059 "scoped-tls", 1823 2060 "serde", 1824 2061 "serde_json", 1825 2062 "serde_urlencoded", 1826 2063 "tokio", 1827 - "tokio-stream", 1828 2064 "tokio-tungstenite", 1829 2065 "tokio-util", 1830 2066 "tower-service", ··· 1838 2074 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1839 2075 1840 2076 [[package]] 1841 - name = "winapi" 1842 - version = "0.3.9" 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]] 2092 + name = "wasm-bindgen" 2093 + version = "0.2.100" 2094 + source = "registry+https://github.com/rust-lang/crates.io-index" 2095 + checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 2096 + dependencies = [ 2097 + "cfg-if", 2098 + "once_cell", 2099 + "wasm-bindgen-macro", 2100 + ] 2101 + 2102 + [[package]] 2103 + name = "wasm-bindgen-backend" 2104 + version = "0.2.100" 2105 + source = "registry+https://github.com/rust-lang/crates.io-index" 2106 + checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 2107 + dependencies = [ 2108 + "bumpalo", 2109 + "log", 2110 + "proc-macro2", 2111 + "quote", 2112 + "syn", 2113 + "wasm-bindgen-shared", 2114 + ] 2115 + 2116 + [[package]] 2117 + name = "wasm-bindgen-macro" 2118 + version = "0.2.100" 2119 + source = "registry+https://github.com/rust-lang/crates.io-index" 2120 + checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 2121 + dependencies = [ 2122 + "quote", 2123 + "wasm-bindgen-macro-support", 2124 + ] 2125 + 2126 + [[package]] 2127 + name = "wasm-bindgen-macro-support" 2128 + version = "0.2.100" 1843 2129 source = "registry+https://github.com/rust-lang/crates.io-index" 1844 - checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2130 + checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1845 2131 dependencies = [ 1846 - "winapi-i686-pc-windows-gnu", 1847 - "winapi-x86_64-pc-windows-gnu", 2132 + "proc-macro2", 2133 + "quote", 2134 + "syn", 2135 + "wasm-bindgen-backend", 2136 + "wasm-bindgen-shared", 1848 2137 ] 1849 2138 1850 2139 [[package]] 1851 - name = "winapi-i686-pc-windows-gnu" 1852 - version = "0.4.0" 2140 + name = "wasm-bindgen-shared" 2141 + version = "0.2.100" 1853 2142 source = "registry+https://github.com/rust-lang/crates.io-index" 1854 - checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2143 + checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2144 + dependencies = [ 2145 + "unicode-ident", 2146 + ] 2147 + 2148 + [[package]] 2149 + name = "web-sys" 2150 + version = "0.3.77" 2151 + source = "registry+https://github.com/rust-lang/crates.io-index" 2152 + checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 2153 + dependencies = [ 2154 + "js-sys", 2155 + "wasm-bindgen", 2156 + ] 2157 + 2158 + [[package]] 2159 + name = "whoami" 2160 + version = "1.6.0" 2161 + source = "registry+https://github.com/rust-lang/crates.io-index" 2162 + checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" 2163 + dependencies = [ 2164 + "redox_syscall", 2165 + "wasite", 2166 + "web-sys", 2167 + ] 1855 2168 1856 2169 [[package]] 1857 2170 name = "winapi-util" 1858 - version = "0.1.5" 2171 + version = "0.1.9" 1859 2172 source = "registry+https://github.com/rust-lang/crates.io-index" 1860 - checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2173 + checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1861 2174 dependencies = [ 1862 - "winapi", 2175 + "windows-sys 0.59.0", 1863 2176 ] 1864 2177 1865 2178 [[package]] 1866 - name = "winapi-x86_64-pc-windows-gnu" 1867 - version = "0.4.0" 2179 + name = "windows-sys" 2180 + version = "0.52.0" 1868 2181 source = "registry+https://github.com/rust-lang/crates.io-index" 1869 - checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2182 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2183 + dependencies = [ 2184 + "windows-targets", 2185 + ] 1870 2186 1871 2187 [[package]] 1872 2188 name = "windows-sys" 1873 - version = "0.48.0" 2189 + version = "0.59.0" 1874 2190 source = "registry+https://github.com/rust-lang/crates.io-index" 1875 - checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2191 + checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1876 2192 dependencies = [ 1877 2193 "windows-targets", 1878 2194 ] 1879 2195 1880 2196 [[package]] 1881 2197 name = "windows-targets" 1882 - version = "0.48.3" 2198 + version = "0.52.6" 1883 2199 source = "registry+https://github.com/rust-lang/crates.io-index" 1884 - checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b" 2200 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1885 2201 dependencies = [ 1886 2202 "windows_aarch64_gnullvm", 1887 2203 "windows_aarch64_msvc", 1888 2204 "windows_i686_gnu", 2205 + "windows_i686_gnullvm", 1889 2206 "windows_i686_msvc", 1890 2207 "windows_x86_64_gnu", 1891 2208 "windows_x86_64_gnullvm", ··· 1894 2211 1895 2212 [[package]] 1896 2213 name = "windows_aarch64_gnullvm" 1897 - version = "0.48.3" 2214 + version = "0.52.6" 1898 2215 source = "registry+https://github.com/rust-lang/crates.io-index" 1899 - checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c" 2216 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1900 2217 1901 2218 [[package]] 1902 2219 name = "windows_aarch64_msvc" 1903 - version = "0.48.3" 2220 + version = "0.52.6" 1904 2221 source = "registry+https://github.com/rust-lang/crates.io-index" 1905 - checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4" 2222 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1906 2223 1907 2224 [[package]] 1908 2225 name = "windows_i686_gnu" 1909 - version = "0.48.3" 2226 + version = "0.52.6" 2227 + source = "registry+https://github.com/rust-lang/crates.io-index" 2228 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2229 + 2230 + [[package]] 2231 + name = "windows_i686_gnullvm" 2232 + version = "0.52.6" 1910 2233 source = "registry+https://github.com/rust-lang/crates.io-index" 1911 - checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83" 2234 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1912 2235 1913 2236 [[package]] 1914 2237 name = "windows_i686_msvc" 1915 - version = "0.48.3" 2238 + version = "0.52.6" 1916 2239 source = "registry+https://github.com/rust-lang/crates.io-index" 1917 - checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4" 2240 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1918 2241 1919 2242 [[package]] 1920 2243 name = "windows_x86_64_gnu" 1921 - version = "0.48.3" 2244 + version = "0.52.6" 1922 2245 source = "registry+https://github.com/rust-lang/crates.io-index" 1923 - checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad" 2246 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1924 2247 1925 2248 [[package]] 1926 2249 name = "windows_x86_64_gnullvm" 1927 - version = "0.48.3" 2250 + version = "0.52.6" 1928 2251 source = "registry+https://github.com/rust-lang/crates.io-index" 1929 - checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d" 2252 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1930 2253 1931 2254 [[package]] 1932 2255 name = "windows_x86_64_msvc" 1933 - version = "0.48.3" 2256 + version = "0.52.6" 1934 2257 source = "registry+https://github.com/rust-lang/crates.io-index" 1935 - checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1" 2258 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1936 2259 1937 2260 [[package]] 1938 2261 name = "winnow" 1939 - version = "0.5.12" 2262 + version = "0.7.10" 1940 2263 source = "registry+https://github.com/rust-lang/crates.io-index" 1941 - checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364" 2264 + checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" 1942 2265 dependencies = [ 1943 2266 "memchr", 1944 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 + ] 2277 + 2278 + [[package]] 2279 + name = "writeable" 2280 + version = "0.6.1" 2281 + source = "registry+https://github.com/rust-lang/crates.io-index" 2282 + checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 2283 + 2284 + [[package]] 2285 + name = "yoke" 2286 + version = "0.8.0" 2287 + source = "registry+https://github.com/rust-lang/crates.io-index" 2288 + checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 2289 + dependencies = [ 2290 + "serde", 2291 + "stable_deref_trait", 2292 + "yoke-derive", 2293 + "zerofrom", 2294 + ] 2295 + 2296 + [[package]] 2297 + name = "yoke-derive" 2298 + version = "0.8.0" 2299 + source = "registry+https://github.com/rust-lang/crates.io-index" 2300 + checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 2301 + dependencies = [ 2302 + "proc-macro2", 2303 + "quote", 2304 + "syn", 2305 + "synstructure", 2306 + ] 2307 + 2308 + [[package]] 2309 + name = "zerocopy" 2310 + version = "0.8.25" 2311 + source = "registry+https://github.com/rust-lang/crates.io-index" 2312 + checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" 2313 + dependencies = [ 2314 + "zerocopy-derive", 2315 + ] 2316 + 2317 + [[package]] 2318 + name = "zerocopy-derive" 2319 + version = "0.8.25" 2320 + source = "registry+https://github.com/rust-lang/crates.io-index" 2321 + checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" 2322 + dependencies = [ 2323 + "proc-macro2", 2324 + "quote", 2325 + "syn", 2326 + ] 2327 + 2328 + [[package]] 2329 + name = "zerofrom" 2330 + version = "0.1.6" 2331 + source = "registry+https://github.com/rust-lang/crates.io-index" 2332 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2333 + dependencies = [ 2334 + "zerofrom-derive", 2335 + ] 2336 + 2337 + [[package]] 2338 + name = "zerofrom-derive" 2339 + version = "0.1.6" 2340 + source = "registry+https://github.com/rust-lang/crates.io-index" 2341 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2342 + dependencies = [ 2343 + "proc-macro2", 2344 + "quote", 2345 + "syn", 2346 + "synstructure", 2347 + ] 2348 + 2349 + [[package]] 2350 + name = "zerotrie" 2351 + version = "0.2.2" 2352 + source = "registry+https://github.com/rust-lang/crates.io-index" 2353 + checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 2354 + dependencies = [ 2355 + "displaydoc", 2356 + "yoke", 2357 + "zerofrom", 2358 + ] 2359 + 2360 + [[package]] 2361 + name = "zerovec" 2362 + version = "0.11.2" 2363 + source = "registry+https://github.com/rust-lang/crates.io-index" 2364 + checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 2365 + dependencies = [ 2366 + "yoke", 2367 + "zerofrom", 2368 + "zerovec-derive", 2369 + ] 2370 + 2371 + [[package]] 2372 + name = "zerovec-derive" 2373 + version = "0.11.1" 2374 + source = "registry+https://github.com/rust-lang/crates.io-index" 2375 + checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 2376 + dependencies = [ 2377 + "proc-macro2", 2378 + "quote", 2379 + "syn", 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.68.2-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.0.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"