aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock166
-rw-r--r--Cargo.toml31
-rw-r--r--Dockerfile47
-rw-r--r--atuin-client/Cargo.toml40
-rw-r--r--atuin-client/config.toml (renamed from config.toml)19
-rw-r--r--atuin-client/src/api_client.rs (renamed from src/local/api_client.rs)9
-rw-r--r--atuin-client/src/database.rs (renamed from src/local/database.rs)0
-rw-r--r--atuin-client/src/encryption.rs (renamed from src/local/encryption.rs)4
-rw-r--r--atuin-client/src/history.rs (renamed from src/local/history.rs)2
-rw-r--r--atuin-client/src/import.rs (renamed from src/local/import.rs)0
-rw-r--r--atuin-client/src/lib.rs (renamed from src/local/mod.rs)7
-rw-r--r--atuin-client/src/settings.rs (renamed from src/settings.rs)59
-rw-r--r--atuin-client/src/sync.rs (renamed from src/local/sync.rs)19
-rw-r--r--atuin-common/Cargo.toml21
-rw-r--r--atuin-common/src/api.rs (renamed from src/api.rs)0
-rw-r--r--atuin-common/src/lib.rs5
-rw-r--r--atuin-common/src/utils.rs (renamed from src/utils.rs)5
-rw-r--r--atuin-server/Cargo.toml38
-rw-r--r--atuin-server/server.toml11
-rw-r--r--atuin-server/src/auth.rs (renamed from src/server/auth.rs)0
-rw-r--r--atuin-server/src/database.rs (renamed from src/server/database.rs)0
-rw-r--r--atuin-server/src/handlers/history.rs (renamed from src/server/handlers/history.rs)6
-rw-r--r--atuin-server/src/handlers/mod.rs (renamed from src/server/handlers/mod.rs)0
-rw-r--r--atuin-server/src/handlers/user.rs (renamed from src/server/handlers/user.rs)11
-rw-r--r--atuin-server/src/lib.rs (renamed from src/server/mod.rs)7
-rw-r--r--atuin-server/src/models.rs (renamed from src/server/models.rs)0
-rw-r--r--atuin-server/src/router.rs (renamed from src/server/router.rs)8
-rw-r--r--atuin-server/src/settings.rs57
-rw-r--r--src/command/history.rs10
-rw-r--r--src/command/import.rs6
-rw-r--r--src/command/login.rs8
-rw-r--r--src/command/mod.rs40
-rw-r--r--src/command/register.rs8
-rw-r--r--src/command/search.rs5
-rw-r--r--src/command/server.rs15
-rw-r--r--src/command/stats.rs8
-rw-r--r--src/command/sync.rs6
-rw-r--r--src/main.rs39
39 files changed, 412 insertions, 306 deletions
diff --git a/.gitignore b/.gitignore
index fedaa2b1..45e115b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/target
+*/target
.env
diff --git a/Cargo.lock b/Cargo.lock
index 2f7d6d73..16e8e82d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,21 +3,6 @@
version = 3
[[package]]
-name = "addr2line"
-version = "0.14.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -100,17 +85,46 @@ name = "atuin"
version = "0.5.0"
dependencies = [
"async-trait",
+ "atuin-client",
+ "atuin-common",
+ "atuin-server",
"base64",
"chrono",
"chrono-english",
"cli-table",
- "config",
"directories",
- "dotenv",
"eyre",
"fern",
"fork",
- "human-panic",
+ "humantime",
+ "indicatif",
+ "itertools",
+ "log",
+ "reqwest",
+ "rusqlite",
+ "serde 1.0.125",
+ "serde_derive",
+ "serde_json",
+ "structopt",
+ "termion",
+ "tokio",
+ "tui",
+ "unicode-width",
+]
+
+[[package]]
+name = "atuin-client"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "atuin-common",
+ "base64",
+ "chrono",
+ "chrono-english",
+ "config",
+ "directories",
+ "eyre",
+ "fern",
"humantime",
"indicatif",
"itertools",
@@ -126,11 +140,55 @@ dependencies = [
"serde_json",
"shellexpand",
"sodiumoxide",
+ "tokio",
+ "urlencoding",
+ "uuid",
+ "whoami",
+]
+
+[[package]]
+name = "atuin-common"
+version = "0.1.0"
+dependencies = [
+ "chrono",
+ "eyre",
+ "rmp-serde",
+ "rust-crypto",
+ "serde 1.0.125",
+ "serde_derive",
+ "serde_json",
+ "sodiumoxide",
+ "uuid",
+ "warp",
+]
+
+[[package]]
+name = "atuin-server"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "atuin-common",
+ "base64",
+ "chrono",
+ "chrono-english",
+ "config",
+ "directories",
+ "eyre",
+ "fern",
+ "fork",
+ "indicatif",
+ "log",
+ "parse_duration",
+ "rand 0.8.3",
+ "reqwest",
+ "rmp-serde",
+ "rust-crypto",
+ "serde 1.0.125",
+ "serde_derive",
+ "serde_json",
+ "sodiumoxide",
"sqlx",
- "structopt",
- "termion",
"tokio",
- "tui",
"unicode-width",
"urlencoding",
"uuid",
@@ -145,20 +203,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
-name = "backtrace"
-version = "0.3.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
-]
-
-[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -772,12 +816,6 @@ dependencies = [
]
[[package]]
-name = "gimli"
-version = "0.23.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
-
-[[package]]
name = "h2"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -908,21 +946,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
[[package]]
-name = "human-panic"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f357a500abcbd7c5f967c1d45c8838585b36743823b9d43488f24850534e36"
-dependencies = [
- "backtrace",
- "os_type",
- "serde 1.0.125",
- "serde_derive",
- "termcolor",
- "toml",
- "uuid",
-]
-
-[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1169,16 +1192,6 @@ dependencies = [
]
[[package]]
-name = "miniz_oxide"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
-dependencies = [
- "adler",
- "autocfg",
-]
-
-[[package]]
name = "mio"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1378,12 +1391,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
-name = "object"
-version = "0.23.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
-
-[[package]]
name = "once_cell"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1429,15 +1436,6 @@ dependencies = [
]
[[package]]
-name = "os_type"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7edc011af0ae98b7f88cf7e4a83b70a54a75d2b8cb013d6efd02e5956207e9eb"
-dependencies = [
- "regex",
-]
-
-[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1901,12 +1899,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
-name = "rustc-demangle"
-version = "0.1.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
-
-[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 9a57f947..57cd00e1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,47 +1,40 @@
[package]
name = "atuin"
version = "0.5.0"
-authors = ["Ellie Huxtable <e@elm.sh>"]
+authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
edition = "2018"
license = "MIT"
description = "atuin - magical shell history"
+[workspace]
+members = ["./atuin-client", "./atuin-server", "./atuin-common"]
+
[dependencies]
+atuin-server = { path = "atuin-server", version = "0.1.0" }
+atuin-client = { path = "atuin-client", version = "0.1.0" }
+atuin-common = { path = "atuin-common", version = "0.1.0" }
+
log = "0.4"
fern = {version = "0.6.0", features = ["colored"] }
chrono = { version = "0.4", features = ["serde"] }
eyre = "0.6"
-shellexpand = "2"
structopt = "0.3"
directories = "3"
-uuid = { version = "0.8", features = ["v4"] }
indicatif = "0.15.0"
-whoami = "1.1.2"
-chrono-english = "0.1.4"
-cli-table = "0.4"
-config = "0.11"
serde_derive = "1.0.125"
serde = "1.0.125"
serde_json = "1.0.64"
-rmp-serde = "0.15.4"
tui = "0.14"
termion = "1.5"
unicode-width = "0.1"
itertools = "0.10.0"
-dotenv = "0.15.0"
-sodiumoxide = "0.2.6"
-reqwest = { version = "0.11", features = ["blocking", "json"] }
-base64 = "0.13.0"
fork = "0.1.18"
-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"
+chrono-english = "0.1.4"
+cli-table = "0.4"
+reqwest = { version = "0.11", features = ["blocking", "json"] }
+base64 = "0.13.0"
humantime = "2.1.0"
[dependencies.rusqlite]
diff --git a/Dockerfile b/Dockerfile
index 0c19ef6d..e7125414 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,31 +1,22 @@
-FROM rust:1.51-buster as builder
+FROM lukemathwalker/cargo-chef as planner
+WORKDIR app
+COPY . .
+RUN cargo chef prepare --recipe-path recipe.json
-RUN cargo new --bin atuin
-WORKDIR /atuin
-COPY ./Cargo.toml ./Cargo.toml
-COPY ./Cargo.lock ./Cargo.lock
+FROM lukemathwalker/cargo-chef as cacher
+WORKDIR app
+COPY --from=planner /app/recipe.json recipe.json
+RUN cargo chef cook --release --recipe-path recipe.json
-RUN cargo build --release
+FROM rust as builder
+WORKDIR app
+COPY . .
+# Copy over the cached dependencies
+COPY --from=cacher /app/target target
+COPY --from=cacher $CARGO_HOME $CARGO_HOME
+RUN cargo build --release --bin atuin
-RUN rm src/*.rs
-
-ADD . ./
-
-RUN rm ./target/release/deps/atuin*
-RUN cargo build --release
-
-FROM debian:buster-slim
-
-RUN apt-get update \
- && apt-get install -y ca-certificates tzdata libpq-dev \
- && rm -rf /var/lib/apt/lists/*
-
-EXPOSE 8888
-
-ENV TZ=Etc/UTC
-ENV RUST_LOG=info
-ENV ATUIN_CONFIG=/config/config.toml
-
-COPY --from=builder /atuin/target/release/atuin ./atuin
-
-ENTRYPOINT ["./atuin"]
+FROM debian:buster-slim as runtime
+WORKDIR app
+COPY --from=builder /app/target/release/atuin /usr/local/bin
+ENTRYPOINT ["/usr/local/bin/atuin"]
diff --git a/atuin-client/Cargo.toml b/atuin-client/Cargo.toml
new file mode 100644
index 00000000..06c96a9a
--- /dev/null
+++ b/atuin-client/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "atuin-client"
+version = "0.1.0"
+authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
+edition = "2018"
+license = "MIT"
+description = "client library for atuin"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+atuin-common = { path = "../atuin-common", version = "0.1.0" }
+
+log = "0.4"
+fern = {version = "0.6.0", features = ["colored"] }
+chrono = { version = "0.4", features = ["serde"] }
+eyre = "0.6"
+directories = "3"
+uuid = { version = "0.8", features = ["v4"] }
+indicatif = "0.15.0"
+whoami = "1.1.2"
+chrono-english = "0.1.4"
+config = "0.11"
+serde_derive = "1.0.125"
+serde = "1.0.125"
+serde_json = "1.0.64"
+rmp-serde = "0.15.4"
+sodiumoxide = "0.2.6"
+reqwest = { version = "0.11", features = ["blocking", "json"] }
+base64 = "0.13.0"
+parse_duration = "2.1.1"
+rand = "0.8.3"
+rust-crypto = "^0.2"
+tokio = { version = "1", features = ["full"] }
+async-trait = "0.1.49"
+urlencoding = "1.1.1"
+humantime = "2.1.0"
+rusqlite= { version = "0.25", features = ["bundled"] }
+itertools = "0.10.0"
+shellexpand = "2"
diff --git a/config.toml b/atuin-client/config.toml
index fe776d6e..33e5b545 100644
--- a/config.toml
+++ b/atuin-client/config.toml
@@ -1,8 +1,3 @@
-# A'tuin example config
-
-# This section specifies the config for a local client,
-# ie where your shell history is on your local machine
-[local]
## where to store your database, default is your system data directory
## mac: ~/Library/Application Support/com.elliehuxtable.atuin/history.db
## linux: ~/.local/share/atuin/history.db
@@ -27,17 +22,3 @@
## address of the sync server
# sync_address = "https://api.atuin.sh"
-
-# This section configures the sync server, if you decide to host your own
-[server]
-## host to bind, can also be passed via CLI args
-# host = "127.0.0.1"
-
-## port to bind, can also be passed via CLI args
-# port = 8888
-
-## whether to allow anyone to register an account
-# open_registration = false
-
-## URI for postgres (using development creds here)
-# db_uri="postgres://username:password@localhost/atuin"
diff --git a/src/local/api_client.rs b/atuin-client/src/api_client.rs
index 1b64a295..db2802c3 100644
--- a/src/local/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -4,10 +4,11 @@ use reqwest::header::{HeaderMap, AUTHORIZATION};
use reqwest::Url;
use sodiumoxide::crypto::secretbox;
-use crate::api::{AddHistoryRequest, CountResponse, SyncHistoryResponse};
-use crate::local::encryption::decrypt;
-use crate::local::history::History;
-use crate::utils::hash_str;
+use atuin_common::api::{AddHistoryRequest, CountResponse, SyncHistoryResponse};
+use atuin_common::utils::hash_str;
+
+use crate::encryption::decrypt;
+use crate::history::History;
pub struct Client<'a> {
sync_addr: &'a str,
diff --git a/src/local/database.rs b/atuin-client/src/database.rs
index abc22bb8..abc22bb8 100644
--- a/src/local/database.rs
+++ b/atuin-client/src/database.rs
diff --git a/src/local/encryption.rs b/atuin-client/src/encryption.rs
index 3c1699e3..37153f94 100644
--- a/src/local/encryption.rs
+++ b/atuin-client/src/encryption.rs
@@ -15,7 +15,7 @@ use std::path::PathBuf;
use eyre::{eyre, Result};
use sodiumoxide::crypto::secretbox;
-use crate::local::history::History;
+use crate::history::History;
use crate::settings::Settings;
#[derive(Debug, Serialize, Deserialize)]
@@ -26,7 +26,7 @@ pub struct EncryptedHistory {
// Loads the secret key, will create + save if it doesn't exist
pub fn load_key(settings: &Settings) -> Result<secretbox::Key> {
- let path = settings.local.key_path.as_str();
+ let path = settings.key_path.as_str();
if PathBuf::from(path).exists() {
let bytes = std::fs::read(path)?;
diff --git a/src/local/history.rs b/atuin-client/src/history.rs
index 1712f8b9..7f607784 100644
--- a/src/local/history.rs
+++ b/atuin-client/src/history.rs
@@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher};
use chrono::Utc;
-use crate::command::uuid_v4;
+use atuin_common::utils::uuid_v4;
// Any new fields MUST be Optional<>!
#[derive(Debug, Clone, Serialize, Deserialize)]
diff --git a/src/local/import.rs b/atuin-client/src/import.rs
index 3b0b2a69..3b0b2a69 100644
--- a/src/local/import.rs
+++ b/atuin-client/src/import.rs
diff --git a/src/local/mod.rs b/atuin-client/src/lib.rs
index 9fe31292..1207bfdb 100644
--- a/src/local/mod.rs
+++ b/atuin-client/src/lib.rs
@@ -1,6 +1,13 @@
+#[macro_use]
+extern crate log;
+
+#[macro_use]
+extern crate serde_derive;
+
pub mod api_client;
pub mod database;
pub mod encryption;
pub mod history;
pub mod import;
+pub mod settings;
pub mod sync;
diff --git a/src/settings.rs b/atuin-client/src/settings.rs
index 5325610e..e28963c0 100644
--- a/src/settings.rs
+++ b/atuin-client/src/settings.rs
@@ -12,7 +12,7 @@ use parse_duration::parse;
pub const HISTORY_PAGE_SIZE: i64 = 100;
#[derive(Clone, Debug, Deserialize)]
-pub struct Local {
+pub struct Settings {
pub dialect: String,
pub auto_sync: bool,
pub sync_address: String,
@@ -26,7 +26,7 @@ pub struct Local {
pub session_token: String,
}
-impl Local {
+impl Settings {
pub fn save_sync_time() -> Result<()> {
let sync_time_path = ProjectDirs::from("com", "elliehuxtable", "atuin")
.ok_or_else(|| eyre!("could not determine key file location"))?;
@@ -66,28 +66,12 @@ impl Local {
match parse(self.sync_frequency.as_str()) {
Ok(d) => {
let d = chrono::Duration::from_std(d).unwrap();
- Ok(Utc::now() - Local::last_sync()? >= d)
+ Ok(Utc::now() - Settings::last_sync()? >= d)
}
Err(e) => Err(eyre!("failed to check sync: {}", e)),
}
}
-}
-#[derive(Clone, Debug, Deserialize)]
-pub struct Server {
- pub host: String,
- pub port: u16,
- pub db_uri: String,
- pub open_registration: bool,
-}
-
-#[derive(Clone, Debug, Deserialize)]
-pub struct Settings {
- pub local: Local,
- pub server: Server,
-}
-
-impl Settings {
pub fn new() -> Result<Self> {
let config_dir = ProjectDirs::from("com", "elliehuxtable", "atuin").unwrap();
let config_dir = config_dir.config_dir();
@@ -103,8 +87,6 @@ impl Settings {
config_file
};
- // create the config file if it does not exist
-
let mut s = Config::new();
let db_path = ProjectDirs::from("com", "elliehuxtable", "atuin")
@@ -122,18 +104,13 @@ impl Settings {
.data_dir()
.join("session");
- s.set_default("local.db_path", db_path.to_str())?;
- s.set_default("local.key_path", key_path.to_str())?;
- s.set_default("local.session_path", session_path.to_str())?;
- s.set_default("local.dialect", "us")?;
- s.set_default("local.auto_sync", true)?;
- s.set_default("local.sync_frequency", "5m")?;
- s.set_default("local.sync_address", "https://api.atuin.sh")?;
-
- s.set_default("server.host", "127.0.0.1")?;
- s.set_default("server.port", 8888)?;
- s.set_default("server.open_registration", false)?;
- s.set_default("server.db_uri", "default_uri")?;
+ s.set_default("db_path", db_path.to_str())?;
+ s.set_default("key_path", key_path.to_str())?;
+ s.set_default("session_path", session_path.to_str())?;
+ s.set_default("dialect", "us")?;
+ s.set_default("auto_sync", true)?;
+ s.set_default("sync_frequency", "5m")?;
+ s.set_default("sync_address", "https://api.atuin.sh")?;
if config_file.exists() {
s.merge(ConfigFile::with_name(config_file.to_str().unwrap()))?;
@@ -146,24 +123,24 @@ impl Settings {
s.merge(Environment::with_prefix("atuin").separator("_"))?;
// all paths should be expanded
- let db_path = s.get_str("local.db_path")?;
+ let db_path = s.get_str("db_path")?;
let db_path = shellexpand::full(db_path.as_str())?;
- s.set("local.db_path", db_path.to_string())?;
+ s.set("db_path", db_path.to_string())?;
- let key_path = s.get_str("local.key_path")?;
+ let key_path = s.get_str("key_path")?;
let key_path = shellexpand::full(key_path.as_str())?;
- s.set("local.key_path", key_path.to_string())?;
+ s.set("key_path", key_path.to_string())?;
- let session_path = s.get_str("local.session_path")?;
+ let session_path = s.get_str("session_path")?;
let session_path = shellexpand::full(session_path.as_str())?;
- s.set("local.session_path", session_path.to_string())?;
+ s.set("session_path", session_path.to_string())?;
// 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.trim())?;
+ s.set("session_token", token.trim())?;
} else {
- s.set("local.session_token", "not logged in")?;
+ s.set("session_token", "not logged in")?;
}
s.try_into()
diff --git a/src/local/sync.rs b/atuin-client/src/sync.rs
index e0feb759..0ca8d3a6 100644
--- a/src/local/sync.rs
+++ b/atuin-client/src/sync.rs
@@ -3,11 +3,12 @@ use std::convert::TryInto;
use chrono::prelude::*;
use eyre::Result;
-use crate::local::api_client;
-use crate::local::database::Database;
-use crate::local::encryption::{encrypt, load_key};
-use crate::settings::{Local, Settings, HISTORY_PAGE_SIZE};
-use crate::{api::AddHistoryRequest, utils::hash_str};
+use atuin_common::{api::AddHistoryRequest, utils::hash_str};
+
+use crate::api_client;
+use crate::database::Database;
+use crate::encryption::{encrypt, load_key};
+use crate::settings::{Settings, HISTORY_PAGE_SIZE};
// Currently sync is kinda naive, and basically just pages backwards through
// history. This means newly added stuff shows up properly! We also just use
@@ -33,7 +34,7 @@ async fn sync_download(
let mut last_sync = if force {
Utc.timestamp_millis(0)
} else {
- Local::last_sync()?
+ Settings::last_sync()?
};
let mut last_timestamp = Utc.timestamp_millis(0);
@@ -124,8 +125,8 @@ async fn sync_upload(
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(),
+ settings.sync_address.as_str(),
+ settings.session_token.as_str(),
load_key(settings)?,
);
@@ -135,7 +136,7 @@ pub async fn sync(settings: &Settings, force: bool, db: &mut (impl Database + Se
debug!("sync downloaded {}", download.0);
- Local::save_sync_time()?;
+ Settings::save_sync_time()?;
Ok(())
}
diff --git a/atuin-common/Cargo.toml b/atuin-common/Cargo.toml
new file mode 100644
index 00000000..efe7da63
--- /dev/null
+++ b/atuin-common/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "atuin-common"
+version = "0.1.0"
+authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
+edition = "2018"
+license = "MIT"
+description = "common library for atuin"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rust-crypto = "^0.2"
+sodiumoxide = "0.2.6"
+chrono = { version = "0.4", features = ["serde"] }
+eyre = "0.6"
+serde_derive = "1.0.125"
+serde = "1.0.125"
+serde_json = "1.0.64"
+rmp-serde = "0.15.4"
+warp = "0.3"
+uuid = { version = "0.8", features = ["v4"] }
diff --git a/src/api.rs b/atuin-common/src/api.rs
index 82ee6604..82ee6604 100644
--- a/src/api.rs
+++ b/atuin-common/src/api.rs
diff --git a/atuin-common/src/lib.rs b/atuin-common/src/lib.rs
new file mode 100644
index 00000000..0a01e10d
--- /dev/null
+++ b/atuin-common/src/lib.rs
@@ -0,0 +1,5 @@
+#[macro_use]
+extern crate serde_derive;
+
+pub mod api;
+pub mod utils;
diff --git a/src/utils.rs b/atuin-common/src/utils.rs
index b395b148..ac5738b3 100644
--- a/src/utils.rs
+++ b/atuin-common/src/utils.rs
@@ -1,6 +1,7 @@
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use sodiumoxide::crypto::pwhash::argon2id13;
+use uuid::Uuid;
pub fn hash_secret(secret: &str) -> String {
sodiumoxide::init().unwrap();
@@ -22,3 +23,7 @@ pub fn hash_str(string: &str) -> String {
hasher.result_str()
}
+
+pub fn uuid_v4() -> String {
+ Uuid::new_v4().to_simple().to_string()
+}
diff --git a/atuin-server/Cargo.toml b/atuin-server/Cargo.toml
new file mode 100644
index 00000000..2cf85d26
--- /dev/null
+++ b/atuin-server/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "atuin-server"
+version = "0.1.0"
+authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
+edition = "2018"
+license = "MIT"
+description = "server library for atuin"
+
+[dependencies]
+atuin-common = { path = "../atuin-common", version = "0.1.0" }
+
+log = "0.4"
+fern = {version = "0.6.0", features = ["colored"] }
+chrono = { version = "0.4", features = ["serde"] }
+eyre = "0.6"
+directories = "3"
+uuid = { version = "0.8", features = ["v4"] }
+indicatif = "0.15.0"
+whoami = "1.1.2"
+chrono-english = "0.1.4"
+config = "0.11"
+serde_derive = "1.0.125"
+serde = "1.0.125"
+serde_json = "1.0.64"
+rmp-serde = "0.15.4"
+unicode-width = "0.1"
+sodiumoxide = "0.2.6"
+reqwest = { version = "0.11", features = ["blocking", "json"] }
+base64 = "0.13.0"
+fork = "0.1.18"
+parse_duration = "2.1.1"
+rand = "0.8.3"
+rust-crypto = "^0.2"
+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"
diff --git a/atuin-server/server.toml b/atuin-server/server.toml
new file mode 100644
index 00000000..808f15f1
--- /dev/null
+++ b/atuin-server/server.toml
@@ -0,0 +1,11 @@
+## host to bind, can also be passed via CLI args
+# host = "127.0.0.1"
+
+## port to bind, can also be passed via CLI args
+# port = 8888
+
+## whether to allow anyone to register an account
+# open_registration = false
+
+## URI for postgres (using development creds here)
+# db_uri="postgres://username:password@localhost/atuin"
diff --git a/src/server/auth.rs b/atuin-server/src/auth.rs
index 52a73108..52a73108 100644
--- a/src/server/auth.rs
+++ b/atuin-server/src/auth.rs
diff --git a/src/server/database.rs b/atuin-server/src/database.rs
index 5945baaf..5945baaf 100644
--- a/src/server/database.rs
+++ b/atuin-server/src/database.rs
diff --git a/src/server/handlers/history.rs b/atuin-server/src/handlers/history.rs
index 4fd6f03f..1aebdde1 100644
--- a/src/server/handlers/history.rs
+++ b/atuin-server/src/handlers/history.rs
@@ -2,11 +2,11 @@ use std::convert::Infallible;
use warp::{http::StatusCode, reply::json};
-use crate::api::{
+use crate::database::Database;
+use crate::models::{NewHistory, User};
+use atuin_common::api::{
AddHistoryRequest, CountResponse, ErrorResponse, SyncHistoryRequest, SyncHistoryResponse,
};
-use crate::server::database::Database;
-use crate::server::models::{NewHistory, User};
pub async fn count(
user: User,
diff --git a/src/server/handlers/mod.rs b/atuin-server/src/handlers/mod.rs
index 3c20538c..3c20538c 100644
--- a/src/server/handlers/mod.rs
+++ b/atuin-server/src/handlers/mod.rs
diff --git a/src/server/handlers/user.rs b/atuin-server/src/handlers/user.rs
index 782d7dbd..6b142cdc 100644
--- a/src/server/handlers/user.rs
+++ b/atuin-server/src/handlers/user.rs
@@ -5,13 +5,14 @@ use uuid::Uuid;
use warp::http::StatusCode;
use warp::reply::json;
-use crate::api::{
+use atuin_common::api::{
ErrorResponse, LoginRequest, LoginResponse, RegisterRequest, RegisterResponse, UserResponse,
};
-use crate::server::database::Database;
-use crate::server::models::{NewSession, NewUser};
+use atuin_common::utils::hash_secret;
+
+use crate::database::Database;
+use crate::models::{NewSession, NewUser};
use crate::settings::Settings;
-use crate::utils::hash_secret;
pub fn verify_str(secret: &str, verify: &str) -> bool {
sodiumoxide::init().unwrap();
@@ -52,7 +53,7 @@ pub async fn register(
settings: Settings,
db: impl Database + Clone + Send + Sync,
) -> Result<Box<dyn warp::Reply>, Infallible> {
- if !settings.server.open_registration {
+ if !settings.open_registration {
return Ok(Box::new(ErrorResponse::reply(
"this server is not open for registrations",
StatusCode::BAD_REQUEST,
diff --git a/src/server/mod.rs b/atuin-server/src/lib.rs
index d5e083df..36b6ffa7 100644
--- a/src/server/mod.rs
+++ b/atuin-server/src/lib.rs
@@ -4,11 +4,18 @@ use eyre::Result;
use crate::settings::Settings;
+#[macro_use]
+extern crate log;
+
+#[macro_use]
+extern crate serde_derive;
+
pub mod auth;
pub mod database;
pub mod handlers;
pub mod models;
pub mod router;
+pub mod settings;
pub async fn launch(settings: &Settings, host: String, port: u16) -> Result<()> {
// routes to run:
diff --git a/src/server/models.rs b/atuin-server/src/models.rs
index fbf1897e..fbf1897e 100644
--- a/src/server/models.rs
+++ b/atuin-server/src/models.rs
diff --git a/src/server/router.rs b/atuin-server/src/router.rs
index ed317ab2..d106068d 100644
--- a/src/server/router.rs
+++ b/atuin-server/src/router.rs
@@ -3,10 +3,12 @@ use std::convert::Infallible;
use eyre::Result;
use warp::Filter;
+use atuin_common::api::SyncHistoryRequest;
+
use super::handlers;
use super::{database::Database, database::Postgres};
-use crate::server::models::User;
-use crate::{api::SyncHistoryRequest, settings::Settings};
+use crate::models::User;
+use crate::settings::Settings;
fn with_settings(
settings: Settings,
@@ -55,7 +57,7 @@ fn with_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 postgres = Postgres::new(settings.db_uri.as_str()).await?;
let index = warp::get().and(warp::path::end()).map(handlers::index);
let count = warp::get()
diff --git a/atuin-server/src/settings.rs b/atuin-server/src/settings.rs
new file mode 100644
index 00000000..596b9018
--- /dev/null
+++ b/atuin-server/src/settings.rs
@@ -0,0 +1,57 @@
+use std::fs::{create_dir_all, File};
+use std::io::prelude::*;
+use std::path::PathBuf;
+
+use config::{Config, Environment, File as ConfigFile};
+use directories::ProjectDirs;
+use eyre::{eyre, Result};
+
+pub const HISTORY_PAGE_SIZE: i64 = 100;
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Settings {
+ pub host: String,
+ pub port: u16,
+ pub db_uri: String,
+ pub open_registration: bool,
+}
+
+impl Settings {
+ pub fn new() -> Result<Self> {
+ let config_dir = ProjectDirs::from("com", "elliehuxtable", "atuin").unwrap();
+ let config_dir = config_dir.config_dir();
+
+ create_dir_all(config_dir)?;
+
+ let config_file = if let Ok(p) = std::env::var("ATUIN_CONFIG") {
+ PathBuf::from(p)
+ } else {
+ let mut config_file = PathBuf::new();
+ config_file.push(config_dir);
+ config_file.push("server.toml");
+ config_file
+ };
+
+ // create the config file if it does not exist
+
+ let mut s = Config::new();
+
+ if config_file.exists() {
+ s.merge(ConfigFile::with_name(config_file.to_str().unwrap()))?;
+ } else {
+ let example_config = include_bytes!("../server.toml");
+ let mut file = File::create(config_file)?;
+ file.write_all(example_config)?;
+ }
+
+ s.set_default("host", "127.0.0.1")?;
+ s.set_default("port", 8888)?;
+ s.set_default("open_registration", false)?;
+ s.set_default("db_uri", "default_uri")?;
+
+ s.merge(Environment::with_prefix("atuin").separator("_"))?;
+
+ s.try_into()
+ .map_err(|e| eyre!("failed to deserialize: {}", e))
+ }
+}
diff --git a/src/command/history.rs b/src/command/history.rs
index 627efae4..2b691bac 100644
--- a/src/command/history.rs
+++ b/src/command/history.rs
@@ -4,10 +4,10 @@ use eyre::Result;
use fork::{fork, Fork};
use structopt::StructOpt;
-use crate::local::database::Database;
-use crate::local::history::History;
-use crate::local::sync;
-use crate::settings::Settings;
+use atuin_client::database::Database;
+use atuin_client::history::History;
+use atuin_client::settings::Settings;
+use atuin_client::sync;
#[derive(StructOpt)]
pub enum Cmd {
@@ -79,7 +79,7 @@ impl Cmd {
db.update(&h)?;
- if settings.local.should_sync()? {
+ if settings.should_sync()? {
match fork() {
Ok(Fork::Parent(child)) => {
debug!("launched sync background process with PID {}", child);
diff --git a/src/command/import.rs b/src/command/import.rs
index ae927aaf..56fb30a7 100644
--- a/src/command/import.rs
+++ b/src/command/import.rs
@@ -5,9 +5,9 @@ use directories::UserDirs;
use eyre::{eyre, Result};
use structopt::StructOpt;
-use crate::local::database::Database;
-use crate::local::history::History;
-use crate::local::import::Zsh;
+use atuin_client::database::Database;
+use atuin_client::history::History;
+use atuin_client::import::Zsh;
use indicatif::ProgressBar;
#[derive(StructOpt)]
diff --git a/src/command/login.rs b/src/command/login.rs
index 636ac0d3..eaeb297f 100644
--- a/src/command/login.rs
+++ b/src/command/login.rs
@@ -5,7 +5,7 @@ use std::io::prelude::*;
use eyre::{eyre, Result};
use structopt::StructOpt;
-use crate::settings::Settings;
+use atuin_client::settings::Settings;
#[derive(StructOpt)]
#[structopt(setting(structopt::clap::AppSettings::DeriveDisplayOrder))]
@@ -26,7 +26,7 @@ impl Cmd {
map.insert("username", self.username.clone());
map.insert("password", self.password.clone());
- let url = format!("{}/login", settings.local.sync_address);
+ let url = format!("{}/login", settings.sync_address);
let client = reqwest::blocking::Client::new();
let resp = client.post(url).json(&map).send()?;
@@ -38,11 +38,11 @@ impl Cmd {
let session = resp.json::<HashMap<String, String>>()?;
let session = session["session"].clone();
- let session_path = settings.local.session_path.as_str();
+ let session_path = settings.session_path.as_str();
let mut file = File::create(session_path)?;
file.write_all(session.as_bytes())?;
- let key_path = settings.local.key_path.as_str();
+ let key_path = settings.key_path.as_str();
let mut file = File::create(key_path)?;
file.write_all(&base64::decode(self.key.clone())?)?;
diff --git a/src/command/mod.rs b/src/command/mod.rs
index cd857e9f..6fd52613 100644
--- a/src/command/mod.rs
+++ b/src/command/mod.rs
@@ -1,9 +1,12 @@
+use std::path::PathBuf;
+
use eyre::Result;
use structopt::StructOpt;
-use uuid::Uuid;
-use crate::local::database::Database;
-use crate::settings::Settings;
+use atuin_client::database::Sqlite;
+use atuin_client::settings::Settings as ClientSettings;
+use atuin_common::utils::uuid_v4;
+use atuin_server::settings::Settings as ServerSettings;
mod event;
mod history;
@@ -58,30 +61,33 @@ pub enum AtuinCmd {
Key,
}
-pub fn uuid_v4() -> String {
- Uuid::new_v4().to_simple().to_string()
-}
-
impl AtuinCmd {
- pub async fn run<T: Database + Send>(self, db: &mut T, settings: &Settings) -> Result<()> {
+ pub async fn run(self) -> Result<()> {
+ let client_settings = ClientSettings::new()?;
+ let server_settings = ServerSettings::new()?;
+
+ let db_path = PathBuf::from(client_settings.db_path.as_str());
+
+ let mut db = Sqlite::new(db_path)?;
+
match self {
- Self::History(history) => history.run(settings, db).await,
- Self::Import(import) => import.run(db),
- Self::Server(server) => server.run(settings).await,
- Self::Stats(stats) => stats.run(db, settings),
+ Self::History(history) => history.run(&client_settings, &mut db).await,
+ Self::Import(import) => import.run(&mut db),
+ Self::Server(server) => server.run(&server_settings).await,
+ Self::Stats(stats) => stats.run(&mut db, &client_settings),
Self::Init => init::init(),
- Self::Search { query } => search::run(&query, db),
+ Self::Search { query } => search::run(&query, &mut db),
- Self::Sync { force } => sync::run(settings, force, db).await,
- Self::Login(l) => l.run(settings),
+ Self::Sync { force } => sync::run(&client_settings, force, &mut db).await,
+ Self::Login(l) => l.run(&client_settings),
Self::Register(r) => register::run(
- settings,
+ &client_settings,
r.username.as_str(),
r.email.as_str(),
r.password.as_str(),
),
Self::Key => {
- let key = std::fs::read(settings.local.key_path.as_str())?;
+ let key = std::fs::read(client_settings.key_path.as_str())?;
println!("{}", base64::encode(key));
Ok(())
}
diff --git a/src/command/register.rs b/src/command/register.rs
index 62bbeaeb..1126645a 100644
--- a/src/command/register.rs
+++ b/src/command/register.rs
@@ -5,7 +5,7 @@ use std::io::prelude::*;
use eyre::{eyre, Result};
use structopt::StructOpt;
-use crate::settings::Settings;
+use atuin_client::settings::Settings;
#[derive(StructOpt)]
#[structopt(setting(structopt::clap::AppSettings::DeriveDisplayOrder))]
@@ -26,7 +26,7 @@ pub fn run(settings: &Settings, username: &str, email: &str, password: &str) ->
map.insert("email", email);
map.insert("password", password);
- let url = format!("{}/user/{}", settings.local.sync_address, username);
+ let url = format!("{}/user/{}", settings.sync_address, username);
let resp = reqwest::blocking::get(url)?;
if resp.status().is_success() {
@@ -34,7 +34,7 @@ pub fn run(settings: &Settings, username: &str, email: &str, password: &str) ->
return Ok(());
}
- let url = format!("{}/register", settings.local.sync_address);
+ let url = format!("{}/register", settings.sync_address);
let client = reqwest::blocking::Client::new();
let resp = client.post(url).json(&map).send()?;
@@ -46,7 +46,7 @@ pub fn run(settings: &Settings, username: &str, email: &str, password: &str) ->
let session = resp.json::<HashMap<String, String>>()?;
let session = session["session"].clone();
- let path = settings.local.session_path.as_str();
+ let path = settings.session_path.as_str();
let mut file = File::create(path)?;
file.write_all(session.as_bytes())?;
diff --git a/src/command/search.rs b/src/command/search.rs
index d7b477da..773c112f 100644
--- a/src/command/search.rs
+++ b/src/command/search.rs
@@ -14,9 +14,10 @@ use tui::{
};
use unicode_width::UnicodeWidthStr;
+use atuin_client::database::Database;
+use atuin_client::history::History;
+
use crate::command::event::{Event, Events};
-use crate::local::database::Database;
-use crate::local::history::History;
const VERSION: &str = env!("CARGO_PKG_VERSION");
diff --git a/src/command/server.rs b/src/command/server.rs
index a7835092..2fcf23d6 100644
--- a/src/command/server.rs
+++ b/src/command/server.rs
@@ -1,8 +1,8 @@
use eyre::Result;
use structopt::StructOpt;
-use crate::server;
-use crate::settings::Settings;
+use atuin_server::launch;
+use atuin_server::settings::Settings;
#[derive(StructOpt)]
pub enum Cmd {
@@ -23,13 +23,12 @@ impl Cmd {
pub async fn run(&self, settings: &Settings) -> Result<()> {
match self {
Self::Start { host, port } => {
- let host = host.as_ref().map_or(
- settings.server.host.clone(),
- std::string::ToString::to_string,
- );
- let port = port.map_or(settings.server.port, |p| p);
+ let host = host
+ .as_ref()
+ .map_or(settings.host.clone(), std::string::ToString::to_string);
+ let port = port.map_or(settings.port, |p| p);
- server::launch(settings, host, port).await
+ launch(settings, host, port).await
}
}
}
diff --git a/src/command/stats.rs b/src/command/stats.rs
index 694484bc..0da303d7 100644
--- a/src/command/stats.rs
+++ b/src/command/stats.rs
@@ -8,9 +8,9 @@ use cli_table::{format::Justify, print_stdout, Cell, Style, Table};
use eyre::{eyre, Result};
use structopt::StructOpt;
-use crate::local::database::Database;
-use crate::local::history::History;
-use crate::settings::Settings;
+use atuin_client::database::Database;
+use atuin_client::history::History;
+use atuin_client::settings::Settings;
#[derive(StructOpt)]
pub enum Cmd {
@@ -80,7 +80,7 @@ impl Cmd {
words.join(" ")
};
- let start = match settings.local.dialect.to_lowercase().as_str() {
+ let start = match settings.dialect.to_lowercase().as_str() {
"uk" => parse_date_string(&words, Local::now(), Dialect::Uk)?,
_ => parse_date_string(&words, Local::now(), Dialect::Us)?,
};
diff --git a/src/command/sync.rs b/src/command/sync.rs
index 88217b3c..d70b554f 100644
--- a/src/command/sync.rs
+++ b/src/command/sync.rs
@@ -1,8 +1,8 @@
use eyre::Result;
-use crate::local::database::Database;
-use crate::local::sync;
-use crate::settings::Settings;
+use atuin_client::database::Database;
+use atuin_client::settings::Settings;
+use atuin_client::sync;
pub async fn run(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> {
sync::sync(settings, force, db).await?;
diff --git a/src/main.rs b/src/main.rs
index 0045a943..c116d1f3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,29 +1,16 @@
#![warn(clippy::pedantic, clippy::nursery)]
#![allow(clippy::use_self)] // not 100% reliable
-use std::path::PathBuf;
-
-use eyre::{eyre, Result};
+use eyre::Result;
use fern::colors::{Color, ColoredLevelConfig};
-use human_panic::setup_panic;
use structopt::{clap::AppSettings, StructOpt};
#[macro_use]
extern crate log;
-#[macro_use]
-extern crate serde_derive;
-
use command::AtuinCmd;
-use local::database::Sqlite;
-use settings::Settings;
-mod api;
mod command;
-mod local;
-mod server;
-mod settings;
-mod utils;
#[derive(StructOpt)]
#[structopt(
@@ -33,28 +20,13 @@ mod utils;
global_settings(&[AppSettings::ColoredHelp, AppSettings::DeriveDisplayOrder])
)]
struct Atuin {
- #[structopt(long, parse(from_os_str), help = "db file path")]
- db: Option<PathBuf>,
-
#[structopt(subcommand)]
atuin: AtuinCmd,
}
impl Atuin {
- async fn run(self, settings: &Settings) -> Result<()> {
- let db_path = if let Some(db_path) = self.db {
- let path = db_path
- .to_str()
- .ok_or_else(|| eyre!("path {:?} was not valid UTF-8", db_path))?;
- let path = shellexpand::full(path)?;
- PathBuf::from(path.as_ref())
- } else {
- PathBuf::from(settings.local.db_path.as_str())
- };
-
- let mut db = Sqlite::new(db_path)?;
-
- self.atuin.run(&mut db, settings).await
+ async fn run(self) -> Result<()> {
+ self.atuin.run().await
}
}
@@ -78,8 +50,5 @@ async fn main() -> Result<()> {
.chain(std::io::stdout())
.apply()?;
- let settings = Settings::new()?;
- setup_panic!();
-
- Atuin::from_args().run(&settings).await
+ Atuin::from_args().run().await
}