//! Service proxy — the generated client for a service. //! //! A `ServiceProxy` wraps a binding and provides typed method calls. //! The codegen (a future agent) will generate typed proxy structs from service //! definitions. This is the runtime base that generated code builds on. use crate::{ binding::{Binding, ServiceRequest, ServiceResponse}, config::ServiceConfig, ServiceResult, }; use std::collections::HashMap; use std::sync::Arc; /// A service method descriptor — used by the proxy and codegen. #[derive(Debug, Clone)] pub struct ServiceMethod { pub name: String, /// Parameter names in order (for positional call support). pub param_names: Vec, pub return_type: String, } impl ServiceMethod { pub fn new(name: impl Into, return_type: impl Into) -> Self { Self { name: name.into(), param_names: Vec::new(), return_type: return_type.into(), } } pub fn with_params(mut self, params: Vec>) -> Self { self.param_names = params.into_iter().map(|p| p.into()).collect(); self } } /// A runtime service proxy. /// /// The codegen produces a typed wrapper around this. /// Directly usable for dynamic invocation (e.g., from the AOP layer). pub struct ServiceProxy { pub service_name: String, pub config: ServiceConfig, pub binding: Arc, pub methods: Vec, } impl ServiceProxy { pub fn new( service_name: impl Into, config: ServiceConfig, binding: Arc, ) -> Self { Self { service_name: service_name.into(), config, binding, methods: Vec::new(), } } pub fn with_method(mut self, method: ServiceMethod) -> Self { self.methods.push(method); self } /// Call a service method by name with named parameters. pub fn call( &self, method_name: &str, params: HashMap, ) -> ServiceResult { let request = ServiceRequest { service: self.service_name.clone(), method: method_name.to_string(), params, }; self.binding.call(request) } /// Call a service method by name with positional parameters. /// Parameters are matched to the method's `param_names` in order. pub fn call_positional( &self, method_name: &str, args: Vec, ) -> ServiceResult { let method = self .methods .iter() .find(|m| m.name == method_name) .ok_or_else(|| crate::ServiceError::MethodNotFound { service: self.service_name.clone(), method: method_name.to_string(), })?; let params: HashMap = method .param_names .iter() .zip(args.iter()) .map(|(name, val)| (name.clone(), val.clone())) .collect(); self.call(method_name, params) } /// List all registered method names on this proxy. pub fn method_names(&self) -> Vec<&str> { self.methods.iter().map(|m| m.name.as_str()).collect() } }