1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Boblight protocol server implementation

use std::net::SocketAddr;

use futures::prelude::*;
use thiserror::Error;
use tokio::net::TcpStream;
use tokio_util::codec::Framed;

use crate::{
    api::boblight::{self, BoblightApiError},
    global::{Global, InputSourceName},
    instance::InstanceHandle,
};

/// Boblight protocol codec definition
mod codec;
use codec::*;

#[derive(Debug, Error)]
pub enum BoblightServerError {
    #[error("i/o error: {0}")]
    Io(#[from] futures_io::Error),
    #[error("codec error: {0}")]
    Codec(#[from] BoblightCodecError),
    #[error(transparent)]
    Api(#[from] BoblightApiError),
}

#[instrument(skip(socket, led_count, instance, global))]
pub async fn handle_client(
    (socket, peer_addr): (TcpStream, SocketAddr),
    led_count: usize,
    instance: InstanceHandle,
    global: Global,
) -> Result<(), BoblightServerError> {
    debug!("accepted new connection");

    let framed = Framed::new(socket, BoblightCodec::new());
    let (mut writer, mut reader) = framed.split();

    let source_handle = global
        .register_input_source(InputSourceName::Boblight { peer_addr }, None)
        .await
        .unwrap();

    let mut connection = boblight::ClientConnection::new(source_handle, led_count, instance);

    while let Some(request) = reader.next().await {
        trace!(request = ?request, "processing");

        match request {
            Ok(request) => match connection.handle_request(request).await {
                Ok(response) => {
                    if let Some(response) = response {
                        writer.send(response).await?;
                        writer.flush().await?;
                    }
                }
                Err(error) => {
                    warn!(error = %error, "boblight error");
                }
            },
            Err(error) => {
                warn!(error = %error, "boblight error");
            }
        }
    }

    Ok(())
}