Add ControllerWsAction
This commit is contained in:
parent
cb47dcda5c
commit
3b596de06f
10 changed files with 134 additions and 34 deletions
|
@ -2,13 +2,12 @@ openapi: 3.0.0
|
|||
info:
|
||||
contact:
|
||||
name: Tobias Reisinger
|
||||
url: 'https://serguzim.me'
|
||||
url: 'https://git.serguzim.me/emgauwa/'
|
||||
title: Emgauwa API v1
|
||||
version: 0.0.1
|
||||
version: 0.5.0
|
||||
description: Server API to manage an Emgauwa system.
|
||||
servers:
|
||||
- url: 'http://emgauwa-test-raspi.fritz.box'
|
||||
- url: 'http://localhost:5000'
|
||||
- url: 'http://localhost:4419'
|
||||
tags:
|
||||
- name: schedules
|
||||
- name: relays
|
||||
|
@ -319,7 +318,7 @@ paths:
|
|||
'404':
|
||||
description: Not Found
|
||||
operationId: delete-controllers-controller_id
|
||||
description: Delete a single controller. To recover the controller you need to use the conbtrollers/discover feature.
|
||||
description: Delete a single controller. To recover the controller you need to use the controllers/discover feature.
|
||||
'/api/v1/controllers/{controller_id}/relays':
|
||||
parameters:
|
||||
- schema:
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::str;
|
|||
use crate::relay_loop::run_relay_loop;
|
||||
use crate::settings::Settings;
|
||||
use emgauwa_lib::db::{DbController, DbRelay};
|
||||
use emgauwa_lib::handlers::v1::ws::controllers::ControllerWsAction;
|
||||
use emgauwa_lib::models::convert_db_list;
|
||||
use emgauwa_lib::types::ControllerUid;
|
||||
use emgauwa_lib::{db, models};
|
||||
|
@ -96,10 +97,6 @@ async fn main() {
|
|||
relays,
|
||||
};
|
||||
|
||||
let this_json = serde_json::to_string(&this).unwrap();
|
||||
|
||||
println!("{}", this_json);
|
||||
|
||||
let url = format!(
|
||||
"ws://{}:{}/api/v1/ws/controllers",
|
||||
settings.core.host, settings.core.port
|
||||
|
@ -112,7 +109,11 @@ async fn main() {
|
|||
|
||||
let (mut write, read) = ws_stream.split();
|
||||
|
||||
write.send(Message::text(this_json)).await.unwrap();
|
||||
let ws_action = ControllerWsAction::Register(this);
|
||||
println!("Sending action: {:?}", ws_action);
|
||||
let ws_action_json = serde_json::to_string(&ws_action).unwrap();
|
||||
println!("Sending json: {}", ws_action_json);
|
||||
write.send(Message::text(ws_action_json)).await.unwrap();
|
||||
let ws_to_stdout = read.for_each(handle_message);
|
||||
let stdin_to_ws = stdin_rx.map(Ok).forward(write);
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ use tokio::time;
|
|||
pub async fn run_relay_loop(settings: Settings) {
|
||||
let default_duration = Duration::from_millis(1000);
|
||||
loop {
|
||||
// naivetime timestamp for now
|
||||
let next_timestamp = Local::now().naive_local().time() + default_duration;
|
||||
time::sleep(default_duration).await;
|
||||
println!("Relay loop: {}", next_timestamp)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use serde_derive::Serialize;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use sqlx::pool::PoolConnection;
|
||||
|
@ -8,9 +8,11 @@ use crate::db::errors::DatabaseError;
|
|||
use crate::db::DbTag;
|
||||
use crate::types::ControllerUid;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbController {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
#[serde(rename = "id")]
|
||||
pub uid: ControllerUid,
|
||||
pub name: String,
|
||||
pub relay_count: i64,
|
||||
|
@ -51,6 +53,19 @@ impl DbController {
|
|||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
uid: &ControllerUid,
|
||||
new_name: &str,
|
||||
new_relay_count: i64,
|
||||
new_active: bool,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
match DbController::get_by_uid(conn, uid).await? {
|
||||
Some(tag) => Ok(tag),
|
||||
None => DbController::create(conn, uid, new_name, new_relay_count, new_active).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use serde_derive::Serialize;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use crate::db::DbController;
|
||||
|
@ -8,7 +8,7 @@ use sqlx::Sqlite;
|
|||
use crate::db::errors::DatabaseError;
|
||||
use crate::db::DbTag;
|
||||
|
||||
#[derive(Debug, Serialize, Clone, sqlx::FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbRelay {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
|
@ -51,6 +51,18 @@ impl DbRelay {
|
|||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_by_controller_and_num_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
controller: &DbController,
|
||||
number: i64,
|
||||
new_name: &str,
|
||||
) -> Result<DbRelay, DatabaseError> {
|
||||
match DbRelay::get_by_controller_and_num(conn, controller, number).await? {
|
||||
Some(relay) => Ok(relay),
|
||||
None => DbRelay::create(conn, new_name, number, controller).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
|
|
|
@ -10,11 +10,11 @@ use crate::db::model_utils::Period;
|
|||
use crate::db::DbTag;
|
||||
use crate::types::ScheduleUid;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbSchedule {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
#[serde(rename(serialize = "id"))]
|
||||
#[serde(rename = "id")]
|
||||
pub uid: ScheduleUid,
|
||||
pub name: String,
|
||||
pub periods: DbPeriods,
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
use crate::db::DbSchedule;
|
||||
use crate::db::errors::DatabaseError;
|
||||
use crate::db::{DbController, DbRelay};
|
||||
use crate::handlers::errors::ApiError;
|
||||
use crate::models::Controller;
|
||||
use actix::{Actor, StreamHandler};
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use actix_web_actors::ws;
|
||||
use actix_web_actors::ws::ProtocolError;
|
||||
use futures::FutureExt;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use ws::Message;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ControllerWsAction {
|
||||
Register(Controller),
|
||||
}
|
||||
|
||||
struct ControllerWs {
|
||||
pub pool: Pool<Sqlite>,
|
||||
}
|
||||
|
@ -15,24 +25,57 @@ impl Actor for ControllerWs {
|
|||
type Context = ws::WebsocketContext<Self>;
|
||||
}
|
||||
|
||||
async fn get_schedules(pool: &mut Pool<Sqlite>) -> Result<Vec<DbSchedule>, ApiError> {
|
||||
let mut pool_conn = pool.acquire().await?;
|
||||
|
||||
Ok(DbSchedule::get_all(&mut pool_conn).await?)
|
||||
}
|
||||
|
||||
impl StreamHandler<Result<Message, ProtocolError>> for ControllerWs {
|
||||
fn handle(&mut self, msg: Result<Message, ProtocolError>, ctx: &mut Self::Context) {
|
||||
let schedules = futures::executor::block_on(get_schedules(&mut self.pool)).unwrap();
|
||||
let schedules_json = serde_json::to_string(&schedules).unwrap();
|
||||
let mut pool_conn = futures::executor::block_on(self.pool.acquire()).unwrap();
|
||||
|
||||
match msg {
|
||||
Ok(Message::Ping(msg)) => ctx.pong(&msg),
|
||||
Ok(Message::Text(text)) => {
|
||||
println!("Got text: {}", text);
|
||||
ctx.text(schedules_json)
|
||||
let action: ControllerWsAction = serde_json::from_str(&text).unwrap();
|
||||
let action_res = futures::executor::block_on(handle_action(&mut pool_conn, action));
|
||||
if let Err(e) = action_res {
|
||||
log::error!("Error handling action: {:?}", e);
|
||||
ctx.text(serde_json::to_string(&e).unwrap());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
//let schedules = futures::executor::block_on(DbSchedule::get_all(&mut pool_conn)).unwrap();
|
||||
//let schedules_json = serde_json::to_string(&schedules).unwrap();
|
||||
//ctx.text(schedules_json);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_action(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
action: ControllerWsAction,
|
||||
) -> Result<(), DatabaseError> {
|
||||
match action {
|
||||
ControllerWsAction::Register(controller) => {
|
||||
log::info!("Registering controller: {:?}", controller);
|
||||
let c = &controller.controller;
|
||||
let controller_db =
|
||||
DbController::get_by_uid_or_create(conn, &c.uid, &c.name, c.relay_count, c.active)
|
||||
.await?;
|
||||
|
||||
println!("Controller: {:?}", controller_db);
|
||||
|
||||
for relay in &controller.relays {
|
||||
let r = &relay.relay;
|
||||
let relay_db = DbRelay::get_by_controller_and_num_or_create(
|
||||
conn,
|
||||
&controller_db,
|
||||
r.number,
|
||||
&r.name,
|
||||
)
|
||||
.await?;
|
||||
println!("Controller relay: {:?}", relay_db);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::db;
|
||||
use crate::db::errors::DatabaseError;
|
||||
use crate::db::{DbRelay, DbSchedule};
|
||||
use crate::types::ControllerUid;
|
||||
use futures::executor;
|
||||
use serde_derive::Serialize;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
|
@ -17,22 +18,23 @@ pub trait FromDbModel {
|
|||
Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Schedule {
|
||||
#[serde(flatten)]
|
||||
pub schedule: DbSchedule,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Relay {
|
||||
#[serde(flatten)]
|
||||
pub relay: DbRelay,
|
||||
pub controller: db::DbController,
|
||||
pub controller_id: ControllerUid,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Controller {
|
||||
#[serde(flatten)]
|
||||
pub controller: db::DbController,
|
||||
|
@ -62,11 +64,13 @@ impl FromDbModel for Relay {
|
|||
) -> Result<Self, DatabaseError> {
|
||||
let relay = db_model.clone();
|
||||
let controller = executor::block_on(relay.get_controller(conn))?;
|
||||
let controller_id = controller.uid.clone();
|
||||
let tags = executor::block_on(relay.get_tags(conn))?;
|
||||
|
||||
Ok(Relay {
|
||||
relay,
|
||||
controller,
|
||||
controller_id,
|
||||
tags,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use serde::{Serialize, Serializer};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use sqlx::database::HasArguments;
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
||||
use sqlx::{Decode, Encode, Sqlite, Type};
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -24,6 +25,16 @@ impl Serialize for ControllerUid {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ControllerUid {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str())
|
||||
.map_err(|_| serde::de::Error::custom("invalid controller uid"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ControllerUid> for String {
|
||||
fn from(uid: &ControllerUid) -> String {
|
||||
uid.0.as_hyphenated().to_string()
|
||||
|
@ -55,6 +66,12 @@ impl<'r> Decode<'r, Sqlite> for ControllerUid {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ControllerUid {
|
||||
fn from(value: &str) -> Self {
|
||||
Self(Uuid::from_str(value).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for ControllerUid {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
Self(Uuid::from_slice(value).unwrap())
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::convert::TryFrom;
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use sqlx::database::HasArguments;
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
|
@ -75,6 +75,16 @@ impl Serialize for ScheduleUid {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ScheduleUid {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str())
|
||||
.map_err(|_| serde::de::Error::custom("invalid schedule uid"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for ScheduleUid {
|
||||
fn from(uid: Uuid) -> Self {
|
||||
match uid.as_u128() {
|
||||
|
|
Loading…
Reference in a new issue