aboutsummaryrefslogtreecommitdiffstats
path: root/src/settings.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings.rs')
-rw-r--r--src/settings.rs131
1 files changed, 110 insertions, 21 deletions
diff --git a/src/settings.rs b/src/settings.rs
index 0e554bed..dcf69a7c 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -1,31 +1,90 @@
-use std::path::PathBuf;
+use std::fs::{create_dir_all, File};
+use std::io::prelude::*;
+use std::path::{Path, PathBuf};
-use config::{Config, File};
+use chrono::prelude::*;
+use chrono::Utc;
+use config::{Config, File as ConfigFile};
use directories::ProjectDirs;
use eyre::{eyre, Result};
-use std::fs;
+use parse_duration::parse;
-#[derive(Debug, Deserialize)]
+pub const HISTORY_PAGE_SIZE: i64 = 100;
+
+#[derive(Clone, Debug, Deserialize)]
pub struct Local {
pub dialect: String,
- pub sync: bool,
+ pub auto_sync: bool,
pub sync_address: String,
pub sync_frequency: String,
pub db_path: String,
+ pub key_path: String,
+ pub session_path: String,
+
+ // This is automatically loaded when settings is created. Do not set in
+ // config! Keep secrets and settings apart.
+ pub session_token: String,
}
-#[derive(Debug, Deserialize)]
-pub struct Remote {
+impl Local {
+ 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"))?;
+ let sync_time_path = sync_time_path.data_dir().join("last_sync_time");
+
+ std::fs::write(sync_time_path, Utc::now().to_rfc3339())?;
+
+ Ok(())
+ }
+
+ pub fn last_sync() -> Result<chrono::DateTime<Utc>> {
+ let sync_time_path = ProjectDirs::from("com", "elliehuxtable", "atuin");
+
+ if sync_time_path.is_none() {
+ debug!("failed to load projectdirs, not syncing");
+ return Err(eyre!("could not load project dirs"));
+ }
+
+ let sync_time_path = sync_time_path.unwrap();
+ let sync_time_path = sync_time_path.data_dir().join("last_sync_time");
+
+ if !sync_time_path.exists() {
+ return Ok(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0));
+ }
+
+ let time = std::fs::read_to_string(sync_time_path)?;
+ let time = chrono::DateTime::parse_from_rfc3339(time.as_str())?;
+
+ Ok(time.with_timezone(&Utc))
+ }
+
+ pub fn should_sync(&self) -> Result<bool> {
+ if !self.auto_sync {
+ return Ok(false);
+ }
+
+ match parse(self.sync_frequency.as_str()) {
+ Ok(d) => {
+ let d = chrono::Duration::from_std(d).unwrap();
+ Ok(Utc::now() - Local::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(Debug, Deserialize)]
+#[derive(Clone, Debug, Deserialize)]
pub struct Settings {
pub local: Local,
- pub remote: Remote,
+ pub server: Server,
}
impl Settings {
@@ -33,7 +92,7 @@ impl Settings {
let config_dir = ProjectDirs::from("com", "elliehuxtable", "atuin").unwrap();
let config_dir = config_dir.config_dir();
- fs::create_dir_all(config_dir)?;
+ create_dir_all(config_dir)?;
let mut config_file = PathBuf::new();
config_file.push(config_dir);
@@ -45,31 +104,61 @@ impl Settings {
let mut s = Config::new();
let db_path = ProjectDirs::from("com", "elliehuxtable", "atuin")
- .ok_or_else(|| {
- eyre!("could not determine db file location\nspecify one using the --db flag")
- })?
+ .ok_or_else(|| eyre!("could not determine db file location"))?
.data_dir()
.join("history.db");
+ let key_path = ProjectDirs::from("com", "elliehuxtable", "atuin")
+ .ok_or_else(|| eyre!("could not determine key file location"))?
+ .data_dir()
+ .join("key");
+
+ let session_path = ProjectDirs::from("com", "elliehuxtable", "atuin")
+ .ok_or_else(|| eyre!("could not determine session file location"))?
+ .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.sync", false)?;
+ s.set_default("local.auto_sync", true)?;
s.set_default("local.sync_frequency", "5m")?;
- s.set_default("local.sync_address", "https://atuin.ellie.wtf")?;
+ s.set_default("local.sync_address", "https://api.atuin.sh")?;
- s.set_default("remote.host", "127.0.0.1")?;
- s.set_default("remote.port", 8888)?;
- s.set_default("remote.open_registration", false)?;
- s.set_default("remote.db_uri", "please set a postgres url")?;
+ 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", "please set a postgres url")?;
if config_file.exists() {
- s.merge(File::with_name(config_file.to_str().unwrap()))?;
+ s.merge(ConfigFile::with_name(config_file.to_str().unwrap()))?;
+ } else {
+ let example_config = include_bytes!("../config.toml");
+ let mut file = File::create(config_file)?;
+ file.write_all(example_config)?;
}
// all paths should be expanded
let db_path = s.get_str("local.db_path")?;
let db_path = shellexpand::full(db_path.as_str())?;
- s.set("local.db.path", db_path.to_string())?;
+ s.set("local.db_path", db_path.to_string())?;
+
+ let key_path = s.get_str("local.key_path")?;
+ let key_path = shellexpand::full(key_path.as_str())?;
+ s.set("local.key_path", key_path.to_string())?;
+
+ let session_path = s.get_str("local.session_path")?;
+ let session_path = shellexpand::full(session_path.as_str())?;
+ s.set("local.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)?;
+ } else {
+ s.set("local.session_token", "not logged in")?;
+ }
s.try_into()
.map_err(|e| eyre!("failed to deserialize: {}", e))