This commit is contained in:
Moritz Ruth 2024-03-01 01:19:28 +01:00
parent 1ced4381b8
commit f44283160a
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
10 changed files with 181 additions and 138 deletions

View file

@ -50,7 +50,6 @@ pub enum HandlerEvent {
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(tag = "command", rename_all = "kebab-case")] #[serde(tag = "command", rename_all = "kebab-case")]
pub enum HandlerCommand { pub enum HandlerCommand {
SetActivePages { key_page_id: String, knob_page_id: String },
SetKeyStyle { path: KeyPath, value: Option<KeyStyle> }, SetKeyStyle { path: KeyPath, value: Option<KeyStyle> },
SetKnobStyle { path: KnobPath, value: Option<KnobStyle> }, SetKnobStyle { path: KnobPath, value: Option<KnobStyle> },
SetKnobValue { path: KnobPath, value: Option<f32> }, SetKnobValue { path: KnobPath, value: Option<f32> },

View file

@ -6,6 +6,7 @@ use crate::style::{KeyStyle, KnobStyle};
#[derive(Debug)] #[derive(Debug)]
pub struct Key { pub struct Key {
pub path: KeyPath, pub path: KeyPath,
pub host_id: Box<str>,
pub base_style: KeyStyle, pub base_style: KeyStyle,
pub style: Option<KeyStyle>, pub style: Option<KeyStyle>,
} }
@ -13,6 +14,7 @@ pub struct Key {
#[derive(Debug)] #[derive(Debug)]
pub struct Knob { pub struct Knob {
pub path: KnobPath, pub path: KnobPath,
pub host_id: Box<str>,
pub base_style: KnobStyle, pub base_style: KnobStyle,
pub style: Option<KnobStyle>, pub style: Option<KnobStyle>,
pub value: Option<f32>, pub value: Option<f32>,

View file

@ -1,4 +1,5 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashSet;
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{BufMut, Bytes, BytesMut};
use resvg::usvg::tiny_skia_path::PathBuilder; use resvg::usvg::tiny_skia_path::PathBuilder;
@ -18,10 +19,11 @@ pub struct GraphicsContext {
pub icon_manager: IconManager, pub icon_manager: IconManager,
} }
pub fn render_key(context: &GraphicsContext, key_size: IntSize, state: Option<&Key>) -> Bytes { pub fn render_key(context: &GraphicsContext, key_size: IntSize, active_remote_handler_host_ids: &HashSet<Box<str>>, state: Option<&Key>) -> Bytes {
let mut pixmap = Pixmap::new(key_size.width(), key_size.height()).expect("constraints were already asserted by IntSize"); let mut pixmap = Pixmap::new(key_size.width(), key_size.height()).expect("constraints were already asserted by IntSize");
if let Some(state) = state { if let Some(state) = state {
if active_remote_handler_host_ids.contains(&state.host_id) {
let style = state.style.as_ref().map(|s| s.merge_over(&state.base_style)); let style = state.style.as_ref().map(|s| s.merge_over(&state.base_style));
let style = style.as_ref().unwrap_or(&state.base_style); let style = style.as_ref().unwrap_or(&state.base_style);
@ -38,8 +40,9 @@ pub fn render_key(context: &GraphicsContext, key_size: IntSize, state: Option<&K
} }
if let Some(color) = style.border { if let Some(color) = style.border {
let path = let path = PathBuilder::from_rect(
PathBuilder::from_rect(Rect::from_xywh(-1.0, -2.0, pixmap.width() as f32, pixmap.height() as f32).expect("width and height are not negative")); Rect::from_xywh(-1.0, -2.0, pixmap.width() as f32, pixmap.height() as f32).expect("width and height are not negative"),
);
let paint = Paint { let paint = Paint {
shader: Shader::SolidColor(Color::from_rgba8(color.r, color.g, color.b, color.a)), shader: Shader::SolidColor(Color::from_rgba8(color.r, color.g, color.b, color.a)),
@ -57,14 +60,16 @@ pub fn render_key(context: &GraphicsContext, key_size: IntSize, state: Option<&K
pixmap.stroke_path(&path, &paint, &STROKE, Transform::identity(), None); pixmap.stroke_path(&path, &paint, &STROKE, Transform::identity(), None);
} }
} }
}
convert_pixels_to_rgb565(pixmap.pixels(), context.buffer_endianness).freeze() convert_pixels_to_rgb565(pixmap.pixels(), context.buffer_endianness).freeze()
} }
pub fn render_knob(context: &GraphicsContext, screen_size: IntSize, state: Option<&Knob>) -> Bytes { pub fn render_knob(context: &GraphicsContext, screen_size: IntSize, active_remote_handler_host_ids: &HashSet<Box<str>>, state: Option<&Knob>) -> Bytes {
let mut pixmap = Pixmap::new(screen_size.width(), screen_size.height()).expect("constraints were already asserted by IntSize"); let mut pixmap = Pixmap::new(screen_size.width(), screen_size.height()).expect("constraints were already asserted by IntSize");
if let Some(state) = state { if let Some(state) = state {
if active_remote_handler_host_ids.contains(&state.host_id) {
let style = state.style.as_ref().map(|s| s.merge_over(&state.base_style)); let style = state.style.as_ref().map(|s| s.merge_over(&state.base_style));
let style = style.as_ref().unwrap_or(&state.base_style); let style = style.as_ref().unwrap_or(&state.base_style);
@ -115,6 +120,7 @@ pub fn render_knob(context: &GraphicsContext, screen_size: IntSize, state: Optio
} }
} }
} }
}
convert_pixels_to_rgb565(pixmap.pixels(), context.buffer_endianness).freeze() convert_pixels_to_rgb565(pixmap.pixels(), context.buffer_endianness).freeze()
} }

View file

@ -21,17 +21,25 @@ use crate::icons::IconManager;
use crate::model::coordinator_config::Config; use crate::model::coordinator_config::Config;
use crate::model::position::ButtonPosition; use crate::model::position::ButtonPosition;
#[derive(Debug, PartialEq, Clone)]
pub enum CoordinatorCommand {
SetActivePages { key_page_id: String, knob_page_id: String },
SetRemoteHostIsActive { host_id: Box<str>, is_active: bool },
}
enum IoWork { enum IoWork {
DeviceEvent(LoupedeckEvent), DeviceEvent(LoupedeckEvent),
Command(HandlerCommand), HandlerCommand(HandlerCommand),
CoordinatorCommand(CoordinatorCommand),
} }
pub struct IoWorkerContext { pub struct IoWorkerContext {
config: Arc<Config>, config: Arc<Config>,
device: LoupedeckDevice, device: LoupedeckDevice,
commands_sender: flume::Sender<HandlerCommand>, coordinator_commands_sender: flume::Sender<CoordinatorCommand>,
events_sender: broadcast::Sender<HandlerEvent>, events_sender: broadcast::Sender<HandlerEvent>,
graphics: GraphicsContext, graphics: GraphicsContext,
state: State,
} }
impl IoWorkerContext { impl IoWorkerContext {
@ -39,52 +47,59 @@ impl IoWorkerContext {
config_directory: &Path, config_directory: &Path,
config: Arc<Config>, config: Arc<Config>,
device: LoupedeckDevice, device: LoupedeckDevice,
commands_sender: flume::Sender<HandlerCommand>, coordinator_commands_sender: flume::Sender<CoordinatorCommand>,
events_sender: broadcast::Sender<HandlerEvent>, events_sender: broadcast::Sender<HandlerEvent>,
) -> Self { ) -> Self {
let buffer_endianness = device.characteristics().key_grid.display.endianness; let buffer_endianness = device.characteristics().key_grid.display.endianness;
let label_renderer = RefCell::new(LabelRenderer::new(config.label_font_family.as_ref())); let label_renderer = RefCell::new(LabelRenderer::new(config.label_font_family.as_ref()));
let dpi = device.characteristics().key_grid.display.dpi; let dpi = device.characteristics().key_grid.display.dpi;
let icon_packs = Arc::clone(&config.icon_packs); let icon_packs = Arc::clone(&config.icon_packs);
let state = State::create(&config);
IoWorkerContext { IoWorkerContext {
config, config,
device, device,
commands_sender, coordinator_commands_sender,
events_sender, events_sender,
graphics: GraphicsContext { graphics: GraphicsContext {
buffer_endianness, buffer_endianness,
label_renderer, label_renderer,
icon_manager: IconManager::new(config_directory.to_path_buf(), icon_packs, dpi), icon_manager: IconManager::new(config_directory.to_path_buf(), icon_packs, dpi),
}, },
state,
} }
} }
} }
pub fn do_io_work(context: IoWorkerContext, commands_receiver: flume::Receiver<HandlerCommand>) { pub fn do_io_work(
let mut state = State::create(&context.config); mut context: IoWorkerContext,
coordinator_commands_receiver: &flume::Receiver<CoordinatorCommand>,
handler_commands_receiver: &flume::Receiver<HandlerCommand>,
) {
let device_events_receiver = context.device.events(); let device_events_receiver = context.device.events();
loop { loop {
let a = flume::Selector::new() let work = flume::Selector::new()
.recv(&device_events_receiver, |e| { .recv(&device_events_receiver, |e| {
IoWork::DeviceEvent(e.expect("the device events channel is not closed by the other side")) IoWork::DeviceEvent(e.expect("the device events channel is not closed by the other side"))
}) })
.recv(&commands_receiver, |c| IoWork::Command(c.unwrap())) .recv(coordinator_commands_receiver, |c| IoWork::CoordinatorCommand(c.unwrap()))
.recv(handler_commands_receiver, |c| IoWork::HandlerCommand(c.unwrap()))
.wait(); .wait();
match a { match work {
IoWork::DeviceEvent(event) => { IoWork::DeviceEvent(event) => {
if !handle_event(&context, &mut state, event) { if !handle_event(&mut context, event) {
break; break;
} }
} }
IoWork::Command(command) => handle_command(&context, &mut state, command), IoWork::CoordinatorCommand(command) => handle_coordinator_command(&mut context, command),
IoWork::HandlerCommand(command) => handle_handler_command(&mut context, command),
} }
} }
} }
fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEvent) -> bool { fn handle_event(context: &mut IoWorkerContext, event: LoupedeckEvent) -> bool {
log::trace!("Handling event: {:?}", &event); log::trace!("Handling event: {:?}", &event);
let send_key_event = |path: KeyPath, event: KeyEvent| { let send_key_event = |path: KeyPath, event: KeyEvent| {
@ -104,10 +119,10 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
let button_config = &context.config.buttons[position]; let button_config = &context.config.buttons[position];
context context
.commands_sender .coordinator_commands_sender
.send(HandlerCommand::SetActivePages { .send(CoordinatorCommand::SetActivePages {
key_page_id: button_config.key_page.as_ref().unwrap_or(&state.active_key_page_id).clone(), key_page_id: button_config.key_page.as_ref().unwrap_or(&context.state.active_key_page_id).clone(),
knob_page_id: button_config.knob_page.as_ref().unwrap_or(&state.active_knob_page_id).clone(), knob_page_id: button_config.knob_page.as_ref().unwrap_or(&context.state.active_knob_page_id).clone(),
}) })
.unwrap() .unwrap()
} }
@ -125,7 +140,7 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
}; };
let path = KeyPath { let path = KeyPath {
page_id: state.active_key_page_id.clone(), page_id: context.state.active_key_page_id.clone(),
position, position,
}; };
@ -137,10 +152,10 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
.expect("the key index is valid because is was returned by get_key_at_global_coordinates"); .expect("the key index is valid because is was returned by get_key_at_global_coordinates");
let kind = if is_end { let kind = if is_end {
state.active_touch_ids.remove(&touch_id); context.state.active_touch_ids.remove(&touch_id);
KeyTouchEventKind::End KeyTouchEventKind::End
} else { } else {
let is_new = state.active_touch_ids.insert(touch_id); let is_new = context.state.active_touch_ids.insert(touch_id);
if is_new { if is_new {
KeyTouchEventKind::Start KeyTouchEventKind::Start
} else { } else {
@ -170,7 +185,7 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
send_knob_event( send_knob_event(
KnobPath { KnobPath {
page_id: state.active_knob_page_id.clone(), page_id: context.state.active_knob_page_id.clone(),
position, position,
}, },
KnobEvent::Rotate { KnobEvent::Rotate {
@ -186,7 +201,7 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
send_knob_event( send_knob_event(
KnobPath { KnobPath {
page_id: state.active_knob_page_id.clone(), page_id: context.state.active_knob_page_id.clone(),
position, position,
}, },
KnobEvent::Press, KnobEvent::Press,
@ -198,46 +213,53 @@ fn handle_event(context: &IoWorkerContext, state: &mut State, event: LoupedeckEv
true true
} }
fn handle_command(context: &IoWorkerContext, state: &mut State, command: HandlerCommand) { fn handle_coordinator_command(context: &mut IoWorkerContext, command: CoordinatorCommand) {
log::trace!("Handling command: {:?}", &command); log::trace!("Handling coordinator command: {:?}", &command);
match command { match command {
HandlerCommand::SetActivePages { key_page_id, knob_page_id } => { CoordinatorCommand::SetActivePages { key_page_id, knob_page_id } => {
state.active_key_page_id = key_page_id; context.state.active_key_page_id = key_page_id;
state.active_knob_page_id = knob_page_id; context.state.active_knob_page_id = knob_page_id;
for button in context.device.characteristics().available_buttons { for button in context.device.characteristics().available_buttons {
context context
.device .device
.set_button_color(button, get_correct_button_color(context, state, ButtonPosition::of(&button))) .set_button_color(button, get_correct_button_color(context, &context.state, ButtonPosition::of(&button)))
.expect("the button is available for this device because that is literally what we are iterating over"); .expect("the button is available for this device because that is literally what we are iterating over");
} }
let key_grid = &context.device.characteristics().key_grid; redraw_visible_page(&context);
for index in 0..(key_grid.rows * key_grid.columns) { }
draw_key_at_index(context, state, index); CoordinatorCommand::SetRemoteHostIsActive { host_id, is_active } => {
if is_active {
context.state.active_remote_handler_host_ids.insert(host_id);
} else {
context.state.active_remote_handler_host_ids.remove(&host_id);
} }
for position in KnobPosition::VARIANTS { redraw_visible_page(&context);
draw_knob_at_position(context, state, *position); }
}
} }
context.device.refresh_display(&key_grid.display).unwrap(); fn handle_handler_command(context: &mut IoWorkerContext, command: HandlerCommand) {
} log::trace!("Handling handler command: {:?}", &command);
match command {
HandlerCommand::SetKeyStyle { path, value } => { HandlerCommand::SetKeyStyle { path, value } => {
state.mutate_key_for_command("SetKeyStyle", &path, |k| { context.state.mutate_key_for_command("SetKeyStyle", &path, |k| {
k.style = value; k.style = value;
}); });
draw_key_at_path_if_visible(context, state, path); draw_key_at_path_if_visible(context, path);
context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap(); context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap();
} }
HandlerCommand::SetKnobStyle { path, value } => { HandlerCommand::SetKnobStyle { path, value } => {
state.mutate_knob_for_command("SetKnobStyle", &path, |k| { context.state.mutate_knob_for_command("SetKnobStyle", &path, |k| {
k.style = value; k.style = value;
}); });
draw_knob_at_path_if_visible(context, state, path); draw_knob_at_path_if_visible(context, path);
context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap(); context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap();
} }
HandlerCommand::SetKnobValue { path, value } => { HandlerCommand::SetKnobValue { path, value } => {
@ -248,15 +270,28 @@ fn handle_command(context: &IoWorkerContext, state: &mut State, command: Handler
} }
} }
state.mutate_knob_for_command("SetKnobValue", &path, |k| { context.state.mutate_knob_for_command("SetKnobValue", &path, |k| {
k.value = value; k.value = value;
}); });
draw_knob_at_path_if_visible(context, state, path); draw_knob_at_path_if_visible(context, path);
} }
} }
} }
fn redraw_visible_page(context: &IoWorkerContext) {
let key_grid = &context.device.characteristics().key_grid;
for index in 0..(key_grid.rows * key_grid.columns) {
draw_key_at_index(context, index);
}
for position in KnobPosition::VARIANTS {
draw_knob_at_position(context, *position);
}
context.device.refresh_display(&key_grid.display).unwrap();
}
// active -> config.active_button_color // active -> config.active_button_color
// no actions defined -> #000000 // no actions defined -> #000000
// inactive -> config.inactive_button_color // inactive -> config.inactive_button_color
@ -306,6 +341,7 @@ fn draw_key(context: &IoWorkerContext, index: u8, key: Option<&Key>) {
let buffer = render_key( let buffer = render_key(
&context.graphics, &context.graphics,
IntSize::from_wh(rect.w as u32, rect.h as u32).expect("rect.w and rect.h are not zero"), IntSize::from_wh(rect.w as u32, rect.h as u32).expect("rect.w and rect.h are not zero"),
&context.state.active_remote_handler_host_ids,
key, key,
); );
context context
@ -314,23 +350,23 @@ fn draw_key(context: &IoWorkerContext, index: u8, key: Option<&Key>) {
.unwrap(); .unwrap();
} }
fn draw_key_at_index(context: &IoWorkerContext, state: &State, index: u8) { fn draw_key_at_index(context: &IoWorkerContext, index: u8) {
let position = get_key_position_for_index(&context.device.characteristics().key_grid, index); let position = get_key_position_for_index(&context.device.characteristics().key_grid, index);
draw_key(context, index, state.active_key_page().keys_by_position.get(&position)); draw_key(context, index, context.state.active_key_page().keys_by_position.get(&position));
} }
fn draw_key_at_position_if_visible(context: &IoWorkerContext, state: &State, position: KeyPosition) { fn draw_key_at_position_if_visible(context: &IoWorkerContext, position: KeyPosition) {
let index = get_key_index_for_position(&context.device.characteristics().key_grid, position); let index = get_key_index_for_position(&context.device.characteristics().key_grid, position);
if let Some(index) = index { if let Some(index) = index {
draw_key(context, index, state.active_key_page().keys_by_position.get(&position)); draw_key(context, index, context.state.active_key_page().keys_by_position.get(&position));
} }
} }
fn draw_key_at_path_if_visible(context: &IoWorkerContext, state: &State, path: KeyPath) { fn draw_key_at_path_if_visible(context: &IoWorkerContext, path: KeyPath) {
if state.active_key_page_id == path.page_id { if context.state.active_key_page_id == path.page_id {
draw_key_at_position_if_visible(context, state, path.position); draw_key_at_position_if_visible(context, path.position);
} }
} }
@ -346,6 +382,7 @@ fn draw_knob(context: &IoWorkerContext, position: KnobPosition, knob: Option<&Kn
let buffer = render_knob( let buffer = render_knob(
&context.graphics, &context.graphics,
IntSize::from_wh(rect.w as u32, rect.h as u32).expect("rect.w and rect.h are not zero."), IntSize::from_wh(rect.w as u32, rect.h as u32).expect("rect.w and rect.h are not zero."),
&context.state.active_remote_handler_host_ids,
knob, knob,
); );
context context
@ -355,13 +392,13 @@ fn draw_knob(context: &IoWorkerContext, position: KnobPosition, knob: Option<&Kn
} }
} }
fn draw_knob_at_position(context: &IoWorkerContext, state: &State, position: KnobPosition) { fn draw_knob_at_position(context: &IoWorkerContext, position: KnobPosition) {
draw_knob(context, position, Some(&state.active_knob_page().knobs_by_position[position])); draw_knob(context, position, Some(&context.state.active_knob_page().knobs_by_position[position]));
} }
fn draw_knob_at_path_if_visible(context: &IoWorkerContext, state: &State, path: KnobPath) { fn draw_knob_at_path_if_visible(context: &IoWorkerContext, path: KnobPath) {
if state.active_knob_page_id == path.page_id { if context.state.active_knob_page_id == path.page_id {
draw_knob_at_position(context, state, path.position); draw_knob_at_position(context, path.position);
} }
} }

View file

@ -12,12 +12,11 @@ use deckster_shared::path::{KeyPath, KnobPath};
use loupedeck_serial::commands::VibrationPattern; use loupedeck_serial::commands::VibrationPattern;
use loupedeck_serial::device::LoupedeckDevice; use loupedeck_serial::device::LoupedeckDevice;
use crate::coordinator::io_worker::{do_io_work, IoWorkerContext}; use crate::coordinator::io_worker::{do_io_work, CoordinatorCommand, IoWorkerContext};
use crate::coordinator::mqtt::start_mqtt_client; use crate::coordinator::mqtt::start_mqtt_client;
use crate::handler_runner; use crate::handler_runner;
use crate::handler_runner::KeyOrKnobHandlerConfig; use crate::handler_runner::KeyOrKnobHandlerConfig;
use crate::model::coordinator_config::Config; use crate::model::coordinator_config::Config;
use crate::model::get_default_host_id;
use crate::model::mqtt::HandlerHostsConfig; use crate::model::mqtt::HandlerHostsConfig;
mod graphics; mod graphics;
@ -33,11 +32,12 @@ pub async fn start(config_directory: &Path, config: Config) -> Result<()> {
let available_device = available_devices.first().wrap_err("No device connected.")?; let available_device = available_devices.first().wrap_err("No device connected.")?;
log::info!("Found {} device(s).", available_devices.len()); log::info!("Found {} device(s).", available_devices.len());
let (commands_sender, commands_receiver) = flume::bounded::<HandlerCommand>(5); 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); let events_sender = broadcast::Sender::<HandlerEvent>::new(5);
commands_sender coordinator_commands_sender
.send(HandlerCommand::SetActivePages { .send(CoordinatorCommand::SetActivePages {
knob_page_id: config.initial.knob_page.clone(), knob_page_id: config.initial.knob_page.clone(),
key_page_id: config.initial.key_page.clone(), key_page_id: config.initial.key_page.clone(),
}) })
@ -91,16 +91,16 @@ pub async fn start(config_directory: &Path, config: Config) -> Result<()> {
if let Some(mqtt_config) = &config.mqtt { if let Some(mqtt_config) = &config.mqtt {
log::info!("Initializing MQTT client…"); log::info!("Initializing MQTT client…");
start_mqtt_client(mqtt_config, &handler_hosts_config, commands_sender.clone(), events_sender.subscribe()).await; start_mqtt_client(mqtt_config, &handler_hosts_config, handler_commands_sender.clone(), events_sender.subscribe()).await;
} }
log::info!("Initializing handler processes…"); log::info!("Initializing handler processes…");
handler_runner::start( handler_runner::start(
get_default_host_id(), String::default().into_boxed_str(),
&config_directory.join("handlers"), &config_directory.join("handlers"),
handler_hosts_config, handler_hosts_config,
commands_sender.clone(), handler_commands_sender.clone(),
events_sender.subscribe(), events_sender.subscribe(),
) )
.await?; .await?;
@ -112,12 +112,12 @@ pub async fn start(config_directory: &Path, config: Config) -> Result<()> {
device.set_brightness(0.5); device.set_brightness(0.5);
device.vibrate(VibrationPattern::RiseFall); device.vibrate(VibrationPattern::RiseFall);
let io_worker_context = IoWorkerContext::create(config_directory, Arc::clone(&config), device, commands_sender.clone(), events_sender); let io_worker_context = IoWorkerContext::create(config_directory, Arc::clone(&config), device, coordinator_commands_sender, events_sender);
let io_worker_thread = thread::Builder::new() let io_worker_thread = thread::Builder::new()
.name("deckster IO worker".to_owned()) .name("deckster IO worker".to_owned())
.spawn(move || { .spawn(move || {
do_io_work(io_worker_context, commands_receiver); do_io_work(io_worker_context, &coordinator_commands_receiver, &handler_commands_receiver);
}) })
.wrap_err("Could not spawn the worker thread")?; .wrap_err("Could not spawn the worker thread")?;

View file

@ -13,6 +13,7 @@ pub struct State {
pub active_key_page_id: String, pub active_key_page_id: String,
pub active_knob_page_id: String, pub active_knob_page_id: String,
pub active_touch_ids: HashSet<u8>, pub active_touch_ids: HashSet<u8>,
pub active_remote_handler_host_ids: HashSet<Box<str>>,
pub key_pages_by_id: HashMap<String, KeyPage>, pub key_pages_by_id: HashMap<String, KeyPage>,
pub knob_pages_by_id: HashMap<String, KnobPage>, pub knob_pages_by_id: HashMap<String, KnobPage>,
} }
@ -32,6 +33,7 @@ impl State {
page_id: p.id.clone(), page_id: p.id.clone(),
position: *position, position: *position,
}, },
host_id: k.host.clone(),
base_style: k.base_style.clone(), base_style: k.base_style.clone(),
style: None, style: None,
}) })
@ -54,6 +56,7 @@ impl State {
page_id: p.id.clone(), page_id: p.id.clone(),
position, position,
}, },
host_id: knob_config.host.clone(),
base_style: knob_config.base_style.clone(), base_style: knob_config.base_style.clone(),
style: None, style: None,
value: None, value: None,
@ -67,6 +70,7 @@ impl State {
active_key_page_id: config.initial.key_page.clone(), active_key_page_id: config.initial.key_page.clone(),
active_knob_page_id: config.initial.knob_page.clone(), active_knob_page_id: config.initial.knob_page.clone(),
active_touch_ids: HashSet::new(), active_touch_ids: HashSet::new(),
active_remote_handler_host_ids: HashSet::new(),
key_pages_by_id, key_pages_by_id,
knob_pages_by_id, knob_pages_by_id,
} }

