1
0
mirror of https://github.com/4yn/slidershim.git synced 2025-02-15 18:12:40 +01:00

231 lines
7.6 KiB
Rust
Raw Normal View History

2022-01-30 17:22:55 +08:00
use directories::ProjectDirs;
2022-02-07 02:01:34 +08:00
use image::Luma;
2022-02-06 17:56:50 +08:00
use log::{info, warn};
2022-02-07 02:01:34 +08:00
use qrcode::QrCode;
2022-01-28 20:17:34 +08:00
use serde_json::Value;
2022-02-12 23:23:22 +08:00
use std::{convert::TryFrom, error::Error, fs, path::PathBuf};
use crate::{
device::config::{DeviceMode, HardwareSpec},
lighting::config::{LedMode, ReactiveLayout},
output::config::{GamepadLayout, KeyboardLayout, OutputMode, PollingRate},
};
pub fn list_ips() -> Result<Vec<String>, Box<dyn Error>> {
let mut ips = vec![];
for adapter in ipconfig::get_adapters()? {
for ip_address in adapter.ip_addresses() {
ips.push(format!("{}", ip_address));
2022-02-09 14:00:36 +08:00
}
}
2022-02-12 23:23:22 +08:00
Ok(ips)
2022-01-28 20:17:34 +08:00
}
#[derive(Debug, Clone)]
pub struct Config {
pub raw: String,
pub device_mode: DeviceMode,
pub output_mode: OutputMode,
pub led_mode: LedMode,
}
impl Config {
2022-01-29 04:23:16 +08:00
pub fn from_str(s: &str) -> Option<Config> {
let v: Value = serde_json::from_str(s).ok()?;
2022-01-28 20:17:34 +08:00
2022-01-29 04:23:16 +08:00
Some(Config {
2022-01-28 20:17:34 +08:00
raw: s.to_string(),
2022-01-29 04:23:16 +08:00
device_mode: match v["deviceMode"].as_str()? {
2022-01-28 20:17:34 +08:00
"none" => DeviceMode::None,
2022-02-09 14:00:36 +08:00
"tasoller-one" => DeviceMode::Hardware {
spec: HardwareSpec::TasollerOne,
},
"tasoller-two" => DeviceMode::Hardware {
spec: HardwareSpec::TasollerTwo,
},
"yuancon" => DeviceMode::Hardware {
spec: HardwareSpec::Yuancon,
},
2022-02-07 03:38:48 +08:00
"brokenithm" => DeviceMode::Brokenithm {
ground_only: false,
led_enabled: false,
},
"brokenithm-led" => DeviceMode::Brokenithm {
ground_only: false,
led_enabled: true,
},
"brokenithm-ground" => DeviceMode::Brokenithm {
ground_only: true,
led_enabled: false,
},
"brokenithm-ground-led" => DeviceMode::Brokenithm {
ground_only: true,
led_enabled: true,
},
2022-01-28 20:17:34 +08:00
_ => panic!("Invalid device mode"),
},
output_mode: match v["outputMode"].as_str().unwrap() {
"none" => OutputMode::None,
"kb-32-tasoller" => OutputMode::Keyboard {
layout: KeyboardLayout::Tasoller,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
"kb-32-yuancon" => OutputMode::Keyboard {
layout: KeyboardLayout::Yuancon,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
2022-02-01 10:37:53 +08:00
"kb-8-deemo" => OutputMode::Keyboard {
2022-01-28 20:17:34 +08:00
layout: KeyboardLayout::Deemo,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
2022-02-01 10:37:53 +08:00
"kb-voltex" => OutputMode::Keyboard {
layout: KeyboardLayout::Voltex,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
},
"kb-neardayo" => OutputMode::Keyboard {
layout: KeyboardLayout::Neardayo,
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-02-01 10:37:53 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
},
2022-02-06 17:56:50 +08:00
"gamepad-voltex" => OutputMode::Gamepad {
layout: GamepadLayout::Voltex,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-02-06 17:56:50 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
},
"gamepad-neardayo" => OutputMode::Gamepad {
layout: GamepadLayout::Neardayo,
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-02-02 15:14:56 +08:00
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
},
2022-01-28 20:17:34 +08:00
"websocket" => OutputMode::Websocket {
2022-02-02 15:14:56 +08:00
url: v["outputWebsocketUrl"].as_str()?.to_string(),
2022-02-09 14:00:36 +08:00
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
2022-01-28 20:17:34 +08:00
},
_ => panic!("Invalid output mode"),
},
2022-01-29 04:23:16 +08:00
led_mode: match v["ledMode"].as_str()? {
2022-01-28 20:17:34 +08:00
"none" => LedMode::None,
"reactive-4" => LedMode::Reactive {
2022-02-01 10:37:53 +08:00
layout: ReactiveLayout::Even { splits: 4 },
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
"reactive-8" => LedMode::Reactive {
2022-02-01 10:37:53 +08:00
layout: ReactiveLayout::Even { splits: 8 },
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
"reactive-16" => LedMode::Reactive {
2022-02-01 10:37:53 +08:00
layout: ReactiveLayout::Even { splits: 16 },
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
},
"reactive-voltex" => LedMode::Reactive {
layout: ReactiveLayout::Voltex,
2022-01-29 04:23:16 +08:00
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
2022-01-28 20:17:34 +08:00
},
"attract" => LedMode::Attract,
"test" => LedMode::Test,
"websocket" => LedMode::Websocket {
2022-02-02 15:14:56 +08:00
url: v["ledWebsocketUrl"].as_str()?.to_string(),
},
"serial" => LedMode::Serial {
port: v["ledSerialPort"].as_str()?.to_string(),
2022-01-28 20:17:34 +08:00
},
_ => panic!("Invalid led mode"),
},
2022-01-29 04:23:16 +08:00
})
}
2022-02-05 18:00:06 +08:00
pub fn get_log_file_path() -> Option<Box<PathBuf>> {
2022-02-05 18:07:18 +08:00
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
2022-02-05 18:00:06 +08:00
let config_dir = project_dir.config_dir();
2022-02-07 15:56:03 +08:00
fs::create_dir_all(config_dir).ok()?;
2022-02-05 18:00:06 +08:00
let log_path = config_dir.join("log.txt");
return Some(Box::new(log_path));
}
2022-02-07 02:01:34 +08:00
pub fn get_brokenithm_qr_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir();
2022-02-07 15:56:03 +08:00
fs::create_dir_all(config_dir).ok()?;
2022-02-07 02:01:34 +08:00
let brokenithm_qr_path = config_dir.join("brokenithm.png");
let ips = list_ips().ok()?;
let link = "http://imp.ress.me/t/sshelper?d=".to_string()
+ &ips
.into_iter()
.filter(|s| s.as_str().chars().filter(|x| *x == '.').count() == 3)
.map(|s| base64::encode_config(s, base64::URL_SAFE_NO_PAD))
.collect::<Vec<String>>()
.join(";");
let qr = QrCode::new(link).ok()?;
let image = qr.render::<Luma<u8>>().build();
image.save(brokenithm_qr_path.as_path()).ok()?;
return Some(Box::new(brokenithm_qr_path));
}
2022-02-07 15:56:03 +08:00
fn get_config_path() -> Option<Box<PathBuf>> {
2022-02-05 18:07:18 +08:00
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
2022-01-29 04:23:16 +08:00
let config_dir = project_dir.config_dir();
2022-02-07 15:56:03 +08:00
fs::create_dir_all(config_dir).ok()?;
2022-01-29 04:23:16 +08:00
let config_path = config_dir.join("config.json");
return Some(Box::new(config_path));
}
2022-02-07 15:56:03 +08:00
fn default() -> Self {
Self::from_str(
r#"{
"deviceMode": "none",
2022-02-09 14:00:36 +08:00
"devicePolling": "100",
2022-02-07 15:56:03 +08:00
"outputMode": "none",
"ledMode": "none",
"keyboardSensitivity": 20,
"outputWebsocketUrl": "localhost:3000",
2022-02-09 14:00:36 +08:00
"outputPolling": "100",
2022-02-07 15:56:03 +08:00
"ledSensitivity": 20,
"ledWebsocketUrl": "localhost:3001",
"ledSerialPort": "COM5"
}"#,
)
.unwrap()
}
2022-01-29 04:23:16 +08:00
fn load_saved() -> Option<Self> {
2022-02-07 15:56:03 +08:00
let config_path = Self::get_config_path()?;
2022-01-29 04:23:16 +08:00
if !config_path.exists() {
return None;
2022-01-28 20:17:34 +08:00
}
2022-01-30 17:22:55 +08:00
info!("Config file found at {:?}", config_path);
2022-02-05 11:44:42 +08:00
let saved_data = fs::read_to_string(config_path.as_path()).ok()?;
2022-01-29 04:23:16 +08:00
return Self::from_str(saved_data.as_str());
}
2022-02-07 15:56:03 +08:00
pub fn load() -> Self {
2022-01-29 04:23:16 +08:00
Self::load_saved()
2022-02-06 17:56:50 +08:00
.or_else(|| {
warn!("Config loading from file failed, using default");
2022-02-07 15:56:03 +08:00
Some(Self::default())
2022-02-06 17:56:50 +08:00
})
2022-01-29 04:23:16 +08:00
.unwrap()
}
pub fn save(&self) -> Option<()> {
2022-01-30 17:22:55 +08:00
info!("Config saving...");
2022-02-07 15:56:03 +08:00
let config_path = Self::get_config_path()?;
2022-01-30 17:22:55 +08:00
info!("Config saving to {:?}", config_path);
2022-01-29 04:23:16 +08:00
fs::write(config_path.as_path(), self.raw.as_str()).unwrap();
2022-01-30 17:22:55 +08:00
info!("Config saved");
2022-02-07 15:56:03 +08:00
2022-01-29 04:23:16 +08:00
Some(())
2022-01-28 20:17:34 +08:00
}
}