cathode/src-tauri/src/main.rs

231 lines
7.0 KiB
Rust

#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use std::{
path::{Path, PathBuf},
sync::{Arc, Mutex},
thread::sleep,
time::Duration,
};
use audio::monitor;
use fs::WebRay;
use log::{debug, error, trace, warn};
use serde_json::Value;
use tauri::{
api::path::{cache_dir, config_dir},
Manager,
State, //, WindowEvent,
};
use crate::config::Config;
mod audio;
mod config;
mod fs;
const MIC_THRESHOLD: f32 = 0.5f32;
struct MicThreshold(Arc<Mutex<f32>>);
struct AudioLevel(Arc<Mutex<f32>>);
struct BlinkInterval(Arc<Mutex<u64>>);
struct CurrentConfig(Arc<Mutex<Config>>);
struct RayToLoad(Arc<Mutex<Option<PathBuf>>>);
struct MicSense(Arc<Mutex<f32>>);
fn main() {
env_logger::init();
let threshold = Arc::new(Mutex::new(MIC_THRESHOLD));
let level = Arc::new(Mutex::new(0.));
let blink_interval = Arc::new(Mutex::new(1500));
let ray = Arc::new(Mutex::new(None));
let sens = Arc::new(Mutex::new(1.0));
if let Some(d) = cache_dir() {
use std::fs;
if let Ok(s) = fs::read_to_string(d.join("cathode").join("last_selected")) {
debug!("Found selected ray in cache");
*ray.lock().unwrap() = Some(Path::new(&s).to_path_buf());
}
}
// Create the config directory if needed
let config = config::load_config();
{
*blink_interval.lock().unwrap() = config.blink_interval;
*sens.lock().unwrap() = config.mic_sens;
}
let current_conf = Arc::new(Mutex::new(config));
let config = current_conf.clone();
// let c2 = current_conf.clone();
tauri::Builder::default()
.manage(MicThreshold(threshold.clone()))
.manage(AudioLevel(level.clone()))
.manage(BlinkInterval(blink_interval.clone()))
.manage(CurrentConfig(current_conf.clone()))
.manage(RayToLoad(ray.clone()))
.manage(MicSense(sens.clone()))
// .on_window_event(move |event| match event.event() {
// WindowEvent::CloseRequested { .. } => {
// debug!("close requested");
// if let Err(e) = config::save_config(&*c2.lock().unwrap()) {
// error!("Error writing config file: {}", e);
// }
// }
// _ => {}
// })
.setup(move |app| {
let window = app.get_window("main").unwrap();
tauri::async_runtime::spawn(async move {
monitor(window, threshold, level, sens).await;
});
let window = app.get_window("main").unwrap();
tauri::async_runtime::spawn(async move {
loop {
if rand::random() {
trace!("Blinking");
if let Some(e) = window.emit_all("blink", "").err() {
warn!("Failed to emit blink event: {}", e);
}
}
let blink = blink_interval.lock().unwrap();
sleep(Duration::from_millis(*blink));
}
});
let window = app.get_window("main").unwrap();
tauri::async_runtime::spawn(async move {
use notify::{event::AccessKind, Event, EventKind, RecursiveMode, Result, Watcher};
if let Some(path) = config_dir() {
let mut watcher =
notify::recommended_watcher(move |res: Result<Event>| match res {
Ok(event) => {
if let EventKind::Access(AccessKind::Close(_)) = event.kind {
*config.lock().unwrap() = config::load_config();
window.emit_all("reload-config", "").unwrap();
}
}
Err(e) => error!("error watching filesystem {:?}", e),
})
.unwrap();
watcher
.watch(
&path.join("cathode").join("config.toml"),
RecursiveMode::NonRecursive,
)
.unwrap();
loop {
sleep(Duration::from_millis(5000));
}
}
});
match app.get_cli_matches() {
Ok(matches) => {
trace!("matches OK");
if let Some(arg) = matches.args.get("file") {
trace!("CLI arg value: {:?}", arg);
if let Value::String(path) = arg.value.clone() {
*ray.lock().unwrap() = Some(PathBuf::from(path));
}
}
}
Err(e) => eprintln!("{}", e),
}
Ok(())
})
.invoke_handler(tauri::generate_handler![
log,
set_mic_threshold,
get_mic_threshold,
set_mic_sens,
get_mic_sens,
get_audio_level,
get_blink_interval,
set_blink_interval,
get_config,
set_config,
save_current_config,
get_ray_to_load,
fs::open_image,
fs::save_ray,
fs::open_ray,
audio::get_devices,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::command]
fn get_ray_to_load(ray: State<'_, RayToLoad>) -> Option<WebRay> {
let ray = { (*ray.0.lock().unwrap()).clone() };
if let Some(r) = ray {
let ray = fs::load_ray(r);
ray
} else {
None
}
}
#[tauri::command]
fn log(msg: String) {
debug!("frontend: {}", msg);
}
#[tauri::command]
fn set_mic_threshold(threshold: f32, current: State<'_, MicThreshold>) {
*current.0.lock().unwrap() = threshold;
}
#[tauri::command]
fn get_mic_threshold(current: State<'_, MicThreshold>) -> f32 {
*current.0.lock().unwrap()
}
#[tauri::command]
fn set_mic_sens(sens: f32, current: State<'_, MicSense>) {
*current.0.lock().unwrap() = sens;
}
#[tauri::command]
fn get_mic_sens(current: State<'_, MicSense>) -> f32 {
*current.0.lock().unwrap()
}
#[tauri::command]
fn get_audio_level(level: State<'_, AudioLevel>) -> f32 {
*level.0.lock().unwrap()
}
#[tauri::command]
fn get_blink_interval(current: State<'_, BlinkInterval>) -> u64 {
*current.0.lock().unwrap()
}
#[tauri::command]
fn set_blink_interval(value: u64, current: State<'_, BlinkInterval>) {
*current.0.lock().unwrap() = value;
}
#[tauri::command]
fn get_config(current: State<'_, CurrentConfig>) -> Config {
current.0.lock().unwrap().clone()
}
#[tauri::command]
fn set_config(config: Config, current: State<'_, CurrentConfig>) {
*current.0.lock().unwrap() = config
}
#[tauri::command]
fn save_current_config(current: State<'_, CurrentConfig>) -> Result<(), String> {
config::save_config(&*current.0.lock().unwrap()).map_err(|e| format!("{}", e))
}