Tobias Reisinger
b742f0f8d6
Some checks failed
/ build-artifacts (arm-unknown-linux-gnueabihf) (push) Failing after 9m27s
188 lines
5.2 KiB
Rust
188 lines
5.2 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use actix::{Actor, Addr, Context, Handler, Message, Recipient};
|
|
use emgauwa_common::db::DbController;
|
|
use emgauwa_common::errors::EmgauwaError;
|
|
use emgauwa_common::models::{convert_db_list, Controller, Relay};
|
|
use emgauwa_common::types::{ControllerWsAction, EmgauwaUid, RelayStates};
|
|
use futures::executor::block_on;
|
|
use sqlx::{Pool, Sqlite};
|
|
|
|
use crate::handlers::v1::ws::relays::{RelaysWs, SendRelays};
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "Result<(), EmgauwaError>")]
|
|
pub struct DisconnectController {
|
|
pub controller_uid: EmgauwaUid,
|
|
}
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "Result<(), EmgauwaError>")]
|
|
pub struct ConnectController {
|
|
pub address: Recipient<ControllerWsAction>,
|
|
pub controller: Controller,
|
|
}
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "()")]
|
|
pub struct UpdateRelayStates {
|
|
pub controller_uid: EmgauwaUid,
|
|
pub relay_states: RelayStates,
|
|
}
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "Result<Vec<Relay>, EmgauwaError>")]
|
|
pub struct GetRelays {}
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "Result<(), EmgauwaError>")]
|
|
pub struct Action {
|
|
pub controller_uid: EmgauwaUid,
|
|
pub action: ControllerWsAction,
|
|
}
|
|
|
|
#[derive(Message)]
|
|
#[rtype(result = "()")]
|
|
pub struct ConnectRelayClient {
|
|
pub addr: Addr<RelaysWs>,
|
|
}
|
|
|
|
pub struct AppState {
|
|
pub pool: Pool<Sqlite>,
|
|
pub connected_controllers: HashMap<EmgauwaUid, (Controller, Recipient<ControllerWsAction>)>,
|
|
pub connected_relay_clients: Vec<Addr<RelaysWs>>,
|
|
}
|
|
|
|
impl AppState {
|
|
pub fn new(pool: Pool<Sqlite>) -> AppState {
|
|
AppState {
|
|
pool,
|
|
connected_controllers: HashMap::new(),
|
|
connected_relay_clients: Vec::new(),
|
|
}
|
|
}
|
|
|
|
fn get_relays(&self) -> Result<Vec<Relay>, EmgauwaError> {
|
|
let mut pool_conn = block_on(self.pool.acquire())?;
|
|
let db_controllers = block_on(DbController::get_all(&mut pool_conn))?;
|
|
let mut controllers: Vec<Controller> = convert_db_list(&mut pool_conn, db_controllers)?;
|
|
|
|
self.connected_controllers
|
|
.iter()
|
|
.for_each(|(uid, (connected_controller, _))| {
|
|
if let Some(c) = controllers.iter_mut().find(|c| c.c.uid == *uid) {
|
|
c.apply_relay_states(&connected_controller.get_relay_states());
|
|
}
|
|
});
|
|
|
|
let mut relays: Vec<Relay> = Vec::new();
|
|
controllers.iter().for_each(|c| {
|
|
relays.extend(c.relays.clone());
|
|
});
|
|
|
|
Ok(relays)
|
|
}
|
|
|
|
fn notify_relay_clients(&mut self) {
|
|
self.connected_relay_clients.retain(|addr| addr.connected());
|
|
|
|
match self.get_relays() {
|
|
Ok(relays) => match serde_json::to_string(&relays) {
|
|
Ok(json) => {
|
|
self.connected_relay_clients.iter_mut().for_each(|addr| {
|
|
let relays_json = json.clone();
|
|
addr.do_send(SendRelays { relays_json });
|
|
});
|
|
}
|
|
Err(err) => {
|
|
log::error!("Failed to serialize relays: {:?}", err);
|
|
}
|
|
},
|
|
Err(err) => {
|
|
log::error!("Failed to get relays: {:?}", err);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
impl Actor for AppState {
|
|
type Context = Context<Self>;
|
|
}
|
|
|
|
impl Handler<DisconnectController> 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<ConnectController> 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<UpdateRelayStates> 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);
|
|
}
|
|
self.notify_relay_clients();
|
|
}
|
|
}
|
|
|
|
impl Handler<GetRelays> for AppState {
|
|
type Result = Result<Vec<Relay>, EmgauwaError>;
|
|
|
|
fn handle(&mut self, _msg: GetRelays, _ctx: &mut Self::Context) -> Self::Result {
|
|
self.get_relays()
|
|
}
|
|
}
|
|
|
|
impl Handler<Action> 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))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Handler<ConnectRelayClient> for AppState {
|
|
type Result = ();
|
|
|
|
fn handle(&mut self, msg: ConnectRelayClient, _ctx: &mut Self::Context) -> Self::Result {
|
|
self.connected_relay_clients.push(msg.addr);
|
|
}
|
|
}
|