231 lines
7.0 KiB
Rust
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))
|
|
}
|