hyperion/api/
flat.rs

1use std::convert::TryFrom;
2use std::net::SocketAddr;
3use std::sync::Arc;
4
5use thiserror::Error;
6
7use super::types::i32_to_duration;
8
9use crate::{
10    component::ComponentName,
11    global::{
12        Global, InputMessage, InputMessageData, InputSourceHandle, InputSourceName, PriorityGuard,
13    },
14    image::{RawImage, RawImageError},
15    models::Color,
16};
17
18/// Schema definitions as Serde serializable structures and enums
19pub mod message;
20
21#[derive(Debug, Error)]
22pub enum FlatApiError {
23    #[error("error broadcasting update: {0}")]
24    Broadcast(#[from] tokio::sync::broadcast::error::SendError<InputMessage>),
25    #[error("source not registered")]
26    Unregistered,
27    #[error("invalid priority for registration, should be in [100, 200), got {0}")]
28    InvalidPriority(i32),
29    #[error("unknown command")]
30    UnknownCommand,
31    #[error("error decoding image: {0}")]
32    RawImageError(#[from] RawImageError),
33}
34
35async fn handle_register(
36    peer_addr: SocketAddr,
37    register: message::Register<'_>,
38    source: &mut Option<InputSourceHandle<InputMessage>>,
39    global: &Global,
40    priority_guard: &mut Option<PriorityGuard>,
41) -> Result<(), FlatApiError> {
42    let priority = register.priority();
43
44    if !(100..200).contains(&priority) {
45        return Err(FlatApiError::InvalidPriority(priority));
46    } else {
47        // unwrap: we checked the priority value before
48        let new_source = global
49            .register_input_source(
50                InputSourceName::FlatBuffers {
51                    peer_addr,
52                    origin: register.origin().to_owned(),
53                },
54                Some(priority),
55            )
56            .await
57            .unwrap();
58
59        // Update priority guard
60        *priority_guard = Some(PriorityGuard::new_broadcast(&new_source));
61        *source = Some(new_source);
62    }
63
64    Ok(())
65}
66
67#[instrument(skip(request, source, global, priority_guard))]
68pub async fn handle_request(
69    peer_addr: SocketAddr,
70    request: message::Request<'_>,
71    source: &mut Option<InputSourceHandle<InputMessage>>,
72    global: &Global,
73    priority_guard: &mut Option<PriorityGuard>,
74) -> Result<(), FlatApiError> {
75    if let Some(handle) = source.as_ref() {
76        // unwrap: we set a priority when we got the register call
77        let priority = handle.priority().unwrap();
78
79        if let Some(clear) = request.command_as_clear() {
80            // Update state
81            if clear.priority() < 0 {
82                handle.send(ComponentName::FlatbufServer, InputMessageData::ClearAll)?;
83            } else {
84                handle.send(
85                    ComponentName::FlatbufServer,
86                    InputMessageData::Clear {
87                        priority: clear.priority(),
88                    },
89                )?;
90            }
91        } else if let Some(color) = request.command_as_color() {
92            let rgb = color.data();
93            let rgb = (
94                (rgb & 0x000_000FF) as u8,
95                ((rgb & 0x0000_FF00) >> 8) as u8,
96                ((rgb & 0x00FF_0000) >> 16) as u8,
97            );
98
99            // Update state
100            handle.send(
101                ComponentName::FlatbufServer,
102                InputMessageData::SolidColor {
103                    // TODO
104                    priority: 0,
105                    duration: i32_to_duration(Some(color.duration())),
106                    color: Color::from_components(rgb),
107                },
108            )?;
109        } else if let Some(image) = request.command_as_image() {
110            // Get raw image
111            let data = image
112                .data_as_raw_image()
113                .ok_or_else(|| RawImageError::RawImageMissing)?;
114
115            // Extract fields
116            let duration = image.duration();
117            let width = data.width();
118            let height = data.height();
119            let data = data.data().ok_or_else(|| RawImageError::RawImageMissing)?;
120
121            // Parse message
122            let width = u32::try_from(width).map_err(|_| RawImageError::InvalidWidth)?;
123            let height = u32::try_from(height).map_err(|_| RawImageError::InvalidHeight)?;
124            let raw_image = RawImage::try_from((data.bytes().to_vec(), width, height))?;
125
126            // Update state
127            handle.send(
128                ComponentName::FlatbufServer,
129                InputMessageData::Image {
130                    priority,
131                    duration: i32_to_duration(Some(duration)),
132                    image: Arc::new(raw_image),
133                },
134            )?;
135        } else if let Some(register) = request.command_as_register() {
136            return handle_register(peer_addr, register, source, global, priority_guard).await;
137        } else {
138            return Err(FlatApiError::UnknownCommand);
139        }
140    } else if let Some(register) = request.command_as_register() {
141        return handle_register(peer_addr, register, source, global, priority_guard).await;
142    } else {
143        return Err(FlatApiError::Unregistered);
144    };
145
146    Ok(())
147}