work to make backend Req -> Res typesafe using Resolve trait

This commit is contained in:
mbecker20
2023-06-09 15:50:13 +00:00
parent fecc5134ad
commit c8a24dbcbc
15 changed files with 212 additions and 177 deletions

View File

@@ -2,7 +2,7 @@
extern crate log;
use anyhow::{anyhow, Context};
use monitor_types::{HasResponse, periphery_api::requests};
use monitor_types::api::{periphery::requests, HasResponse};
use reqwest::StatusCode;
use serde_json::json;

View File

@@ -8,8 +8,11 @@ license.workspace = true
[dependencies]
serde.workspace = true
serde_json.workspace = true
axum.workspace = true
diff-struct.workspace = true
typeshare.workspace = true
strum.workspace = true
strum_macros.workspace = true
async-trait.workspace = true
async-trait.workspace = true
anyhow.workspace = true

41
lib/types/src/api/mod.rs Normal file
View File

@@ -0,0 +1,41 @@
use anyhow::Context;
use axum::{headers::ContentType, http::StatusCode, TypedHeader};
use serde::{de::DeserializeOwned, Serialize};
pub mod core;
pub mod periphery;
pub trait HasResponse: Serialize + DeserializeOwned + std::fmt::Debug + Send + 'static {
type Response: Serialize + DeserializeOwned + std::fmt::Debug;
fn req_type() -> &'static str;
}
#[async_trait::async_trait]
pub trait Resolve<Req: HasResponse> {
async fn resolve(&self, req: Req) -> anyhow::Result<Req::Response>;
async fn resolve_to_response(
&self,
req: Req,
) -> Result<(TypedHeader<ContentType>, String), (StatusCode, String)> {
let res = self
.resolve(req)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:#?}")))?;
let res = serde_json::to_string(&res)
.context("failed at serializing response")
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:#?}")))?;
Ok((TypedHeader(ContentType::json()), res))
}
}
#[macro_export]
macro_rules! impl_has_response {
($req:ty, $res:ty) => {
impl $crate::api::HasResponse for $req {
type Response = $res;
fn req_type() -> &'static str {
stringify!($req)
}
}
};
}

View File

@@ -1,8 +1,11 @@
use serde::{Deserialize, Serialize};
use crate::SystemCommand;
use crate::entities::SystemCommand;
use self::requests::{GetHealth, GetVersion, GetSystemInformation, GetBasicSystemStats, GetDiskUsage, GetNetworkUsage, GetSystemProcesses, GetAllSystemStats, GetSystemComponents, GetCpuUsage};
use self::requests::{
GetAllSystemStats, GetBasicSystemStats, GetCpuUsage, GetDiskUsage, GetHealth, GetNetworkUsage,
GetSystemComponents, GetSystemInformation, GetSystemProcesses, GetVersion,
};
pub mod requests;

View File

@@ -1,2 +1,129 @@
use diff::Diff;
use serde::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};
use typeshare::typeshare;
pub mod server;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Diff)]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub struct SystemCommand {
#[serde(default)]
pub path: String,
#[serde(default)]
pub command: String,
}
#[typeshare]
#[derive(
Serialize,
Deserialize,
Debug,
Display,
EnumString,
PartialEq,
Hash,
Eq,
Clone,
Copy,
Diff,
Default,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub enum Timelength {
#[serde(rename = "1-sec")]
#[strum(serialize = "1-sec")]
OneSecond,
#[serde(rename = "5-sec")]
#[strum(serialize = "5-sec")]
FiveSeconds,
#[serde(rename = "10-sec")]
#[strum(serialize = "10-sec")]
TenSeconds,
#[serde(rename = "15-sec")]
#[strum(serialize = "15-sec")]
FifteenSeconds,
#[serde(rename = "30-sec")]
#[strum(serialize = "30-sec")]
ThirtySeconds,
#[default]
#[serde(rename = "1-min")]
#[strum(serialize = "1-min")]
OneMinute,
#[serde(rename = "2-min")]
#[strum(serialize = "2-min")]
TwoMinutes,
#[serde(rename = "5-min")]
#[strum(serialize = "5-min")]
FiveMinutes,
#[serde(rename = "10-min")]
#[strum(serialize = "10-min")]
TenMinutes,
#[serde(rename = "15-min")]
#[strum(serialize = "15-min")]
FifteenMinutes,
#[serde(rename = "30-min")]
#[strum(serialize = "30-min")]
ThirtyMinutes,
#[serde(rename = "1-hr")]
#[strum(serialize = "1-hr")]
OneHour,
#[serde(rename = "2-hr")]
#[strum(serialize = "2-hr")]
TwoHours,
#[serde(rename = "6-hr")]
#[strum(serialize = "6-hr")]
SixHours,
#[serde(rename = "8-hr")]
#[strum(serialize = "8-hr")]
EightHours,
#[serde(rename = "12-hr")]
#[strum(serialize = "12-hr")]
TwelveHours,
#[serde(rename = "1-day")]
#[strum(serialize = "1-day")]
OneDay,
#[serde(rename = "3-day")]
#[strum(serialize = "3-day")]
ThreeDay,
#[serde(rename = "1-wk")]
#[strum(serialize = "1-wk")]
OneWeek,
#[serde(rename = "2-wk")]
#[strum(serialize = "2-wk")]
TwoWeeks,
#[serde(rename = "30-day")]
#[strum(serialize = "30-day")]
ThirtyDays,
}
#[typeshare]
#[derive(
Serialize,
Deserialize,
Debug,
Display,
EnumString,
Hash,
Clone,
Copy,
Diff,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub enum PermissionLevel {
#[default]
None,
Read,
Execute,
Update,
}

