use std::collections::HashMap;
use crate::binary::SignedInvocation;
use crate::dispatch::handler::{SharedArgs, ToolHandler, ToolResult};
use crate::protocol::schema::SchemaValidator;
use crate::protocol::ToolSchema;
use crate::security::{NonceStore, Verifier};
use crate::{CapabilityManifest, DCPError, SecurityError};
pub struct BinaryTrieRouter {
handlers: Vec<Option<Box<dyn ToolHandler>>>,
name_to_id: HashMap<String, u16>,
max_tool_id: u16,
}
impl BinaryTrieRouter {
pub const MAX_TOOLS: usize = CapabilityManifest::MAX_TOOLS;
pub fn new() -> Self {
Self {
handlers: Vec::new(),
name_to_id: HashMap::new(),
max_tool_id: 0,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
handlers: Vec::with_capacity(capacity.min(Self::MAX_TOOLS)),
name_to_id: HashMap::with_capacity(capacity),
max_tool_id: 0,
}
}
pub fn register(&mut self, handler: Box<dyn ToolHandler>) -> Result<u16, DCPError> {
let tool_id = handler.tool_id();
let tool_name = handler.tool_name().to_string();
let id_usize = tool_id as usize;
if id_usize >= Self::MAX_TOOLS {
return Err(DCPError::ValidationFailed);
}
if self.name_to_id.contains_key(&tool_name) {
return Err(DCPError::ValidationFailed);
}
if self
.handlers
.get(id_usize)
.and_then(|handler| handler.as_ref())
.is_some()
{
return Err(DCPError::ValidationFailed);
}
while self.handlers.len() <= id_usize {
self.handlers.push(None);
}
self.handlers[id_usize] = Some(handler);
self.name_to_id.insert(tool_name, tool_id);
if tool_id > self.max_tool_id {
self.max_tool_id = tool_id;
}
Ok(tool_id)
}
#[inline(always)]
pub(crate) fn dispatch(&self, tool_id: u16) -> Option<&dyn ToolHandler> {
self.handlers
.get(tool_id as usize)
.and_then(|h| h.as_ref())
.map(|h| h.as_ref())
}
pub fn tool_schema(&self, tool_id: u16) -> Option<&ToolSchema> {
self.dispatch(tool_id).map(|handler| handler.schema())
}
pub fn execute(&self, tool_id: u16, args: &SharedArgs) -> Result<ToolResult, DCPError> {
let _ = (tool_id, args);
Err(DCPError::CapabilityDenied)
}
pub fn execute_authorized(
&self,
capabilities: &CapabilityManifest,
tool_id: u16,
args: &SharedArgs,
) -> Result<ToolResult, SecurityError> {
let handler = self.validate_authorized_tool(capabilities, tool_id, args)?;
handler
.execute(args)
.map_err(|_| SecurityError::InsufficientCapabilities)
}
pub fn execute_signed_authorized(
&self,
capabilities: &CapabilityManifest,
invocation: &SignedInvocation,
public_key: &[u8; 32],
nonce_store: &mut NonceStore,
args: &SharedArgs,
) -> Result<ToolResult, SecurityError> {
Verifier::verify_invocation(invocation, public_key)?;
if !Verifier::verify_args_hash(invocation, args.data()) {
return Err(SecurityError::ArgsHashMismatch);
}
let tool_id = u16::try_from(invocation.tool_id)
.map_err(|_| SecurityError::InsufficientCapabilities)?;
nonce_store.check_nonce(invocation.nonce, invocation.timestamp)?;
let handler = self.validate_authorized_tool(capabilities, tool_id, args)?;
handler
.execute(args)
.map_err(|_| SecurityError::InsufficientCapabilities)
}
fn validate_authorized_tool(
&self,
capabilities: &CapabilityManifest,
tool_id: u16,
args: &SharedArgs,
) -> Result<&dyn ToolHandler, SecurityError> {
capabilities.require_tool(tool_id)?;
let handler = self
.dispatch(tool_id)
.ok_or(SecurityError::InsufficientCapabilities)?;
SchemaValidator::validate_shared_args(&handler.schema().input, args)
.map_err(|_| SecurityError::ValidationFailed)?;
Ok(handler)
}
pub fn resolve_name(&self, name: &str) -> Option<u16> {
self.name_to_id.get(name).copied()
}
pub fn max_tool_id(&self) -> u16 {
self.max_tool_id
}
pub fn tool_count(&self) -> usize {
self.handlers.iter().filter(|h| h.is_some()).count()
}
pub fn has_tool(&self, tool_id: u16) -> bool {
self.dispatch(tool_id).is_some()
}
pub fn tool_names(&self) -> impl Iterator<Item = &str> {
self.name_to_id.keys().map(|s| s.as_str())
}
pub fn capabilities(&self) -> ServerCapabilities {
ServerCapabilities {
tools: self.tool_count() > 0,
resources: false, prompts: false, logging: true,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ServerCapabilities {
pub tools: bool,
pub resources: bool,
pub prompts: bool,
pub logging: bool,
}
impl Default for BinaryTrieRouter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::schema::{InputSchema, ToolSchema};
struct TestHandler {
schema: ToolSchema,
}
impl TestHandler {
fn new(id: u16, name: &'static str) -> Self {
Self {
schema: ToolSchema {
name,
id,
description: "Test tool",
input: InputSchema::new(),
},
}
}
}
impl ToolHandler for TestHandler {
fn execute(&self, _args: &SharedArgs) -> Result<ToolResult, DCPError> {
Ok(ToolResult::success(vec![self.schema.id as u8]))
}
fn schema(&self) -> &ToolSchema {
&self.schema
}
}
#[test]
fn test_register_and_dispatch() {
let mut router = BinaryTrieRouter::new();
let handler = Box::new(TestHandler::new(1, "test_tool"));
router.register(handler).unwrap();
assert!(router.has_tool(1));
assert!(!router.has_tool(0));
assert!(!router.has_tool(2));
let dispatched = router.dispatch(1).unwrap();
assert_eq!(dispatched.tool_id(), 1);
}
#[test]
fn test_resolve_name() {
let mut router = BinaryTrieRouter::new();
router
.register(Box::new(TestHandler::new(42, "my_tool")))
.unwrap();
assert_eq!(router.resolve_name("my_tool"), Some(42));
assert_eq!(router.resolve_name("unknown"), None);
}
#[test]
fn test_raw_execute_is_deny_by_default() {
let mut router = BinaryTrieRouter::new();
router
.register(Box::new(TestHandler::new(5, "exec_test")))
.unwrap();
let args = SharedArgs::new(&[], 0);
let result = router.execute(5, &args);
assert_eq!(result, Err(DCPError::CapabilityDenied));
}
#[test]
fn test_raw_execute_hides_tool_existence() {
let router = BinaryTrieRouter::new();
let args = SharedArgs::new(&[], 0);
let result = router.execute(999, &args);
assert_eq!(result, Err(DCPError::CapabilityDenied));
}
#[test]
fn test_multiple_tools() {
let mut router = BinaryTrieRouter::new();
for i in 0..10 {
let name: &'static str = Box::leak(format!("tool_{}", i).into_boxed_str());
router
.register(Box::new(TestHandler::new(i, name)))
.unwrap();
}
assert_eq!(router.tool_count(), 10);
assert_eq!(router.max_tool_id(), 9);
for i in 0..10 {
assert!(router.has_tool(i));
}
}
#[test]
fn test_sparse_registration() {
let mut router = BinaryTrieRouter::new();
router
.register(Box::new(TestHandler::new(0, "first")))
.unwrap();
router
.register(Box::new(TestHandler::new(100, "hundredth")))
.unwrap();
router
.register(Box::new(TestHandler::new(1000, "thousandth")))
.unwrap();
assert_eq!(router.tool_count(), 3);
assert!(router.has_tool(0));
assert!(router.has_tool(100));
assert!(router.has_tool(1000));
assert!(!router.has_tool(50));
}
}