137 lines
4.5 KiB
Rust
137 lines
4.5 KiB
Rust
fn js_error_to_string(value: JsValue) -> String {
|
|
value
|
|
.as_string()
|
|
.or_else(|| {
|
|
js_sys::Reflect::get(&value, &JsValue::from_str("message"))
|
|
.ok()
|
|
.and_then(|message| message.as_string())
|
|
})
|
|
.unwrap_or_else(|| "Tauri command failed".to_string())
|
|
}
|
|
|
|
fn color_to_hex(color: &[u8; 3]) -> String {
|
|
format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2])
|
|
}
|
|
|
|
fn hex_to_rgb(hex: &str) -> [u8; 3] {
|
|
if hex.len() != 7 || !hex.starts_with('#') {
|
|
return [255, 255, 255];
|
|
}
|
|
[
|
|
u8::from_str_radix(&hex[1..3], 16).unwrap_or(255),
|
|
u8::from_str_radix(&hex[3..5], 16).unwrap_or(255),
|
|
u8::from_str_radix(&hex[5..7], 16).unwrap_or(255),
|
|
]
|
|
}
|
|
|
|
fn bytes_to_hex(bytes: &[u8]) -> String {
|
|
bytes
|
|
.iter()
|
|
.map(|byte| format!("{byte:02x}"))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
}
|
|
|
|
fn parse_hex_bytes(input: &str) -> Vec<u8> {
|
|
input
|
|
.split(|ch: char| ch.is_whitespace() || ch == ',' || ch == ':')
|
|
.filter(|segment| !segment.is_empty())
|
|
.filter_map(|segment| {
|
|
let cleaned = segment.strip_prefix("0x").unwrap_or(segment);
|
|
u8::from_str_radix(cleaned, 16).ok()
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn format_log_timestamp(timestamp_ms: u64) -> String {
|
|
if timestamp_ms == 0 {
|
|
return "--:--:--".to_string();
|
|
}
|
|
let date = js_sys::Date::new(&JsValue::from_f64(timestamp_ms as f64));
|
|
format!(
|
|
"{:02}:{:02}:{:02}",
|
|
date.get_hours(),
|
|
date.get_minutes(),
|
|
date.get_seconds()
|
|
)
|
|
}
|
|
|
|
fn format_macro_operations_yaml(operations: &[MacroOperationState]) -> Result<String, String> {
|
|
let yaml_ops = operations
|
|
.iter()
|
|
.map(|operation| (operation.category.clone(), operation.payload.clone()))
|
|
.collect::<Vec<_>>();
|
|
serde_yaml::to_string(&yaml_ops).map_err(|error| error.to_string())
|
|
}
|
|
|
|
fn parse_macro_operations_yaml(input: &str) -> Result<Vec<MacroOperationState>, String> {
|
|
let value = serde_yaml::from_str::<serde_yaml::Value>(input).map_err(|error| error.to_string())?;
|
|
let Some(items) = value.as_sequence() else {
|
|
return Err("Macro YAML must be a list of operations".to_string());
|
|
};
|
|
|
|
items.iter()
|
|
.map(|item| {
|
|
if let Some(mapping) = item.as_mapping() {
|
|
let category = mapping
|
|
.get(serde_yaml::Value::String("category".to_string()))
|
|
.and_then(serde_yaml::Value::as_str)
|
|
.ok_or_else(|| "Macro operation object is missing category".to_string())?;
|
|
let payload = mapping
|
|
.get(serde_yaml::Value::String("payload".to_string()))
|
|
.cloned()
|
|
.unwrap_or(serde_yaml::Value::Null);
|
|
return Ok(MacroOperationState {
|
|
category: category.to_string(),
|
|
payload: serde_json::to_value(payload).map_err(|error| error.to_string())?,
|
|
});
|
|
}
|
|
|
|
let Some(pair) = item.as_sequence() else {
|
|
return Err("Macro operation must be a [category, payload] pair or object".to_string());
|
|
};
|
|
if pair.len() != 2 {
|
|
return Err("Macro operation pair must contain exactly two items".to_string());
|
|
}
|
|
let category = pair[0]
|
|
.as_str()
|
|
.ok_or_else(|| "Macro operation category must be a string".to_string())?;
|
|
Ok(MacroOperationState {
|
|
category: category.to_string(),
|
|
payload: serde_json::to_value(pair[1].clone()).map_err(|error| error.to_string())?,
|
|
})
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn mock_led_state(profile: String) -> LedState {
|
|
LedState {
|
|
profile,
|
|
regions: vec![
|
|
LedRegionState {
|
|
region: "wheel".to_string(),
|
|
effect: "wave".to_string(),
|
|
mode: 1,
|
|
speed: 180,
|
|
colors: vec![],
|
|
brightness: 200,
|
|
},
|
|
LedRegionState {
|
|
region: "logo".to_string(),
|
|
effect: "static".to_string(),
|
|
mode: 0,
|
|
speed: 0,
|
|
colors: vec![[0, 255, 0]],
|
|
brightness: 180,
|
|
},
|
|
LedRegionState {
|
|
region: "strip".to_string(),
|
|
effect: "spectrum".to_string(),
|
|
mode: 1,
|
|
speed: 180,
|
|
colors: vec![],
|
|
brightness: 255,
|
|
},
|
|
],
|
|
}
|
|
}
|