View File

@@ -1,9 +1,11 @@
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::{I64, Timelength};
use crate::I64;
use super::Timelength;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
@@ -119,4 +121,4 @@ pub struct SystemComponent {
pub max: f32,
#[serde(skip_serializing_if = "Option::is_none")]
pub critical: Option<f32>,
}
}

View File

@@ -1,157 +1,7 @@
use diff::Diff;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use strum_macros::{Display, EnumString};
use typeshare::typeshare;
pub mod core_api;
pub mod api;
pub mod entities;
pub mod periphery_api;
#[typeshare(serialized_as = "number")]
pub type I64 = i64;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Diff)]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub struct SystemCommand {
#[serde(default)]
pub path: String,
#[serde(default)]
pub command: String,
}
#[typeshare]
#[derive(
Serialize,
Deserialize,
Debug,
Display,
EnumString,
PartialEq,
Hash,
Eq,
Clone,
Copy,
Diff,
Default,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub enum Timelength {
#[serde(rename = "1-sec")]
#[strum(serialize = "1-sec")]
OneSecond,
#[serde(rename = "5-sec")]
#[strum(serialize = "5-sec")]
FiveSeconds,
#[serde(rename = "10-sec")]
#[strum(serialize = "10-sec")]
TenSeconds,
#[serde(rename = "15-sec")]
#[strum(serialize = "15-sec")]
FifteenSeconds,
#[serde(rename = "30-sec")]
#[strum(serialize = "30-sec")]
ThirtySeconds,
#[default]
#[serde(rename = "1-min")]
#[strum(serialize = "1-min")]
OneMinute,
#[serde(rename = "2-min")]
#[strum(serialize = "2-min")]
TwoMinutes,
#[serde(rename = "5-min")]
#[strum(serialize = "5-min")]
FiveMinutes,
#[serde(rename = "10-min")]
#[strum(serialize = "10-min")]
TenMinutes,
#[serde(rename = "15-min")]
#[strum(serialize = "15-min")]
FifteenMinutes,
#[serde(rename = "30-min")]
#[strum(serialize = "30-min")]
ThirtyMinutes,
#[serde(rename = "1-hr")]
#[strum(serialize = "1-hr")]
OneHour,
#[serde(rename = "2-hr")]
#[strum(serialize = "2-hr")]
TwoHours,
#[serde(rename = "6-hr")]
#[strum(serialize = "6-hr")]
SixHours,
#[serde(rename = "8-hr")]
#[strum(serialize = "8-hr")]
EightHours,
#[serde(rename = "12-hr")]
#[strum(serialize = "12-hr")]
TwelveHours,
#[serde(rename = "1-day")]
#[strum(serialize = "1-day")]
OneDay,
#[serde(rename = "3-day")]
#[strum(serialize = "3-day")]
ThreeDay,
#[serde(rename = "1-wk")]
#[strum(serialize = "1-wk")]
OneWeek,
#[serde(rename = "2-wk")]
#[strum(serialize = "2-wk")]
TwoWeeks,
#[serde(rename = "30-day")]
#[strum(serialize = "30-day")]
ThirtyDays,
}
#[typeshare]
#[derive(
Serialize,
Deserialize,
Debug,
Display,
EnumString,
Hash,
Clone,
Copy,
Diff,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
pub enum PermissionLevel {
#[default]
None,
Read,
Execute,
Update,
}
pub trait HasResponse: Serialize + std::fmt::Debug {
type Response: DeserializeOwned + std::fmt::Debug;
fn req_type() -> &'static str;
}
#[async_trait::async_trait]
pub trait Resolve<Req: HasResponse> {
async fn resolve(&self, req: Req) -> Req::Response;
}
#[macro_export]
macro_rules! impl_has_response {
($req:ty, $res:ty) => {
impl $crate::HasResponse for $req {
type Response = $res;
fn req_type() -> &'static str {
stringify!($req)
}
}
};
}