//! Service binding implementations. //! //! Each binding protocol implements the `Binding` trait. //! The proxy uses whatever binding is configured in `el.toml`. pub mod direct; pub mod grpc; pub mod rest; pub mod websocket; use crate::ServiceResult; use std::collections::HashMap; /// Which protocol this service binding uses. #[derive(Debug, Clone, PartialEq, Eq)] pub enum BindingKind { /// HTTP REST — maps service methods to HTTP endpoints. Rest, /// WebSocket — persistent connection, message-based RPC. WebSocket, /// gRPC — protobuf over HTTP/2 (stub; codegen is a future TODO). Grpc, /// Direct — server-side only; calls Rust functions directly, zero network. Direct, } impl BindingKind { pub fn from_str(s: &str) -> Option { match s.to_lowercase().as_str() { "rest" => Some(Self::Rest), "websocket" | "ws" => Some(Self::WebSocket), "grpc" => Some(Self::Grpc), "direct" => Some(Self::Direct), _ => None, } } pub fn as_str(&self) -> &'static str { match self { Self::Rest => "rest", Self::WebSocket => "websocket", Self::Grpc => "grpc", Self::Direct => "direct", } } } /// A service call request — method name and parameters. #[derive(Debug, Clone)] pub struct ServiceRequest { pub service: String, pub method: String, /// Parameters as key-value pairs. Complex types are JSON-serialized strings. pub params: HashMap, } impl ServiceRequest { pub fn new(service: impl Into, method: impl Into) -> Self { Self { service: service.into(), method: method.into(), params: HashMap::new(), } } pub fn with_param(mut self, key: impl Into, value: impl Into) -> Self { self.params.insert(key.into(), value.into()); self } } /// A service call response — raw body string (JSON, protobuf bytes as hex, etc.) #[derive(Debug, Clone)] pub struct ServiceResponse { pub status: u16, pub body: String, pub headers: HashMap, } impl ServiceResponse { pub fn ok(body: impl Into) -> Self { Self { status: 200, body: body.into(), headers: HashMap::new(), } } pub fn error(status: u16, body: impl Into) -> Self { Self { status, body: body.into(), headers: HashMap::new(), } } pub fn is_success(&self) -> bool { (200..300).contains(&self.status) } } /// The core binding trait — implemented by each protocol. pub trait Binding: Send + Sync { /// The kind of binding this is. fn kind(&self) -> BindingKind; /// Execute a service method call and return the response. fn call(&self, request: ServiceRequest) -> ServiceResult; /// Whether this binding supports streaming responses. fn supports_streaming(&self) -> bool { false } }