use async_trait::async_trait;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::server::brp::{builtin_methods, BrpRequest, BrpResponse};
use crate::server::brp_validation::BrpValidator;
use crate::server::error::{Error, Result};
#[derive(Debug, Clone)]
pub struct CommandVersion {
pub major: u16,
pub minor: u16,
pub patch: u16,
}
impl CommandVersion {
pub fn new(major: u16, minor: u16, patch: u16) -> Self {
Self { major, minor, patch }
}
pub fn is_compatible_with(&self, other: &CommandVersion) -> bool {
self.major == other.major
}
}
impl Default for CommandVersion {
fn default() -> Self {
Self::new(1, 0, 0)
}
}
#[derive(Debug, Clone)]
pub struct CommandHandlerMetadata {
pub name: String,
pub version: CommandVersion,
pub description: String,
pub supported_commands: Vec<String>,
}
#[async_trait]
pub trait BrpCommandHandler: Send + Sync {
fn metadata(&self) -> CommandHandlerMetadata;
fn can_handle(&self, request: &BrpRequest) -> bool;
async fn handle(&self, request: BrpRequest) -> Result<BrpResponse>;
async fn validate(&self, request: &BrpRequest) -> Result<()> {
crate::server::brp_validation::validate_method_name(&request.method)
.map_err(Error::Validation)
}
fn priority(&self) -> i32 {
0
}
}
pub struct CommandHandlerRegistry {
handlers: Arc<RwLock<Vec<Arc<dyn BrpCommandHandler>>>>,
version_map: Arc<RwLock<HashMap<String, CommandVersion>>>,
validator: Arc<BrpValidator>,
}
impl CommandHandlerRegistry {
pub fn new() -> Self {
Self {
handlers: Arc::new(RwLock::new(Vec::new())),
version_map: Arc::new(RwLock::new(HashMap::new())),
validator: Arc::new(BrpValidator::new()),
}
}
pub fn with_validator(validator: BrpValidator) -> Self {
Self {
handlers: Arc::new(RwLock::new(Vec::new())),
version_map: Arc::new(RwLock::new(HashMap::new())),
validator: Arc::new(validator),
}
}
pub async fn register(&self, handler: Arc<dyn BrpCommandHandler>) {
let metadata = handler.metadata();
let mut version_map = self.version_map.write().await;
version_map.insert(metadata.name.clone(), metadata.version.clone());
let mut handlers = self.handlers.write().await;
handlers.push(handler);
handlers.sort_by_key(|h| -h.priority()); }
pub async fn find_handler(&self, request: &BrpRequest) -> Option<Arc<dyn BrpCommandHandler>> {
let handlers = self.handlers.read().await;
for handler in handlers.iter() {
if handler.can_handle(request) {
return Some(handler.clone());
}
}
None
}
pub async fn process(&self, request: BrpRequest) -> Result<BrpResponse> {
self.process_with_session(request, "default_session").await
}
pub async fn process_with_session(&self, request: BrpRequest, session_id: &str) -> Result<BrpResponse> {
if let Some(handler) = self.find_handler(&request).await {
let request_size = serde_json::to_vec(&request)
.map_err(|e| crate::server::error::Error::Json(e))?
.len();
self.validator.validate_request(&request, session_id, request_size).await?;
handler.validate(&request).await?;
handler.handle(request).await
} else {
Err(crate::server::error::Error::Validation(format!(
"No handler found for request type: {:?}",
request
)))
}
}
pub async fn get_versions(&self) -> HashMap<String, CommandVersion> {
self.version_map.read().await.clone()
}
pub async fn is_version_supported(&self, handler_name: &str, version: &CommandVersion) -> bool {
let version_map = self.version_map.read().await;
if let Some(registered_version) = version_map.get(handler_name) {
registered_version.is_compatible_with(version)
} else {
false
}
}
pub fn get_validator(&self) -> Arc<BrpValidator> {
self.validator.clone()
}
}
pub struct CoreBrpHandler;
#[async_trait]
impl BrpCommandHandler for CoreBrpHandler {
fn metadata(&self) -> CommandHandlerMetadata {
CommandHandlerMetadata {
name: "core".to_string(),
version: CommandVersion::new(1, 0, 0),
description: "Handler for core BRP methods".to_string(),
supported_commands: vec![
builtin_methods::BRP_QUERY_METHOD.to_string(),
builtin_methods::BRP_GET_COMPONENTS_METHOD.to_string(),
builtin_methods::BRP_SPAWN_ENTITY_METHOD.to_string(),
builtin_methods::BRP_DESPAWN_COMPONENTS_METHOD.to_string(),
builtin_methods::BRP_INSERT_COMPONENTS_METHOD.to_string(),
builtin_methods::BRP_REMOVE_COMPONENTS_METHOD.to_string(),
builtin_methods::BRP_REPARENT_ENTITIES_METHOD.to_string(),
builtin_methods::BRP_LIST_COMPONENTS_METHOD.to_string(),
],
}
}
fn can_handle(&self, request: &BrpRequest) -> bool {
matches!(
request.method.as_str(),
builtin_methods::BRP_QUERY_METHOD
| builtin_methods::BRP_GET_COMPONENTS_METHOD
| builtin_methods::BRP_SPAWN_ENTITY_METHOD
| builtin_methods::BRP_DESPAWN_COMPONENTS_METHOD
| builtin_methods::BRP_INSERT_COMPONENTS_METHOD
| builtin_methods::BRP_REMOVE_COMPONENTS_METHOD
| builtin_methods::BRP_REPARENT_ENTITIES_METHOD
| builtin_methods::BRP_LIST_COMPONENTS_METHOD
)
}
async fn handle(&self, _request: BrpRequest) -> Result<BrpResponse> {
Err(Error::Validation(
"CoreBrpHandler does not execute requests locally".to_string(),
))
}
fn priority(&self) -> i32 {
-100 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_version_compatibility() {
let v1 = CommandVersion::new(1, 0, 0);
let v2 = CommandVersion::new(1, 1, 0);
let v3 = CommandVersion::new(2, 0, 0);
assert!(v1.is_compatible_with(&v2));
assert!(!v1.is_compatible_with(&v3));
}
#[tokio::test]
async fn test_handler_registry() {
let registry = CommandHandlerRegistry::new();
let handler = Arc::new(CoreBrpHandler);
registry.register(handler.clone()).await;
let request = BrpRequest {
method: builtin_methods::BRP_LIST_COMPONENTS_METHOD.to_string(),
id: None,
params: None,
};
let found = registry.find_handler(&request).await;
assert!(found.is_some());
}
#[tokio::test]
async fn test_handler_priority() {
struct HighPriorityHandler;
#[async_trait]
impl BrpCommandHandler for HighPriorityHandler {
fn metadata(&self) -> CommandHandlerMetadata {
CommandHandlerMetadata {
name: "high_priority".to_string(),
version: CommandVersion::default(),
description: "High priority handler".to_string(),
supported_commands: vec![
builtin_methods::BRP_LIST_COMPONENTS_METHOD.to_string()
],
}
}
fn can_handle(&self, request: &BrpRequest) -> bool {
request.method == builtin_methods::BRP_LIST_COMPONENTS_METHOD
}
async fn handle(&self, _request: BrpRequest) -> Result<BrpResponse> {
Err(Error::Validation("test stub".to_string()))
}
fn priority(&self) -> i32 {
100 }
}
let registry = CommandHandlerRegistry::new();
registry.register(Arc::new(CoreBrpHandler)).await;
registry.register(Arc::new(HighPriorityHandler)).await;
let request = BrpRequest {
method: builtin_methods::BRP_LIST_COMPONENTS_METHOD.to_string(),
id: None,
params: None,
};
let handler = registry.find_handler(&request).await.unwrap();
assert_eq!(handler.priority(), 100);
}
}