2022-08-14 20:27:41 +00:00
|
|
|
#![cfg_attr(
|
2022-12-14 05:50:34 +00:00
|
|
|
all(not(debug_assertions), target_os = "windows"),
|
|
|
|
windows_subsystem = "windows"
|
2022-08-14 20:27:41 +00:00
|
|
|
)]
|
2023-04-28 21:33:04 +00:00
|
|
|
use std::error::Error;
|
2022-08-14 20:27:41 +00:00
|
|
|
|
2023-04-30 17:52:46 +00:00
|
|
|
use once_cell::sync::OnceCell;
|
2023-04-28 21:33:04 +00:00
|
|
|
use sqlx::{
|
|
|
|
SqlitePool,
|
|
|
|
sqlite::SqlitePoolOptions,
|
|
|
|
sqlite::SqliteConnectOptions,
|
|
|
|
};
|
|
|
|
use tauri::{
|
|
|
|
App,
|
|
|
|
AppHandle,
|
|
|
|
Manager,
|
|
|
|
async_runtime as rt,
|
|
|
|
};
|
2022-11-28 06:03:15 +00:00
|
|
|
|
2022-12-21 21:42:12 +00:00
|
|
|
mod config;
|
2022-11-29 00:16:33 +00:00
|
|
|
mod errors;
|
2022-12-04 05:47:09 +00:00
|
|
|
mod clientinfo;
|
2022-11-29 00:16:33 +00:00
|
|
|
mod ipc;
|
|
|
|
mod state;
|
|
|
|
mod server;
|
2022-12-21 22:49:01 +00:00
|
|
|
mod tray;
|
2022-08-14 20:27:41 +00:00
|
|
|
|
2023-04-28 21:33:04 +00:00
|
|
|
use config::AppConfig;
|
|
|
|
use server::Server;
|
|
|
|
use errors::*;
|
2022-12-21 21:42:12 +00:00
|
|
|
use state::AppState;
|
|
|
|
|
2022-08-14 20:27:41 +00:00
|
|
|
|
2022-12-23 00:36:32 +00:00
|
|
|
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
|
|
|
|
2022-12-14 05:50:34 +00:00
|
|
|
|
2023-04-28 21:33:04 +00:00
|
|
|
async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
|
|
|
|
APP.set(app.handle()).unwrap();
|
|
|
|
|
|
|
|
let conn_opts = SqliteConnectOptions::new()
|
2023-04-29 05:34:17 +00:00
|
|
|
.filename(config::get_or_create_db_path()?)
|
2023-04-28 21:33:04 +00:00
|
|
|
.create_if_missing(true);
|
|
|
|
let pool_opts = SqlitePoolOptions::new();
|
|
|
|
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
|
|
|
|
sqlx::migrate!().run(&pool).await?;
|
|
|
|
|
|
|
|
let conf = AppConfig::load(&pool).await?;
|
|
|
|
let session = AppState::load_creds(&pool).await?;
|
|
|
|
let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
|
|
|
|
|
|
|
|
config::set_auto_launch(conf.start_on_login)?;
|
|
|
|
if !conf.start_minimized {
|
|
|
|
app.get_window("main")
|
|
|
|
.ok_or(RequestError::NoMainWindow)?
|
|
|
|
.show()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let state = AppState::new(conf, session, srv, pool);
|
|
|
|
app.manage(state);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-30 17:52:46 +00:00
|
|
|
fn run() -> tauri::Result<()> {
|
2022-12-14 05:50:34 +00:00
|
|
|
tauri::Builder::default()
|
2023-04-30 21:10:21 +00:00
|
|
|
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
|
|
|
|
app.get_window("main")
|
|
|
|
.map(|w| w.show().error_popup("Failed to show main window"));
|
|
|
|
}))
|
2022-12-21 22:49:01 +00:00
|
|
|
.system_tray(tray::create())
|
|
|
|
.on_system_tray_event(tray::handle_event)
|
2022-12-14 05:50:34 +00:00
|
|
|
.invoke_handler(tauri::generate_handler![
|
|
|
|
ipc::unlock,
|
|
|
|
ipc::respond,
|
|
|
|
ipc::get_session_status,
|
|
|
|
ipc::save_credentials,
|
2022-12-23 00:36:32 +00:00
|
|
|
ipc::get_config,
|
2023-04-26 05:10:14 +00:00
|
|
|
ipc::save_config,
|
2022-12-14 05:50:34 +00:00
|
|
|
])
|
2023-04-28 21:33:04 +00:00
|
|
|
.setup(|app| rt::block_on(setup(app)))
|
2023-04-30 17:52:46 +00:00
|
|
|
.build(tauri::generate_context!())?
|
2022-12-21 22:49:01 +00:00
|
|
|
.run(|app, run_event| match run_event {
|
|
|
|
tauri::RunEvent::WindowEvent { label, event, .. } => match event {
|
|
|
|
tauri::WindowEvent::CloseRequested { api, .. } => {
|
|
|
|
let _ = app.get_window(&label).map(|w| w.hide());
|
|
|
|
api.prevent_close();
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
_ => ()
|
2023-04-30 17:52:46 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
2023-04-30 21:10:21 +00:00
|
|
|
run().error_popup("Creddy failed to start");
|
2022-12-23 00:36:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! get_state {
|
|
|
|
($prop:ident as $name:ident) => {
|
|
|
|
use tauri::Manager;
|
|
|
|
let app = crate::APP.get().unwrap(); // as long as the app is running, this is fine
|
|
|
|
let state = app.state::<crate::state::AppState>();
|
|
|
|
let $name = state.$prop.read().unwrap(); // only panics if another thread has already panicked
|
|
|
|
};
|
|
|
|
(config.$prop:ident as $name:ident) => {
|
|
|
|
use tauri::Manager;
|
|
|
|
let app = crate::APP.get().unwrap();
|
|
|
|
let state = app.state::<crate::state::AppState>();
|
|
|
|
let config = state.config.read().unwrap();
|
|
|
|
let $name = config.$prop;
|
|
|
|
};
|
|
|
|
|
|
|
|
(mut $prop:ident as $name:ident) => {
|
|
|
|
use tauri::Manager;
|
|
|
|
let app = crate::APP.get().unwrap();
|
|
|
|
let state = app.state::<crate::state::AppState>();
|
|
|
|
let $name = state.$prop.write().unwrap();
|
|
|
|
};
|
|
|
|
(mut config.$prop:ident as $name:ident) => {
|
|
|
|
use tauri::Manager;
|
|
|
|
let app = crate::APP.get().unwrap();
|
|
|
|
let state = app.state::<crate::state::AppState>();
|
|
|
|
let config = state.config.write().unwrap();
|
|
|
|
let $name = config.$prop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) use get_state;
|