Implement Commanding (#6)

Reviewed-on: #6
Co-authored-by: Sergey Savelyev <sergeysav.nn@gmail.com>
Co-committed-by: Sergey Savelyev <sergeysav.nn@gmail.com>
This commit was merged in pull request #6.
This commit is contained in:
2025-12-28 13:39:12 -08:00
committed by sergeysav
parent 8cfaf468e9
commit f658b55586
33 changed files with 1389 additions and 98 deletions

View File

@@ -0,0 +1,34 @@
use crate::command::service::CommandManagementService;
use crate::http::error::HttpServerResultError;
use actix_web::{get, post, web, Responder};
use std::sync::Arc;
#[post("/cmd/{name:[\\w\\d/_-]+}")]
pub(super) async fn send_command(
command_service: web::Data<Arc<CommandManagementService>>,
name: web::Path<String>,
parameters: web::Json<serde_json::Map<String, serde_json::Value>>,
) -> Result<impl Responder, HttpServerResultError> {
let result = command_service
.send_command(name.to_string(), parameters.into_inner())
.await?;
Ok(web::Json(result))
}
#[get("/cmd")]
pub(super) async fn get_all(
command_service: web::Data<Arc<CommandManagementService>>,
) -> Result<impl Responder, HttpServerResultError> {
Ok(web::Json(command_service.get_commands()?))
}
#[get("/cmd/{name:[\\w\\d/_-]+}")]
pub(super) async fn get_one(
command_service: web::Data<Arc<CommandManagementService>>,
name: web::Path<String>,
) -> Result<impl Responder, HttpServerResultError> {
Ok(web::Json(
command_service.get_command_definition(&name.to_string()),
))
}

View File

@@ -1,3 +1,4 @@
mod cmd;
mod panels;
mod tlm;
@@ -11,5 +12,8 @@ pub fn setup_api(cfg: &mut web::ServiceConfig) {
.service(panels::get_all)
.service(panels::get_one)
.service(panels::set)
.service(panels::delete);
.service(panels::delete)
.service(cmd::send_command)
.service(cmd::get_all)
.service(cmd::get_one);
}

View File

@@ -2,7 +2,6 @@ use actix_web::error::ResponseError;
use actix_web::http::header::ContentType;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use anyhow::Error;
use thiserror::Error;
#[derive(Error, Debug)]
@@ -16,31 +15,28 @@ pub enum HttpServerResultError {
#[error("Timed out")]
Timeout,
#[error("Internal Error")]
InternalError(anyhow::Error),
InternalError(#[from] anyhow::Error),
#[error("Panel Uuid Not Found: {uuid}")]
PanelUuidNotFound { uuid: String },
#[error(transparent)]
Command(#[from] crate::command::error::Error),
}
impl ResponseError for HttpServerResultError {
fn status_code(&self) -> StatusCode {
match *self {
match self {
HttpServerResultError::TlmNameNotFound { .. } => StatusCode::NOT_FOUND,
HttpServerResultError::TlmUuidNotFound { .. } => StatusCode::NOT_FOUND,
HttpServerResultError::InvalidDateTime { .. } => StatusCode::BAD_REQUEST,
HttpServerResultError::Timeout => StatusCode::GATEWAY_TIMEOUT,
HttpServerResultError::InternalError { .. } => StatusCode::INTERNAL_SERVER_ERROR,
HttpServerResultError::PanelUuidNotFound { .. } => StatusCode::NOT_FOUND,
HttpServerResultError::Command(inner) => inner.status_code(),
}
}
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status_code())
.insert_header(ContentType::html())
.insert_header(ContentType::plaintext())
.body(self.to_string())
}
}
impl From<anyhow::Error> for HttpServerResultError {
fn from(value: Error) -> Self {
Self::InternalError(value)
}
}

View File

@@ -2,6 +2,7 @@ mod api;
mod error;
mod websocket;
use crate::command::service::CommandManagementService;
use crate::http::api::setup_api;
use crate::http::websocket::setup_websocket;
use crate::panels::PanelService;
@@ -16,10 +17,12 @@ pub async fn setup(
cancellation_token: CancellationToken,
telemetry_definitions: Arc<TelemetryManagementService>,
panel_service: PanelService,
command_service: Arc<CommandManagementService>,
) -> anyhow::Result<()> {
let data = web::Data::new(telemetry_definitions);
let cancel_token = web::Data::new(cancellation_token);
let panel_service = web::Data::new(Arc::new(panel_service));
let command_service = web::Data::new(command_service);
info!("Starting HTTP Server");
HttpServer::new(move || {
@@ -27,6 +30,7 @@ pub async fn setup(
.app_data(data.clone())
.app_data(cancel_token.clone())
.app_data(panel_service.clone())
.app_data(command_service.clone())
.service(web::scope("/ws").configure(setup_websocket))
.service(web::scope("/api").configure(setup_api))
.wrap(Logger::default())