new-home-proxy 0.1.2

This is a part of the New Home IoT System. It is used to make the core available in the www.
use std::sync::Arc;
use std::time::SystemTime;

use actix::clock::Duration;
use actix::{Actor, AsyncContext, Handler, StreamHandler};
use actix_web_actors::ws::{Message as WebsocketMessage, ProtocolError, WebsocketContext};
use serde_json::to_string as json_to_string;

use crate::communication::{
    ProxyRequest, ProxyResponse, WebsocketCommand, WebsocketSignal, WrappedMessage,
};
use crate::server::client_manager::ClientManager;

pub struct WebsocketHandler {
    last_ping: SystemTime,
    client_manager: Arc<ClientManager>,
    client_id: String,
}

impl WebsocketHandler {
    pub fn new(client_manager: Arc<ClientManager>, client_id: String) -> Self {
        WebsocketHandler {
            last_ping: SystemTime::now(),
            client_manager,
            client_id,
        }
    }
}

impl Actor for WebsocketHandler {
    type Context = WebsocketContext<Self>;
}

impl StreamHandler<Result<WebsocketMessage, ProtocolError>> for WebsocketHandler {
    fn handle(
        &mut self,
        message: Result<WebsocketMessage, ProtocolError>,
        ctx: &mut Self::Context,
    ) {
        match message {
            Ok(WebsocketMessage::Text(message)) => {
                if let Ok(message) = serde_json::from_str::<WrappedMessage<ProxyResponse>>(&message)
                {
                    if let Err(error) = self
                        .client_manager
                        .response(message.id.clone(), message.into_inner())
                    {
                        println!("Could not respond to message: {}", error);
                    }
                }
            }
            Ok(WebsocketMessage::Ping(_)) => {
                self.last_ping = SystemTime::now();
                ctx.pong(&[]);
            }
            _ => {}
        }
    }

    fn started(&mut self, ctx: &mut Self::Context) {
        self.last_ping = SystemTime::now();

        if let Err(error) = self
            .client_manager
            .register_client(self.client_id.clone(), ctx.address())
        {
            println!("Client could not be registered: {}", error);

            ctx.close(None);
        }
    }

    fn finished(&mut self, _: &mut Self::Context) {
        if let Err(_) = self.client_manager.unregister_client(&self.client_id) {}
    }
}

impl Handler<WrappedMessage<ProxyRequest>> for WebsocketHandler {
    type Result = ();

    fn handle(
        &mut self,
        msg: WrappedMessage<ProxyRequest>,
        ctx: &mut Self::Context,
    ) -> Self::Result {
        ctx.text(json_to_string(&msg).unwrap_or_default());

        ()
    }
}

impl Handler<WebsocketCommand> for WebsocketHandler {
    type Result = ();

    fn handle(&mut self, command: WebsocketCommand, ctx: &mut Self::Context) -> Self::Result {
        match command.0 {
            WebsocketSignal::Close => {
                ctx.close(None);

                self.client_manager
                    .unregister_client(&self.client_id)
                    .unwrap_or_default();
            }
            WebsocketSignal::CheckPing => {
                let ping_age = SystemTime::now()
                    .duration_since(self.last_ping)
                    .unwrap_or(Duration::from_secs(99))
                    .as_millis();

                if ping_age > 1500 {
                    ctx.close(None);

                    self.client_manager
                        .unregister_client(&self.client_id)
                        .unwrap_or_default();
                }
            }
            _ => {}
        }
    }
}