mirror of
https://codeberg.org/Fl1tzi/microdeck.git
synced 2024-05-19 19:20:20 +00:00
implement module registry instead of pattern matching solution
This commit is contained in:
parent
8bed8a6fa9
commit
4536e0a8cd
|
@ -20,3 +20,4 @@ tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
font-loader = "0.11.0"
|
font-loader = "0.11.0"
|
||||||
clru = "0.6.1"
|
clru = "0.6.1"
|
||||||
|
once_cell = "1.19.0"
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Button, ConfigError, DeviceConfig, Space},
|
config::{Button, ConfigError, DeviceConfig, Space},
|
||||||
modules::{retrieve_module_from_name, start_module, HostEvent},
|
modules::{start_module, HostEvent, MODULE_REGISTRY},
|
||||||
unwrap_or_error,
|
unwrap_or_error,
|
||||||
};
|
};
|
||||||
use clru::CLruCache;
|
use clru::CLruCache;
|
||||||
|
@ -141,7 +141,7 @@ impl Device {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("Runtime has to be created before module can be spawned");
|
.expect("Runtime has to be created before module can be spawned");
|
||||||
let (module_sender, module_receiver) = mpsc::channel(4);
|
let (module_sender, module_receiver) = mpsc::channel(4);
|
||||||
if let Some(module) = retrieve_module_from_name(&btn.module) {
|
if let Some(module) = MODULE_REGISTRY.get_module(&btn.module) {
|
||||||
{
|
{
|
||||||
// initialize the module
|
// initialize the module
|
||||||
let ser = self.serial.clone();
|
let ser = self.serial.clone();
|
||||||
|
@ -150,7 +150,7 @@ impl Device {
|
||||||
let image_cache = self.image_cache.clone();
|
let image_cache = self.image_cache.clone();
|
||||||
|
|
||||||
runtime.spawn(async move {
|
runtime.spawn(async move {
|
||||||
start_module(ser, b, module, dev, module_receiver, image_cache).await
|
start_module(ser, b, *module, dev, module_receiver, image_cache).await
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// if the receiver already dropped the listener then just directly insert none.
|
// if the receiver already dropped the listener then just directly insert none.
|
||||||
|
|
|
@ -8,7 +8,6 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
process::exit,
|
process::exit,
|
||||||
sync::{Arc, Mutex, OnceLock},
|
sync::{Arc, Mutex, OnceLock},
|
||||||
thread,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tracing::{debug, error, info, trace, warn};
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
|
@ -17,6 +17,8 @@ use ::image::DynamicImage;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
pub use deck_driver as streamdeck;
|
pub use deck_driver as streamdeck;
|
||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::{error::Error, pin::Pin, sync::Arc};
|
use std::{error::Error, pin::Pin, sync::Arc};
|
||||||
use streamdeck::info::ImageFormat;
|
use streamdeck::info::ImageFormat;
|
||||||
use streamdeck::info::Kind;
|
use streamdeck::info::Kind;
|
||||||
|
@ -25,6 +27,8 @@ use streamdeck::StreamDeckError;
|
||||||
use tokio::sync::{mpsc, Mutex};
|
use tokio::sync::{mpsc, Mutex};
|
||||||
use tracing::{debug, error, trace};
|
use tracing::{debug, error, trace};
|
||||||
|
|
||||||
|
pub static MODULE_REGISTRY: Lazy<ModuleRegistry> = Lazy::new(|| ModuleRegistry::default());
|
||||||
|
|
||||||
/// Events that are coming from the host
|
/// Events that are coming from the host
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum HostEvent {
|
pub enum HostEvent {
|
||||||
|
@ -39,12 +43,34 @@ pub type ModuleFuture =
|
||||||
Pin<Box<dyn Future<Output = Result<ModuleObject, ButtonConfigError>> + Send>>;
|
Pin<Box<dyn Future<Output = Result<ModuleObject, ButtonConfigError>> + Send>>;
|
||||||
pub type ModuleInitFunction = fn(Arc<Button>, ModuleCache) -> ModuleFuture;
|
pub type ModuleInitFunction = fn(Arc<Button>, ModuleCache) -> ModuleFuture;
|
||||||
|
|
||||||
pub fn retrieve_module_from_name(name: &str) -> Option<ModuleInitFunction> {
|
pub type ModuleMap = HashMap<&'static str, ModuleInitFunction>;
|
||||||
match name {
|
|
||||||
"space" => Some(Space::new as ModuleInitFunction),
|
/// Registry of available modules
|
||||||
"counter" => Some(Counter::new as ModuleInitFunction),
|
pub struct ModuleRegistry {
|
||||||
"image" => Some(Image::new as ModuleInitFunction),
|
modules: ModuleMap,
|
||||||
_ => None,
|
}
|
||||||
|
|
||||||
|
impl Default for ModuleRegistry {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut modules = ModuleMap::new();
|
||||||
|
modules.insert("space", Space::new as ModuleInitFunction);
|
||||||
|
modules.insert("image", Image::new as ModuleInitFunction);
|
||||||
|
modules.insert("counter", Counter::new as ModuleInitFunction);
|
||||||
|
ModuleRegistry { modules }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleRegistry {
|
||||||
|
/// Retrieve a module from the registry
|
||||||
|
pub fn get_module(&self, name: &str) -> Option<&ModuleInitFunction> {
|
||||||
|
self.modules.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Idk if the &&str will be fine in the future
|
||||||
|
/// List all available modules
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn list_modules(&self) -> Vec<&&str> {
|
||||||
|
self.modules.keys().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +93,10 @@ pub async fn start_module(
|
||||||
);
|
);
|
||||||
let da = DeviceAccess::new(device, button.index).await;
|
let da = DeviceAccess::new(device, button.index).await;
|
||||||
|
|
||||||
// run init first
|
// init
|
||||||
//
|
//
|
||||||
// panic should be prevented by the config being checked before running
|
// This function should be called after the config was checked,
|
||||||
|
// otherwise it will panic and the module wont be started.
|
||||||
let mut module = match module_init_function(button, mc).await {
|
let mut module = match module_init_function(button, mc).await {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
|
@ -198,6 +225,9 @@ pub trait Module: Sync + Send {
|
||||||
/// Function for validating configuration and creating module instance. Every time the config
|
/// Function for validating configuration and creating module instance. Every time the config
|
||||||
/// is checked this function gets called. It therefore should validate the most efficient
|
/// is checked this function gets called. It therefore should validate the most efficient
|
||||||
/// things first.
|
/// things first.
|
||||||
|
///
|
||||||
|
/// This function should **not** panic as the panic will not be catched and therefore would be
|
||||||
|
/// not noticed.
|
||||||
async fn new(
|
async fn new(
|
||||||
config: Arc<Button>,
|
config: Arc<Button>,
|
||||||
mut cache: ModuleCache,
|
mut cache: ModuleCache,
|
||||||
|
@ -206,6 +236,8 @@ pub trait Module: Sync + Send {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
/// Function for actually running the module and interacting with the device. Errors that
|
/// Function for actually running the module and interacting with the device. Errors that
|
||||||
/// happen here should be mostly prevented.
|
/// happen here should be mostly prevented.
|
||||||
|
///
|
||||||
|
/// TODO: The return error is not sent anywhere and is just a panic
|
||||||
async fn run(
|
async fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
device: DeviceAccess,
|
device: DeviceAccess,
|
||||||
|
|
Loading…
Reference in a new issue