View file

@ -135,7 +135,6 @@ pub async fn start_mqtt_client(
tokio::spawn(async move { tokio::spawn(async move {
while let Ok(command) = commands_receiver.recv_async().await { while let Ok(command) = commands_receiver.recv_async().await {
match command { match command {
HandlerCommand::SetActivePages { .. } => log::warn!("HandlerCommand::SetActivePages is not supported for remote handlers."),
HandlerCommand::SetKeyStyle { path, value } => client HandlerCommand::SetKeyStyle { path, value } => client
.publish( .publish(
format!("{topic_prefix}/keys/{path}/style"), format!("{topic_prefix}/keys/{path}/style"),

View file

@ -50,7 +50,7 @@ pub struct Key {
#[serde(default, flatten)] #[serde(default, flatten)]
pub base_style: KeyStyle, pub base_style: KeyStyle,
#[serde(default = "super::get_default_host_id")] #[serde(default)]
pub host: Box<str>, pub host: Box<str>,
pub handler: Box<str>, pub handler: Box<str>,
pub config: Arc<toml::Table>, pub config: Arc<toml::Table>,

View file

@ -24,7 +24,7 @@ pub struct Knob {
#[serde(default, flatten)] #[serde(default, flatten)]
pub base_style: KnobStyle, pub base_style: KnobStyle,
#[serde(default = "super::get_default_host_id")] #[serde(default)]
pub host: Box<str>, pub host: Box<str>,
pub handler: Box<str>, pub handler: Box<str>,
pub config: Arc<toml::Table>, pub config: Arc<toml::Table>,

View file

@ -5,7 +5,3 @@ pub mod key_page;
pub mod knob_page; pub mod knob_page;
pub mod mqtt; pub mod mqtt;
pub mod position; pub mod position;
pub fn get_default_host_id() -> Box<str> {
"local".to_owned().into_boxed_str()
}