1use sim_kernel::{CapabilityName, Cx, Expr, Result, Symbol};
12use sim_lib_stream_core::{
13 PushResult, StreamEnvelope, StreamInspectorSnapshot, StreamInspectorStatus, StreamItem,
14 StreamStats, stream_cancel_capability, stream_open_capability, stream_push_capability,
15 stream_read_capability, stream_stats_capability,
16};
17use sim_lib_stream_fabric::{
18 stream_control_cancel_symbol, stream_control_next_symbol, stream_control_open_symbol,
19 stream_control_push_symbol, stream_control_stats_symbol,
20};
21use sim_lib_view::Operation;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum SessionStatus {
26 Connecting,
28 Connected,
30 Disconnected,
32 Reconnecting,
34 Closed,
36}
37
38impl SessionStatus {
39 pub fn is_live(self) -> bool {
41 matches!(self, SessionStatus::Connected)
42 }
43}
44
45#[derive(Clone, Debug, PartialEq, Eq)]
47pub struct ChangeEvent {
48 pub resource: Symbol,
50}
51
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub enum BrowserStreamStatus {
55 Live,
57 Disconnected,
59 Reconnecting,
61 RefusedProfile,
63 BufferOverflow,
65 Cancelled,
67 Ended,
69}
70
71impl BrowserStreamStatus {
72 pub fn wire_label(self) -> &'static str {
74 match self {
75 Self::Live => "live",
76 Self::Disconnected => "disconnected",
77 Self::Reconnecting => "reconnecting",
78 Self::RefusedProfile => "refused-profile",
79 Self::BufferOverflow => "buffer-overflow",
80 Self::Cancelled => "cancelled",
81 Self::Ended => "ended",
82 }
83 }
84
85 pub fn symbol(self) -> Symbol {
87 Symbol::qualified("stream/browser-status", self.wire_label())
88 }
89
90 pub fn inspector_status(self) -> StreamInspectorStatus {
92 match self {
93 Self::Live => StreamInspectorStatus::Live,
94 Self::Disconnected => StreamInspectorStatus::Disconnected,
95 Self::Reconnecting => StreamInspectorStatus::Reconnecting,
96 Self::RefusedProfile => StreamInspectorStatus::RefusedProfile,
97 Self::BufferOverflow => StreamInspectorStatus::BufferOverflow,
98 Self::Cancelled => StreamInspectorStatus::Cancelled,
99 Self::Ended => StreamInspectorStatus::Ended,
100 }
101 }
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106pub enum WebStreamOperation {
107 Read,
109 Subscribe,
111 Push,
113 Cancel,
115 Stats,
117}
118
119impl WebStreamOperation {
120 pub fn wire_label(self) -> &'static str {
122 match self {
123 Self::Read => "read",
124 Self::Subscribe => "subscribe",
125 Self::Push => "push",
126 Self::Cancel => "cancel",
127 Self::Stats => "stats",
128 }
129 }
130
131 pub fn symbol(self) -> Symbol {
133 Symbol::qualified("stream/web", self.wire_label())
134 }
135
136 pub fn fabric_symbol(self) -> Symbol {
138 match self {
139 Self::Read => stream_control_next_symbol(),
140 Self::Subscribe => stream_control_open_symbol(),
141 Self::Push => stream_control_push_symbol(),
142 Self::Cancel => stream_control_cancel_symbol(),
143 Self::Stats => stream_control_stats_symbol(),
144 }
145 }
146
147 pub fn capability(self) -> CapabilityName {
149 match self {
150 Self::Read => stream_read_capability(),
151 Self::Subscribe => stream_open_capability(),
152 Self::Push => stream_push_capability(),
153 Self::Cancel => stream_cancel_capability(),
154 Self::Stats => stream_stats_capability(),
155 }
156 }
157}
158
159pub fn web_stream_operation_symbols() -> [Symbol; 5] {
161 [
162 WebStreamOperation::Read.symbol(),
163 WebStreamOperation::Subscribe.symbol(),
164 WebStreamOperation::Push.symbol(),
165 WebStreamOperation::Cancel.symbol(),
166 WebStreamOperation::Stats.symbol(),
167 ]
168}
169
170pub fn web_stream_operation_capability_names() -> Vec<CapabilityName> {
172 [
173 WebStreamOperation::Read,
174 WebStreamOperation::Subscribe,
175 WebStreamOperation::Push,
176 WebStreamOperation::Cancel,
177 WebStreamOperation::Stats,
178 ]
179 .into_iter()
180 .map(WebStreamOperation::capability)
181 .collect()
182}
183
184#[derive(Clone, Debug, PartialEq, Eq)]
186pub struct StreamInspectorRecord {
187 pub stream_id: Symbol,
189 pub status: BrowserStreamStatus,
191 pub buffered: usize,
193 pub stats: StreamStats,
195 pub diagnostics: Vec<Symbol>,
197 pub snapshot: StreamInspectorSnapshot,
199}
200
201#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum TransportKind {
204 Fixture,
206 Wasm,
208 LocalServer,
210 RemoteServer,
212 Fabric,
215}
216
217pub trait Transport {
222 fn kind(&self) -> TransportKind;
224
225 fn status(&self) -> SessionStatus;
227
228 fn read(&mut self, cx: &mut Cx, resource: &Symbol) -> Result<Expr>;
230
231 fn realize(&mut self, cx: &mut Cx, resource: &Symbol, operation: &Expr) -> Result<Expr> {
237 self.realize_operation(cx, resource, &Operation::new(operation.clone()))
238 }
239
240 fn realize_operation(
244 &mut self,
245 cx: &mut Cx,
246 resource: &Symbol,
247 operation: &Operation,
248 ) -> Result<Expr> {
249 self.commit_operation(cx, resource, operation, None)
250 }
251
252 fn commit_operation(
255 &mut self,
256 cx: &mut Cx,
257 resource: &Symbol,
258 operation: &Operation,
259 expected_current: Option<&Expr>,
260 ) -> Result<Expr> {
261 if let Some(expected) = expected_current {
262 let current = self.read(cx, resource)?;
263 if ¤t != expected {
264 return Err(sim_kernel::Error::HostError(format!(
265 "resource '{resource}' is stale; refresh before committing"
266 )));
267 }
268 }
269 self.realize_operation(cx, resource, operation)
270 }
271
272 fn drain_events(&mut self, cx: &mut Cx) -> Result<Vec<ChangeEvent>>;
274
275 fn stream_subscribe(
277 &mut self,
278 cx: &mut Cx,
279 stream_id: &Symbol,
280 ) -> Result<StreamInspectorRecord>;
281
282 fn stream_read(
284 &mut self,
285 cx: &mut Cx,
286 stream_id: &Symbol,
287 limit: usize,
288 ) -> Result<Vec<StreamItem>>;
289
290 fn stream_push(
292 &mut self,
293 cx: &mut Cx,
294 stream_id: &Symbol,
295 envelope: StreamEnvelope,
296 ) -> Result<PushResult>;
297
298 fn stream_cancel(&mut self, cx: &mut Cx, stream_id: &Symbol) -> Result<()>;
300
301 fn stream_stats(&mut self, cx: &mut Cx, stream_id: &Symbol) -> Result<StreamStats>;
303
304 fn stream_inspector(
306 &mut self,
307 cx: &mut Cx,
308 stream_id: &Symbol,
309 ) -> Result<StreamInspectorRecord>;
310}