viam_bridge_sdk/bridge.rs
1use async_trait::async_trait;
2use tokio::runtime::Runtime;
3use std::{any::{Any, TypeId}, sync::Arc};
4use serde_json::Value;
5use anyhow::Result;
6use std::collections::HashMap;
7
8#[derive(Clone, Debug, Default)]
9pub struct Context {
10 pub component_id: Option<String>,
11 pub tracing: HashMap<String, String>,
12 // You could add more fields as needed:
13 // pub request_id: Option<String>,
14 // pub timestamp: Option<u64>,
15}
16
17pub struct BridgeContext {
18 runtime: Arc<Runtime>,
19 // Add other context fields as needed
20}
21
22impl BridgeContext {
23 pub fn new(runtime: Arc<Runtime>) -> Self {
24 Self { runtime }
25 }
26
27 pub fn runtime(&self) -> Arc<Runtime> {
28 self.runtime.clone()
29 }
30}
31
32/// Interface for bridge instances that can be used at runtime
33#[async_trait]
34pub trait BridgeInstance: Send + Sync {
35 /// Get instance as Any for downcasting
36 fn as_any(&self) -> &dyn Any;
37
38 fn is_async(&self) -> bool {
39 false // Default to sync
40 }
41
42 /// Get all interfaces exposed by this bridge instance
43 fn get_interfaces(&self) -> Vec<BridgeInterface>;
44
45 /// Dispatch a function call to this bridge instance
46 fn dispatch_call(
47 &self,
48 context: &Context,
49 interface_name: &str,
50 function_name: &str,
51 args: &[wasmtime::component::Val],
52 //store: &mut wasmtime::StoreContextMut<'_, ComApiWasmHost>,
53 ) -> Result<Vec<wasmtime::component::Val>, Box<dyn std::error::Error>>;
54
55 async fn dispatch_call_async(
56 &self,
57 context: &Context,
58 interface_name: &str,
59 function_name: &str,
60 args: &[wasmtime::component::Val],
61 //store: &mut wasmtime::StoreContextMut<'_, ComApiWasmHost>,
62 //host_state: &mut ComApiWasmHost,
63 ) -> Result<Vec<wasmtime::component::Val>, Box<dyn std::error::Error + Send + Sync>>;
64
65 //fn register_with_host(&self, linker: &mut wasmtime::component::Linker<ComApiWasmHost>, host: &mut ComApiWasmHost) -> Result<()>; //anyhow::Result<Vec<(String, Box<dyn Fn<(wasmtime::StoreContextMut<'_, ComApiWasmHost>,), Output=anyhow::Result<(String,)>> + Send + 'static>)>>;
66}
67
68/// Represents a function parameter or result
69pub struct BridgeType {
70 /// The type of the parameter or result
71 pub ty: wasmtime::component::Type,
72 /// Optional name of the parameter (for documentation)
73 pub name: Option<String>,
74}
75
76/// Represents a function exposed by a bridge
77pub struct BridgeFunc {
78 /// Name of the function
79 pub name: String,
80 /// Parameters of the function
81 pub params: Vec<BridgeType>,
82 /// Results of the function
83 pub results: Vec<BridgeType>,
84 /// Optional documentation
85 pub docs: Option<String>,
86}
87
88/// Represents an interface exposed by a bridge
89pub struct BridgeInterface {
90 /// Full name of the interface (e.g., "postgres-bridge:db/db@0.1.0")
91 pub full_name: String,
92 /// Base namespace of the interface (e.g., "postgres-bridge:db")
93 pub namespace: String,
94 /// Functions exposed by this interface
95 pub functions: Vec<BridgeFunc>,
96}
97
98/// Core trait for extension bridges - these methods are all dyn-compatible
99pub trait ExtensionBridge: Send + Sync {
100 /// Get the bridge's name
101 fn name(&self) -> &str;
102
103 /// Get the list of interfaces that this bridge provides
104 fn interfaces(&self) -> Vec<&str>;
105
106 /// Initialize the bridge with configuration
107 fn initialize(&mut self, config: Value) -> Result<()>;
108
109 /// Create bridge instances
110 fn create_instances(&self) -> Result<Vec<Arc<dyn BridgeInstance>>>;
111
112 /// Get the bridge as Any for downcasting
113 fn as_any(&self) -> &dyn Any;
114
115 /// Get the bridge as mutable Any for downcasting
116 fn as_any_mut(&mut self) -> &mut dyn Any;
117
118 /// Get an object ID to uniquely identify this bridge
119 fn object_id(&self) -> TypeId;
120}
121
122/// Type-erased registry callback
123pub struct TypedRegistryCallback {
124 /// The type ID of the host type this callback works with
125 pub host_type_id: TypeId,
126
127 /// The callback function, erased to an Any type
128 callback: Box<dyn Any + Send + Sync>,
129}
130
131impl TypedRegistryCallback {
132 // Create a new typed registry callback for a specific host type
133 // pub fn new<T: Send + 'static>(
134 // callback: Box<dyn Fn(&mut Linker<T>, Box<dyn Fn(&T) -> &HostData + Send + Sync>) -> Result<()> + Send + Sync>
135 // ) -> Self {
136 // Self {
137 // host_type_id: TypeId::of::<T>(),
138 // callback: Box::new(callback) as Box<dyn Any + Send + Sync>,
139 // }
140 // }
141
142 // /// Try to use this callback with a specific host type
143 // pub fn call<T: Send + 'static>(
144 // &self,
145 // linker: &mut Linker<T>,
146 // host_accessor: Box<dyn Fn(&T) -> &HostData + Send + Sync>
147 // ) -> Result<()> {
148 // if self.host_type_id != TypeId::of::<T>() {
149 // return Err(anyhow::anyhow!("Type mismatch in registry callback"));
150 // }
151
152 // let callback = self.callback
153 // .downcast_ref::<Box<dyn Fn(&mut Linker<T>, Box<dyn Fn(&T) -> &HostData + Send + Sync>) -> Result<()> + Send + Sync>>()
154 // .ok_or_else(|| anyhow::anyhow!("Failed to downcast registry callback"))?;
155
156 // callback(linker, host_accessor)
157 // }
158}
159
160/// Bridge type registry trait - handles registration for specific host types
161/// This is intentionally separate from ExtensionBridge to maintain dyn-compatibility
162pub trait BridgeTypeRegistry: Send + Sync {
163 /// Register a callback for a specific host type
164 fn register_callback(&mut self, callback: TypedRegistryCallback);
165
166 /// Get callbacks that match a specific host type ID
167 fn get_callbacks_for(&self, host_type_id: TypeId) -> Vec<&TypedRegistryCallback>;
168}
169
170/// Combined trait for extension bridges that also support type registry
171pub trait ExtensionBridgeWithRegistry: ExtensionBridge + BridgeTypeRegistry {}
172
173// Auto-implement the combined trait for any type that implements both traits
174impl<T> ExtensionBridgeWithRegistry for T
175where
176 T: ExtensionBridge + BridgeTypeRegistry
177{}