hyperion/servers/
boblight.rs1use std::net::SocketAddr;
4
5use futures::prelude::*;
6use thiserror::Error;
7use tokio::net::TcpStream;
8use tokio_util::codec::Framed;
9
10use crate::{
11 api::boblight::{self, BoblightApiError},
12 global::{Global, InputSourceName},
13 instance::InstanceHandle,
14};
15
16mod codec;
18use codec::*;
19
20#[derive(Debug, Error)]
21pub enum BoblightServerError {
22 #[error("i/o error: {0}")]
23 Io(#[from] futures_io::Error),
24 #[error("codec error: {0}")]
25 Codec(#[from] BoblightCodecError),
26 #[error(transparent)]
27 Api(#[from] BoblightApiError),
28}
29
30#[instrument(skip(socket, led_count, instance, global))]
31pub async fn handle_client(
32 (socket, peer_addr): (TcpStream, SocketAddr),
33 led_count: usize,
34 instance: InstanceHandle,
35 global: Global,
36) -> Result<(), BoblightServerError> {
37 debug!("accepted new connection");
38
39 let framed = Framed::new(socket, BoblightCodec::new());
40 let (mut writer, mut reader) = framed.split();
41
42 let source_handle = global
43 .register_input_source(InputSourceName::Boblight { peer_addr }, None)
44 .await
45 .unwrap();
46
47 let mut connection = boblight::ClientConnection::new(source_handle, led_count, instance);
48
49 while let Some(request) = reader.next().await {
50 trace!(request = ?request, "processing");
51
52 match request {
53 Ok(request) => match connection.handle_request(request).await {
54 Ok(response) => {
55 if let Some(response) = response {
56 writer.send(response).await?;
57 writer.flush().await?;
58 }
59 }
60 Err(error) => {
61 warn!(error = %error, "boblight error");
62 }
63 },
64 Err(error) => {
65 warn!(error = %error, "boblight error");
66 }
67 }
68 }
69
70 Ok(())
71}