aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/rust.yml16
-rw-r--r--Cargo.lock1473
-rw-r--r--Cargo.toml16
-rw-r--r--Dockerfile5
-rw-r--r--config.toml2
-rw-r--r--src/api.rs42
-rw-r--r--src/command/history.rs8
-rw-r--r--src/command/login.rs7
-rw-r--r--src/command/mod.rs8
-rw-r--r--src/command/search.rs110
-rw-r--r--src/command/server.rs6
-rw-r--r--src/command/sync.rs4
-rw-r--r--src/local/api_client.rs87
-rw-r--r--src/local/database.rs8
-rw-r--r--src/local/import.rs7
-rw-r--r--src/local/sync.rs36
-rw-r--r--src/main.rs43
-rw-r--r--src/remote/database.rs22
-rw-r--r--src/remote/mod.rs5
-rw-r--r--src/remote/server.rs61
-rw-r--r--src/remote/views.rs185
-rw-r--r--src/schema.rs30
-rw-r--r--src/server/auth.rs (renamed from src/remote/auth.rs)2
-rw-r--r--src/server/database.rs202
-rw-r--r--src/server/handlers/history.rs89
-rw-r--r--src/server/handlers/mod.rs6
-rw-r--r--src/server/handlers/user.rs140
-rw-r--r--src/server/mod.rs23
-rw-r--r--src/server/models.rs (renamed from src/remote/models.rs)43
-rw-r--r--src/server/router.rs121
-rw-r--r--src/settings.rs2
-rw-r--r--src/shell/atuin.zsh1
32 files changed, 1503 insertions, 1307 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 5518d905..1a8ac289 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -16,10 +16,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Install latest nightly
+ - name: Install rust
uses: actions-rs/toolchain@v1
with:
- toolchain: nightly
+ toolchain: stable
override: true
- name: Run cargo build
@@ -31,10 +31,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Install latest nightly
+ - name: Install rust
uses: actions-rs/toolchain@v1
with:
- toolchain: nightly
+ toolchain: stable
override: true
- name: Run cargo test
@@ -46,10 +46,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Install latest nightly
+ - name: Install latest rust
uses: actions-rs/toolchain@v1
with:
- toolchain: nightly
+ toolchain: stable
override: true
components: clippy
@@ -62,10 +62,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Install latest nightly
+ - name: Install latest rust
uses: actions-rs/toolchain@v1
with:
- toolchain: nightly
+ toolchain: stable
override: true
components: rustfmt
diff --git a/Cargo.lock b/Cargo.lock
index 24df36e8..2f7d6d73 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,67 +18,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
-name = "aead"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cf01b9b56e767bb57b94ebf91a58b338002963785cdd7013e21c0d4679471e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "aes"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9"
-dependencies = [
- "aes-soft",
- "aesni",
- "block-cipher-trait",
-]
-
-[[package]]
-name = "aes-gcm"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "834a6bda386024dbb7c8fc51322856c10ffe69559f972261c868485f5759c638"
-dependencies = [
- "aead",
- "aes",
- "block-cipher-trait",
- "ghash",
- "subtle 2.4.0",
- "zeroize",
-]
-
-[[package]]
-name = "aes-soft"
-version = "0.3.3"
+name = "ahash"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d"
-dependencies = [
- "block-cipher-trait",
- "byteorder",
- "opaque-debug",
-]
+checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]]
-name = "aesni"
-version = "0.6.0"
+name = "ahash"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
+checksum = "7f200cbb1e856866d9eade941cf3aa0c5d7dd36f74311c4273b494f4ef036957"
dependencies = [
- "block-cipher-trait",
- "opaque-debug",
+ "getrandom 0.2.2",
+ "once_cell",
+ "version_check",
]
[[package]]
-name = "ahash"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
-
-[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -93,7 +49,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -109,6 +65,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
+name = "async-trait"
+version = "0.1.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589652ce7ccb335d1e7ecb3be145425702b290dbcb7029bbeaae263fc1d87b48"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "atoi"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5"
+dependencies = [
+ "num-traits 0.2.14",
+]
+
+[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -116,35 +92,33 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
name = "atuin"
version = "0.5.0"
dependencies = [
- "base64 0.13.0",
+ "async-trait",
+ "base64",
"chrono",
"chrono-english",
"cli-table",
"config",
- "diesel",
- "diesel_migrations",
"directories",
"dotenv",
"eyre",
"fern",
"fork",
"human-panic",
+ "humantime",
"indicatif",
"itertools",
- "log 0.4.14",
+ "log",
"parse_duration",
"rand 0.8.3",
"reqwest",
"rmp-serde",
- "rocket",
- "rocket_contrib",
"rusqlite",
"rust-crypto",
"serde 1.0.125",
@@ -152,11 +126,15 @@ dependencies = [
"serde_json",
"shellexpand",
"sodiumoxide",
+ "sqlx",
"structopt",
"termion",
+ "tokio",
"tui",
"unicode-width",
+ "urlencoding",
"uuid",
+ "warp",
"whoami",
]
@@ -173,7 +151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc"
dependencies = [
"addr2line",
- "cfg-if 1.0.0",
+ "cfg-if",
"libc",
"miniz_oxide",
"object",
@@ -182,22 +160,6 @@ dependencies = [
[[package]]
name = "base64"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
-dependencies = [
- "byteorder",
- "safemem",
-]
-
-[[package]]
-name = "base64"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
-
-[[package]]
-name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
@@ -209,6 +171,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
+name = "bitvec"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -221,45 +195,40 @@ dependencies = [
[[package]]
name = "block-buffer"
-version = "0.7.3"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
- "block-padding",
- "byte-tools",
- "byteorder",
"generic-array",
]
[[package]]
-name = "block-cipher-trait"
-version = "0.6.2"
+name = "bstr"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
+checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
dependencies = [
- "generic-array",
+ "lazy_static",
+ "memchr",
+ "regex-automata",
+ "serde 1.0.125",
]
[[package]]
-name = "block-padding"
-version = "0.1.5"
+name = "buf_redux"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
+checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
dependencies = [
- "byte-tools",
+ "memchr",
+ "safemem",
]
[[package]]
-name = "bstr"
-version = "0.2.15"
+name = "build_const"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
-dependencies = [
- "lazy_static",
- "memchr",
- "regex-automata",
- "serde 1.0.125",
-]
+checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
[[package]]
name = "bumpalo"
@@ -268,12 +237,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
-name = "byte-tools"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
-
-[[package]]
name = "byteorder"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -299,12 +262,6 @@ checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
@@ -320,7 +277,7 @@ dependencies = [
"num-traits 0.2.14",
"serde 1.0.125",
"time",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -367,9 +324,20 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efe942512e068e15991cbcef4e8182884555febbb21b5b4faf5dd5561850141a"
dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "colored"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
]
[[package]]
@@ -379,12 +347,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369"
dependencies = [
"lazy_static",
- "nom",
+ "nom 5.1.2",
"rust-ini",
"serde 1.0.125",
"serde-hjson",
"serde_json",
- "toml 0.5.8",
+ "toml",
"yaml-rust",
]
@@ -400,7 +368,7 @@ dependencies = [
"regex",
"terminal_size",
"unicode-width",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -410,22 +378,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
-name = "cookie"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5795cda0897252e34380a27baf884c53aa7ad9990329cdad96d4c5d027015d44"
-dependencies = [
- "aes-gcm",
- "base64 0.12.3",
- "hkdf",
- "hmac",
- "percent-encoding 2.1.0",
- "rand 0.7.3",
- "sha2",
- "time",
-]
-
-[[package]]
name = "core-foundation"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -442,24 +394,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]]
+name = "cpuid-bool"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
+
+[[package]]
+name = "crc"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
+dependencies = [
+ "build_const",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
name = "crossbeam-utils"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [
"autocfg",
- "cfg-if 1.0.0",
+ "cfg-if",
"lazy_static",
]
[[package]]
name = "crypto-mac"
-version = "0.7.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
+checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6"
dependencies = [
"generic-array",
- "subtle 1.0.0",
+ "subtle",
]
[[package]]
@@ -485,86 +472,28 @@ dependencies = [
]
[[package]]
-name = "devise"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3"
-dependencies = [
- "devise_codegen",
- "devise_core",
-]
-
-[[package]]
-name = "devise_codegen"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7"
-dependencies = [
- "devise_core",
- "quote 0.6.13",
-]
-
-[[package]]
-name = "devise_core"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487"
-dependencies = [
- "bitflags",
- "proc-macro2 0.4.30",
- "quote 0.6.13",
- "syn 0.15.44",
-]
-
-[[package]]
-name = "diesel"
-version = "1.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542"
-dependencies = [
- "bitflags",
- "byteorder",
- "chrono",
- "diesel_derives",
- "pq-sys",
- "r2d2",
-]
-
-[[package]]
-name = "diesel_derives"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
-dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
-]
-
-[[package]]
-name = "diesel_migrations"
-version = "1.4.0"
+name = "digest"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
- "migrations_internals",
- "migrations_macros",
+ "generic-array",
]
[[package]]
-name = "digest"
-version = "0.8.1"
+name = "directories"
+version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
dependencies = [
- "generic-array",
+ "dirs-sys",
]
[[package]]
-name = "directories"
+name = "dirs"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
+checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
dependencies = [
"dirs-sys",
]
@@ -575,7 +504,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"dirs-sys-next",
]
@@ -587,7 +516,7 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [
"libc",
"redox_users 0.3.5",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -598,7 +527,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users 0.4.0",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -625,7 +554,7 @@ version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
]
[[package]]
@@ -639,12 +568,6 @@ dependencies = [
]
[[package]]
-name = "fake-simd"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
-
-[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -662,19 +585,8 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
dependencies = [
- "log 0.4.14",
-]
-
-[[package]]
-name = "filetime"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
-dependencies = [
- "cfg-if 1.0.0",
- "libc",
- "redox_syscall 0.2.4",
- "winapi 0.3.9",
+ "colored",
+ "log",
]
[[package]]
@@ -714,95 +626,110 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
- "percent-encoding 2.1.0",
+ "percent-encoding",
]
[[package]]
-name = "fsevent"
-version = "0.4.0"
+name = "fuchsia-cprng"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
-dependencies = [
- "bitflags",
- "fsevent-sys",
-]
+checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
-name = "fsevent-sys"
-version = "2.0.1"
+name = "funty"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
-dependencies = [
- "libc",
-]
+checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
+name = "futures"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
[[package]]
-name = "fuchsia-zircon"
-version = "0.3.3"
+name = "futures-channel"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
dependencies = [
- "bitflags",
- "fuchsia-zircon-sys",
+ "futures-core",
+ "futures-sink",
]
[[package]]
-name = "fuchsia-zircon-sys"
-version = "0.3.3"
+name = "futures-core"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
[[package]]
-name = "futures-channel"
-version = "0.3.13"
+name = "futures-executor"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
+checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d"
dependencies = [
"futures-core",
+ "futures-task",
+ "futures-util",
]
[[package]]
-name = "futures-core"
-version = "0.3.13"
+name = "futures-io"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
+checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
[[package]]
-name = "futures-io"
-version = "0.3.13"
+name = "futures-macro"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
+checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "futures-sink"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
+checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
[[package]]
name = "futures-task"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
+checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc"
[[package]]
name = "futures-util"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
+checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
dependencies = [
+ "futures-channel",
"futures-core",
"futures-io",
+ "futures-macro",
+ "futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
+ "proc-macro-hack",
+ "proc-macro-nested",
"slab",
]
@@ -814,11 +741,12 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
[[package]]
name = "generic-array"
-version = "0.12.3"
+version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
+ "version_check",
]
[[package]]
@@ -827,7 +755,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
@@ -838,33 +766,18 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
-name = "ghash"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f0930ed19a7184089ea46d2fedead2f6dc2b674c5db4276b7da336c7cd83252"
-dependencies = [
- "polyval",
-]
-
-[[package]]
name = "gimli"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
[[package]]
-name = "glob"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
-
-[[package]]
name = "h2"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -889,7 +802,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
- "ahash",
+ "ahash 0.4.7",
]
[[package]]
@@ -902,6 +815,31 @@ dependencies = [
]
[[package]]
+name = "headers"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855"
+dependencies = [
+ "base64",
+ "bitflags",
+ "bytes",
+ "headers-core",
+ "http",
+ "mime",
+ "sha-1",
+ "time",
+]
+
+[[package]]
+name = "headers-core"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
+dependencies = [
+ "http",
+]
+
+[[package]]
name = "heck"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -920,20 +858,16 @@ dependencies = [
]
[[package]]
-name = "hkdf"
-version = "0.8.0"
+name = "hex"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3"
-dependencies = [
- "digest",
- "hmac",
-]
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
-version = "0.7.1"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
+checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
dependencies = [
"crypto-mac",
"digest",
@@ -984,28 +918,15 @@ dependencies = [
"serde 1.0.125",
"serde_derive",
"termcolor",
- "toml 0.5.8",
+ "toml",
"uuid",
]
[[package]]
-name = "hyper"
-version = "0.10.16"
+name = "humantime"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273"
-dependencies = [
- "base64 0.9.3",
- "httparse",
- "language-tags",
- "log 0.3.9",
- "mime 0.2.6",
- "num_cpus",
- "time",
- "traitobject",
- "typeable",
- "unicase",
- "url 1.7.2",
-]
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
@@ -1038,7 +959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
- "hyper 0.14.5",
+ "hyper",
"native-tls",
"tokio",
"tokio-native-tls",
@@ -1046,17 +967,6 @@ dependencies = [
[[package]]
name = "idna"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
-dependencies = [
- "matches",
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "idna"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21"
@@ -1095,23 +1005,12 @@ dependencies = [
]
[[package]]
-name = "inotify"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
-dependencies = [
- "bitflags",
- "inotify-sys",
- "libc",
-]
-
-[[package]]
-name = "inotify-sys"
-version = "0.1.5"
+name = "input_buffer"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413"
dependencies = [
- "libc",
+ "bytes",
]
[[package]]
@@ -1120,16 +1019,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
- "cfg-if 1.0.0",
-]
-
-[[package]]
-name = "iovec"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
-dependencies = [
- "libc",
+ "cfg-if",
]
[[package]]
@@ -1163,34 +1053,12 @@ dependencies = [
]
[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
-
-[[package]]
-name = "language-tags"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
-
-[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
-[[package]]
name = "lexical-core"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1198,7 +1066,7 @@ checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374"
dependencies = [
"arrayvec",
"bitflags",
- "cfg-if 1.0.0",
+ "cfg-if",
"ryu",
"static_assertions",
]
@@ -1248,21 +1116,18 @@ dependencies = [
[[package]]
name = "log"
-version = "0.3.9"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
- "log 0.4.14",
+ "cfg-if",
]
[[package]]
-name = "log"
-version = "0.4.14"
+name = "maplit"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
-dependencies = [
- "cfg-if 1.0.0",
-]
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
@@ -1271,46 +1136,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
-name = "memchr"
-version = "2.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
-
-[[package]]
-name = "migrations_internals"
-version = "1.4.1"
+name = "md-5"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b4fc84e4af020b837029e017966f86a1c2d5e83e64b589963d5047525995860"
+checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
dependencies = [
- "diesel",
+ "block-buffer",
+ "digest",
+ "opaque-debug",
]
[[package]]
-name = "migrations_macros"
-version = "1.4.2"
+name = "memchr"
+version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
-dependencies = [
- "migrations_internals",
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
-]
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "mime"
-version = "0.2.6"
+version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
-dependencies = [
- "log 0.3.9",
-]
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
-name = "mime"
-version = "0.3.16"
+name = "mime_guess"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
[[package]]
name = "miniz_oxide"
@@ -1324,67 +1180,42 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.6.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
-dependencies = [
- "cfg-if 0.1.10",
- "fuchsia-zircon",
- "fuchsia-zircon-sys",
- "iovec",
- "kernel32-sys",
- "libc",
- "log 0.4.14",
- "miow 0.2.2",
- "net2",
- "slab",
- "winapi 0.2.8",
-]
-
-[[package]]
-name = "mio"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
dependencies = [
"libc",
- "log 0.4.14",
- "miow 0.3.7",
+ "log",
+ "miow",
"ntapi",
- "winapi 0.3.9",
-]
-
-[[package]]
-name = "mio-extras"
-version = "2.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
-dependencies = [
- "lazycell",
- "log 0.4.14",
- "mio 0.6.23",
- "slab",
+ "winapi",
]
[[package]]
name = "miow"
-version = "0.2.2"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
- "kernel32-sys",
- "net2",
- "winapi 0.2.8",
- "ws2_32-sys",
+ "winapi",
]
[[package]]
-name = "miow"
-version = "0.3.7"
+name = "multipart"
+version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4"
dependencies = [
- "winapi 0.3.9",
+ "buf_redux",
+ "httparse",
+ "log",
+ "mime",
+ "mime_guess",
+ "quick-error",
+ "rand 0.7.3",
+ "safemem",
+ "tempfile",
+ "twoway",
]
[[package]]
@@ -1395,7 +1226,7 @@ checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
dependencies = [
"lazy_static",
"libc",
- "log 0.4.14",
+ "log",
"openssl",
"openssl-probe",
"openssl-sys",
@@ -1406,17 +1237,6 @@ dependencies = [
]
[[package]]
-name = "net2"
-version = "0.2.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
-dependencies = [
- "cfg-if 0.1.10",
- "libc",
- "winapi 0.3.9",
-]
-
-[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1424,25 +1244,20 @@ checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"lexical-core",
"memchr",
- "version_check 0.9.2",
+ "version_check",
]
[[package]]
-name = "notify"
-version = "4.0.15"
+name = "nom"
+version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
+checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
- "bitflags",
- "filetime",
- "fsevent",
- "fsevent-sys",
- "inotify",
- "libc",
- "mio 0.6.23",
- "mio-extras",
- "walkdir",
- "winapi 0.3.9",
+ "bitvec",
+ "funty",
+ "lexical-core",
+ "memchr",
+ "version_check",
]
[[package]]
@@ -1451,7 +1266,7 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -1576,9 +1391,9 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "opaque-debug"
-version = "0.2.3"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
@@ -1587,7 +1402,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
dependencies = [
"bitflags",
- "cfg-if 1.0.0",
+ "cfg-if",
"foreign-types",
"libc",
"once_cell",
@@ -1639,12 +1454,12 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"instant",
"libc",
"redox_syscall 0.2.4",
"smallvec",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -1659,34 +1474,6 @@ dependencies = [
]
[[package]]
-name = "pear"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5320f212db967792b67cfe12bd469d08afd6318a249bd917d5c19bc92200ab8a"
-dependencies = [
- "pear_codegen",
-]
-
-[[package]]
-name = "pear_codegen"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfc1c836fdc3d1ef87c348b237b5b5c4dff922156fb2d968f57734f9669768ca"
-dependencies = [
- "proc-macro2 0.4.30",
- "quote 0.6.13",
- "syn 0.15.44",
- "version_check 0.9.2",
- "yansi",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
-
-[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1707,9 +1494,9 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5"
dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
@@ -1731,41 +1518,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
-name = "polyval"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ec3341498978de3bfd12d1b22f1af1de22818f5473a11e8a6ef997989e3a212"
-dependencies = [
- "cfg-if 0.1.10",
- "universal-hash",
-]
-
-[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
-name = "pq-sys"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
-dependencies = [
- "vcpkg",
-]
-
-[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
- "version_check 0.9.2",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
]
[[package]]
@@ -1774,19 +1542,22 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "version_check 0.9.2",
+ "proc-macro2",
+ "quote",
+ "version_check",
]
[[package]]
-name = "proc-macro2"
-version = "0.4.30"
+name = "proc-macro-hack"
+version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-dependencies = [
- "unicode-xid 0.1.0",
-]
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro-nested"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
@@ -1794,17 +1565,14 @@ version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
- "unicode-xid 0.2.1",
+ "unicode-xid",
]
[[package]]
-name = "quote"
-version = "0.6.13"
+name = "quick-error"
+version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
-dependencies = [
- "proc-macro2 0.4.30",
-]
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
@@ -1812,19 +1580,14 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
- "proc-macro2 1.0.26",
+ "proc-macro2",
]
[[package]]
-name = "r2d2"
-version = "0.8.9"
+name = "radium"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f"
-dependencies = [
- "log 0.4.14",
- "parking_lot",
- "scheduled-thread-pool",
-]
+checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
@@ -1846,7 +1609,7 @@ dependencies = [
"libc",
"rand_core 0.3.1",
"rdrand",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2032,7 +1795,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2041,29 +1804,29 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
dependencies = [
- "base64 0.13.0",
+ "base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"http",
"http-body",
- "hyper 0.14.5",
+ "hyper",
"hyper-tls",
"ipnet",
"js-sys",
"lazy_static",
- "log 0.4.14",
- "mime 0.3.16",
+ "log",
+ "mime",
"native-tls",
- "percent-encoding 2.1.0",
+ "percent-encoding",
"pin-project-lite",
"serde 1.0.125",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
- "url 2.2.1",
+ "url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -2092,87 +1855,6 @@ dependencies = [
]
[[package]]
-name = "rocket"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7febfdfd4d43facfc7daba20349ebe2c310c6735bd6a2a9255ea8bc425b4cb13"
-dependencies = [
- "atty",
- "base64 0.12.3",
- "log 0.4.14",
- "memchr",
- "num_cpus",
- "pear",
- "rocket_codegen",
- "rocket_http",
- "state",
- "time",
- "toml 0.4.10",
- "version_check 0.9.2",
- "yansi",
-]
-
-[[package]]
-name = "rocket_codegen"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceac2c55b2c8b1cdc53add64332defa5fc227f64263b86b4114d1386286d42a3"
-dependencies = [
- "devise",
- "glob",
- "indexmap",
- "quote 0.6.13",
- "rocket_http",
- "version_check 0.9.2",
- "yansi",
-]
-
-[[package]]
-name = "rocket_contrib"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7954a707f9ca18aa74ca8c1f5d1f900f52a4dceb68e96e3112143f759cfd20e"
-dependencies = [
- "diesel",
- "log 0.4.14",
- "notify",
- "r2d2",
- "rocket",
- "rocket_contrib_codegen",
- "serde 1.0.125",
- "serde_json",
-]
-
-[[package]]
-name = "rocket_contrib_codegen"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30deb6dec53b91fac3538a2a3935cf13e0f462745f9f33bf27bedffbe7265b5d"
-dependencies = [
- "devise",
- "quote 0.6.13",
- "version_check 0.9.2",
- "yansi",
-]
-
-[[package]]
-name = "rocket_http"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce364100ed7a1bf39257b69ebd014c1d5b4979b0d365d8c9ab0aa9c79645493d"
-dependencies = [
- "cookie",
- "hyper 0.10.16",
- "indexmap",
- "pear",
- "percent-encoding 1.0.1",
- "smallvec",
- "state",
- "time",
- "unicode-xid 0.1.0",
-]
-
-[[package]]
name = "rusqlite"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2193,7 +1875,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
- "base64 0.13.0",
+ "base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
@@ -2243,15 +1925,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
name = "scanlex"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2264,17 +1937,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
-name = "scheduled-thread-pool"
-version = "0.2.5"
+name = "scoped-tls"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7"
-dependencies = [
- "parking_lot",
-]
+checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scopeguard"
@@ -2316,6 +1986,9 @@ name = "serde"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
+dependencies = [
+ "serde_derive",
+]
[[package]]
name = "serde-hjson"
@@ -2335,9 +2008,9 @@ version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
@@ -2364,14 +2037,28 @@ dependencies = [
]
[[package]]
+name = "sha-1"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f"
+dependencies = [
+ "block-buffer",
+ "cfg-if",
+ "cpuid-bool",
+ "digest",
+ "opaque-debug",
+]
+
+[[package]]
name = "sha2"
-version = "0.8.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
+checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de"
dependencies = [
"block-buffer",
+ "cfg-if",
+ "cpuid-bool",
"digest",
- "fake-simd",
"opaque-debug",
]
@@ -2385,6 +2072,15 @@ dependencies = [
]
[[package]]
+name = "signal-hook-registry"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2403,7 +2099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2418,10 +2114,107 @@ dependencies = [
]
[[package]]
-name = "state"
-version = "0.4.2"
+name = "sqlformat"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d86e3c77ff882a828346ba401a7ef4b8e440df804491c6064fe8295765de71c"
+dependencies = [
+ "lazy_static",
+ "maplit",
+ "nom 6.1.2",
+ "regex",
+ "unicode_categories",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d582b9bc04ec6c03084196efc42c2226b018e9941f03ee62bd88921d500917c0"
+dependencies = [
+ "sqlx-core",
+ "sqlx-macros",
+]
+
+[[package]]
+name = "sqlx-core"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de52d1d473cebb2abb79c886ef6a8023e965e34c0676a99cfeac2cc7f0fde4c1"
+dependencies = [
+ "ahash 0.7.2",
+ "atoi",
+ "base64",
+ "bitflags",
+ "byteorder",
+ "bytes",
+ "chrono",
+ "crc",
+ "crossbeam-channel",
+ "crossbeam-queue",
+ "crossbeam-utils",
+ "dirs",
+ "either",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "hashlink",
+ "hex",
+ "hmac",
+ "itoa",
+ "libc",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "parking_lot",
+ "percent-encoding",
+ "rand 0.8.3",
+ "serde 1.0.125",
+ "serde_json",
+ "sha-1",
+ "sha2",
+ "smallvec",
+ "sqlformat",
+ "sqlx-rt",
+ "stringprep",
+ "thiserror",
+ "tokio-stream",
+ "url",
+ "uuid",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-macros"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
+checksum = "1a40f0be97e704d3fbf059e7e3333c3735639146a72d586c5534c70e79da88a4"
+dependencies = [
+ "dotenv",
+ "either",
+ "futures",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "sha2",
+ "sqlx-core",
+ "sqlx-rt",
+ "syn",
+ "url",
+]
+
+[[package]]
+name = "sqlx-rt"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6ae97ab05063ed515cdc23d90253213aa24dda0a288c5ec079af3d10f9771bc"
+dependencies = [
+ "native-tls",
+ "once_cell",
+ "tokio",
+ "tokio-native-tls",
+]
[[package]]
name = "static_assertions"
@@ -2430,6 +2223,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
+name = "stringprep"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2454,44 +2257,33 @@ checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
dependencies = [
"heck",
"proc-macro-error",
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
name = "subtle"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
-
-[[package]]
-name = "subtle"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
-version = "0.15.44"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
+checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
- "proc-macro2 0.4.30",
- "quote 0.6.13",
- "unicode-xid 0.1.0",
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
]
[[package]]
-name = "syn"
-version = "1.0.69"
+name = "tap"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
-dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "unicode-xid 0.2.1",
-]
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
@@ -2499,12 +2291,12 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"libc",
"rand 0.8.3",
"redox_syscall 0.2.4",
"remove_dir_all",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2523,7 +2315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2548,6 +2340,26 @@ dependencies = [
]
[[package]]
+name = "thiserror"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2563,7 +2375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2591,9 +2403,25 @@ dependencies = [
"bytes",
"libc",
"memchr",
- "mio 0.7.11",
+ "mio",
"num_cpus",
+ "once_cell",
+ "parking_lot",
"pin-project-lite",
+ "signal-hook-registry",
+ "tokio-macros",
+ "winapi",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
@@ -2607,26 +2435,41 @@ dependencies = [
]
[[package]]
-name = "tokio-util"
-version = "0.6.5"
+name = "tokio-stream"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5143d049e85af7fbc36f5454d990e62c2df705b3589f123b71f441b6b59f443f"
+checksum = "e177a5d8c3bf36de9ebe6d58537d8879e964332f93fb3339e43f618c81361af0"
dependencies = [
- "bytes",
"futures-core",
- "futures-sink",
- "log 0.4.14",
"pin-project-lite",
"tokio",
]
[[package]]
-name = "toml"
-version = "0.4.10"
+name = "tokio-tungstenite"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
+checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b"
dependencies = [
- "serde 1.0.125",
+ "futures-util",
+ "log",
+ "pin-project",
+ "tokio",
+ "tungstenite",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5143d049e85af7fbc36f5454d990e62c2df705b3589f123b71f441b6b59f443f"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
]
[[package]]
@@ -2650,7 +2493,8 @@ version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
+ "log",
"pin-project-lite",
"tracing-core",
]
@@ -2665,12 +2509,6 @@ dependencies = [
]
[[package]]
-name = "traitobject"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
-
-[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2690,10 +2528,32 @@ dependencies = [
]
[[package]]
-name = "typeable"
-version = "0.1.2"
+name = "tungstenite"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
+checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24"
+dependencies = [
+ "base64",
+ "byteorder",
+ "bytes",
+ "http",
+ "httparse",
+ "input_buffer",
+ "log",
+ "rand 0.8.3",
+ "sha-1",
+ "url",
+ "utf-8",
+]
+
+[[package]]
+name = "twoway"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
+dependencies = [
+ "memchr",
+]
[[package]]
name = "typenum"
@@ -2703,11 +2563,11 @@ checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
[[package]]
name = "unicase"
-version = "1.4.2"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
- "version_check 0.1.5",
+ "version_check",
]
[[package]]
@@ -2742,36 +2602,15 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-
-[[package]]
-name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
-name = "universal-hash"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df0c900f2f9b4116803415878ff48b63da9edb268668e08cf9292d7503114a01"
-dependencies = [
- "generic-array",
- "subtle 2.4.0",
-]
-
-[[package]]
-name = "url"
-version = "1.7.2"
+name = "unicode_categories"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
-dependencies = [
- "idna 0.1.5",
- "matches",
- "percent-encoding 1.0.1",
-]
+checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "url"
@@ -2780,12 +2619,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b"
dependencies = [
"form_urlencoded",
- "idna 0.2.2",
+ "idna",
"matches",
- "percent-encoding 2.1.0",
+ "percent-encoding",
]
[[package]]
+name = "urlencoding"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593"
+
+[[package]]
+name = "utf-8"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
+
+[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2808,35 +2659,47 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
-
-[[package]]
-name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
-name = "walkdir"
-version = "2.3.1"
+name = "want"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
dependencies = [
- "same-file",
- "winapi 0.3.9",
- "winapi-util",
+ "log",
+ "try-lock",
]
[[package]]
-name = "want"
-version = "0.3.0"
+name = "warp"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054"
dependencies = [
- "log 0.4.14",
- "try-lock",
+ "bytes",
+ "futures",
+ "headers",
+ "http",
+ "hyper",
+ "log",
+ "mime",
+ "mime_guess",
+ "multipart",
+ "percent-encoding",
+ "pin-project",
+ "scoped-tls",
+ "serde 1.0.125",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-stream",
+ "tokio-tungstenite",
+ "tokio-util",
+ "tower-service",
+ "tracing",
]
[[package]]
@@ -2857,7 +2720,7 @@ version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"serde 1.0.125",
"serde_json",
"wasm-bindgen-macro",
@@ -2871,10 +2734,10 @@ checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
dependencies = [
"bumpalo",
"lazy_static",
- "log 0.4.14",
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
"wasm-bindgen-shared",
]
@@ -2884,7 +2747,7 @@ version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
@@ -2896,7 +2759,7 @@ version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
dependencies = [
- "quote 1.0.9",
+ "quote",
"wasm-bindgen-macro-support",
]
@@ -2906,9 +2769,9 @@ version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
dependencies = [
- "proc-macro2 1.0.26",
- "quote 1.0.9",
- "syn 1.0.69",
+ "proc-macro2",
+ "quote",
+ "syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2941,12 +2804,6 @@ dependencies = [
[[package]]
name = "winapi"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-
-[[package]]
-name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
@@ -2956,12 +2813,6 @@ dependencies = [
]
[[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
-
-[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2973,7 +2824,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
@@ -2988,18 +2839,14 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
-name = "ws2_32-sys"
-version = "0.2.1"
+name = "wyz"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
+checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "yaml-rust"
@@ -3009,15 +2856,3 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
-
-[[package]]
-name = "yansi"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
-
-[[package]]
-name = "zeroize"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36"
diff --git a/Cargo.toml b/Cargo.toml
index 66955c75..9a57f947 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,7 +8,7 @@ description = "atuin - magical shell history"
[dependencies]
log = "0.4"
-fern = "0.6.0"
+fern = {version = "0.6.0", features = ["colored"] }
chrono = { version = "0.4", features = ["serde"] }
eyre = "0.6"
shellexpand = "2"
@@ -17,7 +17,6 @@ directories = "3"
uuid = { version = "0.8", features = ["v4"] }
indicatif = "0.15.0"
whoami = "1.1.2"
-rocket = "0.4.7"
chrono-english = "0.1.4"
cli-table = "0.4"
config = "0.11"
@@ -29,8 +28,6 @@ tui = "0.14"
termion = "1.5"
unicode-width = "0.1"
itertools = "0.10.0"
-diesel = { version = "1.4.4", features = ["postgres", "chrono"] }
-diesel_migrations = "1.4.0"
dotenv = "0.15.0"
sodiumoxide = "0.2.6"
reqwest = { version = "0.11", features = ["blocking", "json"] }
@@ -40,12 +37,13 @@ parse_duration = "2.1.1"
rand = "0.8.3"
rust-crypto = "^0.2"
human-panic = "1.0.3"
+tokio = { version = "1", features = ["full"] }
+warp = "0.3"
+sqlx = { version = "0.5", features = [ "runtime-tokio-native-tls", "uuid", "chrono", "postgres" ] }
+async-trait = "0.1.49"
+urlencoding = "1.1.1"
+humantime = "2.1.0"
[dependencies.rusqlite]
version = "0.25"
features = ["bundled"]
-
-[dependencies.rocket_contrib]
-version = "0.4.7"
-default-features = false
-features = ["diesel_postgres_pool", "json"]
diff --git a/Dockerfile b/Dockerfile
index 774468ed..0c19ef6d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,4 @@
-FROM rust as builder
-
-RUN rustup default nightly
-
+FROM rust:1.51-buster as builder
RUN cargo new --bin atuin
WORKDIR /atuin
diff --git a/config.toml b/config.toml
index 9d5452cb..fe776d6e 100644
--- a/config.toml
+++ b/config.toml
@@ -29,7 +29,7 @@
# sync_address = "https://api.atuin.sh"
# This section configures the sync server, if you decide to host your own
-[remote]
+[server]
## host to bind, can also be passed via CLI args
# host = "127.0.0.1"
diff --git a/src/api.rs b/src/api.rs
index 90977404..82ee6604 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -1,8 +1,9 @@
use chrono::Utc;
-// This is shared between the client and the server, and has the data structures
-// representing the requests/responses for each method.
-// TODO: Properly define responses rather than using json!
+#[derive(Debug, Serialize, Deserialize)]
+pub struct UserResponse {
+ pub username: String,
+}
#[derive(Debug, Serialize, Deserialize)]
pub struct RegisterRequest {
@@ -12,12 +13,22 @@ pub struct RegisterRequest {
}
#[derive(Debug, Serialize, Deserialize)]
+pub struct RegisterResponse {
+ pub session: String,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct LoginRequest {
pub username: String,
pub password: String,
}
#[derive(Debug, Serialize, Deserialize)]
+pub struct LoginResponse {
+ pub session: String,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct AddHistoryRequest {
pub id: String,
pub timestamp: chrono::DateTime<Utc>,
@@ -31,6 +42,29 @@ pub struct CountResponse {
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct ListHistoryResponse {
+pub struct SyncHistoryRequest {
+ pub sync_ts: chrono::DateTime<chrono::FixedOffset>,
+ pub history_ts: chrono::DateTime<chrono::FixedOffset>,
+ pub host: String,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct SyncHistoryResponse {
pub history: Vec<String>,
}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct ErrorResponse {
+ pub reason: String,
+}
+
+impl ErrorResponse {
+ pub fn reply(reason: &str, status: warp::http::StatusCode) -> impl warp::Reply {
+ warp::reply::with_status(
+ warp::reply::json(&ErrorResponse {
+ reason: String::from(reason),
+ }),
+ status,
+ )
+ }
+}
diff --git a/src/command/history.rs b/src/command/history.rs
index 3b4a717c..627efae4 100644
--- a/src/command/history.rs
+++ b/src/command/history.rs
@@ -53,7 +53,7 @@ fn print_list(h: &[History]) {
}
impl Cmd {
- pub fn run(&self, settings: &Settings, db: &mut impl Database) -> Result<()> {
+ pub async fn run(&self, settings: &Settings, db: &mut (impl Database + Send)) -> Result<()> {
match self {
Self::Start { command: words } => {
let command = words.join(" ");
@@ -69,6 +69,10 @@ impl Cmd {
}
Self::End { id, exit } => {
+ if id.trim() == "" {
+ return Ok(());
+ }
+
let mut h = db.load(id)?;
h.exit = *exit;
h.duration = chrono::Utc::now().timestamp_nanos() - h.timestamp.timestamp_nanos();
@@ -82,7 +86,7 @@ impl Cmd {
}
Ok(Fork::Child) => {
debug!("running periodic background sync");
- sync::sync(settings, false, db)?;
+ sync::sync(settings, false, db).await?;
}
Err(_) => println!("Fork failed"),
}
diff --git a/src/command/login.rs b/src/command/login.rs
index 4f58b77f..636ac0d3 100644
--- a/src/command/login.rs
+++ b/src/command/login.rs
@@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
-use eyre::Result;
+use eyre::{eyre, Result};
use structopt::StructOpt;
use crate::settings::Settings;
@@ -28,8 +28,13 @@ impl Cmd {
let url = format!("{}/login", settings.local.sync_address);
let client = reqwest::blocking::Client::new();
+
let resp = client.post(url).json(&map).send()?;
+ if resp.status() != reqwest::StatusCode::OK {
+ return Err(eyre!("invalid login details"));
+ }
+
let session = resp.json::<HashMap<String, String>>()?;
let session = session["session"].clone();
diff --git a/src/command/mod.rs b/src/command/mod.rs
index eeb11a87..cd857e9f 100644
--- a/src/command/mod.rs
+++ b/src/command/mod.rs
@@ -63,16 +63,16 @@ pub fn uuid_v4() -> String {
}
impl AtuinCmd {
- pub fn run(self, db: &mut impl Database, settings: &Settings) -> Result<()> {
+ pub async fn run<T: Database + Send>(self, db: &mut T, settings: &Settings) -> Result<()> {
match self {
- Self::History(history) => history.run(settings, db),
+ Self::History(history) => history.run(settings, db).await,
Self::Import(import) => import.run(db),
- Self::Server(server) => server.run(settings),
+ Self::Server(server) => server.run(settings).await,
Self::Stats(stats) => stats.run(db, settings),
Self::Init => init::init(),
Self::Search { query } => search::run(&query, db),
- Self::Sync { force } => sync::run(settings, force, db),
+ Self::Sync { force } => sync::run(settings, force, db).await,
Self::Login(l) => l.run(settings),
Self::Register(r) => register::run(
settings,
diff --git a/src/command/search.rs b/src/command/search.rs
index b9f3987c..d7b477da 100644
--- a/src/command/search.rs
+++ b/src/command/search.rs
@@ -1,6 +1,8 @@
use eyre::Result;
use itertools::Itertools;
use std::io::stdout;
+use std::time::Duration;
+
use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen};
use tui::{
backend::TermionBackend,
@@ -26,6 +28,78 @@ struct State {
results_state: ListState,
}
+#[allow(clippy::clippy::cast_sign_loss)]
+impl State {
+ fn durations(&self) -> Vec<String> {
+ self.results
+ .iter()
+ .map(|h| {
+ let duration =
+ Duration::from_millis(std::cmp::max(h.duration, 0) as u64 / 1_000_000);
+ let duration = humantime::format_duration(duration).to_string();
+ let duration: Vec<&str> = duration.split(' ').collect();
+
+ duration[0].to_string()
+ })
+ .collect()
+ }
+
+ fn render_results<T: tui::backend::Backend>(
+ &mut self,
+ f: &mut tui::Frame<T>,
+ r: tui::layout::Rect,
+ ) {
+ let durations = self.durations();
+ let max_length = durations
+ .iter()
+ .fold(0, |largest, i| std::cmp::max(largest, i.len()));
+
+ let results: Vec<ListItem> = self
+ .results
+ .iter()
+ .enumerate()
+ .map(|(i, m)| {
+ let command = m.command.to_string().replace("\n", " ").replace("\t", " ");
+
+ let mut command = Span::raw(command);
+
+ let mut duration = durations[i].clone();
+
+ while duration.len() < max_length {
+ duration.push(' ');
+ }
+
+ let duration = Span::styled(
+ duration,
+ Style::default().fg(if m.exit == 0 || m.duration == -1 {
+ Color::Green
+ } else {
+ Color::Red
+ }),
+ );
+
+ if let Some(selected) = self.results_state.selected() {
+ if selected == i {
+ command.style =
+ Style::default().fg(Color::Red).add_modifier(Modifier::BOLD);
+ }
+ }
+
+ let spans = Spans::from(vec![duration, Span::raw(" "), command]);
+
+ ListItem::new(spans)
+ })
+ .collect();
+
+ let results = List::new(results)
+ .block(Block::default().borders(Borders::ALL).title("History"))
+ .start_corner(Corner::BottomLeft)
+ .highlight_symbol(">> ");
+
+ f.render_stateful_widget(results, r, &mut self.results_state);
+ }
+}
+
fn query_results(app: &mut State, db: &mut impl Database) {
let results = match app.input.as_str() {
"" => db.list(),
@@ -48,7 +122,11 @@ fn key_handler(input: Key, db: &mut impl Database, app: &mut State) -> Option<St
Key::Esc | Key::Char('\n') => {
let i = app.results_state.selected().unwrap_or(0);
- return Some(app.results.get(i).unwrap().command.clone());
+ return Some(
+ app.results
+ .get(i)
+ .map_or("".to_string(), |h| h.command.clone()),
+ );
}
Key::Char(c) => {
app.input.push(c);
@@ -163,32 +241,8 @@ fn select_history(query: &[String], db: &mut impl Database) -> Result<String> {
let help = Text::from(Spans::from(help));
let help = Paragraph::new(help);
- let input = Paragraph::new(app.input.as_ref())
- .block(Block::default().borders(Borders::ALL).title("Search"));
-
- let results: Vec<ListItem> = app
- .results
- .iter()
- .enumerate()
- .map(|(i, m)| {
- let mut content =
- Span::raw(m.command.to_string().replace("\n", " ").replace("\t", " "));
-
- if let Some(selected) = app.results_state.selected() {
- if selected == i {
- content.style =
- Style::default().fg(Color::Red).add_modifier(Modifier::BOLD);
- }
- }
-
- ListItem::new(content)
- })
- .collect();
-
- let results = List::new(results)
- .block(Block::default().borders(Borders::ALL).title("History"))
- .start_corner(Corner::BottomLeft)
- .highlight_symbol(">> ");
+ let input = Paragraph::new(app.input.clone())
+ .block(Block::default().borders(Borders::ALL).title("Query"));
let stats = Paragraph::new(Text::from(Span::raw(format!(
"history count: {}",
@@ -199,8 +253,8 @@ fn select_history(query: &[String], db: &mut impl Database) -> Result<String> {
f.render_widget(title, top_left_chunks[0]);
f.render_widget(help, top_left_chunks[1]);
+ app.render_results(f, chunks[1]);
f.render_widget(stats, top_right_chunks[0]);
- f.render_stateful_widget(results, chunks[1], &mut app.results_state);
f.render_widget(input, chunks[2]);
f.set_cursor(
diff --git a/src/command/server.rs b/src/command/server.rs
index bf757948..a7835092 100644
--- a/src/command/server.rs
+++ b/src/command/server.rs
@@ -1,7 +1,7 @@
use eyre::Result;
use structopt::StructOpt;
-use crate::remote::server;
+use crate::server;
use crate::settings::Settings;
#[derive(StructOpt)]
@@ -20,7 +20,7 @@ pub enum Cmd {
}
impl Cmd {
- pub fn run(&self, settings: &Settings) -> Result<()> {
+ pub async fn run(&self, settings: &Settings) -> Result<()> {
match self {
Self::Start { host, port } => {
let host = host.as_ref().map_or(
@@ -29,7 +29,7 @@ impl Cmd {
);
let port = port.map_or(settings.server.port, |p| p);
- server::launch(settings, host, port)
+ server::launch(settings, host, port).await
}
}
}
diff --git a/src/command/sync.rs b/src/command/sync.rs
index facbe578..88217b3c 100644
--- a/src/command/sync.rs
+++ b/src/command/sync.rs
@@ -4,8 +4,8 @@ use crate::local::database::Database;
use crate::local::sync;
use crate::settings::Settings;
-pub fn run(settings: &Settings, force: bool, db: &mut impl Database) -> Result<()> {
- sync::sync(settings, force, db)?;
+pub async fn run(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> {
+ sync::sync(settings, force, db).await?;
println!(
"Sync complete! {} items in database, force: {}",
db.history_count()?,
diff --git a/src/local/api_client.rs b/src/local/api_client.rs
index 434c07ba..1b64a295 100644
--- a/src/local/api_client.rs
+++ b/src/local/api_client.rs
@@ -1,93 +1,94 @@
use chrono::Utc;
use eyre::Result;
-use reqwest::header::AUTHORIZATION;
+use reqwest::header::{HeaderMap, AUTHORIZATION};
+use reqwest::Url;
+use sodiumoxide::crypto::secretbox;
-use crate::api::{AddHistoryRequest, CountResponse, ListHistoryResponse};
-use crate::local::encryption::{decrypt, load_key};
+use crate::api::{AddHistoryRequest, CountResponse, SyncHistoryResponse};
+use crate::local::encryption::decrypt;
use crate::local::history::History;
-use crate::settings::Settings;
use crate::utils::hash_str;
pub struct Client<'a> {
- settings: &'a Settings,
+ sync_addr: &'a str,
+ token: &'a str,
+ key: secretbox::Key,
+ client: reqwest::Client,
}
impl<'a> Client<'a> {
- pub const fn new(settings: &'a Settings) -> Self {
- Client { settings }
+ pub fn new(sync_addr: &'a str, token: &'a str, key: secretbox::Key) -> Self {
+ Client {
+ sync_addr,
+ token,
+ key,
+ client: reqwest::Client::new(),
+ }
}
- pub fn count(&self) -> Result<i64> {
- let url = format!("{}/sync/count", self.settings.local.sync_address);
- let client = reqwest::blocking::Client::new();
+ pub async fn count(&self) -> Result<i64> {
+ let url = format!("{}/sync/count", self.sync_addr);
+ let url = Url::parse(url.as_str())?;
+ let token = format!("Token {}", self.token);
+ let token = token.parse()?;
- let resp = client
- .get(url)
- .header(
- AUTHORIZATION,
- format!("Token {}", self.settings.local.session_token),
- )
- .send()?;
+ let mut headers = HeaderMap::new();
+ headers.insert(AUTHORIZATION, token);
+
+ let resp = self.client.get(url).headers(headers).send().await?;
- let count = resp.json::<CountResponse>()?;
+ let count = resp.json::<CountResponse>().await?;
Ok(count.count)
}
- pub fn get_history(
+ pub async fn get_history(
&self,
sync_ts: chrono::DateTime<Utc>,
history_ts: chrono::DateTime<Utc>,
host: Option<String>,
) -> Result<Vec<History>> {
- let key = load_key(self.settings)?;
-
let host = match host {
None => hash_str(&format!("{}:{}", whoami::hostname(), whoami::username())),
Some(h) => h,
};
- // this allows for syncing between users on the same machine
let url = format!(
"{}/sync/history?sync_ts={}&history_ts={}&host={}",
- self.settings.local.sync_address,
- sync_ts.to_rfc3339(),
- history_ts.to_rfc3339(),
+ self.sync_addr,
+ urlencoding::encode(sync_ts.to_rfc3339().as_str()),
+ urlencoding::encode(history_ts.to_rfc3339().as_str()),
host,
);
- let client = reqwest::blocking::Client::new();
- let resp = client
+ let resp = self
+ .client
.get(url)
- .header(
- AUTHORIZATION,
- format!("Token {}", self.settings.local.session_token),
- )
- .send()?;
+ .header(AUTHORIZATION, format!("Token {}", self.token))
+ .send()
+ .await?;
- let history = resp.json::<ListHistoryResponse>()?;
+ let history = resp.json::<SyncHistoryResponse>().await?;
let history = history
.history
.iter()
.map(|h| serde_json::from_str(h).expect("invalid base64"))
- .map(|h| decrypt(&h, &key).expect("failed to decrypt history! check your key"))
+ .map(|h| decrypt(&h, &self.key).expect("failed to decrypt history! check your key"))
.collect();
Ok(history)
}
- pub fn post_history(&self, history: &[AddHistoryRequest]) -> Result<()> {
- let client = reqwest::blocking::Client::new();
+ pub async fn post_history(&self, history: &[AddHistoryRequest]) -> Result<()> {
+ let url = format!("{}/history", self.sync_addr);
+ let url = Url::parse(url.as_str())?;
- let url = format!("{}/history", self.settings.local.sync_address);
- client
+ self.client
.post(url)
.json(history)
- .header(
- AUTHORIZATION,
- format!("Token {}", self.settings.local.session_token),
- )
- .send()?;
+ .header(AUTHORIZATION, format!("Token {}", self.token))
+ .send()
+ .await?;
Ok(())
}
diff --git a/src/local/database.rs b/src/local/database.rs
index 977f11cc..abc22bb8 100644
--- a/src/local/database.rs
+++ b/src/local/database.rs
@@ -215,9 +215,9 @@ impl Database for Sqlite {
}
fn before(&self, timestamp: chrono::DateTime<Utc>, count: i64) -> Result<Vec<History>> {
- let mut stmt = self.conn.prepare(
- "SELECT * FROM history where timestamp <= ? order by timestamp desc limit ?",
- )?;
+ let mut stmt = self
+ .conn
+ .prepare("SELECT * FROM history where timestamp < ? order by timestamp desc limit ?")?;
let history_iter = stmt.query_map(params![timestamp.timestamp_nanos(), count], |row| {
history_from_sqlite_row(None, row)
@@ -236,7 +236,7 @@ impl Database for Sqlite {
fn prefix_search(&self, query: &str) -> Result<Vec<History>> {
self.query(
- "select * from history where command like ?1 || '%' order by timestamp asc",
+ "select * from history where command like ?1 || '%' order by timestamp asc limit 1000",
&[query],
)
}
diff --git a/src/local/import.rs b/src/local/import.rs
index d0f679c9..3b0b2a69 100644
--- a/src/local/import.rs
+++ b/src/local/import.rs
@@ -7,6 +7,7 @@ use std::{fs::File, path::Path};
use chrono::prelude::*;
use chrono::Utc;
use eyre::{eyre, Result};
+use itertools::Itertools;
use super::history::History;
@@ -42,8 +43,8 @@ impl Zsh {
fn parse_extended(line: &str, counter: i64) -> History {
let line = line.replacen(": ", "", 2);
- let (time, duration) = line.split_once(':').unwrap();
- let (duration, command) = duration.split_once(';').unwrap();
+ let (time, duration) = line.splitn(2, ':').collect_tuple().unwrap();
+ let (duration, command) = duration.splitn(2, ';').collect_tuple().unwrap();
let time = time
.parse::<i64>()
@@ -60,7 +61,7 @@ fn parse_extended(line: &str, counter: i64) -> History {
time,
command.trim_end().to_string(),
String::from("unknown"),
- -1,
+ 0, // assume 0, we have no way of knowing :(
duration,
None,
None,
diff --git a/src/local/sync.rs b/src/local/sync.rs
index c22d2f27..e0feb759 100644
--- a/src/local/sync.rs
+++ b/src/local/sync.rs
@@ -20,12 +20,12 @@ use crate::{api::AddHistoryRequest, utils::hash_str};
// Check if remote has things we don't, and if so, download them.
// Returns (num downloaded, total local)
-fn sync_download(
+async fn sync_download(
force: bool,
- client: &api_client::Client,
- db: &mut impl Database,
+ client: &api_client::Client<'_>,
+ db: &mut (impl Database + Send),
) -> Result<(i64, i64)> {
- let remote_count = client.count()?;
+ let remote_count = client.count().await?;
let initial_local = db.history_count()?;
let mut local_count = initial_local;
@@ -41,7 +41,9 @@ fn sync_download(
let host = if force { Some(String::from("")) } else { None };
while remote_count > local_count {
- let page = client.get_history(last_sync, last_timestamp, host.clone())?;
+ let page = client
+ .get_history(last_sync, last_timestamp, host.clone())
+ .await?;
if page.len() < HISTORY_PAGE_SIZE.try_into().unwrap() {
break;
@@ -71,13 +73,13 @@ fn sync_download(
}
// Check if we have things remote doesn't, and if so, upload them
-fn sync_upload(
+async fn sync_upload(
settings: &Settings,
_force: bool,
- client: &api_client::Client,
- db: &mut impl Database,
+ client: &api_client::Client<'_>,
+ db: &mut (impl Database + Send),
) -> Result<()> {
- let initial_remote_count = client.count()?;
+ let initial_remote_count = client.count().await?;
let mut remote_count = initial_remote_count;
let local_count = db.history_count()?;
@@ -111,21 +113,25 @@ fn sync_upload(
}
// anything left over outside of the 100 block size
- client.post_history(&buffer)?;
+ client.post_history(&buffer).await?;
cursor = buffer.last().unwrap().timestamp;
- remote_count = client.count()?;
+ remote_count = client.count().await?;
}
Ok(())
}
-pub fn sync(settings: &Settings, force: bool, db: &mut impl Database) -> Result<()> {
- let client = api_client::Client::new(settings);
+pub async fn sync(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> {
+ let client = api_client::Client::new(
+ settings.local.sync_address.as_str(),
+ settings.local.session_token.as_str(),
+ load_key(settings)?,
+ );
- sync_upload(settings, force, &client, db)?;
+ sync_upload(settings, force, &client, db).await?;
- let download = sync_download(force, &client, db)?;
+ let download = sync_download(force, &client, db).await?;
debug!("sync downloaded {}", download.0);
diff --git a/src/main.rs b/src/main.rs
index 94c7366d..0045a943 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,10 @@
-#![feature(proc_macro_hygiene)]
-#![feature(decl_macro)]
#![warn(clippy::pedantic, clippy::nursery)]
#![allow(clippy::use_self)] // not 100% reliable
use std::path::PathBuf;
use eyre::{eyre, Result};
+use fern::colors::{Color, ColoredLevelConfig};
use human_panic::setup_panic;
use structopt::{clap::AppSettings, StructOpt};
@@ -13,20 +12,8 @@ use structopt::{clap::AppSettings, StructOpt};
extern crate log;
#[macro_use]
-extern crate rocket;
-
-#[macro_use]
extern crate serde_derive;
-#[macro_use]
-extern crate diesel;
-
-#[macro_use]
-extern crate diesel_migrations;
-
-#[macro_use]
-extern crate rocket_contrib;
-
use command::AtuinCmd;
use local::database::Sqlite;
use settings::Settings;
@@ -34,12 +21,10 @@ use settings::Settings;
mod api;
mod command;
mod local;
-mod remote;
+mod server;
mod settings;
mod utils;
-pub mod schema;
-
#[derive(StructOpt)]
#[structopt(
author = "Ellie Huxtable <e@elm.sh>",
@@ -56,7 +41,7 @@ struct Atuin {
}
impl Atuin {
- fn run(self, settings: &Settings) -> Result<()> {
+ async fn run(self, settings: &Settings) -> Result<()> {
let db_path = if let Some(db_path) = self.db {
let path = db_path
.to_str()
@@ -69,26 +54,32 @@ impl Atuin {
let mut db = Sqlite::new(db_path)?;
- self.atuin.run(&mut db, settings)
+ self.atuin.run(&mut db, settings).await
}
}
-fn main() -> Result<()> {
- setup_panic!();
- let settings = Settings::new()?;
+#[tokio::main]
+async fn main() -> Result<()> {
+ let colors = ColoredLevelConfig::new()
+ .warn(Color::Yellow)
+ .error(Color::Red);
fern::Dispatch::new()
- .format(|out, message, record| {
+ .format(move |out, message, record| {
out.finish(format_args!(
"{} [{}] {}",
- chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
- record.level(),
+ chrono::Local::now().to_rfc3339(),
+ colors.color(record.level()),
message
))
})
.level(log::LevelFilter::Info)
+ .level_for("sqlx", log::LevelFilter::Warn)
.chain(std::io::stdout())
.apply()?;
- Atuin::from_args().run(&settings)
+ let settings = Settings::new()?;
+ setup_panic!();
+
+ Atuin::from_args().run(&settings).await
}
diff --git a/src/remote/database.rs b/src/remote/database.rs
deleted file mode 100644
index 03973ca1..00000000
--- a/src/remote/database.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use diesel::pg::PgConnection;
-use diesel::prelude::*;
-use eyre::{eyre, Result};
-
-use crate::settings::Settings;
-
-#[database("atuin")]
-pub struct AtuinDbConn(diesel::PgConnection);
-
-// TODO: connection pooling
-pub fn establish_connection(settings: &Settings) -> Result<PgConnection> {
- if settings.server.db_uri == "default_uri" {
- Err(eyre!(
- "Please configure your database! Set db_uri in config.toml"
- ))
- } else {
- let database_url = &settings.server.db_uri;
- let conn = PgConnection::establish(database_url)?;
-
- Ok(conn)
- }
-}
diff --git a/src/remote/mod.rs b/src/remote/mod.rs
deleted file mode 100644
index 7147b88e..00000000
--- a/src/remote/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub mod auth;
-pub mod database;
-pub mod models;
-pub mod server;
-pub mod views;
diff --git a/src/remote/server.rs b/src/remote/server.rs
deleted file mode 100644
index ee481ca4..00000000
--- a/src/remote/server.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use std::collections::HashMap;
-
-use crate::remote::database::establish_connection;
-use crate::settings::Settings;
-
-use super::database::AtuinDbConn;
-
-use eyre::Result;
-use rocket::config::{Config, Environment, LoggingLevel, Value};
-
-// a bunch of these imports are generated by macros, it's easier to wildcard
-#[allow(clippy::clippy::wildcard_imports)]
-use super::views::*;
-
-#[allow(clippy::clippy::wildcard_imports)]
-use super::auth::*;
-
-embed_migrations!("migrations");
-
-pub fn launch(settings: &Settings, host: String, port: u16) -> Result<()> {
- let settings: Settings = settings.clone(); // clone so rocket can manage it
-
- let mut database_config = HashMap::new();
- let mut databases = HashMap::new();
-
- database_config.insert("url", Value::from(settings.server.db_uri.clone()));
- databases.insert("atuin", Value::from(database_config));
-
- let connection = establish_connection(&settings)?;
-
- embedded_migrations::run(&connection).expect("failed to run migrations");
-
- let config = Config::build(Environment::Production)
- .address(host)
- .log_level(LoggingLevel::Normal)
- .port(port)
- .extra("databases", databases)
- .finalize()
- .unwrap();
-
- let app = rocket::custom(config);
-
- app.mount(
- "/",
- routes![
- index,
- register,
- add_history,
- login,
- get_user,
- sync_count,
- sync_list
- ],
- )
- .manage(settings)
- .attach(AtuinDbConn::fairing())
- .register(catchers![internal_error, bad_request])
- .launch();
-
- Ok(())
-}
diff --git a/src/remote/views.rs b/src/remote/views.rs
deleted file mode 100644
index 08dff13e..00000000
--- a/src/remote/views.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-use chrono::Utc;
-use rocket::http::uri::Uri;
-use rocket::http::RawStr;
-use rocket::http::{ContentType, Status};
-use rocket::request::FromFormValue;
-use rocket::request::Request;
-use rocket::response;
-use rocket::response::{Responder, Response};
-use rocket_contrib::databases::diesel;
-use rocket_contrib::json::{Json, JsonValue};
-
-use self::diesel::prelude::*;
-
-use crate::api::AddHistoryRequest;
-use crate::schema::history;
-use crate::settings::HISTORY_PAGE_SIZE;
-
-use super::database::AtuinDbConn;
-use super::models::{History, NewHistory, User};
-
-#[derive(Debug)]
-pub struct ApiResponse {
- pub json: JsonValue,
- pub status: Status,
-}
-
-impl<'r> Responder<'r> for ApiResponse {
- fn respond_to(self, req: &Request) -> response::Result<'r> {
- Response::build_from(self.json.respond_to(req).unwrap())
- .status(self.status)
- .header(ContentType::JSON)
- .ok()
- }
-}
-
-#[get("/")]
-pub const fn index() -> &'static str {
- "\"Through the fathomless deeps of space swims the star turtle Great A\u{2019}Tuin, bearing on its back the four giant elephants who carry on their shoulders the mass of the Discworld.\"\n\t-- Sir Terry Pratchett"
-}
-
-#[catch(500)]
-pub fn internal_error(_req: &Request) -> ApiResponse {
- ApiResponse {
- status: Status::InternalServerError,
- json: json!({"status": "error", "message": "an internal server error has occured"}),
- }
-}
-
-#[catch(400)]
-pub fn bad_request(_req: &Request) -> ApiResponse {
- ApiResponse {
- status: Status::InternalServerError,
- json: json!({"status": "error", "message": "bad request. don't do that."}),
- }
-}
-
-#[post("/history", data = "<add_history>")]
-#[allow(
- clippy::clippy::cast_sign_loss,
- clippy::cast_possible_truncation,
- clippy::clippy::needless_pass_by_value
-)]
-pub fn add_history(
- conn: AtuinDbConn,
- user: User,
- add_history: Json<Vec<AddHistoryRequest>>,
-) -> ApiResponse {
- let new_history: Vec<NewHistory> = add_history
- .iter()
- .map(|h| NewHistory {
- client_id: h.id.as_str(),
- hostname: h.hostname.to_string(),
- user_id: user.id,
- timestamp: h.timestamp.naive_utc(),
- data: h.data.as_str(),
- })
- .collect();
-
- match diesel::insert_into(history::table)
- .values(&new_history)
- .on_conflict_do_nothing()
- .execute(&*conn)
- {
- Ok(_) => ApiResponse {
- status: Status::Ok,
- json: json!({"status": "ok", "message": "history added"}),
- },
- Err(_) => ApiResponse {
- status: Status::BadRequest,
- json: json!({"status": "error", "message": "failed to add history"}),
- },
- }
-}
-
-#[get("/sync/count")]
-#[allow(clippy::wildcard_imports, clippy::needless_pass_by_value)]
-pub fn sync_count(conn: AtuinDbConn, user: User) -> ApiResponse {
- use crate::schema::history::dsl::*;
-
- // we need to return the number of history items we have for this user
- // in the future I'd like to use something like a merkel tree to calculate
- // which day specifically needs syncing
- let count = history
- .filter(user_id.eq(user.id))
- .count()
- .first::<i64>(&*conn);
-
- if count.is_err() {
- error!("failed to count: {}", count.err().unwrap());
-
- return ApiResponse {
- json: json!({"message": "internal server error"}),
- status: Status::InternalServerError,
- };
- }
-
- ApiResponse {
- status: Status::Ok,
- json: json!({"count": count.ok()}),
- }
-}
-
-pub struct UtcDateTime(chrono::DateTime<Utc>);
-
-impl<'v> FromFormValue<'v> for UtcDateTime {
- type Error = &'v RawStr;
-
- fn from_form_value(form_value: &'v RawStr) -> Result<UtcDateTime, &'v RawStr> {
- let time = Uri::percent_decode(form_value.as_bytes()).map_err(|_| form_value)?;
- let time = time.to_string();
-
- match chrono::DateTime::parse_from_rfc3339(time.as_str()) {
- Ok(t) => Ok(UtcDateTime(t.with_timezone(&Utc))),
- Err(e) => {
- error!("failed to parse time {}, got: {}", time, e);
- Err(form_value)
- }
- }
- }
-}
-
-// Request a list of all history items added to the DB after a given timestamp.
-// Provide the current hostname, so that we don't send the client data that
-// originated from them
-#[get("/sync/history?<sync_ts>&<history_ts>&<host>")]
-#[allow(clippy::wildcard_imports, clippy::needless_pass_by_value)]
-pub fn sync_list(
- conn: AtuinDbConn,
- user: User,
- sync_ts: UtcDateTime,
- history_ts: UtcDateTime,
- host: String,
-) -> ApiResponse {
- use crate::schema::history::dsl::*;
-
- // we need to return the number of history items we have for this user
- // in the future I'd like to use something like a merkel tree to calculate
- // which day specifically needs syncing
- // TODO: Allow for configuring the page size, both from params, and setting
- // the max in config. 100 is fine for now.
- let h = history
- .filter(user_id.eq(user.id))
- .filter(hostname.ne(host))
- .filter(created_at.ge(sync_ts.0.naive_utc()))
- .filter(timestamp.ge(history_ts.0.naive_utc()))
- .order(timestamp.asc())
- .limit(HISTORY_PAGE_SIZE)
- .load::<History>(&*conn);
-
- if let Err(e) = h {
- error!("failed to load history: {}", e);
-
- return ApiResponse {
- json: json!({"message": "internal server error"}),
- status: Status::InternalServerError,
- };
- }
-
- let user_data: Vec<String> = h.unwrap().iter().map(|i| i.data.to_string()).collect();
-
- ApiResponse {
- status: Status::Ok,
- json: json!({ "history": user_data }),
- }
-}
diff --git a/src/schema.rs b/src/schema.rs
deleted file mode 100644
index 84bf5bab..00000000
--- a/src/schema.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-table! {
- history (id) {
- id -> Int8,
- client_id -> Text,
- user_id -> Int8,
- hostname -> Text,
- timestamp -> Timestamp,
- data -> Varchar,
- created_at -> Timestamp,
- }
-}
-
-table! {
- sessions (id) {
- id -> Int8,
- user_id -> Int8,
- token -> Varchar,
- }
-}
-
-table! {
- users (id) {
- id -> Int8,
- username -> Varchar,
- email -> Varchar,
- password -> Varchar,
- }
-}
-
-allow_tables_to_appear_in_same_query!(history, sessions, users,);
diff --git a/src/remote/auth.rs b/src/server/auth.rs
index cf61b077..52a73108 100644
--- a/src/remote/auth.rs
+++ b/src/server/auth.rs
@@ -1,3 +1,4 @@
+/*
use self::diesel::prelude::*;
use eyre::Result;
use rocket::http::Status;
@@ -218,3 +219,4 @@ pub fn login(conn: AtuinDbConn, login: Json<LoginRequest>) -> ApiResponse {
json: json!({"session": session.token}),
}
}
+*/
diff --git a/src/server/database.rs b/src/server/database.rs
new file mode 100644
index 00000000..5945baaf
--- /dev/null
+++ b/src/server/database.rs
@@ -0,0 +1,202 @@
+use async_trait::async_trait;
+
+use eyre::{eyre, Result};
+use sqlx::postgres::PgPoolOptions;
+
+use crate::settings::HISTORY_PAGE_SIZE;
+
+use super::models::{History, NewHistory, NewSession, NewUser, Session, User};
+
+#[async_trait]
+pub trait Database {
+ async fn get_session(&self, token: &str) -> Result<Session>;
+ async fn get_session_user(&self, token: &str) -> Result<User>;
+ async fn add_session(&self, session: &NewSession) -> Result<()>;
+
+ async fn get_user(&self, username: String) -> Result<User>;
+ async fn get_user_session(&self, u: &User) -> Result<Session>;
+ async fn add_user(&self, user: NewUser) -> Result<i64>;
+
+ async fn count_history(&self, user: &User) -> Result<i64>;
+ async fn list_history(
+ &self,
+ user: &User,
+ created_since: chrono::NaiveDateTime,
+ since: chrono::NaiveDateTime,
+ host: String,
+ ) -> Result<Vec<History>>;
+ async fn add_history(&self, history: &[NewHistory]) -> Result<()>;
+}
+
+#[derive(Clone)]
+pub struct Postgres {
+ pool: sqlx::Pool<sqlx::postgres::Postgres>,
+}
+
+impl Postgres {
+ pub async fn new(uri: &str) -> Result<Self, sqlx::Error> {
+ let pool = PgPoolOptions::new()
+ .max_connections(100)
+ .connect(uri)
+ .await?;
+
+ Ok(Self { pool })
+ }
+}
+
+#[async_trait]
+impl Database for Postgres {
+ async fn get_session(&self, token: &str) -> Result<Session> {
+ let res: Option<Session> =
+ sqlx::query_as::<_, Session>("select * from sessions where token = $1")
+ .bind(token)
+ .fetch_optional(&self.pool)
+ .await?;
+
+ if let Some(s) = res {
+ Ok(s)
+ } else {
+ Err(eyre!("could not find session"))
+ }
+ }
+
+ async fn get_user(&self, username: String) -> Result<User> {
+ let res: Option<User> =
+ sqlx::query_as::<_, User>("select * from users where username = $1")
+ .bind(username)
+ .fetch_optional(&self.pool)
+ .await?;
+
+ if let Some(u) = res {
+ Ok(u)
+ } else {
+ Err(eyre!("could not find user"))
+ }
+ }
+
+ async fn get_session_user(&self, token: &str) -> Result<User> {
+ let res: Option<User> = sqlx::query_as::<_, User>(
+ "select * from users
+ inner join sessions
+ on users.id = sessions.user_id
+ and sessions.token = $1",
+ )
+ .bind(token)
+ .fetch_optional(&self.pool)
+ .await?;
+
+ if let Some(u) = res {
+ Ok(u)
+ } else {
+ Err(eyre!("could not find user"))
+ }
+ }
+
+ async fn count_history(&self, user: &User) -> Result<i64> {
+ let res: (i64,) = sqlx::query_as(
+ "select count(1) from history
+ where user_id = $1",
+ )
+ .bind(user.id)
+ .fetch_one(&self.pool)
+ .await?;
+
+ Ok(res.0)
+ }
+
+ async fn list_history(
+ &self,
+ user: &User,
+ created_since: chrono::NaiveDateTime,
+ since: chrono::NaiveDateTime,
+ host: String,
+ ) -> Result<Vec<History>> {
+ let res = sqlx::query_as::<_, History>(
+ "select * from history
+ where user_id = $1
+ and hostname != $2
+ and created_at >= $3
+ and timestamp >= $4
+ order by timestamp asc
+ limit $5",
+ )
+ .bind(user.id)
+ .bind(host)
+ .bind(created_since)
+ .bind(since)
+ .bind(HISTORY_PAGE_SIZE)
+ .fetch_all(&self.pool)
+ .await?;
+
+ Ok(res)
+ }
+
+ async fn add_history(&self, history: &[NewHistory]) -> Result<()> {
+ let mut tx = self.pool.begin().await?;
+
+ for i in history {
+ sqlx::query(
+ "insert into history
+ (client_id, user_id, hostname, timestamp, data)
+ values ($1, $2, $3, $4, $5)
+ on conflict do nothing
+ ",
+ )
+ .bind(i.client_id)
+ .bind(i.user_id)
+ .bind(i.hostname)
+ .bind(i.timestamp)
+ .bind(i.data)
+ .execute(&mut tx)
+ .await?;
+ }
+
+ tx.commit().await?;
+
+ Ok(())
+ }
+
+ async fn add_user(&self, user: NewUser) -> Result<i64> {
+ let res: (i64,) = sqlx::query_as(
+ "insert into users
+ (username, email, password)
+ values($1, $2, $3)
+ returning id",
+ )
+ .bind(user.username.as_str())
+ .bind(user.email.as_str())
+ .bind(user.password)
+ .fetch_one(&self.pool)
+ .await?;
+
+ Ok(res.0)
+ }
+
+ async fn add_session(&self, session: &NewSession) -> Result<()> {
+ sqlx::query(
+ "insert into sessions
+ (user_id, token)
+ values($1, $2)",
+ )
+ .bind(session.user_id)
+ .bind(session.token)
+ .execute(&self.pool)
+ .await?;
+
+ Ok(())
+ }
+
+ async fn get_user_session(&self, u: &User) -> Result<Session> {
+ let res: Option<Session> =
+ sqlx::query_as::<_, Session>("select * from sessions where user_id = $1")
+ .bind(u.id)
+ .fetch_optional(&self.pool)
+ .await?;
+
+ if let Some(s) = res {
+ Ok(s)
+ } else {
+ Err(eyre!("could not find session"))
+ }
+ }
+}
diff --git a/src/server/handlers/history.rs b/src/server/handlers/history.rs
new file mode 100644
index 00000000..4fd6f03f
--- /dev/null
+++ b/src/server/handlers/history.rs
@@ -0,0 +1,89 @@
+use std::convert::Infallible;
+
+use warp::{http::StatusCode, reply::json};
+
+use crate::api::{
+ AddHistoryRequest, CountResponse, ErrorResponse, SyncHistoryRequest, SyncHistoryResponse,
+};
+use crate::server::database::Database;
+use crate::server::models::{NewHistory, User};
+
+pub async fn count(
+ user: User,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ db.count_history(&user).await.map_or(
+ Ok(Box::new(ErrorResponse::reply(
+ "failed to query history count",
+ StatusCode::INTERNAL_SERVER_ERROR,
+ ))),
+ |count| Ok(Box::new(json(&CountResponse { count }))),
+ )
+}
+
+pub async fn list(
+ req: SyncHistoryRequest,
+ user: User,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ let history = db
+ .list_history(
+ &user,
+ req.sync_ts.naive_utc(),
+ req.history_ts.naive_utc(),
+ req.host,
+ )
+ .await;
+
+ if let Err(e) = history {
+ error!("failed to load history: {}", e);
+ let resp =
+ ErrorResponse::reply("failed to load history", StatusCode::INTERNAL_SERVER_ERROR);
+ let resp = Box::new(resp);
+ return Ok(resp);
+ }
+
+ let history: Vec<String> = history
+ .unwrap()
+ .iter()
+ .map(|i| i.data.to_string())
+ .collect();
+
+ debug!(
+ "loaded {} items of history for user {}",
+ history.len(),
+ user.id
+ );
+
+ Ok(Box::new(json(&SyncHistoryResponse { history })))
+}
+
+pub async fn add(
+ req: Vec<AddHistoryRequest>,
+ user: User,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ debug!("request to add {} history items", req.len());
+
+ let history: Vec<NewHistory> = req
+ .iter()
+ .map(|h| NewHistory {
+ client_id: h.id.as_str(),
+ user_id: user.id,
+ hostname: h.hostname.as_str(),
+ timestamp: h.timestamp.naive_utc(),
+ data: h.data.as_str(),
+ })
+ .collect();
+
+ if let Err(e) = db.add_history(&history).await {
+ error!("failed to add history: {}", e);
+
+ return Ok(Box::new(ErrorResponse::reply(
+ "failed to add history",
+ StatusCode::INTERNAL_SERVER_ERROR,
+ )));
+ };
+
+ Ok(Box::new(warp::reply()))
+}
diff --git a/src/server/handlers/mod.rs b/src/server/handlers/mod.rs
new file mode 100644
index 00000000..3c20538c
--- /dev/null
+++ b/src/server/handlers/mod.rs
@@ -0,0 +1,6 @@
+pub mod history;
+pub mod user;
+
+pub const fn index() -> &'static str {
+ "\"Through the fathomless deeps of space swims the star turtle Great A\u{2019}Tuin, bearing on its back the four giant elephants who carry on their shoulders the mass of the Discworld.\"\n\t-- Sir Terry Pratchett"
+}
diff --git a/src/server/handlers/user.rs b/src/server/handlers/user.rs
new file mode 100644
index 00000000..782d7dbd
--- /dev/null
+++ b/src/server/handlers/user.rs
@@ -0,0 +1,140 @@
+use std::convert::Infallible;
+
+use sodiumoxide::crypto::pwhash::argon2id13;
+use uuid::Uuid;
+use warp::http::StatusCode;
+use warp::reply::json;
+
+use crate::api::{
+ ErrorResponse, LoginRequest, LoginResponse, RegisterRequest, RegisterResponse, UserResponse,
+};
+use crate::server::database::Database;
+use crate::server::models::{NewSession, NewUser};
+use crate::settings::Settings;
+use crate::utils::hash_secret;
+
+pub fn verify_str(secret: &str, verify: &str) -> bool {
+ sodiumoxide::init().unwrap();
+
+ let mut padded = [0_u8; 128];
+ secret.as_bytes().iter().enumerate().for_each(|(i, val)| {
+ padded[i] = *val;
+ });
+
+ match argon2id13::HashedPassword::from_slice(&padded) {
+ Some(hp) => argon2id13::pwhash_verify(&hp, verify.as_bytes()),
+ None => false,
+ }
+}
+
+pub async fn get(
+ username: String,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ let user = match db.get_user(username).await {
+ Ok(user) => user,
+ Err(e) => {
+ debug!("user not found: {}", e);
+ return Ok(Box::new(ErrorResponse::reply(
+ "user not found",
+ StatusCode::NOT_FOUND,
+ )));
+ }
+ };
+
+ Ok(Box::new(warp::reply::json(&UserResponse {
+ username: user.username,
+ })))
+}
+
+pub async fn register(
+ register: RegisterRequest,
+ settings: Settings,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ if !settings.server.open_registration {
+ return Ok(Box::new(ErrorResponse::reply(
+ "this server is not open for registrations",
+ StatusCode::BAD_REQUEST,
+ )));
+ }
+
+ let hashed = hash_secret(register.password.as_str());
+
+ let new_user = NewUser {
+ email: register.email,
+ username: register.username,
+ password: hashed,
+ };
+
+ let user_id = match db.add_user(new_user).await {
+ Ok(id) => id,
+ Err(e) => {
+ error!("failed to add user: {}", e);
+ return Ok(Box::new(ErrorResponse::reply(
+ "failed to add user",
+ StatusCode::BAD_REQUEST,
+ )));
+ }
+ };
+
+ let token = Uuid::new_v4().to_simple().to_string();
+
+ let new_session = NewSession {
+ user_id,
+ token: token.as_str(),
+ };
+
+ match db.add_session(&new_session).await {
+ Ok(_) => Ok(Box::new(json(&RegisterResponse { session: token }))),
+ Err(e) => {
+ error!("failed to add session: {}", e);
+ Ok(Box::new(ErrorResponse::reply(
+ "failed to register user",
+ StatusCode::BAD_REQUEST,
+ )))
+ }
+ }
+}
+
+pub async fn login(
+ login: LoginRequest,
+ db: impl Database + Clone + Send + Sync,
+) -> Result<Box<dyn warp::Reply>, Infallible> {
+ let user = match db.get_user(login.username.clone()).await {
+ Ok(u) => u,
+ Err(e) => {
+ error!("failed to get user {}: {}", login.username.clone(), e);
+
+ return Ok(Box::new(ErrorResponse::reply(
+ "user not found",
+ StatusCode::NOT_FOUND,
+ )));
+ }
+ };
+
+ let session = match db.get_user_session(&user).await {
+ Ok(u) => u,
+ Err(e) => {
+ error!("failed to get session for {}: {}", login.username, e);
+
+ return Ok(Box::new(ErrorResponse::reply(
+ "user not found",
+ StatusCode::NOT_FOUND,
+ )));
+ }
+ };
+
+ let verified = verify_str(user.password.as_str(), login.password.as_str());
+
+ if !verified {
+ return Ok(Box::new(ErrorResponse::reply(
+ "user not found",
+ StatusCode::NOT_FOUND,
+ )));
+ }
+
+ Ok(Box::new(warp::reply::json(&LoginResponse {
+ session: session.token,
+ })))
+}
diff --git a/src/server/mod.rs b/src/server/mod.rs
new file mode 100644
index 00000000..d5e083df
--- /dev/null
+++ b/src/server/mod.rs
@@ -0,0 +1,23 @@
+use std::net::IpAddr;
+
+use eyre::Result;
+
+use crate::settings::Settings;
+
+pub mod auth;
+pub mod database;
+pub mod handlers;
+pub mod models;
+pub mod router;
+
+pub async fn launch(settings: &Settings, host: String, port: u16) -> Result<()> {
+ // routes to run:
+ // index, register, add_history, login, get_user, sync_count, sync_list
+ let host = host.parse::<IpAddr>()?;
+
+ let r = router::router(settings).await?;
+
+ warp::serve(r).run((host, port)).await;
+
+ Ok(())
+}
diff --git a/src/remote/models.rs b/src/server/models.rs
index 7f6f7766..fbf1897e 100644
--- a/src/remote/models.rs
+++ b/src/server/models.rs
@@ -1,10 +1,6 @@
use chrono::prelude::*;
-use crate::schema::{history, sessions, users};
-
-#[derive(Deserialize, Serialize, Identifiable, Queryable, Associations)]
-#[table_name = "history"]
-#[belongs_to(User)]
+#[derive(sqlx::FromRow)]
pub struct History {
pub id: i64,
pub client_id: String, // a client generated ID
@@ -17,7 +13,16 @@ pub struct History {
pub created_at: NaiveDateTime,
}
-#[derive(Identifiable, Queryable, Associations)]
+pub struct NewHistory<'a> {
+ pub client_id: &'a str,
+ pub user_id: i64,
+ pub hostname: &'a str,
+ pub timestamp: chrono::NaiveDateTime,
+
+ pub data: &'a str,
+}
+
+#[derive(sqlx::FromRow)]
pub struct User {
pub id: i64,
pub username: String,
@@ -25,35 +30,19 @@ pub struct User {
pub password: String,
}
-#[derive(Queryable, Identifiable, Associations)]
-#[belongs_to(User)]
+#[derive(sqlx::FromRow)]
pub struct Session {
pub id: i64,
pub user_id: i64,
pub token: String,
}
-#[derive(Insertable)]
-#[table_name = "history"]
-pub struct NewHistory<'a> {
- pub client_id: &'a str,
- pub user_id: i64,
- pub hostname: String,
- pub timestamp: chrono::NaiveDateTime,
-
- pub data: &'a str,
-}
-
-#[derive(Insertable)]
-#[table_name = "users"]
-pub struct NewUser<'a> {
- pub username: &'a str,
- pub email: &'a str,
- pub password: &'a str,
+pub struct NewUser {
+ pub username: String,
+ pub email: String,
+ pub password: String,
}
-#[derive(Insertable)]
-#[table_name = "sessions"]
pub struct NewSession<'a> {
pub user_id: i64,
pub token: &'a str,
diff --git a/src/server/router.rs b/src/server/router.rs
new file mode 100644
index 00000000..ed317ab2
--- /dev/null
+++ b/src/server/router.rs
@@ -0,0 +1,121 @@
+use std::convert::Infallible;
+
+use eyre::Result;
+use warp::Filter;
+
+use super::handlers;
+use super::{database::Database, database::Postgres};
+use crate::server::models::User;
+use crate::{api::SyncHistoryRequest, settings::Settings};
+
+fn with_settings(
+ settings: Settings,
+) -> impl Filter<Extract = (Settings,), Error = Infallible> + Clone {
+ warp::any().map(move || settings.clone())
+}
+
+fn with_db(
+ db: impl Database + Clone + Send + Sync,
+) -> impl Filter<Extract = (impl Database + Clone,), Error = Infallible> + Clone {
+ warp::any().map(move || db.clone())
+}
+
+fn with_user(
+ postgres: Postgres,
+) -> impl Filter<Extract = (User,), Error = warp::Rejection> + Clone {
+ warp::header::<String>("authorization").and_then(move |header: String| {
+ // async closures are still buggy :(
+ let postgres = postgres.clone();
+
+ async move {
+ let header: Vec<&str> = header.split(' ').collect();
+
+ let token;
+
+ if header.len() == 2 {
+ if header[0] != "Token" {
+ return Err(warp::reject());
+ }
+
+ token = header[1];
+ } else {
+ return Err(warp::reject());
+ }
+
+ let user = postgres
+ .get_session_user(token)
+ .await
+ .map_err(|_| warp::reject())?;
+
+ Ok(user)
+ }
+ })
+}
+
+pub async fn router(
+ settings: &Settings,
+) -> Result<impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone> {
+ let postgres = Postgres::new(settings.server.db_uri.as_str()).await?;
+ let index = warp::get().and(warp::path::end()).map(handlers::index);
+
+ let count = warp::get()
+ .and(warp::path("sync"))
+ .and(warp::path("count"))
+ .and(warp::path::end())
+ .and(with_user(postgres.clone()))
+ .and(with_db(postgres.clone()))
+ .and_then(handlers::history::count);
+
+ let sync = warp::get()
+ .and(warp::path("sync"))
+ .and(warp::path("history"))
+ .and(warp::query::<SyncHistoryRequest>())
+ .and(warp::path::end())
+ .and(with_user(postgres.clone()))
+ .and(with_db(postgres.clone()))
+ .and_then(handlers::history::list);
+
+ let add_history = warp::post()
+ .and(warp::path("history"))
+ .and(warp::path::end())
+ .and(warp::body::json())
+ .and(with_user(postgres.clone()))
+ .and(with_db(postgres.clone()))
+ .and_then(handlers::history::add);
+
+ let user = warp::get()
+ .and(warp::path("user"))
+ .and(warp::path::param::<String>())
+ .and(warp::path::end())
+ .and(with_db(postgres.clone()))
+ .and_then(handlers::user::get);
+
+ let register = warp::post()
+ .and(warp::path("register"))
+ .and(warp::path::end())
+ .and(warp::body::json())
+ .and(with_settings(settings.clone()))
+ .and(with_db(postgres.clone()))
+ .and_then(handlers::user::register);
+
+ let login = warp::post()
+ .and(warp::path("login"))
+ .and(warp::path::end())
+ .and(warp::body::json())
+ .and(with_db(postgres))
+ .and_then(handlers::user::login);
+
+ let r = warp::any()
+ .and(
+ index
+ .or(count)
+ .or(sync)
+ .or(add_history)
+ .or(user)
+ .or(register)
+ .or(login),
+ )
+ .with(warp::filters::log::log("atuin::api"));
+
+ Ok(r)
+}
diff --git a/src/settings.rs b/src/settings.rs
index f3bc62e6..5325610e 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -161,7 +161,7 @@ impl Settings {
// Finally, set the auth token
if Path::new(session_path.to_string().as_str()).exists() {
let token = std::fs::read_to_string(session_path.to_string())?;
- s.set("local.session_token", token)?;
+ s.set("local.session_token", token.trim())?;
} else {
s.set("local.session_token", "not logged in")?;
}
diff --git a/src/shell/atuin.zsh b/src/shell/atuin.zsh
index d2abf3c1..d6d58f53 100644
--- a/src/shell/atuin.zsh
+++ b/src/shell/atuin.zsh
@@ -16,6 +16,7 @@ _atuin_precmd(){
[[ -z "${ATUIN_HISTORY_ID}" ]] && return
atuin history end $ATUIN_HISTORY_ID --exit $EXIT
+ export ATUIN_HISTORY_ID=""
}
_atuin_search(){