This repository has been archived on 2026-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
el-retired/ui/vessels/el-services/src/proxy.rs
T

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()
}
}