summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEllie Huxtable <e@elm.sh>2021-04-20 17:07:11 +0100
committerGitHub <noreply@github.com>2021-04-20 16:07:11 +0000
commit34888827f8a06de835cbe5833a06914f28cce514 (patch)
tree8b56f20e50065cd2c222d5e8e067ec55cf1947a1 /src
parentf6de558070c4ed4dbecf4bbbf4693e396a5577dc (diff)
Switch to Warp + SQLx, use async, switch to Rust stable (#36)
* Switch to warp + sql, use async and stable rust * Update CI to use stable
Diffstat (limited to 'src')
-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
27 files changed, 832 insertions, 466 deletions
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 mo