Add *very* basic login flow
This commit is contained in:
@@ -15,6 +15,8 @@ use either::Either;
|
||||
use futures::{FutureExt, future::WeakShared};
|
||||
use tokio::{fs, task::JoinHandle};
|
||||
|
||||
use crate::xdg::BASE_DIRECTORIES;
|
||||
|
||||
pub trait Fetcher<V>: Send + Sync + 'static {
|
||||
type Key: ToString + FromStr;
|
||||
|
||||
@@ -86,9 +88,8 @@ where
|
||||
serialize: fn(&K, &V) -> Vec<u8>,
|
||||
deserialize: fn(&K, &[u8]) -> anyhow::Result<V>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let crate_name = env!("CARGO_CRATE_NAME");
|
||||
let data_dir = xdg::BaseDirectories::new()
|
||||
.create_cache_directory(format!("{crate_name}/thumbnails"))
|
||||
let data_dir = BASE_DIRECTORIES
|
||||
.create_cache_directory("thumbnails")
|
||||
.context(anyhow!(
|
||||
"Failed to create XDG data folder for {cache_name:?}"
|
||||
))?;
|
||||
|
||||
46
src/config.rs
Normal file
46
src/config.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs;
|
||||
|
||||
use crate::xdg::BASE_DIRECTORIES;
|
||||
|
||||
const CONFIG_FILE: &str = "config.toml";
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub immich: Option<ImmichLogin>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ImmichLogin {
|
||||
pub url: String,
|
||||
pub api_key: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub async fn load() -> anyhow::Result<Self> {
|
||||
let Some(config_path) = BASE_DIRECTORIES.get_config_file(CONFIG_FILE) else {
|
||||
bail!("No config file exists")
|
||||
};
|
||||
|
||||
let config = fs::read_to_string(&config_path)
|
||||
.await
|
||||
.context(anyhow!("Failed to read config file at {config_path:?}"))?;
|
||||
|
||||
toml::from_str(&config).context(anyhow!(
|
||||
"Failed to deserialize config file at {config_path:?}"
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn save(&self) -> anyhow::Result<()> {
|
||||
let config_path = BASE_DIRECTORIES
|
||||
.place_config_file(CONFIG_FILE)
|
||||
.context(anyhow!("Failed to create config folder"))?;
|
||||
|
||||
let config = toml::to_string_pretty(self)?;
|
||||
|
||||
fs::write(&config_path, config)
|
||||
.await
|
||||
.context(anyhow!("Failed to write config file to {config_path:?}"))
|
||||
}
|
||||
}
|
||||
70
src/main.rs
70
src/main.rs
@@ -13,6 +13,7 @@ use tracing::Level;
|
||||
|
||||
use crate::{
|
||||
api::{Api, TimeBucketKey},
|
||||
config::Config,
|
||||
ui::{AppWindow, ImageBucket},
|
||||
};
|
||||
|
||||
@@ -20,22 +21,20 @@ use crate::{
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
|
||||
|
||||
mod api;
|
||||
pub mod api;
|
||||
pub mod cachemap;
|
||||
mod thumbhash;
|
||||
pub mod config;
|
||||
pub mod thumbhash;
|
||||
pub mod xdg;
|
||||
|
||||
pub const CRATE_NAME: &str = env!("CARGO_CRATE_NAME");
|
||||
|
||||
mod ui {
|
||||
slint::include_modules!();
|
||||
}
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
struct Opt {
|
||||
#[clap(long, env = "IMMICH_BASE_URL")]
|
||||
pub immich_base_url: String,
|
||||
|
||||
#[clap(long, env = "IMMICH_API_KEY")]
|
||||
pub immich_api_key: String,
|
||||
}
|
||||
struct Opt {}
|
||||
|
||||
// enum ApiReq<M: Send + 'static>
|
||||
// where
|
||||
@@ -59,7 +58,7 @@ struct Opt {
|
||||
// }
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let opt = Opt::parse();
|
||||
let _opt = Opt::parse();
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(Level::DEBUG)
|
||||
@@ -68,12 +67,53 @@ fn main() -> anyhow::Result<()> {
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let _rt_guard = runtime.enter();
|
||||
|
||||
let immich_config =
|
||||
immich_sdk::Config::new(opt.immich_base_url).with_api_key(opt.immich_api_key);
|
||||
let api_ = Api::new(immich_sdk::Client::new(immich_config).unwrap());
|
||||
let config_ = runtime
|
||||
.block_on(Config::load())
|
||||
.inspect_err(|e| tracing::debug!("{e}"))
|
||||
.map(Arc::new)
|
||||
.unwrap_or_default();
|
||||
|
||||
let app = ui::AppWindow::new()?;
|
||||
let global = app.global::<ui::Global>();
|
||||
|
||||
let config = Arc::clone(&config_);
|
||||
let app_weak = app.as_weak();
|
||||
global.on_login_api_key(move |url, api_key| {
|
||||
tracing::debug!("url: {url}, api_key: {api_key}");
|
||||
|
||||
let mut config = config.as_ref().clone();
|
||||
let immich_config = config::ImmichLogin {
|
||||
url: url.to_string(),
|
||||
api_key: api_key.to_string(),
|
||||
};
|
||||
config.immich = Some(immich_config.clone());
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = config.save().await {
|
||||
tracing::error!("{e}");
|
||||
}
|
||||
});
|
||||
|
||||
let _ = app_weak.upgrade_in_event_loop(move |app| {
|
||||
start_api(&app, &immich_config);
|
||||
});
|
||||
});
|
||||
|
||||
if let Some(immich) = &config_.immich {
|
||||
start_api(&app, immich);
|
||||
}
|
||||
|
||||
app.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_api(app: &AppWindow, immich: &config::ImmichLogin) {
|
||||
let immich_config = immich_sdk::Config::new(&immich.url).with_api_key(&immich.api_key);
|
||||
let api_ = Api::new(immich_sdk::Client::new(immich_config).unwrap());
|
||||
|
||||
let global = app.global::<ui::Global>();
|
||||
global.set_logged_in(true);
|
||||
global.set_image_buckets(ModelRc::new(VecModel::default()));
|
||||
|
||||
let app_weak = app.as_weak();
|
||||
@@ -130,10 +170,6 @@ fn main() -> anyhow::Result<()> {
|
||||
calculate_timeline_visibility(&app, api, scroll);
|
||||
});
|
||||
});
|
||||
|
||||
app.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_timeline_visibility(app: &AppWindow, api: Arc<Api>, scroll: f32) {
|
||||
|
||||
8
src/xdg.rs
Normal file
8
src/xdg.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use crate::CRATE_NAME;
|
||||
|
||||
pub static BASE_DIRECTORIES: LazyLock<BaseDirectories> =
|
||||
LazyLock::new(|| BaseDirectories::with_prefix(CRATE_NAME));
|
||||
Reference in New Issue
Block a user