implement module registry instead of pattern matching solution

This commit is contained in:
Fl1tzi 2023-12-23 23:13:59 +01:00
parent 8bed8a6fa9
commit 4536e0a8cd
No known key found for this signature in database
GPG key ID: 06B333727810C686
4 changed files with 44 additions and 12 deletions

View file

@ -20,3 +20,4 @@ tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
font-loader = "0.11.0"
clru = "0.6.1"
once_cell = "1.19.0"

View file

@ -1,6 +1,6 @@
use crate::{
config::{Button, ConfigError, DeviceConfig, Space},
modules::{retrieve_module_from_name, start_module, HostEvent},
modules::{start_module, HostEvent, MODULE_REGISTRY},
unwrap_or_error,
};
use clru::CLruCache;
@ -141,7 +141,7 @@ impl Device {
.as_ref()
.expect("Runtime has to be created before module can be spawned");
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
let ser = self.serial.clone();
@ -150,7 +150,7 @@ impl Device {
let image_cache = self.image_cache.clone();
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.

View file

@ -8,7 +8,6 @@ use std::{
collections::HashMap,
process::exit,
sync::{Arc, Mutex, OnceLock},
thread,
time::Duration,
};
use tracing::{debug, error, info, trace, warn};

View file

@ -17,6 +17,8 @@ use ::image::DynamicImage;
use async_trait::async_trait;
pub use deck_driver as streamdeck;
use futures_util::Future;
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::{error::Error, pin::Pin, sync::Arc};
use streamdeck::info::ImageFormat;
use streamdeck::info::Kind;
@ -25,6 +27,8 @@ use streamdeck::StreamDeckError;
use tokio::sync::{mpsc, Mutex};
use tracing::{debug, error, trace};
pub static MODULE_REGISTRY: Lazy<ModuleRegistry> = Lazy::new(|| ModuleRegistry::default());
/// Events that are coming from the host
#[derive(Clone, Copy, Debug)]
pub enum HostEvent {
@ -39,12 +43,34 @@ pub type ModuleFuture =
Pin<Box<dyn Future<Output = Result<ModuleObject, ButtonConfigError>> + Send>>;
pub type ModuleInitFunction = fn(Arc<Button>, ModuleCache) -> ModuleFuture;
pub fn retrieve_module_from_name(name: &str) -> Option<ModuleInitFunction> {
match name {
"space" => Some(Space::new as ModuleInitFunction),
"counter" => Some(Counter::new as ModuleInitFunction),
"image" => Some(Image::new as ModuleInitFunction),
_ => None,
pub type ModuleMap = HashMap<&'static str, ModuleInitFunction>;
/// Registry of available modules
pub struct ModuleRegistry {
modules: ModuleMap,
}
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;
// 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 {
Ok(m) => m,
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
/// is checked this function gets called. It therefore should validate the most efficient
/// things first.
///
/// This function should **not** panic as the panic will not be catched and therefore would be
/// not noticed.
async fn new(
config: Arc<Button>,
mut cache: ModuleCache,
@ -206,6 +236,8 @@ pub trait Module: Sync + Send {
Self: Sized;
/// Function for actually running the module and interacting with the device. Errors that
/// happen here should be mostly prevented.
///
/// TODO: The return error is not sent anywhere and is just a panic
async fn run(
&mut self,
device: DeviceAccess,