Archived
114 lines
3.2 KiB
Rust
114 lines
3.2 KiB
Rust
//! 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<String>,
|
|
pub return_type: String,
|
|
}
|
|
|
|
impl ServiceMethod {
|
|
pub fn new(name: impl Into<String>, return_type: impl Into<String>) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
param_names: Vec::new(),
|
|
return_type: return_type.into(),
|
|
}
|
|
}
|
|
|
|
pub fn with_params(mut self, params: Vec<impl Into<String>>) -> 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<dyn Binding>,
|
|
pub methods: Vec<ServiceMethod>,
|
|
}
|
|
|
|
impl ServiceProxy {
|
|
pub fn new(
|
|
service_name: impl Into<String>,
|
|
config: ServiceConfig,
|
|
binding: Arc<dyn Binding>,
|
|
) -> 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<String, String>,
|
|
) -> ServiceResult<ServiceResponse> {
|
|
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<String>,
|
|
) -> ServiceResult<ServiceResponse> {
|
|
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<String, String> = 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()
|
|
}
|
|
}
|