1use anyhow::Result;
4use std::any::{Any, TypeId};
5use std::collections::HashMap;
6use std::fmt;
7use std::future::Future;
8use std::pin::Pin;
9
10pub fn default_scope() -> String {
11 "any".to_string()
12}
13
14#[derive(Debug, Clone)]
16pub struct CapabilityDefinition {
17 pub name: String,
18 pub kind: String,
19 pub scope: String,
20 pub properties: HashMap<String, serde_json::Value>,
21}
22
23#[derive(Debug, Clone)]
25pub struct ComponentDefinition {
26 pub name: String,
27 pub uri: String,
28 pub scope: String,
29 pub imports: Vec<String>,
30 pub interceptors: Vec<String>,
31 pub config: HashMap<String, serde_json::Value>,
32}
33
34pub struct ComponentState {
36 pub wasi_ctx: wasmtime_wasi::WasiCtx,
37 pub wasi_http_ctx: Option<wasmtime_wasi_http::WasiHttpCtx>,
38 pub resource_table: wasmtime_wasi::ResourceTable,
39 pub(crate) extensions: HashMap<TypeId, Box<dyn Any + Send>>,
40}
41
42impl ComponentState {
43 pub fn get_extension<T: 'static + Send>(&self) -> Option<&T> {
45 self.extensions
46 .get(&TypeId::of::<T>())
47 .and_then(|boxed| boxed.downcast_ref())
48 }
49
50 pub fn get_extension_mut<T: 'static + Send>(&mut self) -> Option<&mut T> {
52 self.extensions
53 .get_mut(&TypeId::of::<T>())
54 .and_then(|boxed| boxed.downcast_mut())
55 }
56
57 pub fn set_extension<T: 'static + Send>(&mut self, value: T) {
59 self.extensions.insert(TypeId::of::<T>(), Box::new(value));
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
66pub struct Interface {
67 namespace: String,
68 package: String,
69 interface: String,
70 version: Option<String>,
71 full_name: String,
72}
73
74impl Interface {
75 pub fn parse(s: &str) -> Result<Self> {
77 if let Some((namespace, rest)) = s.split_once(':')
78 && let Some((package, after_slash)) = rest.split_once('/')
79 {
80 let (interface, version) = if let Some((i, v)) = after_slash.split_once('@') {
81 (i, Some(v.to_string()))
82 } else {
83 (after_slash, None)
84 };
85
86 return Ok(Self {
87 namespace: namespace.to_string(),
88 package: package.to_string(),
89 interface: interface.to_string(),
90 version,
91 full_name: s.to_string(),
92 });
93 }
94
95 Err(anyhow::anyhow!(
96 "Invalid WIT interface format: expected namespace:package/interface[@version], got: {s}"
97 ))
98 }
99
100 pub fn as_str(&self) -> &str {
102 &self.full_name
103 }
104
105 pub fn namespace(&self) -> &str {
107 &self.namespace
108 }
109
110 pub fn package(&self) -> &str {
112 &self.package
113 }
114
115 pub fn interface_name(&self) -> &str {
117 &self.interface
118 }
119
120 pub fn version(&self) -> Option<&str> {
122 self.version.as_deref()
123 }
124}
125
126impl fmt::Display for Interface {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "{}", self.full_name)
129 }
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
134pub struct Function {
135 interface: Option<Interface>,
136 function_name: String,
137 docs: String,
138 params: Vec<FunctionParam>,
139 result: Option<serde_json::Value>,
140}
141
142impl Function {
143 pub fn new(
145 interface: Option<Interface>,
146 function_name: String,
147 docs: String,
148 params: Vec<FunctionParam>,
149 result: Option<serde_json::Value>,
150 ) -> Self {
151 Self {
152 interface,
153 function_name,
154 docs,
155 params,
156 result,
157 }
158 }
159
160 pub fn interface(&self) -> Option<&Interface> {
162 self.interface.as_ref()
163 }
164
165 pub fn function_name(&self) -> &str {
167 &self.function_name
168 }
169
170 pub fn docs(&self) -> &str {
172 &self.docs
173 }
174
175 pub fn params(&self) -> &[FunctionParam] {
177 &self.params
178 }
179
180 pub fn result(&self) -> Option<&serde_json::Value> {
182 self.result.as_ref()
183 }
184
185 pub fn key(&self) -> String {
189 match &self.interface {
190 Some(iface) => format!("{}.{}", iface.interface_name(), self.function_name),
191 None => self.function_name.clone(),
192 }
193 }
194}
195
196impl fmt::Display for Function {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 match &self.interface {
199 Some(iface) => write!(f, "{}#{}", iface, self.function_name),
200 None => write!(f, "{}", self.function_name),
201 }
202 }
203}
204
205#[derive(Clone, Debug, PartialEq, Eq, Hash)]
207pub struct FunctionParam {
208 pub name: String,
209 pub is_optional: bool,
210 pub json_schema: serde_json::Value,
211}
212
213#[derive(Debug, Clone)]
215pub struct Component {
216 pub name: String,
217 pub functions: HashMap<String, Function>,
218}
219
220pub trait ComponentInvoker: Send + Sync {
222 fn get_component(&self, name: &str) -> Option<Component>;
223
224 fn invoke<'a>(
225 &'a self,
226 component_name: &'a str,
227 function_name: &'a str,
228 args: Vec<serde_json::Value>,
229 ) -> Pin<Box<dyn Future<Output = Result<serde_json::Value>> + Send + 'a>>;
230}
231
232pub trait MessagePublisher: Send + Sync {
234 fn publish<'a>(
235 &'a self,
236 channel: &'a str,
237 body: Vec<u8>,
238 headers: HashMap<String, String>,
239 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>;
240}