136 lines
4.5 KiB
Rust
136 lines
4.5 KiB
Rust
use std::path::Path;
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
|
|
use color_eyre::eyre::{ContextCompat, WrapErr};
|
|
use color_eyre::Result;
|
|
use nanoid::nanoid;
|
|
use tokio::sync::broadcast;
|
|
|
|
use deckster_shared::handler_communication::{HandlerCommand, HandlerEvent};
|
|
use deckster_shared::path::{KeyPath, KnobPath};
|
|
use loupedeck_serial::commands::VibrationPattern;
|
|
use loupedeck_serial::device::LoupedeckDevice;
|
|
|
|
use crate::coordinator::io_worker::{do_io_work, CoordinatorCommand, IoWorkerContext};
|
|
use crate::coordinator::mqtt::start_mqtt_client;
|
|
use crate::handler_runner;
|
|
use crate::handler_runner::KeyOrKnobHandlerConfig;
|
|
use crate::model::coordinator_config::Config;
|
|
use crate::model::mqtt::HandlerHostsConfig;
|
|
|
|
mod graphics;
|
|
mod io_worker;
|
|
mod mqtt;
|
|
pub mod state;
|
|
|
|
pub async fn start(config_directory: &Path, config: Config) -> Result<()> {
|
|
let config = Arc::new(config);
|
|
log::info!("Discovering devices…");
|
|
|
|
let available_devices = LoupedeckDevice::discover()?;
|
|
let available_device = available_devices.first().wrap_err("No device connected.")?;
|
|
log::info!("Found {} device(s).", available_devices.len());
|
|
|
|
let (coordinator_commands_sender, coordinator_commands_receiver) = flume::bounded::<CoordinatorCommand>(5);
|
|
let (handler_commands_sender, handler_commands_receiver) = flume::bounded::<HandlerCommand>(5);
|
|
let events_sender = broadcast::Sender::<HandlerEvent>::new(5);
|
|
|
|
coordinator_commands_sender
|
|
.send(CoordinatorCommand::SetActivePages {
|
|
knob_page_id: config.initial.knob_page.clone(),
|
|
key_page_id: config.initial.key_page.clone(),
|
|
})
|
|
.unwrap();
|
|
|
|
let handler_hosts_config = HandlerHostsConfig {
|
|
run_id: nanoid!().into_boxed_str(),
|
|
keys: config
|
|
.key_pages_by_id
|
|
.iter()
|
|
.flat_map(|(page_id, p)| {
|
|
p.keys.iter().map(|(position, k)| {
|
|
(
|
|
KeyPath {
|
|
page_id: page_id.clone(),
|
|
position: *position,
|
|
},
|
|
KeyOrKnobHandlerConfig {
|
|
host_id: k.host.clone(),
|
|
name: k.handler.clone(),
|
|
config: Arc::clone(&k.config),
|
|
},
|
|
)
|
|
})
|
|
})
|
|
.collect(),
|
|
knobs: config
|
|
.knob_pages_by_id
|
|
.iter()
|
|
.flat_map(|(page_id, p)| {
|
|
p.knobs.iter().filter_map(|(position, k)| {
|
|
if k.handler.is_empty() {
|
|
return None;
|
|
}
|
|
|
|
Some((
|
|
KnobPath {
|
|
page_id: page_id.clone(),
|
|
position,
|
|
},
|
|
KeyOrKnobHandlerConfig {
|
|
host_id: k.host.clone(),
|
|
name: k.handler.clone(),
|
|
config: Arc::clone(&k.config),
|
|
},
|
|
))
|
|
})
|
|
})
|
|
.collect(),
|
|
};
|
|
|
|
if let Some(mqtt_config) = &config.mqtt {
|
|
log::info!("Initializing MQTT client…");
|
|
start_mqtt_client(
|
|
mqtt_config,
|
|
&handler_hosts_config,
|
|
coordinator_commands_sender.clone(),
|
|
handler_commands_sender.clone(),
|
|
events_sender.subscribe(),
|
|
)
|
|
.await;
|
|
}
|
|
|
|
log::info!("Initializing handler processes…");
|
|
|
|
handler_runner::start(
|
|
String::default().into_boxed_str(),
|
|
&config_directory.join("handlers"),
|
|
&config.handlers,
|
|
handler_hosts_config,
|
|
handler_commands_sender.clone(),
|
|
events_sender.subscribe(),
|
|
)
|
|
.await?;
|
|
|
|
log::info!("Connecting to the device…");
|
|
let device = available_device.connect().wrap_err("Connecting to the device failed.")?;
|
|
log::info!("Connected.");
|
|
|
|
device.set_brightness(config.initial.screen_brightness);
|
|
device.vibrate(VibrationPattern::RiseFall);
|
|
|
|
let io_worker_context = IoWorkerContext::create(config_directory, Arc::clone(&config), device, coordinator_commands_sender, events_sender);
|
|
|
|
let io_worker_thread = thread::Builder::new()
|
|
.name("deckster IO worker".to_owned())
|
|
.spawn(move || {
|
|
do_io_work(io_worker_context, &coordinator_commands_receiver, &handler_commands_receiver);
|
|
})
|
|
.wrap_err("Could not spawn the worker thread")?;
|
|
|
|
log::info!("Ready.");
|
|
io_worker_thread.join().unwrap();
|
|
|
|
Ok(())
|
|
}
|