├── .dockerignore ├── .env ├── .gitattributes ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── Dockerfile.prod ├── Dockerfile.rust ├── Makefile ├── assets └── .gitkeep ├── build.rs ├── gotest.jl ├── readme.md ├── sql ├── user.up.mysql.sql ├── user.up.postgres.sql └── user.up.sqlite.sql ├── src ├── api.rs ├── config.rs ├── handlers │ └── mod.rs ├── how.rs ├── main.rs ├── middlewares │ ├── auth.rs │ └── mod.rs ├── models │ └── mod.rs ├── state.rs └── users │ ├── dao.rs │ ├── mod.rs │ ├── routes.rs │ └── user.rs └── template.json /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | !target/release/actixweb-sqlx-jwt 3 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL=mysql://root:'MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg='@sh1/templatedb?timeout=60&serverTimezone=Hongkong 2 | #DATABASE_URL="postgres://template:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@sh1:5432/templatedb?timeout=60&serverTimezone=Hongkong" 3 | #DATABASE_URL=sqlite://./target/lite.db 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rs linguist-language=Rust 2 | *.jl linguist-language=Julia 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .idea 3 | .DS_Store 4 | .db 5 | # Cargo.lock 6 | *.bk 7 | .vscode 8 | -------------------------------------------------------------------------------- /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 = "actix-codec" 7 | version = "0.5.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" 10 | dependencies = [ 11 | "bitflags", 12 | "bytes", 13 | "futures-core", 14 | "futures-sink", 15 | "log", 16 | "memchr", 17 | "pin-project-lite", 18 | "tokio", 19 | "tokio-util 0.7.1", 20 | ] 21 | 22 | [[package]] 23 | name = "actix-files" 24 | version = "0.6.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "d81bde9a79336aa51ebed236e91fc1a0528ff67cfdf4f68ca4c61ede9fd26fb5" 27 | dependencies = [ 28 | "actix-http", 29 | "actix-service", 30 | "actix-utils", 31 | "actix-web", 32 | "askama_escape", 33 | "bitflags", 34 | "bytes", 35 | "derive_more", 36 | "futures-core", 37 | "http-range", 38 | "log", 39 | "mime", 40 | "mime_guess", 41 | "percent-encoding", 42 | "pin-project-lite", 43 | ] 44 | 45 | [[package]] 46 | name = "actix-http" 47 | version = "3.0.4" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "a5885cb81a0d4d0d322864bea1bb6c2a8144626b4fdc625d4c51eba197e7797a" 50 | dependencies = [ 51 | "actix-codec", 52 | "actix-rt", 53 | "actix-service", 54 | "actix-utils", 55 | "ahash", 56 | "base64 0.13.0", 57 | "bitflags", 58 | "brotli", 59 | "bytes", 60 | "bytestring", 61 | "derive_more", 62 | "encoding_rs", 63 | "flate2", 64 | "futures-core", 65 | "h2", 66 | "http", 67 | "httparse", 68 | "httpdate", 69 | "itoa 1.0.1", 70 | "language-tags", 71 | "local-channel", 72 | "log", 73 | "mime", 74 | "percent-encoding", 75 | "pin-project-lite", 76 | "rand", 77 | "sha-1 0.10.0", 78 | "smallvec", 79 | "zstd", 80 | ] 81 | 82 | [[package]] 83 | name = "actix-macros" 84 | version = "0.2.3" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" 87 | dependencies = [ 88 | "quote", 89 | "syn", 90 | ] 91 | 92 | [[package]] 93 | name = "actix-router" 94 | version = "0.5.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" 97 | dependencies = [ 98 | "bytestring", 99 | "firestorm", 100 | "http", 101 | "log", 102 | "regex", 103 | "serde", 104 | ] 105 | 106 | [[package]] 107 | name = "actix-rt" 108 | version = "2.7.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" 111 | dependencies = [ 112 | "actix-macros", 113 | "futures-core", 114 | "tokio", 115 | ] 116 | 117 | [[package]] 118 | name = "actix-server" 119 | version = "2.1.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" 122 | dependencies = [ 123 | "actix-rt", 124 | "actix-service", 125 | "actix-utils", 126 | "futures-core", 127 | "futures-util", 128 | "mio", 129 | "num_cpus", 130 | "socket2", 131 | "tokio", 132 | "tracing", 133 | ] 134 | 135 | [[package]] 136 | name = "actix-service" 137 | version = "2.0.2" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" 140 | dependencies = [ 141 | "futures-core", 142 | "paste", 143 | "pin-project-lite", 144 | ] 145 | 146 | [[package]] 147 | name = "actix-utils" 148 | version = "3.0.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" 151 | dependencies = [ 152 | "local-waker", 153 | "pin-project-lite", 154 | ] 155 | 156 | [[package]] 157 | name = "actix-web" 158 | version = "4.0.1" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "f4e5ebffd51d50df56a3ae0de0e59487340ca456f05dd0b90c0a7a6dd6a74d31" 161 | dependencies = [ 162 | "actix-codec", 163 | "actix-http", 164 | "actix-macros", 165 | "actix-router", 166 | "actix-rt", 167 | "actix-server", 168 | "actix-service", 169 | "actix-utils", 170 | "actix-web-codegen", 171 | "ahash", 172 | "bytes", 173 | "bytestring", 174 | "cfg-if", 175 | "cookie", 176 | "derive_more", 177 | "encoding_rs", 178 | "futures-core", 179 | "futures-util", 180 | "itoa 1.0.1", 181 | "language-tags", 182 | "log", 183 | "mime", 184 | "once_cell", 185 | "pin-project-lite", 186 | "regex", 187 | "serde", 188 | "serde_json", 189 | "serde_urlencoded", 190 | "smallvec", 191 | "socket2", 192 | "time 0.3.9", 193 | "url", 194 | ] 195 | 196 | [[package]] 197 | name = "actix-web-codegen" 198 | version = "4.0.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "7525bedf54704abb1d469e88d7e7e9226df73778798a69cea5022d53b2ae91bc" 201 | dependencies = [ 202 | "actix-router", 203 | "proc-macro2", 204 | "quote", 205 | "syn", 206 | ] 207 | 208 | [[package]] 209 | name = "actixweb-sqlx-jwt" 210 | version = "0.1.0" 211 | dependencies = [ 212 | "actix-files", 213 | "actix-rt", 214 | "actix-web", 215 | "anyhow", 216 | "async-trait", 217 | "bcrypt", 218 | "chrono", 219 | "clap", 220 | "futures", 221 | "hex", 222 | "json5", 223 | "jsonwebtoken", 224 | "lazy_static", 225 | "mobc", 226 | "mobc-redis", 227 | "nonblock-logger", 228 | "ring", 229 | "rust_decimal", 230 | "serde", 231 | "serde_json", 232 | "serde_qs", 233 | "sqlx", 234 | "thiserror", 235 | "tokio", 236 | "url", 237 | "uuid", 238 | "validator", 239 | "vergen", 240 | ] 241 | 242 | [[package]] 243 | name = "adler" 244 | version = "1.0.2" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 247 | 248 | [[package]] 249 | name = "ahash" 250 | version = "0.7.6" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 253 | dependencies = [ 254 | "getrandom", 255 | "once_cell", 256 | "version_check", 257 | ] 258 | 259 | [[package]] 260 | name = "aho-corasick" 261 | version = "0.7.18" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 264 | dependencies = [ 265 | "memchr", 266 | ] 267 | 268 | [[package]] 269 | name = "alloc-no-stdlib" 270 | version = "2.0.3" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" 273 | 274 | [[package]] 275 | name = "alloc-stdlib" 276 | version = "0.2.1" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" 279 | dependencies = [ 280 | "alloc-no-stdlib", 281 | ] 282 | 283 | [[package]] 284 | name = "anyhow" 285 | version = "1.0.57" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" 288 | 289 | [[package]] 290 | name = "arrayvec" 291 | version = "0.7.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" 294 | 295 | [[package]] 296 | name = "askama_escape" 297 | version = "0.10.3" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 300 | 301 | [[package]] 302 | name = "async-trait" 303 | version = "0.1.53" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" 306 | dependencies = [ 307 | "proc-macro2", 308 | "quote", 309 | "syn", 310 | ] 311 | 312 | [[package]] 313 | name = "atoi" 314 | version = "0.4.0" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" 317 | dependencies = [ 318 | "num-traits", 319 | ] 320 | 321 | [[package]] 322 | name = "atty" 323 | version = "0.2.14" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 326 | dependencies = [ 327 | "hermit-abi", 328 | "libc", 329 | "winapi", 330 | ] 331 | 332 | [[package]] 333 | name = "autocfg" 334 | version = "1.1.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 337 | 338 | [[package]] 339 | name = "base64" 340 | version = "0.12.3" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 343 | 344 | [[package]] 345 | name = "base64" 346 | version = "0.13.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 349 | 350 | [[package]] 351 | name = "base64ct" 352 | version = "1.5.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" 355 | 356 | [[package]] 357 | name = "bcrypt" 358 | version = "0.10.1" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "f691e63585950d8c1c43644d11bab9073e40f5060dd2822734ae7c3dc69a3a80" 361 | dependencies = [ 362 | "base64 0.13.0", 363 | "blowfish", 364 | "getrandom", 365 | ] 366 | 367 | [[package]] 368 | name = "bitflags" 369 | version = "1.3.2" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 372 | 373 | [[package]] 374 | name = "block-buffer" 375 | version = "0.7.3" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 378 | dependencies = [ 379 | "block-padding", 380 | "byte-tools", 381 | "byteorder", 382 | "generic-array 0.12.4", 383 | ] 384 | 385 | [[package]] 386 | name = "block-buffer" 387 | version = "0.10.2" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 390 | dependencies = [ 391 | "generic-array 0.14.5", 392 | ] 393 | 394 | [[package]] 395 | name = "block-padding" 396 | version = "0.1.5" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 399 | dependencies = [ 400 | "byte-tools", 401 | ] 402 | 403 | [[package]] 404 | name = "blowfish" 405 | version = "0.8.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" 408 | dependencies = [ 409 | "byteorder", 410 | "cipher", 411 | "opaque-debug 0.3.0", 412 | ] 413 | 414 | [[package]] 415 | name = "brotli" 416 | version = "3.3.4" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" 419 | dependencies = [ 420 | "alloc-no-stdlib", 421 | "alloc-stdlib", 422 | "brotli-decompressor", 423 | ] 424 | 425 | [[package]] 426 | name = "brotli-decompressor" 427 | version = "2.3.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" 430 | dependencies = [ 431 | "alloc-no-stdlib", 432 | "alloc-stdlib", 433 | ] 434 | 435 | [[package]] 436 | name = "bumpalo" 437 | version = "3.9.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 440 | 441 | [[package]] 442 | name = "byte-tools" 443 | version = "0.3.1" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 446 | 447 | [[package]] 448 | name = "byteorder" 449 | version = "1.4.3" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 452 | 453 | [[package]] 454 | name = "bytes" 455 | version = "1.1.0" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 458 | 459 | [[package]] 460 | name = "bytestring" 461 | version = "1.0.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" 464 | dependencies = [ 465 | "bytes", 466 | ] 467 | 468 | [[package]] 469 | name = "cc" 470 | version = "1.0.73" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 473 | dependencies = [ 474 | "jobserver", 475 | ] 476 | 477 | [[package]] 478 | name = "cfg-if" 479 | version = "1.0.0" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 482 | 483 | [[package]] 484 | name = "chrono" 485 | version = "0.4.19" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 488 | dependencies = [ 489 | "libc", 490 | "num-integer", 491 | "num-traits", 492 | "serde", 493 | "time 0.1.44", 494 | "winapi", 495 | ] 496 | 497 | [[package]] 498 | name = "cipher" 499 | version = "0.3.0" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 502 | dependencies = [ 503 | "generic-array 0.14.5", 504 | ] 505 | 506 | [[package]] 507 | name = "clap" 508 | version = "3.1.15" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "85a35a599b11c089a7f49105658d089b8f2cf0882993c17daf6de15285c2c35d" 511 | dependencies = [ 512 | "atty", 513 | "bitflags", 514 | "clap_derive", 515 | "clap_lex", 516 | "indexmap", 517 | "lazy_static", 518 | "strsim", 519 | "termcolor", 520 | "textwrap", 521 | ] 522 | 523 | [[package]] 524 | name = "clap_derive" 525 | version = "3.1.7" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" 528 | dependencies = [ 529 | "heck", 530 | "proc-macro-error", 531 | "proc-macro2", 532 | "quote", 533 | "syn", 534 | ] 535 | 536 | [[package]] 537 | name = "clap_lex" 538 | version = "0.2.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" 541 | dependencies = [ 542 | "os_str_bytes", 543 | ] 544 | 545 | [[package]] 546 | name = "colored" 547 | version = "2.0.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 550 | dependencies = [ 551 | "atty", 552 | "lazy_static", 553 | "winapi", 554 | ] 555 | 556 | [[package]] 557 | name = "combine" 558 | version = "4.6.4" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" 561 | dependencies = [ 562 | "bytes", 563 | "futures-core", 564 | "memchr", 565 | "pin-project-lite", 566 | "tokio", 567 | "tokio-util 0.7.1", 568 | ] 569 | 570 | [[package]] 571 | name = "const-oid" 572 | version = "0.7.1" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" 575 | 576 | [[package]] 577 | name = "convert_case" 578 | version = "0.4.0" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 581 | 582 | [[package]] 583 | name = "cookie" 584 | version = "0.16.0" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" 587 | dependencies = [ 588 | "percent-encoding", 589 | "time 0.3.9", 590 | "version_check", 591 | ] 592 | 593 | [[package]] 594 | name = "cpufeatures" 595 | version = "0.2.2" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" 598 | dependencies = [ 599 | "libc", 600 | ] 601 | 602 | [[package]] 603 | name = "crc32fast" 604 | version = "1.3.2" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 607 | dependencies = [ 608 | "cfg-if", 609 | ] 610 | 611 | [[package]] 612 | name = "crossbeam-channel" 613 | version = "0.5.4" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" 616 | dependencies = [ 617 | "cfg-if", 618 | "crossbeam-utils", 619 | ] 620 | 621 | [[package]] 622 | name = "crossbeam-queue" 623 | version = "0.3.5" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" 626 | dependencies = [ 627 | "cfg-if", 628 | "crossbeam-utils", 629 | ] 630 | 631 | [[package]] 632 | name = "crossbeam-utils" 633 | version = "0.8.8" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" 636 | dependencies = [ 637 | "cfg-if", 638 | "lazy_static", 639 | ] 640 | 641 | [[package]] 642 | name = "crypto-bigint" 643 | version = "0.3.2" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" 646 | dependencies = [ 647 | "generic-array 0.14.5", 648 | "subtle", 649 | ] 650 | 651 | [[package]] 652 | name = "crypto-common" 653 | version = "0.1.3" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 656 | dependencies = [ 657 | "generic-array 0.14.5", 658 | "typenum", 659 | ] 660 | 661 | [[package]] 662 | name = "der" 663 | version = "0.5.1" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" 666 | dependencies = [ 667 | "const-oid", 668 | "crypto-bigint", 669 | "pem-rfc7468", 670 | ] 671 | 672 | [[package]] 673 | name = "derive_more" 674 | version = "0.99.17" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 677 | dependencies = [ 678 | "convert_case", 679 | "proc-macro2", 680 | "quote", 681 | "rustc_version 0.4.0", 682 | "syn", 683 | ] 684 | 685 | [[package]] 686 | name = "digest" 687 | version = "0.8.1" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 690 | dependencies = [ 691 | "generic-array 0.12.4", 692 | ] 693 | 694 | [[package]] 695 | name = "digest" 696 | version = "0.10.3" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 699 | dependencies = [ 700 | "block-buffer 0.10.2", 701 | "crypto-common", 702 | "subtle", 703 | ] 704 | 705 | [[package]] 706 | name = "dirs" 707 | version = "4.0.0" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 710 | dependencies = [ 711 | "dirs-sys", 712 | ] 713 | 714 | [[package]] 715 | name = "dirs-sys" 716 | version = "0.3.7" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 719 | dependencies = [ 720 | "libc", 721 | "redox_users", 722 | "winapi", 723 | ] 724 | 725 | [[package]] 726 | name = "dotenv" 727 | version = "0.15.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 730 | 731 | [[package]] 732 | name = "dtoa" 733 | version = "0.4.8" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" 736 | 737 | [[package]] 738 | name = "either" 739 | version = "1.6.1" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 742 | 743 | [[package]] 744 | name = "encoding_rs" 745 | version = "0.8.31" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 748 | dependencies = [ 749 | "cfg-if", 750 | ] 751 | 752 | [[package]] 753 | name = "enum-iterator" 754 | version = "0.7.0" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" 757 | dependencies = [ 758 | "enum-iterator-derive", 759 | ] 760 | 761 | [[package]] 762 | name = "enum-iterator-derive" 763 | version = "0.7.0" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" 766 | dependencies = [ 767 | "proc-macro2", 768 | "quote", 769 | "syn", 770 | ] 771 | 772 | [[package]] 773 | name = "event-listener" 774 | version = "2.5.2" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" 777 | 778 | [[package]] 779 | name = "fake-simd" 780 | version = "0.1.2" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 783 | 784 | [[package]] 785 | name = "firestorm" 786 | version = "0.5.0" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "4d3d6188b8804df28032815ea256b6955c9625c24da7525f387a7af02fbb8f01" 789 | 790 | [[package]] 791 | name = "flate2" 792 | version = "1.0.23" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" 795 | dependencies = [ 796 | "cfg-if", 797 | "crc32fast", 798 | "libc", 799 | "miniz_oxide", 800 | ] 801 | 802 | [[package]] 803 | name = "flume" 804 | version = "0.10.12" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a" 807 | dependencies = [ 808 | "futures-core", 809 | "futures-sink", 810 | "pin-project", 811 | "spin 0.9.3", 812 | ] 813 | 814 | [[package]] 815 | name = "fnv" 816 | version = "1.0.7" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 819 | 820 | [[package]] 821 | name = "form_urlencoded" 822 | version = "1.0.1" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 825 | dependencies = [ 826 | "matches", 827 | "percent-encoding", 828 | ] 829 | 830 | [[package]] 831 | name = "futures" 832 | version = "0.3.21" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" 835 | dependencies = [ 836 | "futures-channel", 837 | "futures-core", 838 | "futures-executor", 839 | "futures-io", 840 | "futures-sink", 841 | "futures-task", 842 | "futures-util", 843 | ] 844 | 845 | [[package]] 846 | name = "futures-channel" 847 | version = "0.3.21" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 850 | dependencies = [ 851 | "futures-core", 852 | "futures-sink", 853 | ] 854 | 855 | [[package]] 856 | name = "futures-core" 857 | version = "0.3.21" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 860 | 861 | [[package]] 862 | name = "futures-executor" 863 | version = "0.3.21" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" 866 | dependencies = [ 867 | "futures-core", 868 | "futures-task", 869 | "futures-util", 870 | ] 871 | 872 | [[package]] 873 | name = "futures-intrusive" 874 | version = "0.4.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" 877 | dependencies = [ 878 | "futures-core", 879 | "lock_api", 880 | "parking_lot 0.11.2", 881 | ] 882 | 883 | [[package]] 884 | name = "futures-io" 885 | version = "0.3.21" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 888 | 889 | [[package]] 890 | name = "futures-macro" 891 | version = "0.3.21" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" 894 | dependencies = [ 895 | "proc-macro2", 896 | "quote", 897 | "syn", 898 | ] 899 | 900 | [[package]] 901 | name = "futures-sink" 902 | version = "0.3.21" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 905 | 906 | [[package]] 907 | name = "futures-task" 908 | version = "0.3.21" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 911 | 912 | [[package]] 913 | name = "futures-timer" 914 | version = "3.0.2" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" 917 | 918 | [[package]] 919 | name = "futures-util" 920 | version = "0.3.21" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 923 | dependencies = [ 924 | "futures-channel", 925 | "futures-core", 926 | "futures-io", 927 | "futures-macro", 928 | "futures-sink", 929 | "futures-task", 930 | "memchr", 931 | "pin-project-lite", 932 | "pin-utils", 933 | "slab", 934 | ] 935 | 936 | [[package]] 937 | name = "generic-array" 938 | version = "0.12.4" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 941 | dependencies = [ 942 | "typenum", 943 | ] 944 | 945 | [[package]] 946 | name = "generic-array" 947 | version = "0.14.5" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 950 | dependencies = [ 951 | "typenum", 952 | "version_check", 953 | ] 954 | 955 | [[package]] 956 | name = "getrandom" 957 | version = "0.2.6" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 960 | dependencies = [ 961 | "cfg-if", 962 | "libc", 963 | "wasi 0.10.0+wasi-snapshot-preview1", 964 | ] 965 | 966 | [[package]] 967 | name = "getset" 968 | version = "0.1.2" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" 971 | dependencies = [ 972 | "proc-macro-error", 973 | "proc-macro2", 974 | "quote", 975 | "syn", 976 | ] 977 | 978 | [[package]] 979 | name = "git2" 980 | version = "0.14.2" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" 983 | dependencies = [ 984 | "bitflags", 985 | "libc", 986 | "libgit2-sys", 987 | "log", 988 | "url", 989 | ] 990 | 991 | [[package]] 992 | name = "h2" 993 | version = "0.3.13" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" 996 | dependencies = [ 997 | "bytes", 998 | "fnv", 999 | "futures-core", 1000 | "futures-sink", 1001 | "futures-util", 1002 | "http", 1003 | "indexmap", 1004 | "slab", 1005 | "tokio", 1006 | "tokio-util 0.7.1", 1007 | "tracing", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "hashbrown" 1012 | version = "0.11.2" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 1015 | dependencies = [ 1016 | "ahash", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "hashlink" 1021 | version = "0.7.0" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" 1024 | dependencies = [ 1025 | "hashbrown", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "heck" 1030 | version = "0.4.0" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 1033 | dependencies = [ 1034 | "unicode-segmentation", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "hermit-abi" 1039 | version = "0.1.19" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 1042 | dependencies = [ 1043 | "libc", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "hex" 1048 | version = "0.4.3" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1051 | 1052 | [[package]] 1053 | name = "hkdf" 1054 | version = "0.12.3" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" 1057 | dependencies = [ 1058 | "hmac", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "hmac" 1063 | version = "0.12.1" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 1066 | dependencies = [ 1067 | "digest 0.10.3", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "http" 1072 | version = "0.2.7" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" 1075 | dependencies = [ 1076 | "bytes", 1077 | "fnv", 1078 | "itoa 1.0.1", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "http-range" 1083 | version = "0.1.5" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" 1086 | 1087 | [[package]] 1088 | name = "httparse" 1089 | version = "1.7.1" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" 1092 | 1093 | [[package]] 1094 | name = "httpdate" 1095 | version = "1.0.2" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 1098 | 1099 | [[package]] 1100 | name = "idna" 1101 | version = "0.2.3" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 1104 | dependencies = [ 1105 | "matches", 1106 | "unicode-bidi", 1107 | "unicode-normalization", 1108 | ] 1109 | 1110 | [[package]] 1111 | name = "if_chain" 1112 | version = "1.0.2" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" 1115 | 1116 | [[package]] 1117 | name = "indexmap" 1118 | version = "1.8.1" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" 1121 | dependencies = [ 1122 | "autocfg", 1123 | "hashbrown", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "instant" 1128 | version = "0.1.12" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1131 | dependencies = [ 1132 | "cfg-if", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "itertools" 1137 | version = "0.10.3" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 1140 | dependencies = [ 1141 | "either", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "itoa" 1146 | version = "0.4.8" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 1149 | 1150 | [[package]] 1151 | name = "itoa" 1152 | version = "1.0.1" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 1155 | 1156 | [[package]] 1157 | name = "jobserver" 1158 | version = "0.1.24" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 1161 | dependencies = [ 1162 | "libc", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "js-sys" 1167 | version = "0.3.57" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" 1170 | dependencies = [ 1171 | "wasm-bindgen", 1172 | ] 1173 | 1174 | [[package]] 1175 | name = "json5" 1176 | version = "0.4.1" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" 1179 | dependencies = [ 1180 | "pest", 1181 | "pest_derive", 1182 | "serde", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "jsonwebtoken" 1187 | version = "7.2.0" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32" 1190 | dependencies = [ 1191 | "base64 0.12.3", 1192 | "pem", 1193 | "ring", 1194 | "serde", 1195 | "serde_json", 1196 | "simple_asn1", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "language-tags" 1201 | version = "0.3.2" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" 1204 | 1205 | [[package]] 1206 | name = "lazy_static" 1207 | version = "1.4.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1210 | dependencies = [ 1211 | "spin 0.5.2", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "libc" 1216 | version = "0.2.125" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" 1219 | 1220 | [[package]] 1221 | name = "libgit2-sys" 1222 | version = "0.13.2+1.4.2" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" 1225 | dependencies = [ 1226 | "cc", 1227 | "libc", 1228 | "libz-sys", 1229 | "pkg-config", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "libm" 1234 | version = "0.2.2" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" 1237 | 1238 | [[package]] 1239 | name = "libsqlite3-sys" 1240 | version = "0.24.2" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" 1243 | dependencies = [ 1244 | "cc", 1245 | "pkg-config", 1246 | "vcpkg", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "libz-sys" 1251 | version = "1.1.6" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e" 1254 | dependencies = [ 1255 | "cc", 1256 | "libc", 1257 | "pkg-config", 1258 | "vcpkg", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "local-channel" 1263 | version = "0.1.3" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" 1266 | dependencies = [ 1267 | "futures-core", 1268 | "futures-sink", 1269 | "futures-util", 1270 | "local-waker", 1271 | ] 1272 | 1273 | [[package]] 1274 | name = "local-waker" 1275 | version = "0.1.3" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" 1278 | 1279 | [[package]] 1280 | name = "lock_api" 1281 | version = "0.4.7" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 1284 | dependencies = [ 1285 | "autocfg", 1286 | "scopeguard", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "log" 1291 | version = "0.4.17" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 1294 | dependencies = [ 1295 | "cfg-if", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "maplit" 1300 | version = "1.0.2" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 1303 | 1304 | [[package]] 1305 | name = "matches" 1306 | version = "0.1.9" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 1309 | 1310 | [[package]] 1311 | name = "md-5" 1312 | version = "0.10.1" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" 1315 | dependencies = [ 1316 | "digest 0.10.3", 1317 | ] 1318 | 1319 | [[package]] 1320 | name = "memchr" 1321 | version = "2.5.0" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 1324 | 1325 | [[package]] 1326 | name = "mime" 1327 | version = "0.3.16" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1330 | 1331 | [[package]] 1332 | name = "mime_guess" 1333 | version = "2.0.4" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 1336 | dependencies = [ 1337 | "mime", 1338 | "unicase", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "minimal-lexical" 1343 | version = "0.2.1" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1346 | 1347 | [[package]] 1348 | name = "miniz_oxide" 1349 | version = "0.5.1" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" 1352 | dependencies = [ 1353 | "adler", 1354 | ] 1355 | 1356 | [[package]] 1357 | name = "mio" 1358 | version = "0.8.2" 1359 | source = "registry+https://github.com/rust-lang/crates.io-index" 1360 | checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" 1361 | dependencies = [ 1362 | "libc", 1363 | "log", 1364 | "miow", 1365 | "ntapi", 1366 | "wasi 0.11.0+wasi-snapshot-preview1", 1367 | "winapi", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "miow" 1372 | version = "0.3.7" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 1375 | dependencies = [ 1376 | "winapi", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "mobc" 1381 | version = "0.7.3" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "7f76d2f2e2dcbb00a8d3b2b09f026a74a82693ea52cd071647aa6cfa7f1ff37e" 1384 | dependencies = [ 1385 | "async-trait", 1386 | "futures-channel", 1387 | "futures-core", 1388 | "futures-timer", 1389 | "futures-util", 1390 | "log", 1391 | "tokio", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "mobc-redis" 1396 | version = "0.7.0" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "e7b5db77b37c9224d5b9949b214041ea3e1c15b6b1e5dd24a5acb8e73975d6d6" 1399 | dependencies = [ 1400 | "mobc", 1401 | "redis", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "nom" 1406 | version = "7.1.1" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 1409 | dependencies = [ 1410 | "memchr", 1411 | "minimal-lexical", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "nonblock-logger" 1416 | version = "0.1.6" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "44c65a1b0b7ae2a119e5ec0d36d2cb202e29cb7a41268a4159e0926bb3112dfc" 1419 | dependencies = [ 1420 | "chrono", 1421 | "colored", 1422 | "crossbeam-channel", 1423 | "log", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "ntapi" 1428 | version = "0.3.7" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" 1431 | dependencies = [ 1432 | "winapi", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "num-bigint" 1437 | version = "0.2.6" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 1440 | dependencies = [ 1441 | "autocfg", 1442 | "num-integer", 1443 | "num-traits", 1444 | ] 1445 | 1446 | [[package]] 1447 | name = "num-bigint" 1448 | version = "0.3.3" 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" 1450 | checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" 1451 | dependencies = [ 1452 | "autocfg", 1453 | "num-integer", 1454 | "num-traits", 1455 | ] 1456 | 1457 | [[package]] 1458 | name = "num-bigint-dig" 1459 | version = "0.8.1" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "566d173b2f9406afbc5510a90925d5a2cd80cae4605631f1212303df265de011" 1462 | dependencies = [ 1463 | "byteorder", 1464 | "lazy_static", 1465 | "libm", 1466 | "num-integer", 1467 | "num-iter", 1468 | "num-traits", 1469 | "rand", 1470 | "smallvec", 1471 | "zeroize", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "num-integer" 1476 | version = "0.1.45" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 1479 | dependencies = [ 1480 | "autocfg", 1481 | "num-traits", 1482 | ] 1483 | 1484 | [[package]] 1485 | name = "num-iter" 1486 | version = "0.1.43" 1487 | source = "registry+https://github.com/rust-lang/crates.io-index" 1488 | checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" 1489 | dependencies = [ 1490 | "autocfg", 1491 | "num-integer", 1492 | "num-traits", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "num-traits" 1497 | version = "0.2.15" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 1500 | dependencies = [ 1501 | "autocfg", 1502 | "libm", 1503 | ] 1504 | 1505 | [[package]] 1506 | name = "num_cpus" 1507 | version = "1.13.1" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 1510 | dependencies = [ 1511 | "hermit-abi", 1512 | "libc", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "num_threads" 1517 | version = "0.1.6" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" 1520 | dependencies = [ 1521 | "libc", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "once_cell" 1526 | version = "1.10.0" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" 1529 | 1530 | [[package]] 1531 | name = "opaque-debug" 1532 | version = "0.2.3" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 1535 | 1536 | [[package]] 1537 | name = "opaque-debug" 1538 | version = "0.3.0" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1541 | 1542 | [[package]] 1543 | name = "os_str_bytes" 1544 | version = "6.0.0" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" 1547 | 1548 | [[package]] 1549 | name = "parking_lot" 1550 | version = "0.11.2" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1553 | dependencies = [ 1554 | "instant", 1555 | "lock_api", 1556 | "parking_lot_core 0.8.5", 1557 | ] 1558 | 1559 | [[package]] 1560 | name = "parking_lot" 1561 | version = "0.12.0" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" 1564 | dependencies = [ 1565 | "lock_api", 1566 | "parking_lot_core 0.9.3", 1567 | ] 1568 | 1569 | [[package]] 1570 | name = "parking_lot_core" 1571 | version = "0.8.5" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1574 | dependencies = [ 1575 | "cfg-if", 1576 | "instant", 1577 | "libc", 1578 | "redox_syscall", 1579 | "smallvec", 1580 | "winapi", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "parking_lot_core" 1585 | version = "0.9.3" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 1588 | dependencies = [ 1589 | "cfg-if", 1590 | "libc", 1591 | "redox_syscall", 1592 | "smallvec", 1593 | "windows-sys", 1594 | ] 1595 | 1596 | [[package]] 1597 | name = "paste" 1598 | version = "1.0.7" 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" 1600 | checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" 1601 | 1602 | [[package]] 1603 | name = "pem" 1604 | version = "0.8.3" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" 1607 | dependencies = [ 1608 | "base64 0.13.0", 1609 | "once_cell", 1610 | "regex", 1611 | ] 1612 | 1613 | [[package]] 1614 | name = "pem-rfc7468" 1615 | version = "0.3.1" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" 1618 | dependencies = [ 1619 | "base64ct", 1620 | ] 1621 | 1622 | [[package]] 1623 | name = "percent-encoding" 1624 | version = "2.1.0" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1627 | 1628 | [[package]] 1629 | name = "pest" 1630 | version = "2.1.3" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 1633 | dependencies = [ 1634 | "ucd-trie", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "pest_derive" 1639 | version = "2.1.0" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" 1642 | dependencies = [ 1643 | "pest", 1644 | "pest_generator", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "pest_generator" 1649 | version = "2.1.3" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" 1652 | dependencies = [ 1653 | "pest", 1654 | "pest_meta", 1655 | "proc-macro2", 1656 | "quote", 1657 | "syn", 1658 | ] 1659 | 1660 | [[package]] 1661 | name = "pest_meta" 1662 | version = "2.1.3" 1663 | source = "registry+https://github.com/rust-lang/crates.io-index" 1664 | checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" 1665 | dependencies = [ 1666 | "maplit", 1667 | "pest", 1668 | "sha-1 0.8.2", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "pin-project" 1673 | version = "1.0.10" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" 1676 | dependencies = [ 1677 | "pin-project-internal", 1678 | ] 1679 | 1680 | [[package]] 1681 | name = "pin-project-internal" 1682 | version = "1.0.10" 1683 | source = "registry+https://github.com/rust-lang/crates.io-index" 1684 | checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" 1685 | dependencies = [ 1686 | "proc-macro2", 1687 | "quote", 1688 | "syn", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "pin-project-lite" 1693 | version = "0.2.9" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1696 | 1697 | [[package]] 1698 | name = "pin-utils" 1699 | version = "0.1.0" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1702 | 1703 | [[package]] 1704 | name = "pkcs1" 1705 | version = "0.3.3" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" 1708 | dependencies = [ 1709 | "der", 1710 | "pkcs8", 1711 | "zeroize", 1712 | ] 1713 | 1714 | [[package]] 1715 | name = "pkcs8" 1716 | version = "0.8.0" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" 1719 | dependencies = [ 1720 | "der", 1721 | "spki", 1722 | "zeroize", 1723 | ] 1724 | 1725 | [[package]] 1726 | name = "pkg-config" 1727 | version = "0.3.25" 1728 | source = "registry+https://github.com/rust-lang/crates.io-index" 1729 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 1730 | 1731 | [[package]] 1732 | name = "ppv-lite86" 1733 | version = "0.2.16" 1734 | source = "registry+https://github.com/rust-lang/crates.io-index" 1735 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1736 | 1737 | [[package]] 1738 | name = "proc-macro-error" 1739 | version = "1.0.4" 1740 | source = "registry+https://github.com/rust-lang/crates.io-index" 1741 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1742 | dependencies = [ 1743 | "proc-macro-error-attr", 1744 | "proc-macro2", 1745 | "quote", 1746 | "syn", 1747 | "version_check", 1748 | ] 1749 | 1750 | [[package]] 1751 | name = "proc-macro-error-attr" 1752 | version = "1.0.4" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1755 | dependencies = [ 1756 | "proc-macro2", 1757 | "quote", 1758 | "version_check", 1759 | ] 1760 | 1761 | [[package]] 1762 | name = "proc-macro2" 1763 | version = "1.0.37" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" 1766 | dependencies = [ 1767 | "unicode-xid", 1768 | ] 1769 | 1770 | [[package]] 1771 | name = "quote" 1772 | version = "1.0.18" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 1775 | dependencies = [ 1776 | "proc-macro2", 1777 | ] 1778 | 1779 | [[package]] 1780 | name = "rand" 1781 | version = "0.8.5" 1782 | source = "registry+https://github.com/rust-lang/crates.io-index" 1783 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1784 | dependencies = [ 1785 | "libc", 1786 | "rand_chacha", 1787 | "rand_core", 1788 | ] 1789 | 1790 | [[package]] 1791 | name = "rand_chacha" 1792 | version = "0.3.1" 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" 1794 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1795 | dependencies = [ 1796 | "ppv-lite86", 1797 | "rand_core", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "rand_core" 1802 | version = "0.6.3" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1805 | dependencies = [ 1806 | "getrandom", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "redis" 1811 | version = "0.19.0" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "1a6ddfecac9391fed21cce10e83c65fa4abafd77df05c98b1c647c65374ce9b3" 1814 | dependencies = [ 1815 | "async-trait", 1816 | "bytes", 1817 | "combine", 1818 | "dtoa", 1819 | "futures-util", 1820 | "itoa 0.4.8", 1821 | "percent-encoding", 1822 | "pin-project-lite", 1823 | "sha1", 1824 | "tokio", 1825 | "tokio-util 0.6.9", 1826 | "url", 1827 | ] 1828 | 1829 | [[package]] 1830 | name = "redox_syscall" 1831 | version = "0.2.13" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 1834 | dependencies = [ 1835 | "bitflags", 1836 | ] 1837 | 1838 | [[package]] 1839 | name = "redox_users" 1840 | version = "0.4.3" 1841 | source = "registry+https://github.com/rust-lang/crates.io-index" 1842 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 1843 | dependencies = [ 1844 | "getrandom", 1845 | "redox_syscall", 1846 | "thiserror", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "regex" 1851 | version = "1.5.5" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" 1854 | dependencies = [ 1855 | "aho-corasick", 1856 | "memchr", 1857 | "regex-syntax", 1858 | ] 1859 | 1860 | [[package]] 1861 | name = "regex-syntax" 1862 | version = "0.6.25" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1865 | 1866 | [[package]] 1867 | name = "ring" 1868 | version = "0.16.20" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1871 | dependencies = [ 1872 | "cc", 1873 | "libc", 1874 | "once_cell", 1875 | "spin 0.5.2", 1876 | "untrusted", 1877 | "web-sys", 1878 | "winapi", 1879 | ] 1880 | 1881 | [[package]] 1882 | name = "rsa" 1883 | version = "0.6.1" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" 1886 | dependencies = [ 1887 | "byteorder", 1888 | "digest 0.10.3", 1889 | "num-bigint-dig", 1890 | "num-integer", 1891 | "num-iter", 1892 | "num-traits", 1893 | "pkcs1", 1894 | "pkcs8", 1895 | "rand_core", 1896 | "smallvec", 1897 | "subtle", 1898 | "zeroize", 1899 | ] 1900 | 1901 | [[package]] 1902 | name = "rust_decimal" 1903 | version = "1.23.1" 1904 | source = "registry+https://github.com/rust-lang/crates.io-index" 1905 | checksum = "22dc69eadbf0ee2110b8d20418c0c6edbaefec2811c4963dc17b6344e11fe0f8" 1906 | dependencies = [ 1907 | "arrayvec", 1908 | "num-traits", 1909 | "serde", 1910 | ] 1911 | 1912 | [[package]] 1913 | name = "rustc_version" 1914 | version = "0.3.3" 1915 | source = "registry+https://github.com/rust-lang/crates.io-index" 1916 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 1917 | dependencies = [ 1918 | "semver 0.11.0", 1919 | ] 1920 | 1921 | [[package]] 1922 | name = "rustc_version" 1923 | version = "0.4.0" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1926 | dependencies = [ 1927 | "semver 1.0.9", 1928 | ] 1929 | 1930 | [[package]] 1931 | name = "rustls" 1932 | version = "0.19.1" 1933 | source = "registry+https://github.com/rust-lang/crates.io-index" 1934 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 1935 | dependencies = [ 1936 | "base64 0.13.0", 1937 | "log", 1938 | "ring", 1939 | "sct", 1940 | "webpki", 1941 | ] 1942 | 1943 | [[package]] 1944 | name = "ryu" 1945 | version = "1.0.9" 1946 | source = "registry+https://github.com/rust-lang/crates.io-index" 1947 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1948 | 1949 | [[package]] 1950 | name = "scopeguard" 1951 | version = "1.1.0" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1954 | 1955 | [[package]] 1956 | name = "sct" 1957 | version = "0.6.1" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1960 | dependencies = [ 1961 | "ring", 1962 | "untrusted", 1963 | ] 1964 | 1965 | [[package]] 1966 | name = "semver" 1967 | version = "0.11.0" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 1970 | dependencies = [ 1971 | "semver-parser", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "semver" 1976 | version = "1.0.9" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" 1979 | 1980 | [[package]] 1981 | name = "semver-parser" 1982 | version = "0.10.2" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 1985 | dependencies = [ 1986 | "pest", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "serde" 1991 | version = "1.0.137" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" 1994 | dependencies = [ 1995 | "serde_derive", 1996 | ] 1997 | 1998 | [[package]] 1999 | name = "serde_derive" 2000 | version = "1.0.137" 2001 | source = "registry+https://github.com/rust-lang/crates.io-index" 2002 | checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" 2003 | dependencies = [ 2004 | "proc-macro2", 2005 | "quote", 2006 | "syn", 2007 | ] 2008 | 2009 | [[package]] 2010 | name = "serde_json" 2011 | version = "1.0.81" 2012 | source = "registry+https://github.com/rust-lang/crates.io-index" 2013 | checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" 2014 | dependencies = [ 2015 | "itoa 1.0.1", 2016 | "ryu", 2017 | "serde", 2018 | ] 2019 | 2020 | [[package]] 2021 | name = "serde_qs" 2022 | version = "0.8.5" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" 2025 | dependencies = [ 2026 | "percent-encoding", 2027 | "serde", 2028 | "thiserror", 2029 | ] 2030 | 2031 | [[package]] 2032 | name = "serde_urlencoded" 2033 | version = "0.7.1" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2036 | dependencies = [ 2037 | "form_urlencoded", 2038 | "itoa 1.0.1", 2039 | "ryu", 2040 | "serde", 2041 | ] 2042 | 2043 | [[package]] 2044 | name = "sha-1" 2045 | version = "0.8.2" 2046 | source = "registry+https://github.com/rust-lang/crates.io-index" 2047 | checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" 2048 | dependencies = [ 2049 | "block-buffer 0.7.3", 2050 | "digest 0.8.1", 2051 | "fake-simd", 2052 | "opaque-debug 0.2.3", 2053 | ] 2054 | 2055 | [[package]] 2056 | name = "sha-1" 2057 | version = "0.10.0" 2058 | source = "registry+https://github.com/rust-lang/crates.io-index" 2059 | checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" 2060 | dependencies = [ 2061 | "cfg-if", 2062 | "cpufeatures", 2063 | "digest 0.10.3", 2064 | ] 2065 | 2066 | [[package]] 2067 | name = "sha1" 2068 | version = "0.6.1" 2069 | source = "registry+https://github.com/rust-lang/crates.io-index" 2070 | checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" 2071 | dependencies = [ 2072 | "sha1_smol", 2073 | ] 2074 | 2075 | [[package]] 2076 | name = "sha1_smol" 2077 | version = "1.0.0" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" 2080 | 2081 | [[package]] 2082 | name = "sha2" 2083 | version = "0.10.2" 2084 | source = "registry+https://github.com/rust-lang/crates.io-index" 2085 | checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" 2086 | dependencies = [ 2087 | "cfg-if", 2088 | "cpufeatures", 2089 | "digest 0.10.3", 2090 | ] 2091 | 2092 | [[package]] 2093 | name = "signal-hook-registry" 2094 | version = "1.4.0" 2095 | source = "registry+https://github.com/rust-lang/crates.io-index" 2096 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 2097 | dependencies = [ 2098 | "libc", 2099 | ] 2100 | 2101 | [[package]] 2102 | name = "simple_asn1" 2103 | version = "0.4.1" 2104 | source = "registry+https://github.com/rust-lang/crates.io-index" 2105 | checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" 2106 | dependencies = [ 2107 | "chrono", 2108 | "num-bigint 0.2.6", 2109 | "num-traits", 2110 | ] 2111 | 2112 | [[package]] 2113 | name = "slab" 2114 | version = "0.4.6" 2115 | source = "registry+https://github.com/rust-lang/crates.io-index" 2116 | checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" 2117 | 2118 | [[package]] 2119 | name = "smallvec" 2120 | version = "1.8.0" 2121 | source = "registry+https://github.com/rust-lang/crates.io-index" 2122 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 2123 | 2124 | [[package]] 2125 | name = "socket2" 2126 | version = "0.4.4" 2127 | source = "registry+https://github.com/rust-lang/crates.io-index" 2128 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 2129 | dependencies = [ 2130 | "libc", 2131 | "winapi", 2132 | ] 2133 | 2134 | [[package]] 2135 | name = "spin" 2136 | version = "0.5.2" 2137 | source = "registry+https://github.com/rust-lang/crates.io-index" 2138 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 2139 | 2140 | [[package]] 2141 | name = "spin" 2142 | version = "0.9.3" 2143 | source = "registry+https://github.com/rust-lang/crates.io-index" 2144 | checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" 2145 | dependencies = [ 2146 | "lock_api", 2147 | ] 2148 | 2149 | [[package]] 2150 | name = "spki" 2151 | version = "0.5.4" 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" 2153 | checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" 2154 | dependencies = [ 2155 | "base64ct", 2156 | "der", 2157 | ] 2158 | 2159 | [[package]] 2160 | name = "sqlformat" 2161 | version = "0.1.8" 2162 | source = "registry+https://github.com/rust-lang/crates.io-index" 2163 | checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" 2164 | dependencies = [ 2165 | "itertools", 2166 | "nom", 2167 | "unicode_categories", 2168 | ] 2169 | 2170 | [[package]] 2171 | name = "sqlx" 2172 | version = "0.5.13" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" 2175 | dependencies = [ 2176 | "sqlx-core", 2177 | "sqlx-macros", 2178 | ] 2179 | 2180 | [[package]] 2181 | name = "sqlx-core" 2182 | version = "0.5.13" 2183 | source = "registry+https://github.com/rust-lang/crates.io-index" 2184 | checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" 2185 | dependencies = [ 2186 | "ahash", 2187 | "atoi", 2188 | "base64 0.13.0", 2189 | "bitflags", 2190 | "byteorder", 2191 | "bytes", 2192 | "chrono", 2193 | "crossbeam-queue", 2194 | "digest 0.10.3", 2195 | "dirs", 2196 | "either", 2197 | "event-listener", 2198 | "flume", 2199 | "futures-channel", 2200 | "futures-core", 2201 | "futures-executor", 2202 | "futures-intrusive", 2203 | "futures-util", 2204 | "generic-array 0.14.5", 2205 | "hashlink", 2206 | "hex", 2207 | "hkdf", 2208 | "hmac", 2209 | "indexmap", 2210 | "itoa 1.0.1", 2211 | "libc", 2212 | "libsqlite3-sys", 2213 | "log", 2214 | "md-5", 2215 | "memchr", 2216 | "num-bigint 0.3.3", 2217 | "once_cell", 2218 | "paste", 2219 | "percent-encoding", 2220 | "rand", 2221 | "rsa", 2222 | "rust_decimal", 2223 | "rustls", 2224 | "serde", 2225 | "serde_json", 2226 | "sha-1 0.10.0", 2227 | "sha2", 2228 | "smallvec", 2229 | "sqlformat", 2230 | "sqlx-rt", 2231 | "stringprep", 2232 | "thiserror", 2233 | "tokio-stream", 2234 | "url", 2235 | "uuid", 2236 | "webpki", 2237 | "webpki-roots", 2238 | "whoami", 2239 | ] 2240 | 2241 | [[package]] 2242 | name = "sqlx-macros" 2243 | version = "0.5.13" 2244 | source = "registry+https://github.com/rust-lang/crates.io-index" 2245 | checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" 2246 | dependencies = [ 2247 | "dotenv", 2248 | "either", 2249 | "heck", 2250 | "once_cell", 2251 | "proc-macro2", 2252 | "quote", 2253 | "serde_json", 2254 | "sqlx-core", 2255 | "sqlx-rt", 2256 | "syn", 2257 | "url", 2258 | ] 2259 | 2260 | [[package]] 2261 | name = "sqlx-rt" 2262 | version = "0.5.13" 2263 | source = "registry+https://github.com/rust-lang/crates.io-index" 2264 | checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" 2265 | dependencies = [ 2266 | "actix-rt", 2267 | "once_cell", 2268 | "tokio", 2269 | "tokio-rustls", 2270 | ] 2271 | 2272 | [[package]] 2273 | name = "stringprep" 2274 | version = "0.1.2" 2275 | source = "registry+https://github.com/rust-lang/crates.io-index" 2276 | checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" 2277 | dependencies = [ 2278 | "unicode-bidi", 2279 | "unicode-normalization", 2280 | ] 2281 | 2282 | [[package]] 2283 | name = "strsim" 2284 | version = "0.10.0" 2285 | source = "registry+https://github.com/rust-lang/crates.io-index" 2286 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 2287 | 2288 | [[package]] 2289 | name = "subtle" 2290 | version = "2.4.1" 2291 | source = "registry+https://github.com/rust-lang/crates.io-index" 2292 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 2293 | 2294 | [[package]] 2295 | name = "syn" 2296 | version = "1.0.92" 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" 2298 | checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" 2299 | dependencies = [ 2300 | "proc-macro2", 2301 | "quote", 2302 | "unicode-xid", 2303 | ] 2304 | 2305 | [[package]] 2306 | name = "termcolor" 2307 | version = "1.1.3" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 2310 | dependencies = [ 2311 | "winapi-util", 2312 | ] 2313 | 2314 | [[package]] 2315 | name = "textwrap" 2316 | version = "0.15.0" 2317 | source = "registry+https://github.com/rust-lang/crates.io-index" 2318 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 2319 | 2320 | [[package]] 2321 | name = "thiserror" 2322 | version = "1.0.31" 2323 | source = "registry+https://github.com/rust-lang/crates.io-index" 2324 | checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" 2325 | dependencies = [ 2326 | "thiserror-impl", 2327 | ] 2328 | 2329 | [[package]] 2330 | name = "thiserror-impl" 2331 | version = "1.0.31" 2332 | source = "registry+https://github.com/rust-lang/crates.io-index" 2333 | checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" 2334 | dependencies = [ 2335 | "proc-macro2", 2336 | "quote", 2337 | "syn", 2338 | ] 2339 | 2340 | [[package]] 2341 | name = "time" 2342 | version = "0.1.44" 2343 | source = "registry+https://github.com/rust-lang/crates.io-index" 2344 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 2345 | dependencies = [ 2346 | "libc", 2347 | "wasi 0.10.0+wasi-snapshot-preview1", 2348 | "winapi", 2349 | ] 2350 | 2351 | [[package]] 2352 | name = "time" 2353 | version = "0.3.9" 2354 | source = "registry+https://github.com/rust-lang/crates.io-index" 2355 | checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" 2356 | dependencies = [ 2357 | "itoa 1.0.1", 2358 | "libc", 2359 | "num_threads", 2360 | "time-macros", 2361 | ] 2362 | 2363 | [[package]] 2364 | name = "time-macros" 2365 | version = "0.2.4" 2366 | source = "registry+https://github.com/rust-lang/crates.io-index" 2367 | checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" 2368 | 2369 | [[package]] 2370 | name = "tinyvec" 2371 | version = "1.6.0" 2372 | source = "registry+https://github.com/rust-lang/crates.io-index" 2373 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 2374 | dependencies = [ 2375 | "tinyvec_macros", 2376 | ] 2377 | 2378 | [[package]] 2379 | name = "tinyvec_macros" 2380 | version = "0.1.0" 2381 | source = "registry+https://github.com/rust-lang/crates.io-index" 2382 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 2383 | 2384 | [[package]] 2385 | name = "tokio" 2386 | version = "1.18.1" 2387 | source = "registry+https://github.com/rust-lang/crates.io-index" 2388 | checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" 2389 | dependencies = [ 2390 | "bytes", 2391 | "libc", 2392 | "memchr", 2393 | "mio", 2394 | "num_cpus", 2395 | "once_cell", 2396 | "parking_lot 0.12.0", 2397 | "pin-project-lite", 2398 | "signal-hook-registry", 2399 | "socket2", 2400 | "winapi", 2401 | ] 2402 | 2403 | [[package]] 2404 | name = "tokio-rustls" 2405 | version = "0.22.0" 2406 | source = "registry+https://github.com/rust-lang/crates.io-index" 2407 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 2408 | dependencies = [ 2409 | "rustls", 2410 | "tokio", 2411 | "webpki", 2412 | ] 2413 | 2414 | [[package]] 2415 | name = "tokio-stream" 2416 | version = "0.1.8" 2417 | source = "registry+https://github.com/rust-lang/crates.io-index" 2418 | checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" 2419 | dependencies = [ 2420 | "futures-core", 2421 | "pin-project-lite", 2422 | "tokio", 2423 | ] 2424 | 2425 | [[package]] 2426 | name = "tokio-util" 2427 | version = "0.6.9" 2428 | source = "registry+https://github.com/rust-lang/crates.io-index" 2429 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 2430 | dependencies = [ 2431 | "bytes", 2432 | "futures-core", 2433 | "futures-sink", 2434 | "log", 2435 | "pin-project-lite", 2436 | "tokio", 2437 | ] 2438 | 2439 | [[package]] 2440 | name = "tokio-util" 2441 | version = "0.7.1" 2442 | source = "registry+https://github.com/rust-lang/crates.io-index" 2443 | checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" 2444 | dependencies = [ 2445 | "bytes", 2446 | "futures-core", 2447 | "futures-sink", 2448 | "pin-project-lite", 2449 | "tokio", 2450 | "tracing", 2451 | ] 2452 | 2453 | [[package]] 2454 | name = "tracing" 2455 | version = "0.1.34" 2456 | source = "registry+https://github.com/rust-lang/crates.io-index" 2457 | checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" 2458 | dependencies = [ 2459 | "cfg-if", 2460 | "log", 2461 | "pin-project-lite", 2462 | "tracing-attributes", 2463 | "tracing-core", 2464 | ] 2465 | 2466 | [[package]] 2467 | name = "tracing-attributes" 2468 | version = "0.1.21" 2469 | source = "registry+https://github.com/rust-lang/crates.io-index" 2470 | checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" 2471 | dependencies = [ 2472 | "proc-macro2", 2473 | "quote", 2474 | "syn", 2475 | ] 2476 | 2477 | [[package]] 2478 | name = "tracing-core" 2479 | version = "0.1.26" 2480 | source = "registry+https://github.com/rust-lang/crates.io-index" 2481 | checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" 2482 | dependencies = [ 2483 | "lazy_static", 2484 | ] 2485 | 2486 | [[package]] 2487 | name = "typenum" 2488 | version = "1.15.0" 2489 | source = "registry+https://github.com/rust-lang/crates.io-index" 2490 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 2491 | 2492 | [[package]] 2493 | name = "ucd-trie" 2494 | version = "0.1.3" 2495 | source = "registry+https://github.com/rust-lang/crates.io-index" 2496 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 2497 | 2498 | [[package]] 2499 | name = "unicase" 2500 | version = "2.6.0" 2501 | source = "registry+https://github.com/rust-lang/crates.io-index" 2502 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 2503 | dependencies = [ 2504 | "version_check", 2505 | ] 2506 | 2507 | [[package]] 2508 | name = "unicode-bidi" 2509 | version = "0.3.8" 2510 | source = "registry+https://github.com/rust-lang/crates.io-index" 2511 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 2512 | 2513 | [[package]] 2514 | name = "unicode-normalization" 2515 | version = "0.1.19" 2516 | source = "registry+https://github.com/rust-lang/crates.io-index" 2517 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 2518 | dependencies = [ 2519 | "tinyvec", 2520 | ] 2521 | 2522 | [[package]] 2523 | name = "unicode-segmentation" 2524 | version = "1.9.0" 2525 | source = "registry+https://github.com/rust-lang/crates.io-index" 2526 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 2527 | 2528 | [[package]] 2529 | name = "unicode-xid" 2530 | version = "0.2.3" 2531 | source = "registry+https://github.com/rust-lang/crates.io-index" 2532 | checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" 2533 | 2534 | [[package]] 2535 | name = "unicode_categories" 2536 | version = "0.1.1" 2537 | source = "registry+https://github.com/rust-lang/crates.io-index" 2538 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 2539 | 2540 | [[package]] 2541 | name = "untrusted" 2542 | version = "0.7.1" 2543 | source = "registry+https://github.com/rust-lang/crates.io-index" 2544 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2545 | 2546 | [[package]] 2547 | name = "url" 2548 | version = "2.2.2" 2549 | source = "registry+https://github.com/rust-lang/crates.io-index" 2550 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 2551 | dependencies = [ 2552 | "form_urlencoded", 2553 | "idna", 2554 | "matches", 2555 | "percent-encoding", 2556 | ] 2557 | 2558 | [[package]] 2559 | name = "uuid" 2560 | version = "0.8.2" 2561 | source = "registry+https://github.com/rust-lang/crates.io-index" 2562 | checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" 2563 | dependencies = [ 2564 | "getrandom", 2565 | "serde", 2566 | ] 2567 | 2568 | [[package]] 2569 | name = "validator" 2570 | version = "0.15.0" 2571 | source = "registry+https://github.com/rust-lang/crates.io-index" 2572 | checksum = "f07b0a1390e01c0fc35ebb26b28ced33c9a3808f7f9fbe94d3cc01e233bfeed5" 2573 | dependencies = [ 2574 | "idna", 2575 | "lazy_static", 2576 | "regex", 2577 | "serde", 2578 | "serde_derive", 2579 | "serde_json", 2580 | "url", 2581 | "validator_derive", 2582 | ] 2583 | 2584 | [[package]] 2585 | name = "validator_derive" 2586 | version = "0.15.0" 2587 | source = "registry+https://github.com/rust-lang/crates.io-index" 2588 | checksum = "ea7ed5e8cf2b6bdd64a6c4ce851da25388a89327b17b88424ceced6bd5017923" 2589 | dependencies = [ 2590 | "if_chain", 2591 | "lazy_static", 2592 | "proc-macro-error", 2593 | "proc-macro2", 2594 | "quote", 2595 | "regex", 2596 | "syn", 2597 | "validator_types", 2598 | ] 2599 | 2600 | [[package]] 2601 | name = "validator_types" 2602 | version = "0.15.0" 2603 | source = "registry+https://github.com/rust-lang/crates.io-index" 2604 | checksum = "d2ddf34293296847abfc1493b15c6e2f5d3cd19f57ad7d22673bf4c6278da329" 2605 | dependencies = [ 2606 | "proc-macro2", 2607 | "syn", 2608 | ] 2609 | 2610 | [[package]] 2611 | name = "vcpkg" 2612 | version = "0.2.15" 2613 | source = "registry+https://github.com/rust-lang/crates.io-index" 2614 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2615 | 2616 | [[package]] 2617 | name = "vergen" 2618 | version = "4.1.0" 2619 | source = "registry+https://github.com/rust-lang/crates.io-index" 2620 | checksum = "7559dbf502657d16ddfdee53eea0827fc40ea7e3a53bc8b92d7317417cf9420e" 2621 | dependencies = [ 2622 | "bitflags", 2623 | "chrono", 2624 | "enum-iterator", 2625 | "getset", 2626 | "git2", 2627 | "rustc_version 0.3.3", 2628 | "serde", 2629 | "serde_derive", 2630 | ] 2631 | 2632 | [[package]] 2633 | name = "version_check" 2634 | version = "0.9.4" 2635 | source = "registry+https://github.com/rust-lang/crates.io-index" 2636 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2637 | 2638 | [[package]] 2639 | name = "wasi" 2640 | version = "0.10.0+wasi-snapshot-preview1" 2641 | source = "registry+https://github.com/rust-lang/crates.io-index" 2642 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 2643 | 2644 | [[package]] 2645 | name = "wasi" 2646 | version = "0.11.0+wasi-snapshot-preview1" 2647 | source = "registry+https://github.com/rust-lang/crates.io-index" 2648 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2649 | 2650 | [[package]] 2651 | name = "wasm-bindgen" 2652 | version = "0.2.80" 2653 | source = "registry+https://github.com/rust-lang/crates.io-index" 2654 | checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" 2655 | dependencies = [ 2656 | "cfg-if", 2657 | "wasm-bindgen-macro", 2658 | ] 2659 | 2660 | [[package]] 2661 | name = "wasm-bindgen-backend" 2662 | version = "0.2.80" 2663 | source = "registry+https://github.com/rust-lang/crates.io-index" 2664 | checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" 2665 | dependencies = [ 2666 | "bumpalo", 2667 | "lazy_static", 2668 | "log", 2669 | "proc-macro2", 2670 | "quote", 2671 | "syn", 2672 | "wasm-bindgen-shared", 2673 | ] 2674 | 2675 | [[package]] 2676 | name = "wasm-bindgen-macro" 2677 | version = "0.2.80" 2678 | source = "registry+https://github.com/rust-lang/crates.io-index" 2679 | checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" 2680 | dependencies = [ 2681 | "quote", 2682 | "wasm-bindgen-macro-support", 2683 | ] 2684 | 2685 | [[package]] 2686 | name = "wasm-bindgen-macro-support" 2687 | version = "0.2.80" 2688 | source = "registry+https://github.com/rust-lang/crates.io-index" 2689 | checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" 2690 | dependencies = [ 2691 | "proc-macro2", 2692 | "quote", 2693 | "syn", 2694 | "wasm-bindgen-backend", 2695 | "wasm-bindgen-shared", 2696 | ] 2697 | 2698 | [[package]] 2699 | name = "wasm-bindgen-shared" 2700 | version = "0.2.80" 2701 | source = "registry+https://github.com/rust-lang/crates.io-index" 2702 | checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" 2703 | 2704 | [[package]] 2705 | name = "web-sys" 2706 | version = "0.3.57" 2707 | source = "registry+https://github.com/rust-lang/crates.io-index" 2708 | checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" 2709 | dependencies = [ 2710 | "js-sys", 2711 | "wasm-bindgen", 2712 | ] 2713 | 2714 | [[package]] 2715 | name = "webpki" 2716 | version = "0.21.4" 2717 | source = "registry+https://github.com/rust-lang/crates.io-index" 2718 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 2719 | dependencies = [ 2720 | "ring", 2721 | "untrusted", 2722 | ] 2723 | 2724 | [[package]] 2725 | name = "webpki-roots" 2726 | version = "0.21.1" 2727 | source = "registry+https://github.com/rust-lang/crates.io-index" 2728 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 2729 | dependencies = [ 2730 | "webpki", 2731 | ] 2732 | 2733 | [[package]] 2734 | name = "whoami" 2735 | version = "1.2.1" 2736 | source = "registry+https://github.com/rust-lang/crates.io-index" 2737 | checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" 2738 | dependencies = [ 2739 | "wasm-bindgen", 2740 | "web-sys", 2741 | ] 2742 | 2743 | [[package]] 2744 | name = "winapi" 2745 | version = "0.3.9" 2746 | source = "registry+https://github.com/rust-lang/crates.io-index" 2747 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2748 | dependencies = [ 2749 | "winapi-i686-pc-windows-gnu", 2750 | "winapi-x86_64-pc-windows-gnu", 2751 | ] 2752 | 2753 | [[package]] 2754 | name = "winapi-i686-pc-windows-gnu" 2755 | version = "0.4.0" 2756 | source = "registry+https://github.com/rust-lang/crates.io-index" 2757 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2758 | 2759 | [[package]] 2760 | name = "winapi-util" 2761 | version = "0.1.5" 2762 | source = "registry+https://github.com/rust-lang/crates.io-index" 2763 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2764 | dependencies = [ 2765 | "winapi", 2766 | ] 2767 | 2768 | [[package]] 2769 | name = "winapi-x86_64-pc-windows-gnu" 2770 | version = "0.4.0" 2771 | source = "registry+https://github.com/rust-lang/crates.io-index" 2772 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2773 | 2774 | [[package]] 2775 | name = "windows-sys" 2776 | version = "0.36.1" 2777 | source = "registry+https://github.com/rust-lang/crates.io-index" 2778 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 2779 | dependencies = [ 2780 | "windows_aarch64_msvc", 2781 | "windows_i686_gnu", 2782 | "windows_i686_msvc", 2783 | "windows_x86_64_gnu", 2784 | "windows_x86_64_msvc", 2785 | ] 2786 | 2787 | [[package]] 2788 | name = "windows_aarch64_msvc" 2789 | version = "0.36.1" 2790 | source = "registry+https://github.com/rust-lang/crates.io-index" 2791 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 2792 | 2793 | [[package]] 2794 | name = "windows_i686_gnu" 2795 | version = "0.36.1" 2796 | source = "registry+https://github.com/rust-lang/crates.io-index" 2797 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 2798 | 2799 | [[package]] 2800 | name = "windows_i686_msvc" 2801 | version = "0.36.1" 2802 | source = "registry+https://github.com/rust-lang/crates.io-index" 2803 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 2804 | 2805 | [[package]] 2806 | name = "windows_x86_64_gnu" 2807 | version = "0.36.1" 2808 | source = "registry+https://github.com/rust-lang/crates.io-index" 2809 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 2810 | 2811 | [[package]] 2812 | name = "windows_x86_64_msvc" 2813 | version = "0.36.1" 2814 | source = "registry+https://github.com/rust-lang/crates.io-index" 2815 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 2816 | 2817 | [[package]] 2818 | name = "zeroize" 2819 | version = "1.5.5" 2820 | source = "registry+https://github.com/rust-lang/crates.io-index" 2821 | checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" 2822 | 2823 | [[package]] 2824 | name = "zstd" 2825 | version = "0.10.0+zstd.1.5.2" 2826 | source = "registry+https://github.com/rust-lang/crates.io-index" 2827 | checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" 2828 | dependencies = [ 2829 | "zstd-safe", 2830 | ] 2831 | 2832 | [[package]] 2833 | name = "zstd-safe" 2834 | version = "4.1.4+zstd.1.5.2" 2835 | source = "registry+https://github.com/rust-lang/crates.io-index" 2836 | checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" 2837 | dependencies = [ 2838 | "libc", 2839 | "zstd-sys", 2840 | ] 2841 | 2842 | [[package]] 2843 | name = "zstd-sys" 2844 | version = "1.6.3+zstd.1.5.2" 2845 | source = "registry+https://github.com/rust-lang/crates.io-index" 2846 | checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" 2847 | dependencies = [ 2848 | "cc", 2849 | "libc", 2850 | ] 2851 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actixweb-sqlx-jwt" 3 | version = "0.1.0" 4 | authors = ["Wspsxing "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | # https://docs.rs/vergen/4.1.0/vergen/ 10 | [build-dependencies] 11 | vergen = { version = "=4.1.0", features = [ "git" ] } 12 | 13 | [features] 14 | default = [ "mysql" ] 15 | postgres = [ "sqlx/postgres"] 16 | sqlite = [ "sqlx/sqlite"] 17 | mysql = [ "sqlx/mysql"] 18 | 19 | [dependencies.sqlx] 20 | version = "0.5.9" 21 | default-features = false 22 | features = [ "runtime-actix-rustls", "macros", "chrono", "decimal", "uuid", "json" ] 23 | # git = "https://github.com/launchbadge/sqlx" 24 | # path = "../sqlx" 25 | 26 | [dependencies] 27 | clap = { version = "3.0", features = [ "derive" ] } 28 | tokio = { version = "1.15.0", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } # copy from actix-rt 29 | nonblock-logger = { version = "0.1.6", default-features = false, features = ["color", "dbg"] } 30 | uuid = { version = "0.8.2", features = ["serde", "v4"] } 31 | chrono = { version = "0.4.19", features = ["serde"] } 32 | rust_decimal = { version = "1.10.3", features = [ "serde-float" ] } 33 | validator = { version = "0.15", features = ["derive"] } 34 | serde = { version = "1.0.123", features = ["derive"] } 35 | serde_qs = "0.8.2" 36 | serde_json = "1.0.63" 37 | json5 = "0.4.0" 38 | ring = "0.16.20" 39 | bcrypt = "0.10.0" 40 | hex = "0.4.2" 41 | jsonwebtoken = "7.2.0" 42 | mobc-redis = "0.7.0" 43 | mobc = "0.7.0" 44 | actix-web = "4.0.1" 45 | actix-files = "0.6.0" 46 | actix-rt = "2.1.0" 47 | lazy_static = "1.4.0" 48 | async-trait = "0.1.42" 49 | futures = "0.3.13" 50 | thiserror = "1.0.24" 51 | anyhow = "1.0.38" 52 | url = "2.2.1" 53 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM clux/muslrust 2 | WORKDIR /volume 3 | # silly docker copy about directory 4 | # sh -c 'cd .. && docker build --network host -t demo -f actixweb-sqlx-jwt/Dockerfile .' 5 | COPY actixweb-sqlx-jwt/ /volume/ 6 | RUN ls -lah && RUSTFLAGS='-C target-feature=+crt-static' cargo build --release && ls -lah target/* 7 | 8 | FROM alpine:latest 9 | RUN apk --no-cache add ca-certificates 10 | WORKDIR /opt/ 11 | COPY --from=0 /volume/target/x86_64-unknown-linux-musl/release/actixweb-sqlx-jwt /usr/bin 12 | RUN actixweb-sqlx-jwt -V 13 | CMD actixweb-sqlx-jwt -v 14 | 15 | -------------------------------------------------------------------------------- /Dockerfile.prod: -------------------------------------------------------------------------------- 1 | From debian:10 2 | WORKDIR /opt 3 | 4 | ARG APP=actixweb-sqlx-jwt 5 | 6 | # # mirror and timezone fot china 7 | # RUN set -eux; \ 8 | # sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list; \ 9 | # sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list; \ 10 | # ln -sfv /usr/share/zoneinfo/Hongkong /etc/localtime; \ 11 | # echo Hongkong > /etc/timezone; 12 | 13 | RUN set -eux; \ 14 | apt-get update; \ 15 | apt-get install -y \ 16 | tzdata \ 17 | libssl-dev; \ 18 | apt-get clean; \ 19 | rm -rf /var/lib/apt 20 | 21 | COPY ./target/release/${APP} /usr/local/bin/ 22 | 23 | ENV APP=${APP} 24 | 25 | RUN $APP -V 26 | 27 | CMD $APP -v 28 | 29 | # docker build -t template-prod:latest -f Dockerfile.prod . 30 | # docker run --rm -it --network host -v $PWD:/opt --name template template-prod actixweb-sqlx-jwt -V 31 | # docker run -d --restart always --network host -v $PWD:/opt --name template template-prod 32 | -------------------------------------------------------------------------------- /Dockerfile.rust: -------------------------------------------------------------------------------- 1 | From debian:10.0 as builder 2 | WORKDIR /opt 3 | 4 | # # mirror and timezone fot china 5 | # RUN set -eux; \ 6 | # sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list; \ 7 | # sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list; \ 8 | # ln -sfv /usr/share/zoneinfo/Hongkong /etc/localtime; \ 9 | # echo Hongkong > /etc/timezone; 10 | 11 | RUN set -eux; \ 12 | apt-get update; \ 13 | apt-get install -y \ 14 | sudo \ 15 | curl \ 16 | gcc \ 17 | file \ 18 | git \ 19 | pkg-config \ 20 | libssl-dev \ 21 | zlib1g-dev \ 22 | libsasl2-dev \ 23 | cmake \ 24 | g++; \ 25 | apt-get clean; \ 26 | rm -rf /var/lib/apt 27 | 28 | # # nightly-2020-09-24 or 1.49.0 29 | RUN set -eux; \ 30 | curl -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain=1.49.0 31 | 32 | ENV PATH="/root/.cargo/bin:${PATH}" 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | app=template 2 | version=v0.1 3 | commit_id=$(shell git describe --always --abbrev=8 --dirty=-modified) 4 | src_path = ${PWD} 5 | src_path_docker = /opt 6 | 7 | # debug or release 8 | # mode=release 9 | ifneq ($(mode), debug) 10 | target = --release 11 | else 12 | target = 13 | endif 14 | 15 | docker_file_rust = Dockerfile.rust 16 | docker_file_prod = Dockerfile.prod 17 | 18 | image_rust = ${app}-rust 19 | image_prod = ${app}-prod 20 | 21 | # println 22 | $(info src: $(src_path)) 23 | $(info commit: $(commit_id)) 24 | $(info mode: $(target)) 25 | 26 | $(shell mkdir -p ${HOME}/.cargo/{git,registry}) 27 | $(shell touch ${HOME}/.cargo/config) 28 | 29 | b: 30 | cargo build ${target} && rm -frv target/*/*.d 31 | 32 | image-rust: 33 | @if [ `docker images | grep ${image_rust} | wc -l` -eq 0 ]; then \ 34 | echo "build rust docker image "; \ 35 | docker build -t ${image_rust}:latest -f ${docker_file_rust} .; \ 36 | else \ 37 | echo "docker image ${image_rust} already exist!";\ 38 | fi 39 | 40 | image: build 41 | @echo "build docker image"; \ 42 | docker build -t ${image_prod}:latest -f ${docker_file_prod} . && \ 43 | docker tag ${image_prod}:latest ${image_prod}:${version}-${commit_id} && \ 44 | echo ${image_prod}:${version}-${commit_id} 45 | 46 | build: image-rust 47 | @echo "docker build ${mode}"; \ 48 | docker run -i --rm \ 49 | -v ${HOME}/.cargo/git:/root/.cargo/git \ 50 | -v ${HOME}/.cargo/config:/root/.cargo/config \ 51 | -v ${HOME}/.cargo/registry:/root/.cargo/registry \ 52 | -v ${src_path}:${src_path_docker} \ 53 | --workdir ${src_path_docker} \ 54 | --network host \ 55 | ${image_rust}:latest \ 56 | bash -c "cd ${src_path_docker}/ && cargo build --target-dir target ${target}" 57 | 58 | run: 59 | docker run -d --restart always --network host -v ${src_path}:/opt --name ${app} ${image_prod} 60 | 61 | clean: 62 | rm -fr target/* 63 | -------------------------------------------------------------------------------- /assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biluohc/actixweb-sqlx-jwt/5754dc6ae7eacf39126516ab79c8f1b08b9fd862/assets/.gitkeep -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate vergen; 2 | 3 | use vergen::{gen, ConstantsFlags}; 4 | 5 | fn main() { 6 | // Setup the flags, toggling off the 'SEMVER_FROM_CARGO_PKG' flag 7 | let mut flags = ConstantsFlags::all(); 8 | flags.toggle(ConstantsFlags::SEMVER_FROM_CARGO_PKG); 9 | 10 | // Generate the 'cargo:' key output 11 | gen(ConstantsFlags::all()).expect("Unable to generate the cargo keys!"); 12 | } 13 | -------------------------------------------------------------------------------- /gotest.jl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # https://docs.julialang.org/en/v1.2/manual/faq/#How-do-I-catch-CTRL-C-in-a-script?-1 3 | #= 4 | exec julia --color=yes -e 'include(popfirst!(ARGS))' \ 5 | "${BASH_SOURCE[0]}" "$@" =# 6 | 7 | 8 | using Test 9 | 10 | checkout() = run(`git checkout -f .env Cargo.toml template.json`) 11 | 12 | bd = read(pipeline(`cargo metadata --format-version 1`, `jq -r .target_directory`), String) |> strip 13 | clean() = run(`rm -frv $bd/release/actixweb-sqlx-jwt`) 14 | 15 | function test(kind::String) 16 | clean() 17 | 18 | run(`cargo build --release`) 19 | proc = run(`$bd/release/actixweb-sqlx-jwt -v`, wait=false) 20 | # wait server startup 21 | sleep(1) 22 | 23 | try 24 | run(`curl 0.0.0.0:8080/assets`) 25 | run(`curl -s --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/register`) 26 | 27 | jwt = read(pipeline(`curl -s --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/login`, `jq -r .data`), String) |> strip 28 | @test length(jwt) > 100 29 | 30 | authead = "Authorization: Bearer $jwt" 31 | code = read(pipeline(`curl -sH $authead localhost:8080/user/info/_`, `jq -r .code`), String) |> strip 32 | @test code == "200" 33 | 34 | authuri = "localhost:8080/user/info/_?access_token=$jwt" 35 | code = read(pipeline(`curl -s $authuri`, `jq -r .code`), String) |> strip 36 | @test code == "200" 37 | catch e 38 | @error "test api for $kind failed: $e" 39 | finally 40 | println() 41 | kill(proc) 42 | clean() 43 | end 44 | end 45 | 46 | function test_and_checkout(kind::String) 47 | checkout() 48 | 49 | @info("Test for $kind prepare") 50 | run(`sed -i "s/default\ =\ \[\ \"mysql\"\ \]/default = [ \"$kind\" ]/g" Cargo.toml `) 51 | kind == "mysql" || run(pipeline(`cat .env `, `grep $kind`, `sed 's/\#//gw .env'`)) 52 | 53 | json = read(pipeline(`cat template.json`, `grep -v sql`), String) 54 | db = read(pipeline(`cat template.json`, `grep $kind`, `sed 's/\/\/ //g'`), String) 55 | json2 = """{$db\n$(json[2:end])""" 56 | run(pipeline(`echo $json2`, `jq .`, `sed 'w template.json'`)) 57 | 58 | @info("Test for $kind ..") 59 | 60 | try 61 | test(kind) 62 | @warn("Test for $kind Ok\n") 63 | catch e 64 | @error("Test for $kind failed: $e\n") 65 | end 66 | 67 | checkout() 68 | end 69 | 70 | test_and_checkout("mysql") 71 | test_and_checkout("sqlite") 72 | test_and_checkout("postgres") 73 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # actixweb-sqlx-jwt 2 | A jwt template project of actix-web and sqlx 3 | 4 | ## sqlx-cli 5 | cargo install sqlx-cli --git https://github.com/launchbadge/sqlx 6 | 7 | ## Usage 8 | 9 | 1. Choose a database(`mysql`, `postgres`, `sqlite`). 10 | 2. Sets the default feature as the database name on Cargo.toml(current is `mysql`). 11 | 3. Configure the databse you can see `sql/user.up.$database.sql`. 12 | 4. Run `cargo run -- -v` after update .env and template.json. 13 | 5. Test current api: 14 | ```sh 15 | curl -v --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/register 16 | 17 | curl -v --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/login 18 | 19 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb2IiLCJleHAiOjE1OTEyNDYwOTR9.O1dbYu3tqiIi6I8OUlixLuj9dp-1tLl4mjmXZ0ve6uo' localhost:8080/user/userInfo 20 | 21 | curl -v -X DELETE -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb2IiLCJleHAiOjE1OTEyNDYwOTR9.O1dbYu3tqiIi6I8OUlixLuj9dp-1tLl4mjmXZ0ve6uo' localhost:8080/user/delete/Bob 22 | 23 | curl 'localhost:8080/user/userInfo?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb2IiLCJleHAiOjE1OTEyNTYxNDd9.zJKlZOozYfq-xMXO89kjUyme6SA8_eziacqt5gvXj2U' 24 | ``` 25 | 6. Modify the code and write your own code, enjoy. 26 | 27 | ## Notice 28 | 1. The sqlx query macros needs to be connected to the database represented by DATABASE_URL in .env, or you can consider using the unchecked version instead. 29 | 30 | ## Redis: No Redis does not affect the program running now 31 | 1. Use docker to start a Redis quickly 32 | ```bash 33 | docker run --name redis-6379 --network host -d redis redis-server --port 6379 --bind 127.0.0.1 --appendonly no # --requirepass pw 34 | 35 | # pip3 install iredis 36 | 37 | # iredis/redis-cli -p 6379 # -a pw 38 | ``` 39 | 2. The Redis client crates, current is mobc. 40 | 1. [redis-rs](https://github.com/mitsuhiko/redis-rs): The most used Redis client. 41 | 1. [mobc](https://github.com/importcjj/mobc): An asynchronous connection pool. 42 | 1. [deadpool](https://github.com/bikeshedder/deadpool): An asynchronous connection pool. 43 | 1. [actix-redis](https://github.com/actix/actix-extras/tree/master/actix-redis): Redis integration for actix framework base on redis-async-rs. 44 | 1. [bb8](https://crates.io/crates/bb8): An asynchronous connection pool provides the same configuration options as r2d2. 45 | 2. [r2d2](https://github.com/sfackler/r2d2): A synchronized connection pool, not recommended. 46 | 3. [redis-async-rs](https://github.com/benashford/redis-async-rs): Another Redis client. 47 | 48 | ### References 49 | 1. actix-web: https://github.com/actix/actix-web 50 | 2. sqlx: https://github.com/launchbadge/sqlx 51 | 2. actix documentation: https://actix.rs/docs/ 52 | 2. actix-web-jwt with mongodb: https://github.com/emreyalvac/actix-web-jwt 53 | 2. actix-examples: https://github.com/actix/examples 54 | 2. an instance: https://github.com/biluohc/KeepStats 55 | 3. ormx: https://github.com/NyxCode/ormx 56 | 3. sea-orm: https://github.com/SeaQL/sea-orm 57 | 3. sea-query: https://github.com/SeaQL/sea-query 58 | 4. Prisma Client Rust: https://github.com/Brendonovich/prisma-client-rust 59 | 5. validator: https://docs.rs/validator 60 | 6. axum: https://github.com/tokio-rs/axum 61 | -------------------------------------------------------------------------------- /sql/user.up.mysql.sql: -------------------------------------------------------------------------------- 1 | -- local: datetime(3) 2 | -- UTC: timestamp 3 | create table users ( 4 | id serial primary key, 5 | name char(10) UNIQUE not null, 6 | email char(20) UNIQUE not null comment 'email address', 7 | pass char(65) not null comment 'passwd hash', 8 | create_dt datetime(3) not null default current_timestamp(3) comment 'create datetime', 9 | update_dt datetime(3) not null default current_timestamp(3) on update current_timestamp(3) comment 'update datetime', 10 | status char(10) not null default 'normal' comment 'status: normal, blocked, deleted' 11 | ); 12 | 13 | 14 | -- docker run -d --restart always --name mysql-demo -p 3306:3306 -e MYSQL_ROOT_PASSWORD=MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg= -d mysql:5.7 15 | -- docker exec -it mysql-demo /bin/bash 16 | -- mysql -u root -pMTcwNzUyNzIzMDY4Nzk2MzQ3Mjg= 17 | -- grant all privileges on *.* to 'root'@'%' identified by '[password]'; 18 | -- select host, user, authentication_string from user; 19 | -- update user set authentication_string=PASSWORD("MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=") where user="root"; 20 | -- flush privileges; 21 | 22 | -- docker restart mysql-demo 23 | 24 | -- create database templatedb; 25 | -- use templatedb; 26 | -- show databases; 27 | 28 | -- create table users 29 | -- SHOW CREATE TABLE users; 30 | -- show tables; desc users; 31 | 32 | -- insert INTO users (name, email, pass) values('Alice', 'Alice@google.com', 'passwd'); 33 | -- insert INTO users (name, email, pass) values('Bob', 'Bob@google.com', 'passwd'); 34 | -- select * from users; 35 | 36 | -- pip3 install mycli 37 | -- mycli -hlocalhost -uroot -pMTcwNzUyNzIzMDY4Nzk2MzQ3Mjg= -Dtemplatedb 38 | -- DATABASE_URL=mysql://root:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@localhost/templatedb?timeout=60&serverTimezone=Hongkong 39 | -------------------------------------------------------------------------------- /sql/user.up.postgres.sql: -------------------------------------------------------------------------------- 1 | -- local: timestamp 2 | -- UTC: timestamptz 3 | create table users ( 4 | id serial8 primary key, 5 | name varchar(10) UNIQUE not null, 6 | email varchar(20) UNIQUE not null, 7 | pass varchar(65) not null, -- 'passwd hash' 8 | create_dt timestamp not null default current_timestamp, -- 'create datetime' 9 | update_dt timestamp not null default current_timestamp, -- 'udpate datetime' 10 | status varchar(10) not null default 'normal'-- comment 'status: normal, blocked, deleted', 11 | ); 12 | 13 | -- COMMENT ON COLUMN "users"."pass" IS 'passwd hash' 14 | 15 | -- docker run -d --restart always --name pg-demo -e POSTGRES_USER=template -e POSTGRES_DB=templatedb -e POSTGRES_PASSWORD=MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg= -p 5432:5432 postgres:14 16 | 17 | -- libpg-dev/postgresql-devel 18 | -- pip3 install pgcli 19 | -- pgcli postgres://template:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@localhost:5432/templatedb 20 | -- create table users 21 | -- \db; \l+; \di; \d users; 22 | 23 | -- DATABASE_URL="postgres://template:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@localhost:5432/templatedb" 24 | -------------------------------------------------------------------------------- /sql/user.up.sqlite.sql: -------------------------------------------------------------------------------- 1 | -- local: (datetime('now','localtime')) 2 | -- UTC: (datetime('now') 3 | -- https://stackoverflow.com/questions/57052204/utc-time-wrong-in-sqlite 4 | create table users ( 5 | id INTEGER primary key AUTOINCREMENT not null, 6 | name text UNIQUE not null, 7 | email char(20) UNIQUE not null, 8 | pass char(65) not null, -- 'passwd hash' 9 | create_dt datetime not null default (datetime('now','localtime')), -- 'create datetime' 10 | update_dt datetime not null default (datetime('now','localtime')), -- 'update datetime' 11 | status char(10) not null default 'normal' -- comment 'status: normal, blocked, deleted' 12 | ); 13 | 14 | -- https://www.sqlite.org/quirks.html 15 | -- SQLite has no DATETIME datatype. Instead, dates and times can be stored in any of these ways: 16 | -- As a TEXT string in the ISO-8601 format. Example: '2018-04-02 12:13:46'. 17 | -- As an INTEGER number of seconds since 1970 (also known as "unix time"). 18 | -- As a REAL value that is the fractional Julian day number. 19 | 20 | -- sqlite3 target/lite.db 21 | -- pip3 install litecli 22 | -- litecli target/lite.db 23 | 24 | -- .tables 25 | -- create table users 26 | -- .schema users 27 | 28 | -- insert INTO users (name, email, pass) values('Alice', 'Alice@google.com', 'passwd'); 29 | -- insert INTO users (name, email, pass) values('Bob', 'Bob@google.com', 'passwd'); 30 | -- select * from users; 31 | -------------------------------------------------------------------------------- /src/api.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use std::borrow::Cow; 3 | 4 | use actix_web::{ 5 | body::BoxBody, error, http::StatusCode, Error, HttpRequest, HttpResponse, Responder, 6 | ResponseError, 7 | }; 8 | 9 | #[derive(Debug, Deserialize, Serialize, Clone)] 10 | pub struct ApiResult { 11 | pub code: i32, 12 | pub msg: Option>, 13 | pub data: Option, 14 | } 15 | 16 | impl ApiResult { 17 | pub fn new() -> Self { 18 | Self { 19 | code: 200, 20 | msg: None, 21 | data: None, 22 | } 23 | } 24 | pub fn code(mut self, code: i32) -> Self { 25 | self.code = code; 26 | self 27 | } 28 | pub fn with_msg>>(mut self, msg: S) -> Self { 29 | self.msg = Some(msg.into()); 30 | self 31 | } 32 | pub fn msg_as_str(&self) -> &str { 33 | self.msg.as_ref().map(|s| s.as_ref()).unwrap_or_default() 34 | } 35 | pub fn with_data(mut self, data: T) -> Self { 36 | self.data = Some(data); 37 | self 38 | } 39 | pub fn log_to_resp(&self, req: &HttpRequest) -> HttpResponse { 40 | self.log(req); 41 | self.to_resp() 42 | } 43 | pub fn log(&self, req: &HttpRequest) { 44 | info!( 45 | "{} \"{} {} {:?}\" {}", 46 | req.peer_addr().unwrap(), 47 | req.method(), 48 | req.uri(), 49 | req.version(), 50 | self.code 51 | ); 52 | } 53 | pub fn to_resp(&self) -> HttpResponse { 54 | let resp = match serde_json::to_string(self) { 55 | Ok(json) => HttpResponse::Ok() 56 | .content_type("application/json") 57 | .body(json), 58 | Err(e) => Error::from(e).into(), 59 | }; 60 | 61 | resp 62 | } 63 | } 64 | 65 | use std::fmt::{self, Debug, Display}; 66 | impl Display for ApiResult { 67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 68 | write!(f, "{:?}", self) 69 | } 70 | } 71 | 72 | pub type ApiError = ApiResult<()>; 73 | impl ResponseError for ApiResult { 74 | fn status_code(&self) -> StatusCode { 75 | StatusCode::OK 76 | } 77 | fn error_response(&self) -> HttpResponse { 78 | self.to_resp() 79 | } 80 | } 81 | 82 | // Either and AsRef/Responder not in crate 83 | pub enum ApiRt { 84 | Ref(L), 85 | T(R), 86 | } 87 | 88 | impl Responder for ApiRt> 89 | where 90 | T: Serialize, 91 | R: AsRef>, 92 | { 93 | type Body = BoxBody; 94 | 95 | fn respond_to(self, req: &HttpRequest) -> HttpResponse { 96 | match self { 97 | ApiRt::Ref(a) => a.as_ref().respond_to(req), 98 | ApiRt::T(b) => b.respond_to(req), 99 | } 100 | } 101 | } 102 | 103 | impl Responder for ApiResult { 104 | type Body = BoxBody; 105 | 106 | fn respond_to(self, req: &HttpRequest) -> HttpResponse { 107 | (&self).respond_to(req) 108 | } 109 | } 110 | impl Responder for &ApiResult { 111 | type Body = BoxBody; 112 | 113 | fn respond_to(self, req: &HttpRequest) -> HttpResponse { 114 | self.log_to_resp(req) 115 | } 116 | } 117 | 118 | // return 200 all 119 | pub fn json_error_handler( 120 | err: E, 121 | req: &HttpRequest, 122 | ) -> error::Error { 123 | let detail = err.to_string(); 124 | let api = ApiResult::new().with_data(()).code(400).with_msg(detail); 125 | let response = api.log_to_resp(req); 126 | 127 | error::InternalError::from_response(err, response).into() 128 | } 129 | 130 | pub async fn notfound(req: HttpRequest) -> Result { 131 | let api = ApiResult::new() 132 | .with_data(()) 133 | .code(404) 134 | .with_msg("route not found"); 135 | 136 | Ok(api.respond_to(&req)) 137 | } 138 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::state::*; 2 | use crate::state::{redis::Client, KvPool, RedisConnectionManager}; 3 | 4 | use std::path::PathBuf; 5 | use std::sync::Arc; 6 | 7 | #[derive(Serialize, Deserialize, Debug, Clone, Default)] 8 | pub struct Config { 9 | pub sql: String, 10 | pub redis: String, 11 | pub listen: String, 12 | pub jwt_priv: String, 13 | } 14 | 15 | #[derive(Debug, Deserialize, PartialEq, Serialize)] 16 | #[serde(rename_all = "camelCase")] 17 | struct DbOptions { 18 | timeout: u64, 19 | #[serde(default)] 20 | server_timezone: String, 21 | } 22 | 23 | impl Config { 24 | pub fn parse_from_file(file: &PathBuf) -> Self { 25 | use std::fs::read_to_string; 26 | 27 | info!("confp: {}", file.display()); 28 | let confstr = read_to_string(file).expect("confile read"); 29 | json5::from_str(&confstr).expect("confile deser") 30 | } 31 | pub async fn into_state(self) -> AppStateRaw { 32 | info!("config: {:?}", self); 33 | let mut pool_options = PoolOptions::new(); 34 | 35 | if let Some(opstr) = url::Url::parse(&self.sql) 36 | .expect("Invalid SqlDB URL") 37 | .query() 38 | { 39 | if let Some(ops) = serde_qs::from_str::(opstr) 40 | .map_err(|e| error!("serde_qs::from_str:: failed: {}", e)) 41 | .ok() 42 | { 43 | pool_options = 44 | pool_options.connect_timeout(std::time::Duration::from_secs(ops.timeout)); 45 | 46 | if !ops.server_timezone.is_empty() { 47 | let key = if cfg!(feature = "mysql") { 48 | "@@session.time_zone =" 49 | } else if cfg!(feature = "postgres") { 50 | "TIME ZONE" 51 | } else { 52 | panic!("sqlite can't set timezone!") 53 | }; 54 | // UTC, +00:00, HongKong, etc 55 | let set = format!("SET {} '{}'", key, ops.server_timezone.clone()); 56 | 57 | // cannot move out of `set_str`, a captured variable in an `Fn` closure 58 | let set_str = unsafe { std::mem::transmute::<_, &'static str>(set.as_str()) }; 59 | std::mem::forget(set); 60 | pool_options = pool_options.after_connect(move |conn| { 61 | Box::pin(async move { 62 | use crate::sqlx::Executor; 63 | conn.execute(set_str).await.map(|_| ()) 64 | }) 65 | }) 66 | } 67 | } 68 | } 69 | 70 | let sql = pool_options.connect(&self.sql).await.expect("sql open"); 71 | let kvm = 72 | RedisConnectionManager::new(Client::open(self.redis.clone()).expect("redis open")); 73 | let kv = KvPool::builder().build(kvm); 74 | 75 | Arc::new(State { 76 | config: self, 77 | sql, 78 | kv, 79 | }) 80 | } 81 | // generate and show config string 82 | pub fn show() { 83 | let de: Self = Default::default(); 84 | println!("{}", serde_json::to_string_pretty(&de).unwrap()) 85 | } 86 | } 87 | 88 | pub fn version_with_gitif() -> &'static str { 89 | concat!( 90 | env!("CARGO_PKG_VERSION"), 91 | " ", 92 | env!("VERGEN_GIT_COMMIT_DATE"), 93 | ": ", 94 | env!("VERGEN_GIT_SHA_SHORT") 95 | ) 96 | } 97 | 98 | #[derive(clap::Parser, Debug)] 99 | // #[clap(name = "template")] 100 | #[clap(version = version_with_gitif())] 101 | pub struct Opts { 102 | // The number of occurrences of the `v/verbose` flag 103 | /// Verbose mode (-v, -vv, -vvv, etc.) 104 | #[clap(short, long, parse(from_occurrences))] 105 | pub verbose: u8, 106 | 107 | /// Config file 108 | #[clap( 109 | short = 'c', 110 | long = "config", 111 | parse(from_os_str), 112 | default_value = "template.json" 113 | )] 114 | pub config: PathBuf, 115 | } 116 | 117 | impl Opts { 118 | pub fn parse_from_args() -> (JoinHandle, Self) { 119 | use clap::Parser; 120 | let opt: Self = Opts::parse(); 121 | 122 | let level = match opt.verbose { 123 | 0 => LevelFilter::Warn, 124 | 1 => LevelFilter::Info, 125 | 2 => LevelFilter::Debug, 126 | _more => LevelFilter::Trace, 127 | }; 128 | 129 | let formater = BaseFormater::new() 130 | .local(true) 131 | .color(true) 132 | .level(4) 133 | .formater(format); 134 | let filter = BaseFilter::new() 135 | .starts_with(true) 136 | .notfound(true) 137 | .max_level(level) 138 | .chain( 139 | "sqlx", 140 | if opt.verbose > 1 { 141 | LevelFilter::Debug 142 | } else { 143 | LevelFilter::Warn 144 | }, 145 | ); 146 | 147 | let handle = NonblockLogger::new() 148 | .filter(filter) 149 | .unwrap() 150 | .formater(formater) 151 | .log_to_stdout() 152 | .map_err(|e| eprintln!("failed to init nonblock_logger: {:?}", e)) 153 | .unwrap(); 154 | 155 | info!("opt: {:?}", opt); 156 | 157 | (handle, opt) 158 | } 159 | } 160 | 161 | use nonblock_logger::{ 162 | log::{LevelFilter, Record}, 163 | BaseFilter, BaseFormater, FixedLevel, JoinHandle, NonblockLogger, 164 | }; 165 | 166 | pub fn format(base: &BaseFormater, record: &Record) -> String { 167 | let level = FixedLevel::with_color(record.level(), base.color_get()) 168 | .length(base.level_get()) 169 | .into_colored() 170 | .into_coloredfg(); 171 | 172 | format!( 173 | "[{} {}#{}:{} {}] {}\n", 174 | chrono::Local::now().format("%Y-%m-%d %H:%M:%S.%3f"), 175 | level, 176 | record.module_path().unwrap_or("*"), 177 | // record.file().unwrap_or("*"), 178 | record.line().unwrap_or(0), 179 | nonblock_logger::current_thread_name(), 180 | record.args() 181 | ) 182 | } 183 | -------------------------------------------------------------------------------- /src/handlers/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biluohc/actixweb-sqlx-jwt/5754dc6ae7eacf39126516ab79c8f1b08b9fd862/src/handlers/mod.rs -------------------------------------------------------------------------------- /src/how.rs: -------------------------------------------------------------------------------- 1 | use mobc_redis::redis::RedisError; 2 | use sqlx::Error as SqlxError; 3 | use tokio::time::error::Elapsed; 4 | 5 | pub use anyhow::Error as AnyError; 6 | pub use anyhow::Result as AnyResult; 7 | 8 | pub type Result = std::result::Result; 9 | 10 | // https://docs.rs/anyhow 11 | #[derive(thiserror::Error, Debug)] 12 | pub enum Error { 13 | #[error("Mobc error: {0}")] 14 | Mobc(#[from] mobc::Error), 15 | #[error("Redis error: {0}")] 16 | Redis(#[from] RedisError), 17 | #[error("Sqlx error: {0}")] 18 | Sqlx(#[from] SqlxError), 19 | #[error("Timout error: {0}")] 20 | Timout(#[from] Elapsed), 21 | } 22 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate nonblock_logger; 3 | #[macro_use] 4 | extern crate async_trait; 5 | #[macro_use] 6 | extern crate validator; 7 | #[macro_use] 8 | extern crate sqlx; 9 | #[macro_use] 10 | extern crate serde; 11 | 12 | use actix_files::Files; 13 | use actix_web::{middleware, web, App, HttpServer}; 14 | 15 | pub mod api; 16 | pub mod config; 17 | pub mod how; 18 | pub mod middlewares; 19 | pub mod models; 20 | pub mod state; 21 | pub mod users; 22 | 23 | use config::{Config, Opts}; 24 | 25 | #[actix_rt::main] 26 | async fn main() -> std::io::Result<()> { 27 | // Config::show(); 28 | let (_handle, opt) = Opts::parse_from_args(); 29 | let state = Config::parse_from_file(&opt.config).into_state().await; 30 | let state2 = state.clone(); 31 | 32 | HttpServer::new(move || { 33 | App::new() 34 | .app_data(web::Data::new(state.clone())) 35 | .app_data(state.clone()) 36 | .app_data(web::PathConfig::default().error_handler(api::json_error_handler)) 37 | .app_data(web::JsonConfig::default().error_handler(api::json_error_handler)) 38 | .app_data(web::QueryConfig::default().error_handler(api::json_error_handler)) 39 | .app_data(web::FormConfig::default().error_handler(api::json_error_handler)) 40 | .wrap(middleware::Compress::default()) 41 | .wrap(middleware::Logger::default()) 42 | .default_service(web::route().to(api::notfound)) 43 | .service(web::scope("/user").configure(users::routes::init)) 44 | .service( 45 | Files::new("/assets", "assets") 46 | .redirect_to_slash_directory() 47 | .show_files_listing() 48 | .use_last_modified(true), 49 | ) 50 | }) 51 | .keep_alive(std::time::Duration::from_secs(300)) 52 | .bind(&state2.config.listen)? 53 | .run() 54 | .await 55 | } 56 | -------------------------------------------------------------------------------- /src/middlewares/auth.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{dev, FromRequest, HttpRequest}; 2 | use futures::future::{err, ok, Ready}; 3 | use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; 4 | use std::borrow::Cow; 5 | 6 | use crate::api::ApiError; 7 | use crate::state::AppStateRaw; 8 | use crate::users::user::Claims; 9 | 10 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 11 | struct QueryParams { 12 | access_token: String, 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct AuthorizationService { 17 | pub claims: Claims, 18 | } 19 | 20 | impl FromRequest for AuthorizationService { 21 | type Error = ApiError; 22 | type Future = Ready>; 23 | 24 | // 1. header: Authorization: Bearer xxx 25 | // 2. URL's query: ?access_token=xxx 26 | // 3x. Body's query: ?access_token=xxx 27 | fn from_request(req: &HttpRequest, _payload: &mut dev::Payload) -> Self::Future { 28 | let token = req 29 | .headers() 30 | .get("Authorization") 31 | .and_then(|h| h.to_str().ok()) 32 | .and_then(|h| { 33 | let words = h.split("Bearer").collect::>(); 34 | let token = words.get(1).map(|w| w.trim()); 35 | debug!("JWT.Authorization: {} -> {:?}", h, token); 36 | token.map(|t| Cow::Borrowed(t)) 37 | }) 38 | .or_else(|| { 39 | let query = req.query_string(); 40 | let token = serde_qs::from_str::(query); 41 | debug!("JWT.access_token: {} -> {:?}", query, token); 42 | token.map(|p| p.access_token.into()).ok() 43 | }); 44 | 45 | match token 46 | .as_ref() 47 | .ok_or_else(|| Cow::Borrowed("Unauthorized")) 48 | .and_then(|token| { 49 | let state = req.app_data::().expect("get AppStateRaw"); 50 | let key = state.config.jwt_priv.as_bytes(); 51 | match decode::( 52 | token, 53 | &DecodingKey::from_secret(key), 54 | &Validation::new(Algorithm::HS256), 55 | ) { 56 | Ok(claims) => Ok(AuthorizationService { 57 | claims: claims.claims, 58 | }), 59 | Err(e) => { 60 | error!("jwt.decode {} failed: {:?}", token, e); 61 | Err(format!("invalid token: {}", e).into()) 62 | } 63 | } 64 | }) { 65 | Ok(service) => ok(service), 66 | Err(e) => { 67 | let api = ApiError::new().code(400).with_msg(e); 68 | api.log(req); 69 | err(api) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/middlewares/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod auth; 2 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/state.rs: -------------------------------------------------------------------------------- 1 | pub use mobc_redis::{redis, RedisConnectionManager}; 2 | pub type Connection = mobc::Connection; 3 | pub type KvPool = mobc::Pool; 4 | 5 | #[cfg(any(feature = "mysql"))] 6 | pub type SqlPool = sqlx::MySqlPool; 7 | #[cfg(any(feature = "mysql"))] 8 | pub type PoolOptions = sqlx::mysql::MySqlPoolOptions; 9 | 10 | #[cfg(any(feature = "sqlite"))] 11 | pub type SqlPool = sqlx::SqlitePool; 12 | #[cfg(any(feature = "sqlite"))] 13 | pub type PoolOptions = sqlx::sqlite::SqlitePoolOptions; 14 | 15 | #[cfg(any(feature = "postgres"))] 16 | pub type SqlPool = sqlx::PgPool; 17 | #[cfg(any(feature = "postgres"))] 18 | pub type PoolOptions = sqlx::postgres::PgPoolOptions; 19 | 20 | use crate::config::Config; 21 | 22 | #[derive(Clone)] 23 | pub struct State { 24 | pub config: Config, 25 | pub sql: SqlPool, 26 | pub kv: KvPool, 27 | } 28 | 29 | pub type AppStateRaw = std::sync::Arc; 30 | pub type AppState = actix_web::web::Data; 31 | -------------------------------------------------------------------------------- /src/users/dao.rs: -------------------------------------------------------------------------------- 1 | use super::user::*; 2 | use crate::state::AppStateRaw; 3 | 4 | #[async_trait] 5 | pub trait IUser: std::ops::Deref { 6 | async fn user_add(&self, form: &Register) -> sqlx::Result; 7 | async fn user_query(&self, who: &str) -> sqlx::Result { 8 | let (column, placeholder) = column_placeholder(who); 9 | 10 | let sql = format!( 11 | "SELECT id, name, email, pass, status, create_dt, update_dt 12 | FROM users 13 | where {} = {};", 14 | column, placeholder 15 | ); 16 | 17 | sqlx::query_as(&sql).bind(who).fetch_one(&self.sql).await 18 | } 19 | async fn user_delete(&self, who: &str) -> sqlx::Result { 20 | let (column, placeholder) = column_placeholder(who); 21 | 22 | let sql = format!( 23 | "update users set status='deleted' where {}={} RETURNING *;", 24 | column, placeholder 25 | ); 26 | 27 | sqlx::query_as(&sql).bind(who).fetch_one(&self.sql).await 28 | } 29 | } 30 | 31 | #[cfg(any(feature = "mysql", feature = "sqlite"))] 32 | #[async_trait] 33 | impl IUser for &AppStateRaw { 34 | async fn user_add(&self, form: &Register) -> sqlx::Result { 35 | let passh = form.passhash(); 36 | 37 | sqlx::query!( 38 | r#" 39 | INSERT INTO users (name, email, pass) 40 | VALUES (?, ?, ?) 41 | "#, 42 | form.name, 43 | form.email, 44 | passh 45 | ) 46 | .execute(&self.sql) 47 | .await 48 | .map(|d| d.rows_affected()) 49 | } 50 | #[cfg(any(feature = "mysql"))] 51 | async fn user_delete(&self, who: &str) -> sqlx::Result { 52 | let (column, placeholder) = column_placeholder(who); 53 | 54 | // mysql doesn't have RETURNING 55 | let sql = format!( 56 | "update users set status='deleted' where {}={};", 57 | column, placeholder 58 | ); 59 | 60 | sqlx::query(&sql).bind(who).execute(&self.sql).await?; 61 | self.user_query(who).await 62 | } 63 | } 64 | 65 | #[cfg(any(feature = "postgres"))] 66 | #[async_trait] 67 | impl IUser for &AppStateRaw { 68 | async fn user_add(&self, form: &Register) -> sqlx::Result { 69 | let passh = form.passhash(); 70 | 71 | sqlx::query!( 72 | r#" 73 | INSERT INTO users (name, email, pass) 74 | VALUES ($1 ,$2 ,$3) 75 | "#, 76 | form.name, 77 | form.email, 78 | passh 79 | ) 80 | .execute(&self.sql) 81 | .await 82 | .map(|d| d.rows_affected()) 83 | } 84 | } 85 | 86 | fn column_placeholder(id_or_name_or_email: &str) -> (&'static str, &'static str) { 87 | let mut column = "name"; 88 | 89 | if id_or_name_or_email.contains("@") { 90 | column = "email"; 91 | } else if first_char_is_number(id_or_name_or_email) { 92 | column = "id"; 93 | } 94 | 95 | // postgres: $1, $2 .. 96 | // mysql/sqlite: ?, ? .. 97 | let placeholder = if cfg!(feature = "postgres") { 98 | "$1" 99 | } else { 100 | "?" 101 | }; 102 | 103 | (column, placeholder) 104 | } 105 | -------------------------------------------------------------------------------- /src/users/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dao; 2 | pub mod routes; 3 | pub mod user; 4 | -------------------------------------------------------------------------------- /src/users/routes.rs: -------------------------------------------------------------------------------- 1 | use super::dao::IUser; 2 | use super::user::{Claims, Login, Register}; 3 | use crate::api::ApiResult; 4 | use crate::middlewares::auth::AuthorizationService; 5 | use crate::state::AppState; 6 | 7 | use actix_web::{delete as del, get, post, web, Responder}; 8 | use validator::Validate; 9 | 10 | // curl -v --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/register 11 | #[post("/register")] 12 | async fn register(form: web::Json, state: AppState) -> impl Responder { 13 | let form = form.into_inner(); 14 | 15 | if let Err(e) = form.validate() { 16 | error!("regitser {:?} error: {:?}", form, e); 17 | return ApiResult::new().code(400).with_msg(e.to_string()); 18 | } 19 | 20 | match state.get_ref().user_add(&form).await { 21 | Ok(res) => { 22 | info!("register {:?} res: {}", form, res); 23 | ApiResult::new().with_msg("ok").with_data(res) 24 | } 25 | Err(e) => { 26 | error!("regitser {:?} error: {:?}", form, e); 27 | ApiResult::new().code(400).with_msg(e.to_string()) 28 | } 29 | } 30 | } 31 | 32 | // curl -v --data '{"name": "Bob", "email": "Bob@google.com", "password": "Bobpass"}' -H "Content-Type: application/json" -X POST localhost:8080/user/login 33 | #[post("/login")] 34 | async fn login(form: web::Json, state: AppState) -> impl Responder { 35 | let form = form.into_inner(); 36 | 37 | use chrono::{DateTime, Duration, Utc}; 38 | use jsonwebtoken::{encode, EncodingKey, Header}; 39 | 40 | // todo: distable login for deleted and blocked users 41 | match state.get_ref().user_query(&form.name).await { 42 | Ok(user) => { 43 | info!("find user {:?} ok: {:?}", form, user); 44 | 45 | if form.verify(&user.pass) { 46 | let exp: DateTime = Utc::now() 47 | + if form.rememberme { 48 | Duration::days(30) 49 | } else { 50 | Duration::hours(1) 51 | }; 52 | 53 | let my_claims = Claims { 54 | sub: user.name, 55 | exp: exp.timestamp() as usize, 56 | }; 57 | let key = state.config.jwt_priv.as_bytes(); 58 | let token = encode( 59 | &Header::default(), 60 | &my_claims, 61 | &EncodingKey::from_secret(key), 62 | ) 63 | .unwrap(); 64 | 65 | ApiResult::new().with_msg("ok").with_data(token) 66 | } else { 67 | ApiResult::new().code(403).with_msg("wrong pass or name") 68 | } 69 | } 70 | Err(e) => { 71 | error!("find user {:?} error: {:?}", form, e); 72 | ApiResult::new().code(400).with_msg(e.to_string()) 73 | } 74 | } 75 | } 76 | 77 | // curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb2IiLCJleHAiOjE1OTEyNDYwOTR9.O1dbYu3tqiIi6I8OUlixLuj9dp-1tLl4mjmXZ0ve6uo' localhost:8080/user/info/who |jq . 78 | // curl 'localhost:8080/user/userInfo?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb2IiLCJleHAiOjE1OTEyNTYxNDd9.zJKlZOozYfq-xMXO89kjUyme6SA8_eziacqt5gvXj2U' |jq . 79 | #[get("/info/{who}")] 80 | async fn info( 81 | form: web::Path, 82 | auth: AuthorizationService, 83 | state: AppState, 84 | ) -> impl Responder { 85 | let who = form.into_inner(); 86 | let w = who.as_str(); 87 | 88 | // me 89 | let user = match state.get_ref().user_query(&auth.claims.sub).await { 90 | Ok(user) => { 91 | debug!("find user {:?} ok: {:?}", auth.claims, user); 92 | 93 | if who == "_" 94 | || [ 95 | user.id.to_string().as_str(), 96 | user.name.as_str(), 97 | user.email.as_str(), 98 | ] 99 | .contains(&w) 100 | { 101 | return ApiResult::new().with_msg("ok").with_data(user); 102 | } 103 | 104 | user 105 | } 106 | Err(e) => { 107 | error!("find user {:?} error: {:?}", auth.claims, e); 108 | return ApiResult::new().code(500).with_msg(e.to_string()); 109 | } 110 | }; 111 | 112 | // todo: add role(admin, user, guest) 113 | if user.status != "normal" { 114 | return ApiResult::new().code(403); 115 | } 116 | 117 | match state.get_ref().user_query(w).await { 118 | Ok(user) => { 119 | debug!("find user {:?} ok: {:?}", w, user); 120 | ApiResult::new().with_msg("ok").with_data(user) 121 | } 122 | Err(e) => { 123 | error!("find user {:?} error: {:?}", w, e); 124 | ApiResult::new().code(500).with_msg(e.to_string()) 125 | } 126 | } 127 | } 128 | 129 | // curl -v -X DELETE localhost:8080/user/who 130 | #[del("/delete/{who}")] 131 | async fn delete( 132 | form: web::Path, 133 | auth: AuthorizationService, 134 | state: AppState, 135 | ) -> impl Responder { 136 | let user = match state.get_ref().user_query(&auth.claims.sub).await { 137 | Ok(user) => user, 138 | Err(e) => { 139 | error!("find user {:?} error: {:?}", auth.claims, e); 140 | return ApiResult::new().code(500).with_msg(e.to_string()); 141 | } 142 | }; 143 | 144 | // todo: add role(admin, user, guest) 145 | if user.status != "normal" { 146 | return ApiResult::new().code(403); 147 | } 148 | 149 | let who = form.into_inner(); 150 | match state.get_ref().user_delete(&who).await { 151 | Ok(res) => { 152 | info!( 153 | "delete {:?} res: {} {} {} {}", 154 | who, res.id, res.name, res.email, res.status 155 | ); 156 | ApiResult::new().with_msg("ok").with_data(res) 157 | } 158 | Err(e) => { 159 | error!("delete {:?} error: {:?}", who, e); 160 | ApiResult::new().code(400).with_msg(e.to_string()) 161 | } 162 | } 163 | } 164 | 165 | pub fn init(cfg: &mut web::ServiceConfig) { 166 | cfg.service(login); 167 | cfg.service(register); 168 | cfg.service(delete); 169 | cfg.service(info); 170 | } 171 | -------------------------------------------------------------------------------- /src/users/user.rs: -------------------------------------------------------------------------------- 1 | // PBKDF2 < bcrypt < scrypt 2 | fn passhash(name: &str, pass: &str) -> String { 3 | let namedpass = format!("{}{}", name, pass); 4 | let hash = bcrypt::hash(namedpass.as_bytes(), bcrypt::DEFAULT_COST).unwrap(); 5 | // info!("{}{}: {}", name, pass, hash); 6 | hash 7 | } 8 | fn passhash_verify(name: &str, pass: &str, hash: &str) -> bool { 9 | let namedpass = format!("{}{}", name, pass); 10 | bcrypt::verify(namedpass.as_bytes(), hash).unwrap() 11 | } 12 | 13 | #[cfg(any(feature = "mysql"))] 14 | type SqlID = u64; 15 | #[cfg(any(feature = "postgres", feature = "sqlite"))] 16 | type SqlID = i64; 17 | 18 | // https://docs.rs/sqlx/0.5.7/sqlx/trait.FromRow.html 19 | // Extend derive(FromRow): https://github.com/launchbadge/sqlx/issues/156 20 | type SqlDateTime = chrono::NaiveDateTime; 21 | 22 | #[derive(FromRow, Serialize, Deserialize, Debug)] 23 | pub struct User { 24 | pub id: SqlID, 25 | pub name: String, 26 | // pub phone: String, 27 | pub email: String, 28 | // not return password 29 | #[serde(skip_serializing)] 30 | pub pass: String, 31 | pub status: String, 32 | pub create_dt: SqlDateTime, 33 | pub update_dt: SqlDateTime, 34 | } 35 | 36 | #[derive(Serialize, Deserialize, Debug)] 37 | pub struct Login { 38 | pub name: String, 39 | pub password: String, 40 | #[serde(default)] 41 | pub rememberme: bool, 42 | } 43 | 44 | impl Login { 45 | pub fn verify(&self, hash: &str) -> bool { 46 | passhash_verify(&self.name, &self.password, hash) 47 | } 48 | } 49 | 50 | #[derive(Debug, Default, Serialize, Deserialize)] 51 | pub struct Claims { 52 | // username 53 | pub sub: String, 54 | pub exp: usize, 55 | } 56 | 57 | #[derive(Serialize, Deserialize, Debug, Validate)] 58 | pub struct Register { 59 | #[validate(length(min = 3, max = 33), custom = "validate_username")] 60 | pub name: String, 61 | #[validate(email)] 62 | pub email: String, 63 | pub password: String, 64 | } 65 | 66 | use validator::ValidationError; 67 | fn validate_username(username: &str) -> Result<(), ValidationError> { 68 | // todo: use regex for robust 69 | if first_char_is_number(username) { 70 | return Err(ValidationError::new( 71 | "terrible_username: first char is number", 72 | )); 73 | } 74 | 75 | if username.contains("@") { 76 | // the value of the username will automatically be added later 77 | return Err(ValidationError::new("terrible_username: contains @")); 78 | } 79 | 80 | Ok(()) 81 | } 82 | 83 | impl Register { 84 | pub fn passhash(&self) -> String { 85 | passhash(&self.name, &self.password) 86 | } 87 | } 88 | 89 | pub fn first_char_is_number(s: &str) -> bool { 90 | s.get(0..1).and_then(|c| c.parse::().ok()).is_some() 91 | } 92 | -------------------------------------------------------------------------------- /template.json: -------------------------------------------------------------------------------- 1 | { 2 | "sql": "mysql://root:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@sh1/templatedb?timeout=60&serverTimezone=Hongkong", 3 | // "sql": "postgres://template:MTcwNzUyNzIzMDY4Nzk2MzQ3Mjg=@sh1:5432/templatedb?timeout=60&serverTimezone=Hongkong", 4 | // "sql": "sqlite://./target/lite.db", 5 | "redis": "redis://127.0.0.1", 6 | "listen": "0.0.0.0:8080", 7 | "jwt_priv": "0xa06f853898a9dd4f32441a56879c52878f96c42730ed31c50e00" 8 | } --------------------------------------------------------------------------------