uses a proc-macro to automate command definitions

This commit is contained in:
2025-12-31 00:23:30 -05:00
parent 6fdbb868b7
commit 0e28b0416a
26 changed files with 757 additions and 177 deletions

73
api/src/client/command.rs Normal file
View File

@@ -0,0 +1,73 @@
use crate::client::Client;
use crate::messages::command::CommandResponse;
use api_core::command::{CommandHeader, IntoCommandDefinition};
use std::fmt::Display;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
pub struct Commanding;
impl Commanding {
pub fn register_handler<C: IntoCommandDefinition, F, E: Display>(
client: Arc<Client>,
command_name: String,
mut callback: F,
) -> CommandHandle
where
F: FnMut(CommandHeader, C) -> Result<String, E> + Send + 'static,
{
let cancellation_token = CancellationToken::new();
let result = CommandHandle {
cancellation_token: cancellation_token.clone(),
};
let command_definition = C::create(command_name);
tokio::spawn(async move {
while !cancellation_token.is_cancelled() {
// This would only fail if the sender closed while trying to insert data
// It would wait until space is made
let Ok(mut rx) = client
.register_callback_channel(command_definition.clone())
.await
else {
continue;
};
while let Some((cmd, responder)) = rx.recv().await {
let header = cmd.header.clone();
let response = match C::parse(cmd) {
Ok(cmd) => match callback(header, cmd) {
Ok(response) => CommandResponse {
success: true,
response,
},
Err(err) => CommandResponse {
success: false,
response: err.to_string(),
},
},
Err(err) => CommandResponse {
success: false,
response: err.to_string(),
},
};
// This should only err if we had an error elsewhere
let _ = responder.send(response);
}
}
});
result
}
}
pub struct CommandHandle {
cancellation_token: CancellationToken,
}
impl Drop for CommandHandle {
fn drop(&mut self) {
self.cancellation_token.cancel();
}
}

View File

@@ -1,3 +1,4 @@
pub mod command;
mod context;
pub mod error;
pub mod telemetry;