Implement instance-level settings

This commit is contained in:
ninjadev64 committed 2023-12-16 22:15:29 +00:00
1 parent adfdd9e9d7
commit 50908effc7
9 files changed
+165 -52

No files matched your search

+10 -5
View File
@@ -1,11 +1,16 @@
use serde::Deserialize;
use super::PayloadEvent;
#[derive(Deserialize)]
pub struct RegisterEvent {
pub uuid: String
}
use tauri::{api::shell::open, Manager};
use serde::Deserialize;
#[derive(Deserialize)]
pub struct OpenUrlEvent {
pub url: String
}
pub async fn open_url(event: PayloadEvent<OpenUrlEvent>) -> Result<(), anyhow::Error> {
let app_handle = crate::APP_HANDLE.lock().await;
open(&app_handle.as_ref().unwrap().shell_scope(), event.payload.url, None)?;
Ok(())
}
+37 -14
View File
@@ -1,31 +1,54 @@
pub mod misc;
mod misc;
mod settings;
use crate::shared::ActionContext;
use serde::Deserialize;
use tauri::{api::shell::open, Manager};
#[derive(Deserialize)]
#[serde(tag = "event", content = "payload")]
#[serde(rename_all = "camelCase")]
pub enum InboundEvent {
OpenUrl(misc::OpenUrlEvent)
pub struct RegisterEvent {
pub uuid: String
}
async fn open_url(event: misc::OpenUrlEvent) -> Result<(), anyhow::Error> {
let app_handle = crate::APP_HANDLE.lock().await;
open(&app_handle.as_ref().unwrap().shell_scope(), event.url, None)?;
Ok(())
#[derive(Deserialize)]
pub struct ContextEvent {
pub context: ActionContext
}
#[derive(Deserialize)]
pub struct PayloadEvent<T> {
pub payload: T
}
#[derive(Deserialize)]
pub struct ContextAndPayloadEvent<T> {
pub context: ActionContext,
pub payload: T
}
#[derive(Deserialize)]
#[serde(tag = "event")]
#[serde(rename_all = "camelCase")]
pub enum InboundEventType {
OpenUrl(PayloadEvent<misc::OpenUrlEvent>),
SetSettings(ContextAndPayloadEvent<serde_json::Value>),
GetSettings(ContextEvent)
}
pub async fn process_incoming_message(data: tokio_tungstenite::tungstenite::Message) -> Result<(), tokio_tungstenite::tungstenite::Error> {
if let tokio_tungstenite::tungstenite::Message::Text(text) = data {
let decoded: InboundEvent = match serde_json::from_str(&text) {
let decoded: InboundEventType = match serde_json::from_str(&text) {
Ok(event) => event,
Err(_) => return Ok(())
};
let _ = match decoded {
InboundEvent::OpenUrl(event) => open_url(event).await
};
if let Err(error) = match decoded {
InboundEventType::OpenUrl(event) => misc::open_url(event).await,
InboundEventType::SetSettings(event) => settings::set_settings(event).await,
InboundEventType::GetSettings(event) => settings::get_settings(event).await
} {
eprintln!("Failed to process incoming event: {}\n\tCaused by: {}", error, error.root_cause())
}
}
Ok(())
+37
View File
@@ -0,0 +1,37 @@
pub async fn set_settings(event: super::ContextAndPayloadEvent<serde_json::Value>) -> Result<(), anyhow::Error> {
let (
app,
mut device_stores,
devices,
mut profile_stores
) = crate::store::profiles::lock_mutexes().await;
let selected_profile = &device_stores.get_device_store(&event.context.device, app.as_ref().unwrap())?.value.selected_profile;
let device = devices.get(&event.context.device).unwrap();
let store = profile_stores.get_profile_store(device, selected_profile, app.as_ref().unwrap())?;
let profile = &mut store.value;
let instance = match event.context.controller.as_str() {
"Encoder" => profile.sliders[event.context.position as usize].as_mut(),
_ => profile.keys[event.context.position as usize].as_mut()
};
if let Some(instance) = instance {
instance.settings = event.payload;
store.save()?;
}
Ok(())
}
pub async fn get_settings(event: super::ContextEvent) -> Result<(), anyhow::Error> {
if let Some(instance) = crate::store::profiles::get_instance(
&event.context.device,
event.context.position,
&event.context.controller
).await? {
crate::events::outbound::settings::did_receive_settings(event.context, &instance).await?;
}
Ok(())
}
+1 -1
View File
@@ -16,7 +16,7 @@ lazy_static! {
}
/// Register a plugin to send and receive events with its WebSocket.
pub async fn register_plugin(data: inbound::misc::RegisterEvent, stream: WebSocketStream<TcpStream>) {
pub async fn register_plugin(data: inbound::RegisterEvent, stream: WebSocketStream<TcpStream>) {
let (read, write) = stream.split();
tokio::spawn(write.try_for_each(inbound::process_incoming_message));
SOCKETS.lock().await.insert(data.uuid.clone(), read);
+3 -2
View File
@@ -1,6 +1,7 @@
use super::{Coordinates, send_to_plugin, get_instance};
use super::{Coordinates, send_to_plugin};
use crate::shared::ActionContext;
use crate::store::profiles::get_instance;
use serde::Serialize;
@@ -29,7 +30,7 @@ pub async fn dial_rotate(device: String, index: u8, ticks: i16) -> Result<(), an
send_to_plugin(&instance.action.plugin, DialRotateEvent {
action: instance.action.uuid.clone(),
event: "keyDown".to_owned(),
event: "dialRotate".to_owned(),
context: instance.context.clone(),
device: instance.context.device.clone(),
payload: DialRotatePayload {
+2 -1
View File
@@ -1,6 +1,7 @@
use super::{Coordinates, send_to_plugin, get_instance};
use super::{Coordinates, send_to_plugin};
use crate::shared::{ActionContext, ActionInstance};
use crate::store::profiles::get_instance;
use serde::Serialize;
+1 -28
View File
@@ -1,13 +1,9 @@
pub mod keypad;
pub mod encoder;
pub mod settings;
use super::SOCKETS;
use crate::APP_HANDLE;
use crate::devices::DEVICES;
use crate::shared::ActionInstance;
use crate::store::profiles::{DEVICE_STORES, PROFILE_STORES};
use serde::Serialize;
use futures_util::SinkExt;
@@ -22,26 +18,3 @@ async fn send_to_plugin(plugin: &str, data: impl Serialize) -> Result<(), anyhow
SOCKETS.lock().await.get_mut(plugin).unwrap().send(message).await?;
Ok(())
}
async fn get_instance(device: &str, index: u8, controller: &str) -> Result<Option<ActionInstance>, anyhow::Error> {
let app = APP_HANDLE.lock().await;
let app = app.as_ref().unwrap();
let mut device_stores = DEVICE_STORES.lock().await;
let selected_profile = &device_stores.get_device_store(device, app)?.value.selected_profile;
let devices = DEVICES.lock().await;
let device = devices.get(device).unwrap();
let mut profile_stores = PROFILE_STORES.lock().await;
let profile = &profile_stores.get_profile_store(device, selected_profile, app)?.value;
let configured = match controller {
"Encoder" => profile.sliders[index as usize].as_ref(),
_ => profile.keys[index as usize].as_ref()
};
match configured {
Some(configured) => Ok(Some(configured.clone())),
None => Ok(None)
}
}
+36
View File
@@ -0,0 +1,36 @@
use super::{Coordinates, send_to_plugin};
use crate::shared::ActionContext;
use serde::Serialize;
#[derive(Serialize)]
pub struct DidReceiveSettingsPayload {
settings: serde_json::Value,
coordinates: Coordinates
}
#[derive(Serialize)]
pub struct DidReceiveSettings {
event: String,
action: String,
context: ActionContext,
device: String,
payload: DidReceiveSettingsPayload
}
pub async fn did_receive_settings(context: crate::shared::ActionContext, instance: &crate::shared::ActionInstance) -> Result<(), anyhow::Error> {
send_to_plugin(&instance.action.plugin, DidReceiveSettings {
event: "didReceiveSettings".to_owned(),
action: instance.action.uuid.clone(),
context: context.clone(),
device: context.device.clone(),
payload: DidReceiveSettingsPayload {
settings: instance.settings.clone(),
coordinates: Coordinates {
row: instance.context.position / 3,
column: instance.context.position % 3
}
}
}).await
}
+38 -1
View File
@@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize};
use anyhow::Context;
use lazy_static::lazy_static;
use tokio::sync::Mutex;
use tokio::sync::{Mutex, MutexGuard};
pub struct ProfileStores {
stores: HashMap<String, Store<Profile>>
@@ -101,3 +101,40 @@ lazy_static! {
/// A singleton object to manage Store instances for device configurations.
pub static ref DEVICE_STORES: Mutex<DeviceStores> = Mutex::new(DeviceStores { stores: HashMap::new() });
}
pub async fn lock_mutexes() -> (
MutexGuard<'static, Option<tauri::AppHandle>>,
MutexGuard<'static, DeviceStores>,
MutexGuard<'static, HashMap<String, crate::devices::DeviceInfo>>,
MutexGuard<'static, ProfileStores>
) {
let app = crate::APP_HANDLE.lock().await;
let device_stores = DEVICE_STORES.lock().await;
let devices = crate::devices::DEVICES.lock().await;
let profile_stores = PROFILE_STORES.lock().await;
(app, device_stores, devices, profile_stores)
}
pub async fn get_instance(device: &str, position: u8, controller: &str) -> Result<Option<crate::shared::ActionInstance>, anyhow::Error> {
let (
app,
mut device_stores,
devices,
mut profile_stores
) = lock_mutexes().await;
let selected_profile = &device_stores.get_device_store(device, app.as_ref().unwrap())?.value.selected_profile;
let device = devices.get(device).unwrap();
let store = profile_stores.get_profile_store(device, selected_profile, app.as_ref().unwrap())?;
let profile = &store.value;
let configured = match controller {
"Encoder" => profile.sliders[position as usize].as_ref(),
_ => profile.keys[position as usize].as_ref()
};
match configured {
Some(configured) => Ok(Some(configured.clone())),
None => Ok(None)
}
}