use std::collections::HashMap; use actix::{Actor, Context, Handler, Message, Recipient}; use emgauwa_lib::errors::EmgauwaError; use emgauwa_lib::models::Controller; use emgauwa_lib::types::{ControllerUid, ControllerWsAction, RelayStates}; use futures::executor::block_on; use sqlx::{Pool, Sqlite}; #[derive(Message)] #[rtype(result = "Result<(), EmgauwaError>")] pub struct DisconnectController { pub controller_uid: ControllerUid, } #[derive(Message)] #[rtype(result = "Result<(), EmgauwaError>")] pub struct ConnectController { pub address: Recipient, pub controller: Controller, } #[derive(Message)] #[rtype(result = "()")] pub struct UpdateRelayStates { pub controller_uid: ControllerUid, pub relay_states: RelayStates, } #[derive(Message)] #[rtype(result = "Result<(), EmgauwaError>")] pub struct Action { pub controller_uid: ControllerUid, pub action: ControllerWsAction, } pub struct AppState { pub pool: Pool, pub connected_controllers: HashMap)>, } impl AppState { pub fn new(pool: Pool) -> AppState { AppState { pool, connected_controllers: HashMap::new(), } } } impl Actor for AppState { type Context = Context; } impl Handler for AppState { type Result = Result<(), EmgauwaError>; fn handle(&mut self, msg: DisconnectController, _ctx: &mut Self::Context) -> Self::Result { let mut pool_conn = block_on(self.pool.acquire())?; if let Some((controller, address)) = self.connected_controllers.remove(&msg.controller_uid) { if let Err(err) = block_on(controller.c.update_active(&mut pool_conn, false)) { log::error!( "Failed to mark controller {} as inactive: {:?}", controller.c.uid, err ); } // TODO: why does the block_on(send()) version not return? The AppState will be stuck. //block_on(address.send(ControllerWsAction::Disconnect))??; address.do_send(ControllerWsAction::Disconnect); } Ok(()) } } impl Handler for AppState { type Result = Result<(), EmgauwaError>; fn handle(&mut self, msg: ConnectController, _ctx: &mut Self::Context) -> Self::Result { log::debug!("Connecting controller: {}", msg.controller.c.uid); self.connected_controllers .insert(msg.controller.c.uid.clone(), (msg.controller, msg.address)); Ok(()) } } impl Handler for AppState { type Result = (); fn handle(&mut self, msg: UpdateRelayStates, _ctx: &mut Self::Context) -> Self::Result { if let Some((controller, _)) = self.connected_controllers.get_mut(&msg.controller_uid) { controller.apply_relay_states(&msg.relay_states); } } } impl Handler for AppState { type Result = Result<(), EmgauwaError>; fn handle(&mut self, msg: Action, _ctx: &mut Self::Context) -> Self::Result { log::debug!("Forwarding action: {:?}", msg.action); if let Some((_, address)) = self.connected_controllers.get(&msg.controller_uid) { // TODO: why does the block_on(send()) version not return? The AppState will be stuck. //block_on(address.send(msg.action))? address.do_send(msg.action); Ok(()) } else { Err(EmgauwaError::Connection(msg.controller_uid)) } } }