use std::convert::TryFrom;
use std::net::SocketAddr;
use std::sync::Arc;
use thiserror::Error;
use super::types::i32_to_duration;
use crate::{
component::ComponentName,
global::{
Global, InputMessage, InputMessageData, InputSourceHandle, InputSourceName, PriorityGuard,
},
image::{RawImage, RawImageError},
models::Color,
};
pub mod message;
#[derive(Debug, Error)]
pub enum FlatApiError {
#[error("error broadcasting update: {0}")]
Broadcast(#[from] tokio::sync::broadcast::error::SendError<InputMessage>),
#[error("source not registered")]
Unregistered,
#[error("invalid priority for registration, should be in [100, 200), got {0}")]
InvalidPriority(i32),
#[error("unknown command")]
UnknownCommand,
#[error("error decoding image: {0}")]
RawImageError(#[from] RawImageError),
}
async fn handle_register(
peer_addr: SocketAddr,
register: message::Register<'_>,
source: &mut Option<InputSourceHandle<InputMessage>>,
global: &Global,
priority_guard: &mut Option<PriorityGuard>,
) -> Result<(), FlatApiError> {
let priority = register.priority();
if !(100..200).contains(&priority) {
return Err(FlatApiError::InvalidPriority(priority));
} else {
let new_source = global
.register_input_source(
InputSourceName::FlatBuffers {
peer_addr,
origin: register.origin().to_owned(),
},
Some(priority),
)
.await
.unwrap();
*priority_guard = Some(PriorityGuard::new_broadcast(&new_source));
*source = Some(new_source);
}
Ok(())
}
#[instrument(skip(request, source, global, priority_guard))]
pub async fn handle_request(
peer_addr: SocketAddr,
request: message::Request<'_>,
source: &mut Option<InputSourceHandle<InputMessage>>,
global: &Global,
priority_guard: &mut Option<PriorityGuard>,
) -> Result<(), FlatApiError> {
if let Some(handle) = source.as_ref() {
let priority = handle.priority().unwrap();
if let Some(clear) = request.command_as_clear() {
if clear.priority() < 0 {
handle.send(ComponentName::FlatbufServer, InputMessageData::ClearAll)?;
} else {
handle.send(
ComponentName::FlatbufServer,
InputMessageData::Clear {
priority: clear.priority(),
},
)?;
}
} else if let Some(color) = request.command_as_color() {
let rgb = color.data();
let rgb = (
(rgb & 0x000_000FF) as u8,
((rgb & 0x0000_FF00) >> 8) as u8,
((rgb & 0x00FF_0000) >> 16) as u8,
);
handle.send(
ComponentName::FlatbufServer,
InputMessageData::SolidColor {
priority: 0,
duration: i32_to_duration(Some(color.duration())),
color: Color::from_components(rgb),
},
)?;
} else if let Some(image) = request.command_as_image() {
let data = image
.data_as_raw_image()
.ok_or_else(|| RawImageError::RawImageMissing)?;
let duration = image.duration();
let width = data.width();
let height = data.height();
let data = data.data().ok_or_else(|| RawImageError::RawImageMissing)?;
let width = u32::try_from(width).map_err(|_| RawImageError::InvalidWidth)?;
let height = u32::try_from(height).map_err(|_| RawImageError::InvalidHeight)?;
let raw_image = RawImage::try_from((data.bytes().to_vec(), width, height))?;
handle.send(
ComponentName::FlatbufServer,
InputMessageData::Image {
priority,
duration: i32_to_duration(Some(duration)),
image: Arc::new(raw_image),
},
)?;
} else if let Some(register) = request.command_as_register() {
return handle_register(peer_addr, register, source, global, priority_guard).await;
} else {
return Err(FlatApiError::UnknownCommand);
}
} else if let Some(register) = request.command_as_register() {
return handle_register(peer_addr, register, source, global, priority_guard).await;
} else {
return Err(FlatApiError::Unregistered);
};
Ok(())
}