├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .rustfmt.toml ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.tpl ├── build.rs ├── readme.md └── src ├── args.rs ├── coll ├── chardetect.rs ├── file.rs ├── ip.rs ├── mod.rs ├── path.rs ├── ping │ ├── mod.rs │ └── ping.rs ├── unzip.rs └── url.rs ├── consts.rs ├── logger.rs └── main.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | # https://github.com/actions-rs/toolchain#profiles 6 | jobs: 7 | ci: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | rust: 12 | - stable 13 | # - beta 14 | # - nightly 15 | # - 1.31.0 # MSRV 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - uses: actions-rs/toolchain@v1 21 | with: 22 | profile: minimal 23 | toolchain: ${{ matrix.rust }} 24 | override: true 25 | components: rustfmt #, clippy 26 | - name: Show 27 | run: rustup show 28 | - name: fmt 29 | run: cargo fmt --check 30 | - name: Build 31 | run: cargo build --release 32 | - name: Run 33 | run: cargo run --release -- -h 34 | - name: Tests 35 | run: cargo test --verbose --release 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | # https://github.com/rust-build/rust-build.action 4 | # https://github.com/taiki-e/upload-rust-binary-action#example-workflow-basic-usage 5 | 6 | on: 7 | push: 8 | tags: 9 | - v[0-9]+.* 10 | 11 | jobs: 12 | create-release: 13 | if: github.repository_owner == 'biluohc' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: taiki-e/create-gh-release-action@v1 18 | # with: 19 | # (optional) 20 | # changelog: CHANGELOG.md 21 | env: 22 | # (required) 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | 25 | upload-assets: 26 | if: github.repository_owner == 'biluohc' 27 | needs: 28 | - create-release 29 | strategy: 30 | matrix: 31 | include: 32 | - target: x86_64-unknown-linux-gnu 33 | - target: x86_64-apple-darwin 34 | os: macos-latest 35 | - target: x86_64-pc-windows-msvc 36 | os: windows-latest 37 | - target: x86_64-unknown-linux-musl 38 | runs-on: ${{ matrix.os || 'ubuntu-latest' }} 39 | steps: 40 | - uses: actions/checkout@v2 41 | - uses: taiki-e/github-actions/install-rust@main 42 | with: 43 | toolchain: stable 44 | - uses: taiki-e/upload-rust-binary-action@v1 45 | with: 46 | bin: zcs 47 | target: ${{ matrix.target }} 48 | tar: none #unix 49 | zip: all #windows 50 | archive: $bin-$tag-$target 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | CARGO_PROFILE_RELEASE_LTO: true 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.bk 3 | *target 4 | *main.html 5 | *.exe 6 | zipcs 7 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | verbose = "Verbose" 2 | 3 | format_strings = false 4 | max_width = 128 5 | tab_spaces = 4 6 | newline_style = "Unix" 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | cache: cargo 4 | rust: 5 | - nightly 6 | - beta 7 | - stable 8 | matrix: 9 | allow_failures: 10 | - rust: nightly 11 | script: | 12 | cargo build && 13 | cargo test #&& 14 | # cargo doc 15 | 16 | notifications: 17 | email: 18 | on_success: never -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aes" 13 | version = "0.7.5" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" 16 | dependencies = [ 17 | "cfg-if 1.0.0", 18 | "cipher", 19 | "cpufeatures", 20 | "opaque-debug", 21 | ] 22 | 23 | [[package]] 24 | name = "aho-corasick" 25 | version = "0.7.18" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 28 | dependencies = [ 29 | "memchr", 30 | ] 31 | 32 | [[package]] 33 | name = "app" 34 | version = "0.6.5" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "447484b8aa534779517055ae8b5a0b7d6fa5cde41d36af977c381ca03aade3c7" 37 | dependencies = [ 38 | "quick-error", 39 | "stderr", 40 | "term", 41 | ] 42 | 43 | [[package]] 44 | name = "arrayref" 45 | version = "0.3.6" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 48 | 49 | [[package]] 50 | name = "arrayvec" 51 | version = "0.5.2" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 54 | 55 | [[package]] 56 | name = "async-compression" 57 | version = "0.3.14" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" 60 | dependencies = [ 61 | "bytes 0.5.6", 62 | "flate2", 63 | "futures-core", 64 | "memchr", 65 | "pin-project-lite 0.2.9", 66 | ] 67 | 68 | [[package]] 69 | name = "atty" 70 | version = "0.2.14" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 73 | dependencies = [ 74 | "hermit-abi", 75 | "libc", 76 | "winapi 0.3.9", 77 | ] 78 | 79 | [[package]] 80 | name = "autocfg" 81 | version = "1.1.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 84 | 85 | [[package]] 86 | name = "base64" 87 | version = "0.12.3" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 90 | 91 | [[package]] 92 | name = "base64" 93 | version = "0.13.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 96 | 97 | [[package]] 98 | name = "base64ct" 99 | version = "1.0.1" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" 102 | 103 | [[package]] 104 | name = "bitflags" 105 | version = "1.3.2" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 108 | 109 | [[package]] 110 | name = "blake2b_simd" 111 | version = "0.5.11" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 114 | dependencies = [ 115 | "arrayref", 116 | "arrayvec", 117 | "constant_time_eq", 118 | ] 119 | 120 | [[package]] 121 | name = "block-buffer" 122 | version = "0.10.2" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 125 | dependencies = [ 126 | "generic-array", 127 | ] 128 | 129 | [[package]] 130 | name = "bumpalo" 131 | version = "3.9.1" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 134 | 135 | [[package]] 136 | name = "byteorder" 137 | version = "1.4.3" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 140 | 141 | [[package]] 142 | name = "bytes" 143 | version = "0.5.6" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" 146 | 147 | [[package]] 148 | name = "bytes" 149 | version = "1.1.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 152 | 153 | [[package]] 154 | name = "bzip2" 155 | version = "0.4.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" 158 | dependencies = [ 159 | "bzip2-sys", 160 | "libc", 161 | ] 162 | 163 | [[package]] 164 | name = "bzip2-sys" 165 | version = "0.1.11+1.0.8" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 168 | dependencies = [ 169 | "cc", 170 | "libc", 171 | "pkg-config", 172 | ] 173 | 174 | [[package]] 175 | name = "cc" 176 | version = "1.0.73" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 179 | dependencies = [ 180 | "jobserver", 181 | ] 182 | 183 | [[package]] 184 | name = "cfg-if" 185 | version = "0.1.10" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 188 | 189 | [[package]] 190 | name = "cfg-if" 191 | version = "1.0.0" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 194 | 195 | [[package]] 196 | name = "chardet" 197 | version = "0.2.4" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "1a48563284b67c003ba0fb7243c87fab68885e1532c605704228a80238512e31" 200 | 201 | [[package]] 202 | name = "chrono" 203 | version = "0.4.19" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 206 | dependencies = [ 207 | "libc", 208 | "num-integer", 209 | "num-traits", 210 | "time 0.1.44", 211 | "winapi 0.3.9", 212 | ] 213 | 214 | [[package]] 215 | name = "cipher" 216 | version = "0.3.0" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 219 | dependencies = [ 220 | "generic-array", 221 | ] 222 | 223 | [[package]] 224 | name = "colored" 225 | version = "2.0.0" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 228 | dependencies = [ 229 | "atty", 230 | "lazy_static 1.4.0", 231 | "winapi 0.3.9", 232 | ] 233 | 234 | [[package]] 235 | name = "constant_time_eq" 236 | version = "0.1.5" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 239 | 240 | [[package]] 241 | name = "cpufeatures" 242 | version = "0.2.2" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" 245 | dependencies = [ 246 | "libc", 247 | ] 248 | 249 | [[package]] 250 | name = "crc32fast" 251 | version = "1.3.2" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 254 | dependencies = [ 255 | "cfg-if 1.0.0", 256 | ] 257 | 258 | [[package]] 259 | name = "crossbeam-channel" 260 | version = "0.5.4" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" 263 | dependencies = [ 264 | "cfg-if 1.0.0", 265 | "crossbeam-utils", 266 | ] 267 | 268 | [[package]] 269 | name = "crossbeam-deque" 270 | version = "0.8.1" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 273 | dependencies = [ 274 | "cfg-if 1.0.0", 275 | "crossbeam-epoch", 276 | "crossbeam-utils", 277 | ] 278 | 279 | [[package]] 280 | name = "crossbeam-epoch" 281 | version = "0.9.8" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" 284 | dependencies = [ 285 | "autocfg", 286 | "cfg-if 1.0.0", 287 | "crossbeam-utils", 288 | "lazy_static 1.4.0", 289 | "memoffset", 290 | "scopeguard", 291 | ] 292 | 293 | [[package]] 294 | name = "crossbeam-utils" 295 | version = "0.8.8" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" 298 | dependencies = [ 299 | "cfg-if 1.0.0", 300 | "lazy_static 1.4.0", 301 | ] 302 | 303 | [[package]] 304 | name = "crypto-common" 305 | version = "0.1.3" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 308 | dependencies = [ 309 | "generic-array", 310 | "typenum", 311 | ] 312 | 313 | [[package]] 314 | name = "digest" 315 | version = "0.10.3" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 318 | dependencies = [ 319 | "block-buffer", 320 | "crypto-common", 321 | "subtle", 322 | ] 323 | 324 | [[package]] 325 | name = "dirs" 326 | version = "1.0.5" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 329 | dependencies = [ 330 | "libc", 331 | "redox_users", 332 | "winapi 0.3.9", 333 | ] 334 | 335 | [[package]] 336 | name = "either" 337 | version = "1.6.1" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 340 | 341 | [[package]] 342 | name = "encoding" 343 | version = "0.2.33" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" 346 | dependencies = [ 347 | "encoding-index-japanese", 348 | "encoding-index-korean", 349 | "encoding-index-simpchinese", 350 | "encoding-index-singlebyte", 351 | "encoding-index-tradchinese", 352 | ] 353 | 354 | [[package]] 355 | name = "encoding-index-japanese" 356 | version = "1.20141219.5" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" 359 | dependencies = [ 360 | "encoding_index_tests", 361 | ] 362 | 363 | [[package]] 364 | name = "encoding-index-korean" 365 | version = "1.20141219.5" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" 368 | dependencies = [ 369 | "encoding_index_tests", 370 | ] 371 | 372 | [[package]] 373 | name = "encoding-index-simpchinese" 374 | version = "1.20141219.5" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" 377 | dependencies = [ 378 | "encoding_index_tests", 379 | ] 380 | 381 | [[package]] 382 | name = "encoding-index-singlebyte" 383 | version = "1.20141219.5" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" 386 | dependencies = [ 387 | "encoding_index_tests", 388 | ] 389 | 390 | [[package]] 391 | name = "encoding-index-tradchinese" 392 | version = "1.20141219.5" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" 395 | dependencies = [ 396 | "encoding_index_tests", 397 | ] 398 | 399 | [[package]] 400 | name = "encoding_index_tests" 401 | version = "0.1.4" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" 404 | 405 | [[package]] 406 | name = "encoding_rs" 407 | version = "0.8.31" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 410 | dependencies = [ 411 | "cfg-if 1.0.0", 412 | ] 413 | 414 | [[package]] 415 | name = "filetime" 416 | version = "0.2.16" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" 419 | dependencies = [ 420 | "cfg-if 1.0.0", 421 | "libc", 422 | "redox_syscall 0.2.13", 423 | "winapi 0.3.9", 424 | ] 425 | 426 | [[package]] 427 | name = "flate2" 428 | version = "1.0.23" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" 431 | dependencies = [ 432 | "cfg-if 1.0.0", 433 | "crc32fast", 434 | "libc", 435 | "miniz_oxide", 436 | ] 437 | 438 | [[package]] 439 | name = "fnv" 440 | version = "1.0.7" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 443 | 444 | [[package]] 445 | name = "form_urlencoded" 446 | version = "1.0.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 449 | dependencies = [ 450 | "matches", 451 | "percent-encoding 2.1.0", 452 | ] 453 | 454 | [[package]] 455 | name = "fuchsia-zircon" 456 | version = "0.3.3" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 459 | dependencies = [ 460 | "bitflags", 461 | "fuchsia-zircon-sys", 462 | ] 463 | 464 | [[package]] 465 | name = "fuchsia-zircon-sys" 466 | version = "0.3.3" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 469 | 470 | [[package]] 471 | name = "futures" 472 | version = "0.3.21" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" 475 | dependencies = [ 476 | "futures-channel", 477 | "futures-core", 478 | "futures-executor", 479 | "futures-io", 480 | "futures-sink", 481 | "futures-task", 482 | "futures-util", 483 | ] 484 | 485 | [[package]] 486 | name = "futures-channel" 487 | version = "0.3.21" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 490 | dependencies = [ 491 | "futures-core", 492 | "futures-sink", 493 | ] 494 | 495 | [[package]] 496 | name = "futures-core" 497 | version = "0.3.21" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 500 | 501 | [[package]] 502 | name = "futures-executor" 503 | version = "0.3.21" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" 506 | dependencies = [ 507 | "futures-core", 508 | "futures-task", 509 | "futures-util", 510 | ] 511 | 512 | [[package]] 513 | name = "futures-io" 514 | version = "0.3.21" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 517 | 518 | [[package]] 519 | name = "futures-macro" 520 | version = "0.3.21" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" 523 | dependencies = [ 524 | "proc-macro2", 525 | "quote", 526 | "syn", 527 | ] 528 | 529 | [[package]] 530 | name = "futures-sink" 531 | version = "0.3.21" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 534 | 535 | [[package]] 536 | name = "futures-task" 537 | version = "0.3.21" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 540 | 541 | [[package]] 542 | name = "futures-util" 543 | version = "0.3.21" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 546 | dependencies = [ 547 | "futures-channel", 548 | "futures-core", 549 | "futures-io", 550 | "futures-macro", 551 | "futures-sink", 552 | "futures-task", 553 | "memchr", 554 | "pin-project-lite 0.2.9", 555 | "pin-utils", 556 | "slab", 557 | ] 558 | 559 | [[package]] 560 | name = "generic-array" 561 | version = "0.14.5" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 564 | dependencies = [ 565 | "typenum", 566 | "version_check", 567 | ] 568 | 569 | [[package]] 570 | name = "getrandom" 571 | version = "0.1.16" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 574 | dependencies = [ 575 | "cfg-if 1.0.0", 576 | "libc", 577 | "wasi 0.9.0+wasi-snapshot-preview1", 578 | ] 579 | 580 | [[package]] 581 | name = "h2" 582 | version = "0.2.7" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" 585 | dependencies = [ 586 | "bytes 0.5.6", 587 | "fnv", 588 | "futures-core", 589 | "futures-sink", 590 | "futures-util", 591 | "http", 592 | "indexmap", 593 | "slab", 594 | "tokio", 595 | "tokio-util", 596 | "tracing", 597 | "tracing-futures", 598 | ] 599 | 600 | [[package]] 601 | name = "hashbrown" 602 | version = "0.11.2" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 605 | 606 | [[package]] 607 | name = "hermit-abi" 608 | version = "0.1.19" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 611 | dependencies = [ 612 | "libc", 613 | ] 614 | 615 | [[package]] 616 | name = "hmac" 617 | version = "0.12.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 620 | dependencies = [ 621 | "digest", 622 | ] 623 | 624 | [[package]] 625 | name = "http" 626 | version = "0.2.7" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" 629 | dependencies = [ 630 | "bytes 1.1.0", 631 | "fnv", 632 | "itoa 1.0.2", 633 | ] 634 | 635 | [[package]] 636 | name = "http-body" 637 | version = "0.3.1" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" 640 | dependencies = [ 641 | "bytes 0.5.6", 642 | "http", 643 | ] 644 | 645 | [[package]] 646 | name = "httparse" 647 | version = "1.7.1" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" 650 | 651 | [[package]] 652 | name = "httpdate" 653 | version = "0.3.2" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" 656 | 657 | [[package]] 658 | name = "hyper" 659 | version = "0.13.10" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" 662 | dependencies = [ 663 | "bytes 0.5.6", 664 | "futures-channel", 665 | "futures-core", 666 | "futures-util", 667 | "h2", 668 | "http", 669 | "http-body", 670 | "httparse", 671 | "httpdate", 672 | "itoa 0.4.8", 673 | "pin-project", 674 | "socket2", 675 | "tokio", 676 | "tower-service", 677 | "tracing", 678 | "want", 679 | ] 680 | 681 | [[package]] 682 | name = "hyper-rustls" 683 | version = "0.21.0" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6" 686 | dependencies = [ 687 | "bytes 0.5.6", 688 | "futures-util", 689 | "hyper", 690 | "log", 691 | "rustls", 692 | "tokio", 693 | "tokio-rustls", 694 | "webpki", 695 | ] 696 | 697 | [[package]] 698 | name = "idna" 699 | version = "0.2.3" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 702 | dependencies = [ 703 | "matches", 704 | "unicode-bidi", 705 | "unicode-normalization", 706 | ] 707 | 708 | [[package]] 709 | name = "indexmap" 710 | version = "1.8.1" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" 713 | dependencies = [ 714 | "autocfg", 715 | "hashbrown", 716 | ] 717 | 718 | [[package]] 719 | name = "iovec" 720 | version = "0.1.4" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 723 | dependencies = [ 724 | "libc", 725 | ] 726 | 727 | [[package]] 728 | name = "ipnet" 729 | version = "2.5.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" 732 | 733 | [[package]] 734 | name = "itoa" 735 | version = "0.4.8" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 738 | 739 | [[package]] 740 | name = "itoa" 741 | version = "1.0.2" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" 744 | 745 | [[package]] 746 | name = "jobserver" 747 | version = "0.1.24" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 750 | dependencies = [ 751 | "libc", 752 | ] 753 | 754 | [[package]] 755 | name = "js-sys" 756 | version = "0.3.57" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" 759 | dependencies = [ 760 | "wasm-bindgen", 761 | ] 762 | 763 | [[package]] 764 | name = "kernel32-sys" 765 | version = "0.2.2" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 768 | dependencies = [ 769 | "winapi 0.2.8", 770 | "winapi-build", 771 | ] 772 | 773 | [[package]] 774 | name = "lazy_static" 775 | version = "0.2.11" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" 778 | 779 | [[package]] 780 | name = "lazy_static" 781 | version = "1.4.0" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 784 | 785 | [[package]] 786 | name = "libc" 787 | version = "0.2.126" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 790 | 791 | [[package]] 792 | name = "log" 793 | version = "0.4.17" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 796 | dependencies = [ 797 | "cfg-if 1.0.0", 798 | ] 799 | 800 | [[package]] 801 | name = "matches" 802 | version = "0.1.9" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 805 | 806 | [[package]] 807 | name = "memchr" 808 | version = "2.5.0" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 811 | 812 | [[package]] 813 | name = "memoffset" 814 | version = "0.6.5" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 817 | dependencies = [ 818 | "autocfg", 819 | ] 820 | 821 | [[package]] 822 | name = "mime" 823 | version = "0.3.16" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 826 | 827 | [[package]] 828 | name = "mime_guess" 829 | version = "2.0.4" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 832 | dependencies = [ 833 | "mime", 834 | "unicase", 835 | ] 836 | 837 | [[package]] 838 | name = "miniz_oxide" 839 | version = "0.5.1" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" 842 | dependencies = [ 843 | "adler", 844 | ] 845 | 846 | [[package]] 847 | name = "mio" 848 | version = "0.6.23" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 851 | dependencies = [ 852 | "cfg-if 0.1.10", 853 | "fuchsia-zircon", 854 | "fuchsia-zircon-sys", 855 | "iovec", 856 | "kernel32-sys", 857 | "libc", 858 | "log", 859 | "miow 0.2.2", 860 | "net2", 861 | "slab", 862 | "winapi 0.2.8", 863 | ] 864 | 865 | [[package]] 866 | name = "mio-named-pipes" 867 | version = "0.1.7" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" 870 | dependencies = [ 871 | "log", 872 | "mio", 873 | "miow 0.3.7", 874 | "winapi 0.3.9", 875 | ] 876 | 877 | [[package]] 878 | name = "mio-uds" 879 | version = "0.6.8" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" 882 | dependencies = [ 883 | "iovec", 884 | "libc", 885 | "mio", 886 | ] 887 | 888 | [[package]] 889 | name = "miow" 890 | version = "0.2.2" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 893 | dependencies = [ 894 | "kernel32-sys", 895 | "net2", 896 | "winapi 0.2.8", 897 | "ws2_32-sys", 898 | ] 899 | 900 | [[package]] 901 | name = "miow" 902 | version = "0.3.7" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 905 | dependencies = [ 906 | "winapi 0.3.9", 907 | ] 908 | 909 | [[package]] 910 | name = "net2" 911 | version = "0.2.37" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" 914 | dependencies = [ 915 | "cfg-if 0.1.10", 916 | "libc", 917 | "winapi 0.3.9", 918 | ] 919 | 920 | [[package]] 921 | name = "nonblock-logger" 922 | version = "0.1.6" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "44c65a1b0b7ae2a119e5ec0d36d2cb202e29cb7a41268a4159e0926bb3112dfc" 925 | dependencies = [ 926 | "chrono", 927 | "colored", 928 | "crossbeam-channel", 929 | "log", 930 | ] 931 | 932 | [[package]] 933 | name = "num-integer" 934 | version = "0.1.45" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 937 | dependencies = [ 938 | "autocfg", 939 | "num-traits", 940 | ] 941 | 942 | [[package]] 943 | name = "num-traits" 944 | version = "0.2.15" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 947 | dependencies = [ 948 | "autocfg", 949 | ] 950 | 951 | [[package]] 952 | name = "num_cpus" 953 | version = "1.13.1" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 956 | dependencies = [ 957 | "hermit-abi", 958 | "libc", 959 | ] 960 | 961 | [[package]] 962 | name = "num_threads" 963 | version = "0.1.6" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" 966 | dependencies = [ 967 | "libc", 968 | ] 969 | 970 | [[package]] 971 | name = "once_cell" 972 | version = "1.11.0" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" 975 | 976 | [[package]] 977 | name = "opaque-debug" 978 | version = "0.3.0" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 981 | 982 | [[package]] 983 | name = "password-hash" 984 | version = "0.3.2" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" 987 | dependencies = [ 988 | "base64ct", 989 | "rand_core", 990 | "subtle", 991 | ] 992 | 993 | [[package]] 994 | name = "pbkdf2" 995 | version = "0.10.1" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" 998 | dependencies = [ 999 | "digest", 1000 | "hmac", 1001 | "password-hash", 1002 | "sha2", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "percent-encoding" 1007 | version = "1.0.1" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 1010 | 1011 | [[package]] 1012 | name = "percent-encoding" 1013 | version = "2.1.0" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1016 | 1017 | [[package]] 1018 | name = "pin-project" 1019 | version = "1.0.10" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" 1022 | dependencies = [ 1023 | "pin-project-internal", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "pin-project-internal" 1028 | version = "1.0.10" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" 1031 | dependencies = [ 1032 | "proc-macro2", 1033 | "quote", 1034 | "syn", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "pin-project-lite" 1039 | version = "0.1.12" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" 1042 | 1043 | [[package]] 1044 | name = "pin-project-lite" 1045 | version = "0.2.9" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1048 | 1049 | [[package]] 1050 | name = "pin-utils" 1051 | version = "0.1.0" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1054 | 1055 | [[package]] 1056 | name = "pkg-config" 1057 | version = "0.3.25" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 1060 | 1061 | [[package]] 1062 | name = "proc-macro2" 1063 | version = "1.0.39" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" 1066 | dependencies = [ 1067 | "unicode-ident", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "quick-error" 1072 | version = "1.2.3" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1075 | 1076 | [[package]] 1077 | name = "quote" 1078 | version = "1.0.18" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 1081 | dependencies = [ 1082 | "proc-macro2", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "rand_core" 1087 | version = "0.6.3" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1090 | 1091 | [[package]] 1092 | name = "rayon" 1093 | version = "1.5.3" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" 1096 | dependencies = [ 1097 | "autocfg", 1098 | "crossbeam-deque", 1099 | "either", 1100 | "rayon-core", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "rayon-core" 1105 | version = "1.9.3" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" 1108 | dependencies = [ 1109 | "crossbeam-channel", 1110 | "crossbeam-deque", 1111 | "crossbeam-utils", 1112 | "num_cpus", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "redox_syscall" 1117 | version = "0.1.57" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1120 | 1121 | [[package]] 1122 | name = "redox_syscall" 1123 | version = "0.2.13" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 1126 | dependencies = [ 1127 | "bitflags", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "redox_users" 1132 | version = "0.3.5" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 1135 | dependencies = [ 1136 | "getrandom", 1137 | "redox_syscall 0.1.57", 1138 | "rust-argon2", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "regex" 1143 | version = "1.5.6" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" 1146 | dependencies = [ 1147 | "aho-corasick", 1148 | "memchr", 1149 | "regex-syntax", 1150 | ] 1151 | 1152 | [[package]] 1153 | name = "regex-syntax" 1154 | version = "0.6.26" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" 1157 | 1158 | [[package]] 1159 | name = "reqwest" 1160 | version = "0.10.10" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" 1163 | dependencies = [ 1164 | "async-compression", 1165 | "base64 0.13.0", 1166 | "bytes 0.5.6", 1167 | "encoding_rs", 1168 | "futures-core", 1169 | "futures-util", 1170 | "http", 1171 | "http-body", 1172 | "hyper", 1173 | "hyper-rustls", 1174 | "ipnet", 1175 | "js-sys", 1176 | "lazy_static 1.4.0", 1177 | "log", 1178 | "mime", 1179 | "mime_guess", 1180 | "percent-encoding 2.1.0", 1181 | "pin-project-lite 0.2.9", 1182 | "rustls", 1183 | "serde", 1184 | "serde_urlencoded", 1185 | "tokio", 1186 | "tokio-rustls", 1187 | "url", 1188 | "wasm-bindgen", 1189 | "wasm-bindgen-futures", 1190 | "web-sys", 1191 | "webpki-roots", 1192 | "winreg", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "ring" 1197 | version = "0.16.20" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1200 | dependencies = [ 1201 | "cc", 1202 | "libc", 1203 | "once_cell", 1204 | "spin", 1205 | "untrusted", 1206 | "web-sys", 1207 | "winapi 0.3.9", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "rust-argon2" 1212 | version = "0.8.3" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" 1215 | dependencies = [ 1216 | "base64 0.13.0", 1217 | "blake2b_simd", 1218 | "constant_time_eq", 1219 | "crossbeam-utils", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "rustls" 1224 | version = "0.18.1" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" 1227 | dependencies = [ 1228 | "base64 0.12.3", 1229 | "log", 1230 | "ring", 1231 | "sct", 1232 | "webpki", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "ryu" 1237 | version = "1.0.10" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" 1240 | 1241 | [[package]] 1242 | name = "scopeguard" 1243 | version = "1.1.0" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1246 | 1247 | [[package]] 1248 | name = "sct" 1249 | version = "0.6.1" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1252 | dependencies = [ 1253 | "ring", 1254 | "untrusted", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "serde" 1259 | version = "1.0.137" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" 1262 | 1263 | [[package]] 1264 | name = "serde_json" 1265 | version = "1.0.81" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" 1268 | dependencies = [ 1269 | "itoa 1.0.2", 1270 | "ryu", 1271 | "serde", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "serde_urlencoded" 1276 | version = "0.7.1" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1279 | dependencies = [ 1280 | "form_urlencoded", 1281 | "itoa 1.0.2", 1282 | "ryu", 1283 | "serde", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "sha1" 1288 | version = "0.10.1" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" 1291 | dependencies = [ 1292 | "cfg-if 1.0.0", 1293 | "cpufeatures", 1294 | "digest", 1295 | ] 1296 | 1297 | [[package]] 1298 | name = "sha2" 1299 | version = "0.10.2" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" 1302 | dependencies = [ 1303 | "cfg-if 1.0.0", 1304 | "cpufeatures", 1305 | "digest", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "signal-hook-registry" 1310 | version = "1.4.0" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1313 | dependencies = [ 1314 | "libc", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "slab" 1319 | version = "0.4.6" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" 1322 | 1323 | [[package]] 1324 | name = "socket2" 1325 | version = "0.3.19" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 1328 | dependencies = [ 1329 | "cfg-if 1.0.0", 1330 | "libc", 1331 | "winapi 0.3.9", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "spin" 1336 | version = "0.5.2" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1339 | 1340 | [[package]] 1341 | name = "stderr" 1342 | version = "0.8.0" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "9ee63545cb3066bed00544996fb5b545426632bf7d14ab3e6567602a49819ef8" 1345 | dependencies = [ 1346 | "lazy_static 0.2.11", 1347 | "time 0.1.44", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "subtle" 1352 | version = "2.4.1" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1355 | 1356 | [[package]] 1357 | name = "syn" 1358 | version = "1.0.95" 1359 | source = "registry+https://github.com/rust-lang/crates.io-index" 1360 | checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" 1361 | dependencies = [ 1362 | "proc-macro2", 1363 | "quote", 1364 | "unicode-ident", 1365 | ] 1366 | 1367 | [[package]] 1368 | name = "term" 1369 | version = "0.5.2" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" 1372 | dependencies = [ 1373 | "byteorder", 1374 | "dirs", 1375 | "winapi 0.3.9", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "time" 1380 | version = "0.1.44" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1383 | dependencies = [ 1384 | "libc", 1385 | "wasi 0.10.0+wasi-snapshot-preview1", 1386 | "winapi 0.3.9", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "time" 1391 | version = "0.3.9" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" 1394 | dependencies = [ 1395 | "itoa 1.0.2", 1396 | "libc", 1397 | "num_threads", 1398 | "time-macros", 1399 | ] 1400 | 1401 | [[package]] 1402 | name = "time-macros" 1403 | version = "0.2.4" 1404 | source = "registry+https://github.com/rust-lang/crates.io-index" 1405 | checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" 1406 | 1407 | [[package]] 1408 | name = "tinyvec" 1409 | version = "1.6.0" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1412 | dependencies = [ 1413 | "tinyvec_macros", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "tinyvec_macros" 1418 | version = "0.1.0" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1421 | 1422 | [[package]] 1423 | name = "tokio" 1424 | version = "0.2.25" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" 1427 | dependencies = [ 1428 | "bytes 0.5.6", 1429 | "fnv", 1430 | "futures-core", 1431 | "iovec", 1432 | "lazy_static 1.4.0", 1433 | "libc", 1434 | "memchr", 1435 | "mio", 1436 | "mio-named-pipes", 1437 | "mio-uds", 1438 | "pin-project-lite 0.1.12", 1439 | "signal-hook-registry", 1440 | "slab", 1441 | "winapi 0.3.9", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "tokio-rustls" 1446 | version = "0.14.1" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" 1449 | dependencies = [ 1450 | "futures-core", 1451 | "rustls", 1452 | "tokio", 1453 | "webpki", 1454 | ] 1455 | 1456 | [[package]] 1457 | name = "tokio-util" 1458 | version = "0.3.1" 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" 1460 | checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" 1461 | dependencies = [ 1462 | "bytes 0.5.6", 1463 | "futures-core", 1464 | "futures-sink", 1465 | "log", 1466 | "pin-project-lite 0.1.12", 1467 | "tokio", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "tower-service" 1472 | version = "0.3.1" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1475 | 1476 | [[package]] 1477 | name = "tracing" 1478 | version = "0.1.34" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" 1481 | dependencies = [ 1482 | "cfg-if 1.0.0", 1483 | "log", 1484 | "pin-project-lite 0.2.9", 1485 | "tracing-core", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "tracing-core" 1490 | version = "0.1.26" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" 1493 | dependencies = [ 1494 | "lazy_static 1.4.0", 1495 | ] 1496 | 1497 | [[package]] 1498 | name = "tracing-futures" 1499 | version = "0.2.5" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 1502 | dependencies = [ 1503 | "pin-project", 1504 | "tracing", 1505 | ] 1506 | 1507 | [[package]] 1508 | name = "try-lock" 1509 | version = "0.2.3" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1512 | 1513 | [[package]] 1514 | name = "typenum" 1515 | version = "1.15.0" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1518 | 1519 | [[package]] 1520 | name = "unicase" 1521 | version = "2.6.0" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1524 | dependencies = [ 1525 | "version_check", 1526 | ] 1527 | 1528 | [[package]] 1529 | name = "unicode-bidi" 1530 | version = "0.3.8" 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" 1532 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 1533 | 1534 | [[package]] 1535 | name = "unicode-ident" 1536 | version = "1.0.0" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" 1539 | 1540 | [[package]] 1541 | name = "unicode-normalization" 1542 | version = "0.1.19" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1545 | dependencies = [ 1546 | "tinyvec", 1547 | ] 1548 | 1549 | [[package]] 1550 | name = "untrusted" 1551 | version = "0.7.1" 1552 | source = "registry+https://github.com/rust-lang/crates.io-index" 1553 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1554 | 1555 | [[package]] 1556 | name = "url" 1557 | version = "2.2.2" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1560 | dependencies = [ 1561 | "form_urlencoded", 1562 | "idna", 1563 | "matches", 1564 | "percent-encoding 2.1.0", 1565 | ] 1566 | 1567 | [[package]] 1568 | name = "version_check" 1569 | version = "0.9.4" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1572 | 1573 | [[package]] 1574 | name = "want" 1575 | version = "0.3.0" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1578 | dependencies = [ 1579 | "log", 1580 | "try-lock", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "wasi" 1585 | version = "0.9.0+wasi-snapshot-preview1" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1588 | 1589 | [[package]] 1590 | name = "wasi" 1591 | version = "0.10.0+wasi-snapshot-preview1" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1594 | 1595 | [[package]] 1596 | name = "wasm-bindgen" 1597 | version = "0.2.80" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" 1600 | dependencies = [ 1601 | "cfg-if 1.0.0", 1602 | "serde", 1603 | "serde_json", 1604 | "wasm-bindgen-macro", 1605 | ] 1606 | 1607 | [[package]] 1608 | name = "wasm-bindgen-backend" 1609 | version = "0.2.80" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" 1612 | dependencies = [ 1613 | "bumpalo", 1614 | "lazy_static 1.4.0", 1615 | "log", 1616 | "proc-macro2", 1617 | "quote", 1618 | "syn", 1619 | "wasm-bindgen-shared", 1620 | ] 1621 | 1622 | [[package]] 1623 | name = "wasm-bindgen-futures" 1624 | version = "0.4.30" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" 1627 | dependencies = [ 1628 | "cfg-if 1.0.0", 1629 | "js-sys", 1630 | "wasm-bindgen", 1631 | "web-sys", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "wasm-bindgen-macro" 1636 | version = "0.2.80" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" 1639 | dependencies = [ 1640 | "quote", 1641 | "wasm-bindgen-macro-support", 1642 | ] 1643 | 1644 | [[package]] 1645 | name = "wasm-bindgen-macro-support" 1646 | version = "0.2.80" 1647 | source = "registry+https://github.com/rust-lang/crates.io-index" 1648 | checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" 1649 | dependencies = [ 1650 | "proc-macro2", 1651 | "quote", 1652 | "syn", 1653 | "wasm-bindgen-backend", 1654 | "wasm-bindgen-shared", 1655 | ] 1656 | 1657 | [[package]] 1658 | name = "wasm-bindgen-shared" 1659 | version = "0.2.80" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" 1662 | 1663 | [[package]] 1664 | name = "web-sys" 1665 | version = "0.3.57" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" 1668 | dependencies = [ 1669 | "js-sys", 1670 | "wasm-bindgen", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "webpki" 1675 | version = "0.21.4" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 1678 | dependencies = [ 1679 | "ring", 1680 | "untrusted", 1681 | ] 1682 | 1683 | [[package]] 1684 | name = "webpki-roots" 1685 | version = "0.20.0" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "0f20dea7535251981a9670857150d571846545088359b28e4951d350bdaf179f" 1688 | dependencies = [ 1689 | "webpki", 1690 | ] 1691 | 1692 | [[package]] 1693 | name = "winapi" 1694 | version = "0.2.8" 1695 | source = "registry+https://github.com/rust-lang/crates.io-index" 1696 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1697 | 1698 | [[package]] 1699 | name = "winapi" 1700 | version = "0.3.9" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1703 | dependencies = [ 1704 | "winapi-i686-pc-windows-gnu", 1705 | "winapi-x86_64-pc-windows-gnu", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "winapi-build" 1710 | version = "0.1.1" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1713 | 1714 | [[package]] 1715 | name = "winapi-i686-pc-windows-gnu" 1716 | version = "0.4.0" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1719 | 1720 | [[package]] 1721 | name = "winapi-x86_64-pc-windows-gnu" 1722 | version = "0.4.0" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1725 | 1726 | [[package]] 1727 | name = "winreg" 1728 | version = "0.7.0" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 1731 | dependencies = [ 1732 | "winapi 0.3.9", 1733 | ] 1734 | 1735 | [[package]] 1736 | name = "ws2_32-sys" 1737 | version = "0.2.1" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1740 | dependencies = [ 1741 | "winapi 0.2.8", 1742 | "winapi-build", 1743 | ] 1744 | 1745 | [[package]] 1746 | name = "zcs" 1747 | version = "0.3.9" 1748 | dependencies = [ 1749 | "app", 1750 | "chardet", 1751 | "chrono", 1752 | "encoding", 1753 | "filetime", 1754 | "futures", 1755 | "lazy_static 1.4.0", 1756 | "nonblock-logger", 1757 | "percent-encoding 1.0.1", 1758 | "rayon", 1759 | "regex", 1760 | "reqwest", 1761 | "time 0.1.44", 1762 | "tokio", 1763 | "zip", 1764 | ] 1765 | 1766 | [[package]] 1767 | name = "zip" 1768 | version = "0.6.2" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" 1771 | dependencies = [ 1772 | "aes", 1773 | "byteorder", 1774 | "bzip2", 1775 | "constant_time_eq", 1776 | "crc32fast", 1777 | "crossbeam-utils", 1778 | "flate2", 1779 | "hmac", 1780 | "pbkdf2", 1781 | "sha1", 1782 | "time 0.3.9", 1783 | "zstd", 1784 | ] 1785 | 1786 | [[package]] 1787 | name = "zstd" 1788 | version = "0.10.2+zstd.1.5.2" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" 1791 | dependencies = [ 1792 | "zstd-safe", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "zstd-safe" 1797 | version = "4.1.6+zstd.1.5.2" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" 1800 | dependencies = [ 1801 | "libc", 1802 | "zstd-sys", 1803 | ] 1804 | 1805 | [[package]] 1806 | name = "zstd-sys" 1807 | version = "1.6.3+zstd.1.5.2" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" 1810 | dependencies = [ 1811 | "cc", 1812 | "libc", 1813 | ] 1814 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcs" 3 | version = "0.3.9" 4 | authors = ["Wspsxing "] 5 | description = "Useful tools collection." 6 | edition = "2018" 7 | repository = "https://github.com/biluohc/zipcs" 8 | # documentation = "https://docs.rs/zipcs/" 9 | readme = "readme.md" 10 | keywords = ["unzip","charset","ping", "url", "ip"] 11 | license = "MIT" 12 | build = "build.rs" 13 | 14 | [profile.release] 15 | opt-level = 3 16 | # lto = true 17 | # debug = true 18 | 19 | [build-dependencies] 20 | encoding = "0.2" 21 | chardet = "0.2" 22 | time = "0.1" 23 | 24 | [dependencies.app] 25 | version = "0.6.5" 26 | # path = "../app" 27 | # git = "https://github.com/biluohc/app" 28 | # branch = "master" 29 | # commit = "" 30 | 31 | [dependencies] 32 | nonblock-logger = { version = "0.1", features = [ "color" ] } 33 | reqwest = { version = "0.10.0", default-features = false, features = ["rustls-tls", "gzip"] } 34 | tokio = { version = "0.2.9", features = ["rt-core", "process", "time"] } 35 | futures = "0.3.2" 36 | percent-encoding = "1.0" 37 | lazy_static = "1.4" 38 | encoding = "0.2.33" # or replace with encoding_rs 39 | filetime = "0.2.8" 40 | chardet = "0.2.3" 41 | chrono = "0.4.8" 42 | regex = "1.3" 43 | rayon = "1.3" 44 | zip = "0.6.2" 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 wspsxing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | br: 2 | echo "\033[35m 正式编译于: `TZ=UTC-8 date +"%Y-%m-%d %H:%M:%S"` \033[0m" 3 | 4 | pwd && ls -al && cargo build --release 5 | 6 | b: 7 | echo "\033[35m 编译于: `TZ=UTC-8 date +"%Y-%m-%d %H:%M:%S"` \033[0m" 8 | 9 | pwd && ls -al && cargo build 10 | 11 | d: 12 | echo "\033[35m 文档编译于: `TZ=UTC-8 date +"%Y-%m-%d %H:%M:%S"` \033[0m" 13 | 14 | cargo doc 15 | 16 | f: 17 | echo "\033[35m 格式化于: `TZ=UTC-8 date +"%Y-%m-%d %H:%M:%S"` \033[0m" 18 | cargo fmt 19 | 20 | a: 21 | make br && echo -n && make b && echo -n && make d 22 | 23 | c: 24 | cargo clean 25 | 26 | t: 27 | cargo test -- --nocapture 28 | 29 | tr: 30 | cargo test --release -- --nocapture 31 | 32 | -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | [![Build status](https://travis-ci.org/biluohc/zipcs.svg?branch=master)](https://github.com/biluohc/zipcs) 2 | 3 | {{readme}} -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate chardet; 2 | extern crate encoding; 3 | extern crate time; 4 | 5 | use chardet::{charset2encoding, detect}; 6 | use encoding::label::encoding_from_whatwg_label; 7 | use encoding::DecoderTrap; 8 | use time::now_utc; 9 | 10 | use std::env; 11 | use std::fs::File; 12 | use std::io::{self, Write}; 13 | use std::path::PathBuf; 14 | use std::process::Command as Cmd; 15 | 16 | /// `include!(concat!(env!("OUT_DIR"), "/zipcs.txt"));` 17 | fn main() { 18 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); 19 | let out_path = out_dir.join("zipcs.txt"); 20 | File::create(&out_path) 21 | .and_then(|mut f| f.write_all(fun().as_bytes())) 22 | .unwrap() 23 | } 24 | 25 | fn fun() -> String { 26 | let rustc = rustc_version() 27 | .map(|s| format!(" rustc{}", s.split(' ').nth(1).unwrap())) 28 | .unwrap_or_default(); 29 | let git = commit_hash() 30 | .and_then(|s| branch_name().map(|b| format!("{}@{}{} ", s, b, rustc))) 31 | .unwrap_or_default(); 32 | 33 | let version = format!("{} ({}{})", env!("CARGO_PKG_VERSION"), git, date_time()); 34 | format!("pub const VERSION: &str = \"{}\";", version) 35 | } 36 | 37 | // date --help 38 | fn date_time() -> String { 39 | now_utc() 40 | // .strftime("%Y-%m-%d/%H:%M:%SUTC") 41 | .strftime("%Y-%m-%dUTC") 42 | .map(|dt| dt.to_string()) 43 | .unwrap_or_default() 44 | } 45 | 46 | // git describe --always --abbrev=10 --dirty=-modified 47 | fn commit_hash() -> io::Result { 48 | Cmd::new("git") 49 | .args(&["describe", "--always", "--abbrev=8", "--dirty=-modified"]) 50 | .output() 51 | .map(|o| decode(&o.stdout)) 52 | .map(|s| s.trim().to_string()) 53 | } 54 | 55 | fn branch_name() -> io::Result { 56 | Cmd::new("git") 57 | .args(&["rev-parse", "--abbrev-ref", "HEAD"]) 58 | .output() 59 | .map(|o| decode(o.stdout.as_slice()).trim().to_string()) 60 | } 61 | 62 | fn rustc_version() -> io::Result { 63 | Cmd::new("rustc") 64 | .arg("--version") 65 | .output() 66 | .map(|o| decode_utf8_unchecked(o.stdout).trim().to_string()) 67 | } 68 | 69 | fn decode_utf8_unchecked(bytes: Vec) -> String { 70 | unsafe { String::from_utf8_unchecked(bytes) } 71 | } 72 | 73 | fn decode(bytes: &[u8]) -> String { 74 | encoding_from_whatwg_label(charset2encoding(&detect(bytes).0)) 75 | .and_then(|code| code.decode(bytes, DecoderTrap::Strict).ok()) 76 | .unwrap_or_else(|| String::from_utf8_lossy(bytes).into_owned()) 77 | } 78 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://travis-ci.org/biluohc/zipcs.svg?branch=master)](https://github.com/biluohc/zipcs) 2 | 3 | ## Useful tools collection. 4 | 5 | ### Usage 6 | 7 | ```sh 8 | cargo install --git https://github.com/biluohc/zipcs 9 | zcs -h 10 | ``` 11 | 12 | ### Or 13 | 14 | ```sh 15 | git clone https://github.com/biluohc/zipcs 16 | cd zipcs 17 | cargo build --release 18 | 19 | ./target/release/zcs --help 20 | ``` 21 | ### Help 22 | 23 | ```sh 24 | zcs 0.3.8 (b6127dc7@master rustc1.59.0 2022-04-13UTC) 25 | Useful tools collection. 26 | Wspsxing 27 | Repo: https://github.com/biluohc/zipcs 28 | 29 | USAGE: 30 | zcs options 31 | zcs [args] 32 | 33 | OPTIONS: 34 | -h, --help Show the help message 35 | -V, --version Show the version message 36 | 37 | CAMMANDS: 38 | zip, z Unzip with charset setting 39 | path, P Paths decoding with charset setting 40 | file, f Files encoding/decoding with charset setting 41 | ping, p ping domains/ips 42 | chardet, c Detect the charset for File(for reference) 43 | charset, C Show all CharSet supported 44 | ip, i Get ip address and it's location 45 | url, u Urls decoding/encoding 46 | ``` 47 | 48 | ### Binary 49 | 50 | * [The Release Page](https://github.com/biluohc/zipcs/releases) 51 | 52 | ### Ps 53 | * 所依赖的[zip-rs](https://github.com/mvdnes/zip-rs)库目前不支持 Multi-disk。 54 | -------------------------------------------------------------------------------- /src/args.rs: -------------------------------------------------------------------------------- 1 | use crate::{coll::*, consts::*}; 2 | 3 | use app::{args, App, Args, Cmd, Opt, OptTypo, OptValue, OptValueParse}; 4 | 5 | #[derive(Debug, Default)] 6 | pub struct Config { 7 | zip: Zips, 8 | ping: Pings, 9 | url: Urls, 10 | path: Paths, 11 | file: Files, 12 | chardet: CharDet, 13 | ips: Ips, 14 | } 15 | 16 | impl Config { 17 | pub fn parse() { 18 | let mut config = Self::default(); 19 | let mut list = false; 20 | let mut detect = false; 21 | let charsets = format!( 22 | "Sets the charset Zipcs using({})\nYou can see all CharSet by `zipcs charset`", 23 | CHARSETS.replace("_", "").to_lowercase() 24 | ); 25 | let helper = { 26 | App::new(NAME) 27 | .version(VERSION) 28 | .author(AUTHOR, EMAIL) 29 | .addr(URL_NAME, URL) 30 | .desc(DESC) 31 | .cmd( 32 | Cmd::new("zip") 33 | .short("z") 34 | .sort_key("1") 35 | .desc("Unzip with charset setting") 36 | .opt( 37 | Opt::new("list", &mut list) 38 | .short('l') 39 | .long("list") 40 | .help("Only list files from ZipArchives"), 41 | ) 42 | .opt( 43 | Opt::new("detect", &mut detect) 44 | .short('d') 45 | .long("chardet") 46 | .help("Detect the charset for File's name from ZipArchive"), 47 | ) 48 | .opt( 49 | Opt::new("charset", &mut config.zip.charset) 50 | .short('c') 51 | .long("charset") 52 | .help(&charsets), 53 | ) 54 | .opt( 55 | Opt::new("outdir", &mut config.zip.outdir) 56 | .optional() 57 | .short('o') 58 | .long("outdir") 59 | .help("Sets Output directory(default is the name of ZipArchive)"), 60 | ) 61 | .opt( 62 | Opt::new("password", &mut config.zip.password) 63 | .optional() 64 | .short('p') 65 | .long("password") 66 | .help("Sets password"), 67 | ) 68 | .args(Args::new("ZipArchive", &mut config.zip.zips).help("ZipArchive need to unzip")), 69 | ) 70 | .cmd( 71 | Cmd::new("path") 72 | .short("P") 73 | .sort_key("2") 74 | .desc("Paths decoding with charset setting") 75 | .opt( 76 | Opt::new("charset", &mut config.path.charset) 77 | .short('c') 78 | .long("charset") 79 | .help(&charsets), 80 | ) 81 | .opt( 82 | Opt::new("depth", &mut config.path.depth) 83 | .optional() 84 | .short('d') 85 | .long("depth") 86 | .help("decode paths recursively depth(default without limit)"), 87 | ) 88 | .opt( 89 | Opt::new("store", &mut config.path.store) 90 | .short('s') 91 | .long("store") 92 | .help("store result by rename"), 93 | ) 94 | .opt( 95 | Opt::new("link", &mut config.path.link) 96 | .short('l') 97 | .long("link") 98 | .help("follow symbolic links"), 99 | ) 100 | .args(Args::new("Path", &mut config.path.strs).help("Path need to decode")), 101 | ) 102 | .cmd( 103 | Cmd::new("file") 104 | .short("f") 105 | .sort_key("3") 106 | .desc("Files encoding/decoding with charset setting") 107 | .opt( 108 | Opt::new("charset", &mut config.file.charset) 109 | .short('c') 110 | .long("charset") 111 | .help(&charsets), 112 | ) 113 | .opt( 114 | Opt::new("charset_out", &mut config.file.charset_out) 115 | .short('C') 116 | .long("charset-out") 117 | .help("charset output(encode) using"), 118 | ) 119 | .opt( 120 | Opt::new("store", &mut config.file.store) 121 | .short('s') 122 | .long("store") 123 | .help("store result by rewrite"), 124 | ) 125 | .args(Args::new("File", &mut config.file.strs).help("File need to encode/decode")), 126 | ) 127 | .cmd( 128 | Cmd::new("ping") 129 | .short("p") 130 | .sort_key("4") 131 | .desc("ping domains/ips") 132 | .opt( 133 | Opt::new("count", &mut config.ping.count) 134 | .short('c') 135 | .long("count") 136 | .help("stop after sending count ECHO_REQUEST packets"), 137 | ) 138 | .opt(Opt::new("_6", &mut config.ping.v6).short('6').help("use IPV6")) 139 | .opt( 140 | Opt::new("only-line", &mut config.ping.only_line) 141 | .short('l') 142 | .long("only-line") 143 | .help("print result only-line"), 144 | ) 145 | .args(Args::new("Host/IP", &mut config.ping.hosts).help("Host or IP need to ping")), 146 | ) 147 | .cmd( 148 | Cmd::new("chardet") 149 | .short("c") 150 | .sort_key("5") 151 | .desc("Detect the charset for File(for reference)") 152 | .args(args("File", &mut config.chardet.files, "The file need to detect charset")), 153 | ) 154 | .cmd( 155 | Cmd::new("charset") 156 | .short("C") 157 | .sort_key("50") 158 | .desc("Show all CharSet supported"), 159 | ) 160 | .cmd( 161 | Cmd::new("ip") 162 | .short("i") 163 | .sort_key("6") 164 | .desc("Get ip address and it's location") 165 | .args(Args::new("Ip", &mut config.ips).optional().help("ip need to geo")), 166 | ) 167 | .cmd( 168 | Cmd::new("url") 169 | .short("u") 170 | .sort_key("7") 171 | .desc("Urls decoding/encoding") 172 | .opt( 173 | Opt::new("encode", &mut config.url.is_encode) 174 | .short('e') 175 | .long("encode") 176 | .help("encode(default is decode)"), 177 | ) 178 | .opt( 179 | Opt::new("all", &mut config.url.encode_all_chars) 180 | .short('a') 181 | .long("all") 182 | .help("encode all chars expect '/'"), 183 | ) 184 | .args(Args::new("Url", &mut config.url.strs).help("Url need to decode/encode")), 185 | ) 186 | .parse_args() 187 | }; 188 | if helper.current_cmd_str() == Some("zip") { 189 | if list && detect { 190 | helper.help_cmd_err_exit(helper.current_cmd_ref(), "Option `--list` conflict with `--chardet`", 1); 191 | } else if list { 192 | config.zip.task = Task::List; 193 | } else if detect { 194 | config.zip.task = Task::Chardet; 195 | } 196 | } 197 | if *helper.args_len() == 0 { 198 | helper.help_exit(0); 199 | } 200 | if let Err(e) = config.check_fix_call(helper.current_cmd_str()) { 201 | helper.help_cmd_err_exit(helper.current_cmd_ref(), e, 1); 202 | } 203 | } 204 | fn check_fix_call(mut self, cmd: Option<&str>) -> Result<(), String> { 205 | debug!("Config: {:?}: {:?}", cmd, self); 206 | match cmd { 207 | Some("zip") => { 208 | self.zip.check_fix()?; 209 | self.zip.call(); 210 | } 211 | Some("ping") => { 212 | self.ping.check_fix()?; 213 | self.ping.call(); 214 | } 215 | Some("chardet") => { 216 | self.chardet.check()?; 217 | self.chardet.call(); 218 | } 219 | Some("charset") => { 220 | CharSet::show(); 221 | } 222 | Some("url") => { 223 | self.url.call(); 224 | } 225 | Some("path") => { 226 | self.path.check_fix()?; 227 | self.path.call(); 228 | } 229 | Some("file") => { 230 | self.file.check_fix()?; 231 | self.file.call(); 232 | } 233 | Some("ip") => { 234 | call(self.ips); 235 | } 236 | _ => unreachable!(), 237 | } 238 | Ok(()) 239 | } 240 | } 241 | 242 | /// Custom `OptValue` by impl `OptValueParse` 243 | impl<'app, 's: 'app> OptValueParse<'app> for &'s mut CharSet { 244 | fn into(self) -> OptValue<'app> { 245 | OptValue::new(Box::from(self)) 246 | } 247 | fn is_bool(&self) -> bool { 248 | false 249 | } 250 | fn default(&self) -> Option { 251 | Some("utf8".to_owned()) 252 | } 253 | fn parse(&mut self, opt_name: &str, msg: &str, count: &mut usize, typo: &mut OptTypo) -> Result<(), String> { 254 | if *count == 0 || typo.is_covered() || typo.is_multiple() { 255 | match CharSet::new(msg) { 256 | Err(_) => { 257 | return Err(format!("OPTION(<{}>) parse fails: \"{}\"", opt_name, msg)); 258 | } 259 | Ok(o) => **self = o, 260 | } 261 | } else if typo.is_single() { 262 | return Err(format!("OPTION(<{}>) can only occurs once, but second: {:?}", opt_name, msg)); 263 | } 264 | Ok(()) 265 | } 266 | /// env::arg could is `""` 267 | fn check(&self, opt_name: &str, optional: &bool, count: &usize, _: &OptTypo) -> Result<(), String> { 268 | if !optional && *count == 0 && self.default().is_none() { 269 | return Err(format!("OPTION(<{}>) missing", opt_name)); 270 | } 271 | Ok(()) 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/coll/chardetect.rs: -------------------------------------------------------------------------------- 1 | use chardet::detect; 2 | use rayon::prelude::*; 3 | 4 | use super::consts::space_fix; 5 | use std::fs::File; 6 | use std::io::{self, BufReader, Read}; 7 | use std::path::Path; 8 | 9 | #[derive(Debug, Default)] 10 | pub struct CharDet { 11 | pub files: Vec, 12 | } 13 | 14 | impl CharDet { 15 | pub fn call(self) { 16 | debug!("{:?}", self); 17 | let max_len = self.files.as_slice().iter().max_by_key(|p| p.len()).unwrap().len(); 18 | // println!("{}{:3}CharSet{:13}Rate{:8}Info", space_fix("File",max_len), "", "", ""); 19 | self.files.par_iter().for_each(|file| match chardet(file) { 20 | Ok(o) => { 21 | let (mut charset, rate, info) = o; 22 | // "WINDOWS_1258".len() = 12 -> 12+6 = 18 23 | if charset.is_empty() { 24 | charset = "Binary".to_owned(); 25 | } 26 | println!( 27 | "{}: {} {:.4}{:6}{}", 28 | space_fix(file, max_len), 29 | space_fix(&charset, 18), 30 | rate, 31 | "", 32 | info 33 | ); 34 | } 35 | Err(e) => eprintln!("{}: {:?}", space_fix(file, max_len), e), 36 | }) 37 | } 38 | pub fn check(&self) -> Result<(), String> { 39 | for path in &self.files { 40 | let path = Path::new(path); 41 | if !path.exists() { 42 | return Err(format!("Args(File): {:?} is not exists", path)); 43 | } 44 | if !path.is_file() { 45 | return Err(format!("Args(File): {:?} is not a file", path)); 46 | } 47 | } 48 | Ok(()) 49 | } 50 | } 51 | 52 | fn chardet(f: &str) -> io::Result<(String, f32, String)> { 53 | let mut file = BufReader::new(File::open(f)?); 54 | let mut bytes = Vec::default(); 55 | file.read_to_end(&mut bytes)?; 56 | Ok(detect(bytes.as_slice())) 57 | } 58 | -------------------------------------------------------------------------------- /src/coll/file.rs: -------------------------------------------------------------------------------- 1 | use super::consts::*; 2 | use std::fs::File; 3 | use std::io::{Read, Write}; 4 | use std::path::Path; 5 | use std::process::exit; 6 | 7 | #[derive(Debug, Default)] 8 | pub struct Files { 9 | pub store: bool, 10 | pub strs: Vec, 11 | pub charset: CharSet, 12 | pub charset_out: CharSet, 13 | } 14 | 15 | impl Files { 16 | pub fn check_fix(&mut self) -> Result<(), String> { 17 | for str in &self.strs { 18 | if !Path::new(str).is_file() { 19 | return Err(format!("File isn't exits {:?}", str)); 20 | } 21 | } 22 | Ok(()) 23 | } 24 | pub fn call(self) { 25 | debug!("Config_file_: {:?}", self); 26 | 27 | for str in &self.strs { 28 | if let Err(e) = file_handle(str, &self) { 29 | eprintln!("{}", e); 30 | exit(1); 31 | } 32 | } 33 | } 34 | } 35 | 36 | fn file_handle(file_name: &str, config: &Files) -> Result<(), String> { 37 | let mut file = File::open(file_name).map_err(|e| format!("{:?} open fails: {}", file_name, e))?; 38 | let mut bytes = Vec::new(); 39 | let _ = file 40 | .read_to_end(&mut bytes) 41 | .map_err(|e| format!("{:?} read fails: {}", file_name, e))?; 42 | let read_result = config.charset.decode(&bytes[..]); 43 | let str = { 44 | if config.charset != CharSet::UTF_8 && read_result.is_ok() { 45 | read_result.unwrap() 46 | } else { 47 | String::from_utf8_lossy(&bytes[..]).into_owned() 48 | } 49 | }; 50 | if config.charset != config.charset_out { 51 | if let Ok(bs) = config.charset_out.encode(&str) { 52 | if config.store { 53 | let mut file = File::create(file_name).map_err(|e| format!("{:?} create fails: {}", file_name, e))?; 54 | file.write_all(&bs[..]) 55 | .map_err(|e| format!("{:?} write fails: {}", file_name, e))?; 56 | file.flush().map_err(|e| format!("{:?} flush fails: {}", file_name, e))?; 57 | println!("{:?} rewrite success", file_name); 58 | } else { 59 | println!("{:?}: \n{}\n", file_name, String::from_utf8_lossy(&bs[..])); 60 | } 61 | } else { 62 | return Err(format!("{:?} encode fails", file_name)); 63 | } 64 | } else { 65 | println!("{:?}: \n{}\n", file_name, str); 66 | } 67 | Ok(()) 68 | } 69 | -------------------------------------------------------------------------------- /src/coll/ip.rs: -------------------------------------------------------------------------------- 1 | use futures::{future::ready, stream::futures_unordered::FuturesUnordered, StreamExt, TryFutureExt}; 2 | use reqwest::{header, Client}; 3 | 4 | use crate::consts::basic_runtime; 5 | use std::{net::IpAddr, time::Duration}; 6 | 7 | static UA: &str = "curl/7.82.0"; 8 | static UA_CHROME: &str = 9 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36"; 10 | static ACCEPT: &str = "Accept: */*"; 11 | static ACCEPT_JSON: &str = "Accept: application/json"; 12 | 13 | type Host<'a> = (&'a str, Option<&'a str>, &'a str, &'a str); 14 | static HOSTS: &[Host] = &[ 15 | // https://www.ipip.net 16 | ("https://myip.ipip.net", None, UA, ACCEPT), 17 | // https://ipinfo.io/developers 18 | // curl ipinfo.io 19 | // curl ipinfo.io/8.8.8.8 20 | ("https://ipinfo.io", Some("/"), UA, ACCEPT_JSON), 21 | // https://ip.sb/api 22 | // curl https://api.ip.sb/geoip 23 | // curl https://api.ip.sb/geoip/185.222.222.222 24 | ("https://api.ip.sb/geoip", Some("/"), UA_CHROME, ACCEPT_JSON), 25 | ("https://checkip.amazonaws.com", None, UA, ACCEPT_JSON), 26 | ]; 27 | 28 | pub type Ips = Vec; 29 | 30 | pub fn call(ips: Ips) { 31 | let mut rt = basic_runtime(); 32 | 33 | let client = Client::builder() 34 | .use_rustls_tls() 35 | .timeout(Duration::from_secs(10)) 36 | .build() 37 | .expect("reqwest Client build failed"); 38 | 39 | let futs = FuturesUnordered::new(); 40 | 41 | if ips.is_empty() { 42 | HOSTS.iter().for_each(|host| futs.push(curl(*host, None, &client))); 43 | } else { 44 | let hosts = HOSTS.iter().filter(|h| h.1.is_some()); 45 | for ip in ips { 46 | hosts.clone().for_each(|host| futs.push(curl(*host, Some(ip), &client))); 47 | } 48 | } 49 | 50 | rt.block_on(futs.for_each(|_| ready(()))) 51 | } 52 | 53 | async fn curl((url, custom_ip_mode, ua, accept): Host<'static>, ip: Option, client: &Client) { 54 | let mut url = std::borrow::Cow::Borrowed(url); 55 | if let Some(ip) = &ip { 56 | let custum_ip_str = custom_ip_mode.unwrap(); 57 | url = format!("{}{}{}", url, custum_ip_str, ip).into(); 58 | } 59 | 60 | let res = client 61 | .get(url.as_ref()) 62 | .header(header::USER_AGENT, ua) 63 | .header(header::ACCEPT, accept) 64 | .send() 65 | .map_err(|e| format!("Send request failed: {}", e)) 66 | .and_then(|resp| { 67 | resp.text() 68 | .map_err(|e| format!("Read response's Body to string failed: {}", e)) 69 | }) 70 | .await; 71 | 72 | match res { 73 | Ok(body) => println!("{}\n{}", url, body), 74 | Err(e) => eprintln!("{}: {}", url, e), 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/coll/mod.rs: -------------------------------------------------------------------------------- 1 | use super::consts; 2 | 3 | mod ping; 4 | pub use self::ping::*; 5 | 6 | mod unzip; 7 | pub use self::unzip::*; 8 | 9 | mod url; 10 | pub use self::url::*; 11 | 12 | mod path; 13 | pub use self::path::*; 14 | 15 | mod file; 16 | pub use self::file::*; 17 | 18 | mod ip; 19 | pub use self::ip::*; 20 | 21 | mod chardetect; 22 | pub use self::chardetect::*; 23 | -------------------------------------------------------------------------------- /src/coll/path.rs: -------------------------------------------------------------------------------- 1 | use super::consts::*; 2 | 3 | use std::borrow::Cow; 4 | use std::ffi::OsStr; 5 | use std::fs::rename; 6 | #[cfg(unix)] 7 | use std::os::unix::ffi::OsStrExt; 8 | use std::path::{Component, Path, PathBuf}; 9 | use std::process::exit; 10 | 11 | #[derive(Debug)] 12 | pub struct Paths { 13 | pub depth: Option, 14 | pub store: bool, 15 | pub link: bool, 16 | pub strs: Vec, 17 | pub charset: CharSet, 18 | } 19 | impl Paths { 20 | pub fn check_fix(&mut self) -> Result<(), String> { 21 | for str in &self.strs { 22 | if !Path::new(str).exists() { 23 | return Err(format!("Path isn't exits {:?}", str)); 24 | } 25 | } 26 | Ok(()) 27 | } 28 | pub fn call(self) { 29 | debug!("Config_path: {:?}", self); 30 | let depth = self.depth; 31 | for str in &self.strs { 32 | if let Err(e) = path_recurse(PathBuf::from(str), depth, &self) { 33 | eprintln!("{}", e); 34 | exit(1); 35 | } 36 | } 37 | } 38 | } 39 | 40 | impl Default for Paths { 41 | fn default() -> Self { 42 | Paths { 43 | depth: None, 44 | store: false, 45 | link: false, 46 | strs: Vec::new(), 47 | charset: CharSet::default(), 48 | } 49 | } 50 | } 51 | 52 | fn path_recurse(mut path: PathBuf, mut depth: Option, config: &Paths) -> Result<(), String> { 53 | let components_last = path.components().last().unwrap().as_os_str().to_os_string(); 54 | let components_last = Component::Normal(components_last.as_os_str()); 55 | match components_last { 56 | Component::Normal(os_str) => match decode(os_str, &config.charset) { 57 | Ok(file_name) => { 58 | let mut path_new = path.clone(); 59 | assert!(path_new.pop()); 60 | path_new.push(&file_name); 61 | println!("{:?}", path_new); 62 | if config.store && ne(&file_name, os_str) { 63 | rename(&path, &path_new).map_err(|e| format!("rename fails: {}: {:?}", e, path))?; 64 | path = path_new; 65 | } 66 | } 67 | Err(_) => { 68 | eprintln!("decode failed by {:?}: {:?} ", config.charset, path); 69 | } 70 | }, 71 | _ => { 72 | println!("{:?}", path); 73 | } 74 | } 75 | 76 | // -d/--depth 77 | if !path.as_path().is_dir() || depth.as_ref() == Some(&0) { 78 | return Ok(()); 79 | } 80 | 81 | // -l/--link 82 | if !config.link { 83 | let metadata = path 84 | .as_path() 85 | .symlink_metadata() 86 | .map_err(|e| format!("{:?} read without symlink fails: {}", path, e))?; 87 | if !metadata.is_dir() { 88 | return Ok(()); 89 | } 90 | } 91 | depth = depth.map(|d| d - 1); 92 | 93 | for entry in path 94 | .as_path() 95 | .read_dir() 96 | .map_err(|e| format!("{:?} read fails: {}", path, e))? 97 | { 98 | let entry = entry.map_err(|ref e| format!("{:?}'s entry read fails: {}", path, e))?; 99 | debug!("{:?}", entry.path()); 100 | path_recurse(entry.path(), depth, config)?; 101 | } 102 | Ok(()) 103 | } 104 | 105 | #[cfg(unix)] 106 | fn decode(path: &OsStr, cs: &CharSet) -> Result> { 107 | cs.decode(path.as_bytes()) 108 | } 109 | #[cfg(windows)] 110 | fn decode(path: &OsStr, cs: &CharSet) -> Result> { 111 | cs.decode(path.to_string_lossy().as_bytes()) 112 | } 113 | 114 | // no-equal 115 | #[cfg(unix)] 116 | fn ne(str: &str, path: &OsStr) -> bool { 117 | str.as_bytes() != path.as_bytes() 118 | } 119 | 120 | #[cfg(windows)] 121 | fn ne(str: &str, path: &OsStr) -> bool { 122 | str.as_bytes() != path.to_string_lossy().as_bytes() 123 | } 124 | -------------------------------------------------------------------------------- /src/coll/ping/mod.rs: -------------------------------------------------------------------------------- 1 | include!("ping.rs"); 2 | 3 | use regex::{self, Regex}; 4 | 5 | #[derive(Debug, Default)] 6 | pub struct RegexList(pub Vec); 7 | 8 | impl RegexList { 9 | pub fn new(res: I) -> Result 10 | where 11 | S: AsRef, 12 | I: IntoIterator, 13 | { 14 | let mut rl = Self::default(); 15 | for re in res { 16 | rl.0.push(Regex::new(re.as_ref())?); 17 | } 18 | Ok(rl) 19 | } 20 | pub fn find<'a>(&self, msg: &'a str) -> Option<&'a str> { 21 | // ::1应该是最短的吧? 22 | let addrs = msg.split('/').filter(|s| s.len() >= 3).collect::>(); 23 | debug!("{:?}", addrs); 24 | 25 | for addr in addrs { 26 | for re in self.0.as_slice().iter() { 27 | if let Some(mat) = re.find(addr) { 28 | let rest = &addr[mat.start()..mat.end()]; 29 | debug!("{:?}\n{:?} -> {:?}\n", re, msg, rest); 30 | return Some(rest); 31 | } 32 | } 33 | } 34 | None 35 | } 36 | #[allow(dead_code)] // for test 37 | pub fn find_by_re<'a>(&self, msg: &'a str, idx: usize) -> Option<&'a str> { 38 | let addrs = msg.split('/').filter(|s| s.len() >= 3).collect::>(); 39 | debug!("{:?}", addrs); 40 | 41 | for addr in addrs { 42 | let rest = self.0[idx].find(addr).map(|mat| &addr[mat.start()..mat.end()]); 43 | if rest.is_some() { 44 | return rest; 45 | } 46 | } 47 | None 48 | } 49 | } 50 | 51 | lazy_static! { 52 | pub static ref RE: RegexList = RegexList::new( 53 | vec![ 54 | // Ipv4 55 | r#"((2[0-4]\d|25[0-4]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-4]|[01]?\d\d?)"#, 56 | // domainName 57 | r#"[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?"#, 58 | r#"localhost"#, 59 | ] 60 | ).unwrap(); 61 | 62 | // localhost 如果管前后的字符的话太麻烦了, 不能方便的写成一个, 而且以后可能需要解析 host 文件, 调用 ToSocketAddrs 有违原则... 63 | // let re = Regex::new(r#"[(.+://)](?P(localhost))([:/].*)?"#).unwrap(); 64 | // println!("{:?}",re.captures("http://localhost").and_then(|c|c.name("localhost"))); 65 | 66 | pub static ref RE6: RegexList = RegexList::new( 67 | // https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses# 68 | vec![ 69 | // Ipv6 70 | r#"fe80:(:[0-9a-fA-F]{0,4}){0,4}"#, // fe80::215:ff:fec0:284e/64 71 | r#"([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}"#, // 1:2:3:4:5:6:7:8 72 | r#"([0-9a-fA-F]{1,4}:){1,7}:"#, // 1:: 1:2:3:4:5:6:7:: 73 | r#"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}"#, // 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 74 | r#"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}"#, // 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 75 | r#"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}"#, // 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 76 | r#"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}"#, // 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 77 | r#"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}"#, // 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 78 | r#"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})"#, // 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 79 | r#":((:[0-9a-fA-F]{1,4}){1,7}|:)"#, // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: 80 | 81 | // fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index) 82 | // r#"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}"#, 83 | 84 | // ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) 85 | r#"::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#, 86 | 87 | // 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address) 88 | r#"([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#, 89 | 90 | // domainName 91 | r#"[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?"#, 92 | r#"localhost"#, 93 | ] 94 | ).unwrap(); 95 | } 96 | -------------------------------------------------------------------------------- /src/coll/ping/ping.rs: -------------------------------------------------------------------------------- 1 | use chardet::{charset2encoding, detect}; 2 | use encoding::label::encoding_from_whatwg_label; 3 | use encoding::DecoderTrap; 4 | use futures::{future::ready, stream::futures_unordered::FuturesUnordered, FutureExt, StreamExt}; 5 | use tokio::process::Command; 6 | 7 | use crate::consts::{basic_runtime, space_fix}; 8 | use std::process::Output; 9 | 10 | #[derive(Debug)] 11 | pub struct Pings { 12 | pub v6: bool, 13 | pub only_line: bool, 14 | pub hosts: Vec, 15 | pub count: u64, 16 | } 17 | impl Pings { 18 | pub fn check_fix(&mut self) -> Result<(), String> { 19 | let mut vs = Vec::new(); 20 | for arg in &self.hosts { 21 | let addr = RE.find(arg).or_else(|| RE6.find(arg)); 22 | if addr.is_none() { 23 | return Err(format!("ARG is't contains reachable domain/ip: {:?} ", arg)); 24 | } 25 | vs.push(addr.unwrap().to_string()) 26 | } 27 | debug_assert!(!vs.is_empty()); 28 | self.hosts = vs; 29 | Ok(()) 30 | } 31 | pub fn call(self) { 32 | debug!("{:?}", self); 33 | 34 | let mut rt = basic_runtime(); 35 | 36 | let host_len_max = self.hosts.as_slice().iter().max_by_key(|p| p.len()).unwrap().len(); 37 | 38 | // sleep sort 39 | let futs = FuturesUnordered::new(); 40 | 41 | let only_line = self.only_line; 42 | for host in self.hosts.clone() { 43 | let fut = ping(host, &self, move |output: Output, host: String| { 44 | callback(output, host, only_line, host_len_max) 45 | }); 46 | 47 | futs.push(fut); 48 | } 49 | 50 | rt.block_on(futs.for_each(|_| ready(()))) 51 | } 52 | } 53 | 54 | impl Default for Pings { 55 | fn default() -> Self { 56 | Pings { 57 | v6: false, 58 | only_line: false, 59 | hosts: Vec::new(), 60 | count: 3, 61 | } 62 | } 63 | } 64 | 65 | async fn ping(host: String, config: &Pings, callback: F) 66 | where 67 | F: Fn(Output, String), 68 | { 69 | let count_str = format!("{}", config.count); 70 | let mut args = Vec::new(); 71 | let mut ping = "ping"; 72 | // -6 73 | if config.v6 { 74 | if cfg!(unix) { 75 | ping = "ping6"; 76 | } else { 77 | args.push("-6"); 78 | } 79 | } 80 | // -count 81 | if cfg!(unix) { 82 | args.push("-c"); 83 | } else { 84 | args.push("-n"); 85 | }; 86 | args.push(&count_str); 87 | 88 | // host 89 | args.push(&host); 90 | 91 | let mut cmd = Command::new(ping); 92 | cmd.args(&args[..]); 93 | cmd.output() 94 | .map(|res| match res { 95 | Ok(output) => callback(output, host), 96 | Err(e) => error!("Running ping command failed: {:?}", e), 97 | }) 98 | .await 99 | } 100 | 101 | fn callback(output: Output, host: String, only_line: bool, host_len_max: usize) { 102 | if output.status.success() && !output.stdout.is_empty() { 103 | printf0(&output, only_line, &host, host_len_max); 104 | } else if !output.status.success() && !output.stdout.is_empty() { 105 | printf1(&output, only_line, &host, host_len_max); 106 | } else if !output.stderr.is_empty() { 107 | printf_err(&output, &host, host_len_max); 108 | } else { 109 | error!( 110 | "ping {:?} -> code: {:?}, stdout.is_empty: {}, stderr.is_empty: {}", 111 | host, 112 | output.status, 113 | output.stdout.is_empty(), 114 | output.stderr.is_empty() 115 | ); 116 | } 117 | } 118 | 119 | fn printf0(msg: &Output, only_line: bool, host: &str, host_len_max: usize) { 120 | let msg = decode(&msg.stdout[..]); 121 | let msg = msg.trim(); 122 | // -l/--only-line 123 | if !only_line { 124 | println!("{}\n", msg); 125 | return; 126 | } 127 | 128 | let vs: Vec = msg.lines().map(|s| s.trim().to_string()).collect(); 129 | debug!("{:?}", msg); 130 | 131 | #[cfg(unix)] 132 | assert!(!vs.len() > 2); 133 | #[cfg(unix)] 134 | println!( 135 | "{}: {} -> {}", 136 | space_fix(host, host_len_max), 137 | vs[vs.len() - 1], 138 | vs[vs.len() - 2] 139 | ); 140 | 141 | #[cfg(windows)] 142 | assert!(!vs.len() > 3); 143 | #[cfg(windows)] 144 | println!( 145 | "{}: {} -> {}", 146 | space_fix(host, host_len_max), 147 | vs[vs.len() - 1], 148 | vs[vs.len() - 3] 149 | ); 150 | } 151 | 152 | // ping fuck.co -c 3 (%1) 153 | // 3 packets transmitted, 0 received, 100% packet loss, time 2016ms 154 | fn printf1(msg: &Output, only_line: bool, host: &str, host_len_max: usize) { 155 | let msg = decode(&msg.stdout[..]); 156 | let msg = msg.trim(); 157 | // -l/--only-line 158 | if !only_line { 159 | println!("{}\n", msg); 160 | return; 161 | } 162 | 163 | let vs: Vec = msg.lines().map(|s| s.trim().to_string()).collect(); 164 | debug!("{:?}", msg); 165 | 166 | #[cfg(unix)] 167 | assert!(!vs.len() > 2); 168 | #[cfg(unix)] 169 | println!("{}: -> {}", space_fix(host, host_len_max), vs[vs.len() - 1]); 170 | 171 | #[cfg(windows)] 172 | assert!(!vs.len() > 3); 173 | #[cfg(windows)] 174 | println!("{}: -> {}", space_fix(host, host_len_max), vs[vs.len() - 1]); 175 | } 176 | fn printf_err(msg: &Output, host: &str, host_len_max: usize) { 177 | let msg = decode(&msg.stderr[..]); 178 | let vs: Vec = msg.trim().lines().map(|s| s.trim().to_string()).collect(); 179 | assert!(!vs.is_empty()); 180 | 181 | eprintln!("{}: {}", space_fix(host, host_len_max), vs[vs.len() - 1]); 182 | } 183 | 184 | // #[cfg(unix)] 185 | // fn decode(msg: &[u8]) -> String { 186 | // String::from_utf8_lossy(msg).into_owned() 187 | // } 188 | 189 | // #[cfg(windows)] 190 | fn decode(bytes: &[u8]) -> String { 191 | encoding_from_whatwg_label(charset2encoding(&detect(bytes).0)) 192 | .and_then(|code| code.decode(bytes, DecoderTrap::Strict).ok()) 193 | .unwrap_or_else(|| String::from_utf8_lossy(bytes).into_owned()) 194 | } 195 | -------------------------------------------------------------------------------- /src/coll/unzip.rs: -------------------------------------------------------------------------------- 1 | use super::consts::*; 2 | 3 | use chardet::{charset2encoding, detect}; 4 | use encoding::label::encoding_from_whatwg_label; 5 | use encoding::DecoderTrap; 6 | use filetime::{set_symlink_file_times, FileTime}; 7 | use zip::read::ZipArchive; 8 | use zip::result::ZipError; 9 | // https://docs.rs/filetime/ not follow symlink? 10 | 11 | use std; 12 | use std::error::Error; 13 | use std::ffi::OsString; 14 | use std::fs::read_dir; 15 | use std::fs::{create_dir_all, File}; 16 | use std::io::copy; 17 | use std::path::Path; 18 | 19 | #[derive(Debug, PartialEq)] 20 | pub enum Task { 21 | Chardet, // Detect the charset for File's name from ZipArchive 22 | List, // zipcs -l/--list 23 | Unzip, // Extract files from archive with full paths 24 | } 25 | impl Default for Task { 26 | fn default() -> Task { 27 | Task::Unzip 28 | } 29 | } 30 | 31 | #[derive(Debug, Default)] 32 | pub struct Zips { 33 | pub charset: CharSet, //zip -cs/--charset //utf-8 34 | pub outdir: String, //zipcs -o/--outdir //./ 35 | pub password: Option, //zipcs -p/--password 36 | pub zips: Vec, //zipcs ZipArchive0 ZipArchive1 ... 37 | pub task: Task, // UNZIP 38 | } 39 | impl Zips { 40 | pub fn check_fix(&mut self) -> Result<(), String> { 41 | let name = "ZipArchives"; 42 | for zip in &self.zips { 43 | let path = Path::new(&zip); 44 | if !path.exists() { 45 | return Err(format!("Arguments({}): \"{:?}\" is not exists", name, path)); 46 | } else if path.is_dir() { 47 | return Err(format!("Arguments({}): \"{:?}\" is a directory", name, path)); 48 | } 49 | File::open(path).map_err(|e| format!("Arguments({}): \"{:?}\" is invalid({})", name, path, e))?; 50 | } 51 | Ok(()) 52 | } 53 | pub fn call(self) { 54 | debug!("Config_zip: {:?}", self); 55 | 56 | for zip_arch_path in self.zips() { 57 | if let Err(e) = for_zip_arch_file(zip_arch_path, &self) { 58 | error!("{:?} -> {}", zip_arch_path, e); 59 | } 60 | } 61 | } 62 | pub fn charset(&self) -> &CharSet { 63 | &self.charset 64 | } 65 | pub fn outdir(&self) -> &String { 66 | &self.outdir 67 | } 68 | pub fn zips(&self) -> &[String] { 69 | self.zips.as_slice() 70 | } 71 | pub fn password(&self) -> Option<&str> { 72 | self.password.as_ref().map(|s| s.as_str()) 73 | } 74 | pub fn task(&self) -> &Task { 75 | &self.task 76 | } 77 | } 78 | 79 | fn for_zip_arch_file(zip_arch_path: &str, config: &Zips) -> Result<(), ZipCSError> { 80 | let zip_arch_path_ = Path::new(zip_arch_path); 81 | let zip_arch = File::open(zip_arch_path)?; 82 | // Use BufReader read encrypt zip has error: corrupt deflate stream: https://github.com/zip-rs/zip/issues/280 83 | // let reader = BufReader::new(zip_arch); 84 | let mut zip_arch = ZipArchive::new(zip_arch)?; 85 | 86 | // LIST 87 | if *config.task() == Task::List { 88 | for i in 0..zip_arch.len() { 89 | let file = match zip_arch.by_index_raw(i) { 90 | Ok(o) => o, 91 | Err(e) => { 92 | eprintln!("{}_Error: {:?}${:?} ->{:?}", NAME, zip_arch_path, i, e); 93 | continue; 94 | } 95 | }; 96 | let name = { 97 | if let Ok(o) = config.charset().decode(file.name_raw()) { 98 | o 99 | } else { 100 | file.name().to_owned() 101 | } 102 | }; 103 | if name.ends_with('/') { 104 | println!("${}-> {:?}", i, name); 105 | } else { 106 | println!("${}-> {:?}: {:?}", i, name, file.size()); 107 | } 108 | } 109 | return Ok(()); 110 | } 111 | 112 | // Chardet 113 | if *config.task() == Task::Chardet { 114 | for i in 0..zip_arch.len() { 115 | let file = match zip_arch.by_index_raw(i) { 116 | Ok(o) => o, 117 | Err(e) => { 118 | eprintln!("{}_Error: {:?}${:?} ->{:?}", NAME, zip_arch_path, i, e); 119 | continue; 120 | } 121 | }; 122 | let charset = detect(file.name_raw()); 123 | let name = encoding_from_whatwg_label(charset2encoding(&charset.0)) 124 | .and_then(|enc| enc.decode(file.name_raw(), DecoderTrap::Strict).ok()) 125 | .unwrap_or_else(|| file.name().to_owned()); 126 | if name.ends_with('/') { 127 | println!("{} ${}-> {:?}", charset.0, i, name); 128 | } else { 129 | println!("{} ${}-> {:?}: {:?}", charset.0, i, name, file.size()); 130 | } 131 | } 132 | return Ok(()); 133 | } 134 | // UNZIP 135 | // Get ouddir 136 | let outdir = if config.outdir.is_empty() { 137 | zip_arch_path_ 138 | .file_stem() 139 | .ok_or("ZipArchive's stem name is None")? 140 | .to_os_string() 141 | } else { 142 | OsString::from(config.outdir()) 143 | }; 144 | 145 | // Check and create oudir 146 | let outdir_path = Path::new(&outdir); 147 | if outdir_path.exists() && outdir_path.is_dir() { 148 | let dir_item = 149 | read_dir(&outdir_path).map_err(|e| format!("Reading OutDir({}) occurs error: {}", outdir_path.display(), e))?; 150 | if dir_item.count() != 0 { 151 | return Err(format!("OutDir({}) is not empty!", outdir_path.display()).into()); 152 | } 153 | } else if outdir_path.exists() && !outdir_path.is_dir() { 154 | return Err(format!("OutDir({}) is not a Dir!", outdir_path.display()).into()); 155 | } else { 156 | create_dir_all(outdir_path)?; 157 | } 158 | 159 | macro_rules! zip_arch_by_index { 160 | ($i: ident) => { 161 | if let Some(pw) = config.password() { 162 | match zip_arch.by_index_decrypt($i, pw.as_bytes()) { 163 | Ok(Ok(o)) => Ok(o), 164 | Err(e) => Err(e), 165 | Ok(Err(e)) => return Err(ZipCSError::Desc(e.to_string())), 166 | } 167 | } else { 168 | zip_arch.by_index($i) 169 | } 170 | }; 171 | } 172 | 173 | for i in 0..zip_arch.len() { 174 | let mut file = match zip_arch_by_index!(i) { 175 | Ok(o) => o, 176 | Err(e) => { 177 | eprintln!("{}_Error: {:?}${:?} ->{:?}", NAME, zip_arch_path, i, e); 178 | continue; 179 | } 180 | }; 181 | // Get name 182 | let name = { 183 | if let Ok(o) = config.charset().decode(file.name_raw()) { 184 | o 185 | } else { 186 | file.name().to_owned() 187 | } 188 | }; 189 | 190 | // Get outpath, use PathBuf.push() to concat 191 | let mut path = outdir_path.to_path_buf(); 192 | path.push(&name); 193 | 194 | // create dir/file 195 | if name.ends_with('/') { 196 | println!("${}-> {:?}", i, path.as_path()); 197 | create_dir_all(&path)?; 198 | } else { 199 | println!("${}-> {:?}: {:?}", i, path.as_path(), file.size()); 200 | if let Some(p) = path.parent() { 201 | if !p.exists() { 202 | create_dir_all(&p)?; 203 | } 204 | } 205 | let mut outfile = File::create(&path)?; 206 | copy(&mut file, &mut outfile)?; 207 | } 208 | 209 | let path_display = path.as_path().display(); 210 | // Get/Set m/atime 211 | match file.last_modified().to_time() { 212 | Err(e) => error!("{} last_modified().to_time() failed: {}", path_display, e), 213 | Ok(tm) => { 214 | let tm = FileTime::from_unix_time(tm.unix_timestamp(), tm.nanosecond()); 215 | set_symlink_file_times(&path, tm, tm) 216 | .map_err(|e| eprintln!("filetime::set_symlink_file_times({}, {:?}) failed: {}", path_display, tm, e)) 217 | .ok(); 218 | } 219 | } 220 | 221 | // Get/Set permissions 222 | #[cfg(unix)] 223 | { 224 | use std::fs::{set_permissions, Permissions}; 225 | use std::os::unix::fs::PermissionsExt; 226 | 227 | if let Some(mode) = file.unix_mode() { 228 | set_permissions(&path, Permissions::from_mode(mode)) 229 | .map_err(|e| eprintln!("fs::set_permissions({}, {:?}) occurs error: {}", path_display, mode, e)) 230 | .ok(); 231 | } 232 | } 233 | } 234 | Ok(()) 235 | } 236 | 237 | #[derive(Debug)] 238 | enum ZipCSError { 239 | IO(std::io::Error), 240 | ZIP(ZipError), 241 | Desc(String), 242 | } 243 | 244 | impl std::error::Error for ZipCSError { 245 | fn source(&self) -> Option<&(dyn Error + 'static)> { 246 | match self { 247 | ZipCSError::IO(e) => Some(e), 248 | ZipCSError::ZIP(ref e) => Some(e), 249 | _ => None, 250 | } 251 | } 252 | } 253 | 254 | use std::fmt; 255 | use std::fmt::Formatter; 256 | 257 | impl fmt::Display for ZipCSError { 258 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 259 | match self { 260 | ZipCSError::IO(e) => e.fmt(f), 261 | ZipCSError::ZIP(e) => e.fmt(f), 262 | ZipCSError::Desc(e) => e.fmt(f), 263 | } 264 | } 265 | } 266 | 267 | impl From for ZipCSError { 268 | fn from(e: std::io::Error) -> Self { 269 | ZipCSError::IO(e) 270 | } 271 | } 272 | 273 | impl From for ZipCSError { 274 | fn from(e: String) -> Self { 275 | ZipCSError::Desc(e) 276 | } 277 | } 278 | impl<'a> From<&'a str> for ZipCSError { 279 | fn from(e: &str) -> Self { 280 | ZipCSError::Desc(e.to_owned()) 281 | } 282 | } 283 | impl From for ZipCSError { 284 | fn from(e: ZipError) -> Self { 285 | ZipCSError::ZIP(e) 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /src/coll/url.rs: -------------------------------------------------------------------------------- 1 | use percent_encoding::{percent_decode, percent_encode_byte, utf8_percent_encode, DEFAULT_ENCODE_SET}; 2 | 3 | #[derive(Debug, Default)] 4 | pub struct Urls { 5 | pub encode_all_chars: bool, 6 | pub is_encode: bool, 7 | pub strs: Vec, 8 | } 9 | 10 | impl Urls { 11 | pub fn call(self) { 12 | for str in &self.strs { 13 | let rest = match (self.is_encode, self.encode_all_chars) { 14 | (true, true) => Ok(encode_chars(str)), 15 | (true, false) => Ok(utf8_percent_encode(str, DEFAULT_ENCODE_SET).to_string()), 16 | _ => percent_decode(str.as_bytes()).decode_utf8().map(|s| s.into_owned()), 17 | }; 18 | match rest { 19 | Ok(o) => { 20 | println!("{}", o); 21 | } 22 | Err(o) => { 23 | eprintln!("{:?}", o); 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | fn encode_chars(str: &str) -> String { 31 | let mut tmp = str 32 | .split('/') 33 | .filter(|c| !c.is_empty()) 34 | .flat_map(|c| "/".chars().chain(c.bytes().flat_map(|cc| percent_encode_byte(cc).chars()))) 35 | .collect::(); 36 | if !str.starts_with('/') { 37 | tmp.remove(0); 38 | } 39 | tmp 40 | } 41 | -------------------------------------------------------------------------------- /src/consts.rs: -------------------------------------------------------------------------------- 1 | #![allow(unknown_lints, const_static_lifetime)] 2 | // crate's info 3 | pub const NAME: &str = env!("CARGO_PKG_NAME"); 4 | // pub const VERSION: &str = env!("CARGO_PKG_VERSION"); 5 | include!(concat!(env!("OUT_DIR"), "/zipcs.txt")); 6 | pub const AUTHOR: &str = "Wspsxing"; 7 | pub const EMAIL: &str = "biluohc@qq.com"; 8 | pub const DESC: &str = env!("CARGO_PKG_DESCRIPTION"); 9 | 10 | pub const URL_NAME: &str = "Repo"; 11 | pub const URL: &str = "https://github.com/biluohc/zipcs"; 12 | 13 | // copy form use@line16 ,but BIG5_2003 is swap by big5. 14 | pub const CHARSETS: &str = "UTF_8, UTF_16BE, UTF_16LE, GBK, GB18030, HZ, BIG5..."; 15 | 16 | pub fn space_fix(msg: &str, msg_len_max: usize) -> String { 17 | let mut str = msg.to_owned(); 18 | while str.len() < msg_len_max { 19 | str += " "; 20 | } 21 | str 22 | } 23 | 24 | use tokio::runtime::{Builder, Runtime}; 25 | pub fn basic_runtime() -> Runtime { 26 | Builder::new() 27 | .basic_scheduler() 28 | .enable_all() 29 | .build() 30 | .expect("tokio runtime build failed") 31 | } 32 | 33 | // https://docs.rs/encoding/0.2.33/encoding/all/index.html 34 | use encoding::all::*; 35 | use encoding::{DecoderTrap, EncoderTrap, Encoding}; 36 | use std::borrow::Cow; 37 | use std::default::Default; 38 | 39 | impl Default for CharSet { 40 | fn default() -> CharSet { 41 | CharSet::UTF_8 42 | } 43 | } 44 | 45 | macro_rules! enum_create { 46 | ($($key: ident => $val: expr),+) => ( 47 | #[allow(non_camel_case_types)] 48 | #[derive(Debug,Clone,PartialEq)] 49 | pub enum CharSet { 50 | $($key),+ 51 | } 52 | impl CharSet { 53 | pub fn new(name :&str)->Result { 54 | match name { 55 | $($val => Ok(CharSet::$key)),+ 56 | , _=> Err(()), 57 | } 58 | } 59 | pub fn decode(&self, bytes: &[u8]) -> Result> { 60 | match *self { 61 | $(CharSet::$key => ($key).decode(bytes, DecoderTrap::Strict)),+ , 62 | } 63 | } 64 | pub fn encode(&self, str: &str) -> Result, Cow<'static, str>> { 65 | match *self { 66 | $(CharSet::$key => ($key).encode(str, EncoderTrap::Strict)),+ , 67 | } 68 | } 69 | pub fn show() { 70 | // println!("{:<16} => {}", "Input_String", "CharSet"); 71 | $( println!("{:<16} => {}", $val, stringify!($key)) ); + 72 | } 73 | } 74 | ); 75 | } 76 | 77 | enum_create!( 78 | UTF_8 => "utf8", 79 | UTF_16BE => "utf16be", 80 | UTF_16LE => "utf16le", 81 | GBK => "gbk", 82 | GB18030 => "gb18030", 83 | HZ => "hz", 84 | BIG5_2003 => "big5", 85 | // ERROR => "error", 86 | ASCII => "ascii", 87 | IBM866 => "ibm866", 88 | EUC_JP => "euc_jp", 89 | ISO_2022_JP => "iso_2022_jp", 90 | ISO_8859_1 => "iso_8859_1", 91 | ISO_8859_2 => "iso_8859_2", 92 | ISO_8859_3 => "iso_8859_3", 93 | ISO_8859_4 => "iso_8859_4", 94 | ISO_8859_5 => "iso_8859_5", 95 | ISO_8859_6 => "iso_8859_6", 96 | ISO_8859_7 => "iso_8859_7", 97 | ISO_8859_8 => "iso_8859_8", 98 | ISO_8859_10 => "iso_8859_10", 99 | ISO_8859_13 => "iso_8859_13", 100 | ISO_8859_14 => "iso_8859_14", 101 | ISO_8859_15 => "iso_8859_15", 102 | ISO_8859_16 => "iso_8859_16", 103 | KOI8_R => "koi8_r", 104 | KOI8_U => "koi8_u", 105 | MAC_CYRILLIC => "mac_cyrillic", 106 | MAC_ROMAN => "mac_roman", 107 | WINDOWS_874 => "windows_874", 108 | WINDOWS_949 => "windows_949", 109 | WINDOWS_1250 => "windows_1250", 110 | WINDOWS_1251 => "windows_1251", 111 | WINDOWS_1252 => "windows_1252", 112 | WINDOWS_1253 => "windows_1253", 113 | WINDOWS_1254 => "windows_1254", 114 | WINDOWS_1255 => "windows_1255", 115 | WINDOWS_1256 => "windows_1256", 116 | WINDOWS_1257 => "windows_1257", 117 | WINDOWS_1258 => "windows_1258", 118 | WINDOWS_31J => "windows_31j" 119 | ); 120 | 121 | // encoding/all/index.html 122 | // Get above map 123 | // for l in s.lines() { 124 | // println!("{} => {:?},",l.trim(),l.trim().to_lowercase()); 125 | // } 126 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | pub use nonblock_logger::{current_thread_name, JoinHandle}; 2 | use nonblock_logger::{ 3 | log::{LevelFilter, Record}, 4 | BaseFilter, BaseFormater, FixedLevel, NonblockLogger, 5 | }; 6 | 7 | pub fn format(base: &BaseFormater, record: &Record) -> String { 8 | let level = FixedLevel::with_color(record.level(), base.color_get()) 9 | .length(base.level_get()) 10 | .into_colored() 11 | .into_coloredfg(); 12 | 13 | format!( 14 | "{} {} [{} {}:{}] {}\n", 15 | chrono::Local::now().format("%Y-%m-%d %H:%M:%S.%3f"), 16 | level, 17 | current_thread_name(), 18 | record.file().unwrap_or("*"), 19 | record.line().unwrap_or(0), 20 | record.args() 21 | ) 22 | } 23 | 24 | pub fn logger_init(verbose: u64) -> JoinHandle { 25 | let pkg = crate::consts::NAME; 26 | let log = match verbose { 27 | 0 => LevelFilter::Warn, 28 | 1 => LevelFilter::Info, 29 | 2 => LevelFilter::Debug, 30 | _more => LevelFilter::Trace, 31 | }; 32 | 33 | if verbose > 2 { 34 | println!("logger_init: pkg: {}, level: {:?}", pkg, log) 35 | }; 36 | 37 | let formater = BaseFormater::new().local(true).color(true).level(4).formater(format); 38 | let filter = BaseFilter::new() 39 | .max_level(log) 40 | .starts_with(true) 41 | .notfound(true) 42 | .chain(pkg, log) 43 | .chain("tokio", LevelFilter::Info) 44 | .chain("hyper", LevelFilter::Info) 45 | .chain("want", LevelFilter::Info) 46 | .chain("mio", LevelFilter::Info); 47 | 48 | NonblockLogger::new() 49 | .formater(formater) 50 | .filter(filter) 51 | .expect("add filiter failed") 52 | .log_to_stdout() 53 | .map_err(|e| eprintln!("failed to init nonblock_logger: {:?}", e)) 54 | .unwrap() 55 | } 56 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # Useful tools collection. 3 | 4 | ## Usage 5 | 6 | ```sh 7 | cargo install --git https://github.com/biluohc/zipcs 8 | zcs -h 9 | ``` 10 | 11 | ## Or 12 | 13 | ```sh 14 | git clone https://github.com/biluohc/zipcs 15 | cd zipcs 16 | cargo build --release 17 | 18 | ./target/release/zcs --help 19 | ``` 20 | ## Help 21 | 22 | ```sh 23 | zcs 0.3.6 (594c5ca7@master rustc1.25.0-nightly 2018-03-02UTC) 24 | Useful tools collection. 25 | Wspsxing 26 | Repo: https://github.com/biluohc/zipcs 27 | 28 | USAGE: 29 | zcs options 30 | zcs [args] 31 | 32 | OPTIONS: 33 | -h, --help Show the help message 34 | -V, --version Show the version message 35 | 36 | CAMMANDS: 37 | zip, z Unzip with charset setting 38 | path, P Paths decoding with charset setting 39 | file, f Files encoding/decoding with charset setting 40 | ping, p ping domains/ips 41 | chardet, c Detect the charset for File(for reference) 42 | charset, C Show all CharSet supported 43 | ip, i Get ip address 44 | url, u Urls decoding/encoding 45 | ``` 46 | 47 | ## Binary 48 | 49 | * [The Release Page](https://github.com/biluohc/zipcs/releases) 50 | 51 | ## Ps 52 | * 所依赖的[zip-rs](https://github.com/mvdnes/zip-rs)库目前不支持加密,所以目前不支持密码。 53 | */ 54 | #[macro_use] 55 | extern crate nonblock_logger; 56 | #[macro_use] 57 | extern crate lazy_static; 58 | 59 | pub mod args; 60 | pub mod coll; 61 | pub mod consts; 62 | pub mod logger; 63 | 64 | use args::Config; 65 | 66 | fn main() { 67 | let _handle = logger::logger_init(1); 68 | Config::parse(); 69 | } 70 | --------------------------------------------------------------------------------