1use std::fmt;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4use thiserror::Error;
5
6pub use wasmer_vfs::FileDescriptor;
7pub use wasmer_vfs::StdioMode;
8
9pub type Result<T> = std::result::Result<T, BusError>;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12#[repr(transparent)]
13pub struct CallDescriptor(u32);
14
15impl CallDescriptor {
16 pub fn raw(&self) -> u32 {
17 self.0
18 }
19}
20
21impl From<u32> for CallDescriptor {
22 fn from(a: u32) -> Self {
23 Self(a)
24 }
25}
26
27pub trait VirtualBus: fmt::Debug + Send + Sync + 'static {
28 fn new_spawn(&self) -> SpawnOptions;
30
31 fn listen(&self) -> Result<Box<dyn VirtualBusListener + Sync>>;
33}
34
35pub trait VirtualBusSpawner {
36 fn spawn(&mut self, name: &str, config: &SpawnOptionsConfig) -> Result<BusSpawnedProcess>;
38}
39
40#[derive(Debug, Clone)]
41pub struct SpawnOptionsConfig {
42 reuse: bool,
43 chroot: bool,
44 args: Vec<String>,
45 preopen: Vec<String>,
46 stdin_mode: StdioMode,
47 stdout_mode: StdioMode,
48 stderr_mode: StdioMode,
49 working_dir: String,
50 remote_instance: Option<String>,
51 access_token: Option<String>,
52}
53
54impl SpawnOptionsConfig {
55 pub const fn reuse(&self) -> bool {
56 self.reuse
57 }
58
59 pub const fn chroot(&self) -> bool {
60 self.chroot
61 }
62
63 pub const fn args(&self) -> &Vec<String> {
64 &self.args
65 }
66
67 pub const fn preopen(&self) -> &Vec<String> {
68 &self.preopen
69 }
70
71 pub const fn stdin_mode(&self) -> StdioMode {
72 self.stdin_mode
73 }
74
75 pub const fn stdout_mode(&self) -> StdioMode {
76 self.stdout_mode
77 }
78
79 pub const fn stderr_mode(&self) -> StdioMode {
80 self.stderr_mode
81 }
82
83 pub fn working_dir(&self) -> &str {
84 self.working_dir.as_str()
85 }
86
87 pub fn remote_instance(&self) -> Option<&str> {
88 self.remote_instance.as_deref()
89 }
90
91 pub fn access_token(&self) -> Option<&str> {
92 self.access_token.as_deref()
93 }
94}
95
96pub struct SpawnOptions {
97 spawner: Box<dyn VirtualBusSpawner>,
98 conf: SpawnOptionsConfig,
99}
100
101impl SpawnOptions {
102 pub fn new(spawner: Box<dyn VirtualBusSpawner>) -> Self {
103 Self {
104 spawner,
105 conf: SpawnOptionsConfig {
106 reuse: false,
107 chroot: false,
108 args: Vec::new(),
109 preopen: Vec::new(),
110 stdin_mode: StdioMode::Null,
111 stdout_mode: StdioMode::Null,
112 stderr_mode: StdioMode::Null,
113 working_dir: "/".to_string(),
114 remote_instance: None,
115 access_token: None,
116 },
117 }
118 }
119 pub fn options(&mut self, options: SpawnOptionsConfig) -> &mut Self {
120 self.conf = options;
121 self
122 }
123
124 pub fn reuse(&mut self, reuse: bool) -> &mut Self {
125 self.conf.reuse = reuse;
126 self
127 }
128
129 pub fn chroot(&mut self, chroot: bool) -> &mut Self {
130 self.conf.chroot = chroot;
131 self
132 }
133
134 pub fn args(&mut self, args: Vec<String>) -> &mut Self {
135 self.conf.args = args;
136 self
137 }
138
139 pub fn preopen(&mut self, preopen: Vec<String>) -> &mut Self {
140 self.conf.preopen = preopen;
141 self
142 }
143
144 pub fn stdin_mode(&mut self, stdin_mode: StdioMode) -> &mut Self {
145 self.conf.stdin_mode = stdin_mode;
146 self
147 }
148
149 pub fn stdout_mode(&mut self, stdout_mode: StdioMode) -> &mut Self {
150 self.conf.stdout_mode = stdout_mode;
151 self
152 }
153
154 pub fn stderr_mode(&mut self, stderr_mode: StdioMode) -> &mut Self {
155 self.conf.stderr_mode = stderr_mode;
156 self
157 }
158
159 pub fn working_dir(&mut self, working_dir: String) -> &mut Self {
160 self.conf.working_dir = working_dir;
161 self
162 }
163
164 pub fn remote_instance(&mut self, remote_instance: String) -> &mut Self {
165 self.conf.remote_instance = Some(remote_instance);
166 self
167 }
168
169 pub fn access_token(&mut self, access_token: String) -> &mut Self {
170 self.conf.access_token = Some(access_token);
171 self
172 }
173
174 pub fn spawn(&mut self, name: &str) -> Result<BusSpawnedProcess> {
176 self.spawner.spawn(name, &self.conf)
177 }
178}
179
180#[derive(Debug)]
181pub struct BusSpawnedProcess {
182 pub inst: Box<dyn VirtualBusProcess + Sync>,
184}
185
186pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static {
187 fn poll_finished(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>;
189}
190
191pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static {
192 fn invoke(
194 &self,
195 topic: String,
196 format: BusDataFormat,
197 buf: &[u8],
198 ) -> Result<Box<dyn VirtualBusInvocation + Sync>>;
199}
200
201pub trait VirtualBusProcess:
202 VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static
203{
204 fn exit_code(&self) -> Option<u32>;
206
207 fn stdin_fd(&self) -> Option<FileDescriptor>;
209
210 fn stdout_fd(&self) -> Option<FileDescriptor>;
212
213 fn stderr_fd(&self) -> Option<FileDescriptor>;
215}
216
217pub trait VirtualBusInvocation:
218 VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static
219{
220 fn poll_event(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<BusInvocationEvent>;
222}
223
224#[derive(Debug)]
225pub enum BusInvocationEvent {
226 Callback {
228 topic: String,
230 format: BusDataFormat,
232 data: Vec<u8>,
234 },
235 Response {
237 format: BusDataFormat,
239 data: Vec<u8>,
241 },
242}
243
244pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static {
245 fn poll_call(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<BusCallEvent>;
247}
248
249#[derive(Debug)]
250pub struct BusCallEvent {
251 pub topic: String,
253 pub called: Box<dyn VirtualBusCalled + Sync>,
255 pub format: BusDataFormat,
257 pub data: Vec<u8>,
259}
260
261pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static {
262 fn callback(&self, topic: String, format: BusDataFormat, buf: &[u8]) -> Result<()>;
264
265 fn fault(self, fault: BusError) -> Result<()>;
267
268 fn reply(self, format: BusDataFormat, buf: &[u8]) -> Result<()>;
270}
271
272#[derive(Debug, Copy, Clone, PartialEq, Eq)]
274pub enum BusDataFormat {
275 Raw,
276 Bincode,
277 MessagePack,
278 Json,
279 Yaml,
280 Xml,
281}
282
283#[derive(Debug, Default)]
284pub struct UnsupportedVirtualBus {}
285
286impl VirtualBus for UnsupportedVirtualBus {
287 fn new_spawn(&self) -> SpawnOptions {
288 SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default()))
289 }
290
291 fn listen(&self) -> Result<Box<dyn VirtualBusListener + Sync>> {
292 Err(BusError::Unsupported)
293 }
294}
295
296#[derive(Debug, Default)]
297pub struct UnsupportedVirtualBusSpawner {}
298
299impl VirtualBusSpawner for UnsupportedVirtualBusSpawner {
300 fn spawn(&mut self, _name: &str, _config: &SpawnOptionsConfig) -> Result<BusSpawnedProcess> {
301 Err(BusError::Unsupported)
302 }
303}
304
305#[derive(Error, Copy, Clone, Debug, PartialEq, Eq)]
306pub enum BusError {
307 #[error("serialization failed")]
309 Serialization,
310 #[error("deserialization failed")]
312 Deserialization,
313 #[error("invalid wapm")]
315 InvalidWapm,
316 #[error("fetch failed")]
318 FetchFailed,
319 #[error("compile error")]
321 CompileError,
322 #[error("WAPM process has an invalid ABI")]
324 InvalidABI,
325 #[error("call aborted")]
327 Aborted,
328 #[error("bad handle")]
330 BadHandle,
331 #[error("invalid topic")]
333 InvalidTopic,
334 #[error("invalid callback")]
336 BadCallback,
337 #[error("unsupported")]
339 Unsupported,
340 #[error("bad request")]
342 BadRequest,
343 #[error("access denied")]
345 AccessDenied,
346 #[error("internal error")]
348 InternalError,
349 #[error("memory allocation failed")]
351 MemoryAllocationFailed,
352 #[error("invocation has failed")]
354 InvokeFailed,
355 #[error("already consumed")]
357 AlreadyConsumed,
358 #[error("memory access violation")]
360 MemoryAccessViolation,
361 #[error("unknown error found")]
363 UnknownError,
364}