sim_lib_web_bridge/
remote.rs1use sim_kernel::{Cx, Error, Expr, Result, Symbol};
10use sim_lib_server::{FrameEnvelope, ServerFrame};
11use sim_lib_stream_core::{
12 BufferPolicy, ClockDomain, PushResult, StreamDirection, StreamEnvelope,
13 StreamInspectorSnapshot, StreamItem, StreamMedia, StreamMetadata, StreamStats,
14 TransportProfile, stream_inspector_route_local_symbol,
15};
16use sim_lib_stream_fabric::{StreamControl, stream_control_frame_from_control};
17use sim_lib_view::Operation;
18
19use crate::transport::{
20 BrowserStreamStatus, ChangeEvent, SessionStatus, StreamInspectorRecord, Transport,
21 TransportKind,
22};
23
24pub struct RemoteTransport {
26 kind: TransportKind,
27 status: SessionStatus,
28 endpoint: String,
29}
30
31impl RemoteTransport {
32 pub fn wasm() -> Self {
34 Self::new(TransportKind::Wasm, "wasm:local")
35 }
36
37 pub fn local_server(endpoint: impl Into<String>) -> Self {
39 Self::new(TransportKind::LocalServer, endpoint)
40 }
41
42 pub fn remote_server(endpoint: impl Into<String>) -> Self {
44 Self::new(TransportKind::RemoteServer, endpoint)
45 }
46
47 fn new(kind: TransportKind, endpoint: impl Into<String>) -> Self {
48 Self {
49 kind,
50 status: SessionStatus::Disconnected,
51 endpoint: endpoint.into(),
52 }
53 }
54
55 pub fn endpoint(&self) -> &str {
57 &self.endpoint
58 }
59
60 pub fn connect(&mut self) {
66 self.status = SessionStatus::Disconnected;
67 }
68
69 pub fn disconnect(&mut self) {
71 self.status = SessionStatus::Disconnected;
72 }
73
74 pub fn begin_reconnect(&mut self) {
76 self.status = SessionStatus::Reconnecting;
77 }
78
79 pub fn stream_control_frame(
81 &self,
82 cx: &mut Cx,
83 codec: Symbol,
84 control: &StreamControl,
85 ) -> Result<ServerFrame> {
86 match self.kind {
87 TransportKind::LocalServer | TransportKind::RemoteServer => {
88 stream_control_frame_from_control(cx, codec, control, FrameEnvelope::default())
89 }
90 TransportKind::Fixture | TransportKind::Wasm | TransportKind::Fabric => {
91 Err(Error::HostError(format!(
92 "{:?} transport does not use server stream-fabric frames",
93 self.kind
94 )))
95 }
96 }
97 }
98
99 fn not_connected(&self) -> Error {
100 Error::HostError(format!(
101 "{:?} transport to {} is unavailable (data channel not implemented)",
102 self.kind, self.endpoint
103 ))
104 }
105}
106
107impl Transport for RemoteTransport {
108 fn kind(&self) -> TransportKind {
109 self.kind
110 }
111
112 fn status(&self) -> SessionStatus {
113 self.status
114 }
115
116 fn read(&self, _resource: &Symbol) -> Result<Expr> {
117 Err(self.not_connected())
118 }
119
120 fn realize_operation(&mut self, _resource: &Symbol, _operation: &Operation) -> Result<Expr> {
121 Err(self.not_connected())
122 }
123
124 fn drain_events(&mut self) -> Vec<ChangeEvent> {
125 Vec::new()
126 }
127
128 fn stream_subscribe(&mut self, stream_id: &Symbol) -> Result<StreamInspectorRecord> {
129 Err(Error::HostError(format!(
130 "cannot subscribe to stream {stream_id}: {}",
131 self.not_connected()
132 )))
133 }
134
135 fn stream_read(&mut self, stream_id: &Symbol, _limit: usize) -> Result<Vec<StreamItem>> {
136 Err(Error::HostError(format!(
137 "cannot read stream {stream_id}: {}",
138 self.not_connected()
139 )))
140 }
141
142 fn stream_push(&mut self, stream_id: &Symbol, _envelope: StreamEnvelope) -> Result<PushResult> {
143 Err(Error::HostError(format!(
144 "cannot push stream {stream_id}: {}",
145 self.not_connected()
146 )))
147 }
148
149 fn stream_cancel(&mut self, stream_id: &Symbol) -> Result<()> {
150 Err(Error::HostError(format!(
151 "cannot cancel stream {stream_id}: {}",
152 self.not_connected()
153 )))
154 }
155
156 fn stream_stats(&self, stream_id: &Symbol) -> Result<StreamStats> {
157 Err(Error::HostError(format!(
158 "cannot inspect stream stats {stream_id}: {}",
159 self.not_connected()
160 )))
161 }
162
163 fn stream_inspector(&self, stream_id: &Symbol) -> Result<StreamInspectorRecord> {
164 let status = match self.status {
165 SessionStatus::Disconnected => BrowserStreamStatus::Disconnected,
166 SessionStatus::Reconnecting => BrowserStreamStatus::Reconnecting,
167 SessionStatus::Closed => BrowserStreamStatus::Cancelled,
168 SessionStatus::Connected => BrowserStreamStatus::Disconnected,
169 SessionStatus::Connecting => BrowserStreamStatus::Disconnected,
170 };
171 Ok(StreamInspectorRecord {
172 stream_id: stream_id.clone(),
173 status,
174 buffered: 0,
175 stats: StreamStats::default(),
176 diagnostics: Vec::new(),
177 snapshot: StreamInspectorSnapshot::new(
178 &StreamMetadata::new(
179 stream_id.clone(),
180 StreamMedia::Data,
181 StreamDirection::Source,
182 ClockDomain::ServerFrame.symbol(),
183 BufferPolicy::bounded(1)?,
184 ),
185 stream_inspector_route_local_symbol(),
186 TransportProfile::remote_stream_fabric().name().clone(),
187 status.inspector_status(),
188 0,
189 &StreamStats::default(),
190 None,
191 Vec::new(),
192 ),
193 })
194 }
195}