1#[cfg(all(feature = "bytecode-observation", feature = "bytecode-instrumentation"))]
2use crate::live_session::InstrumentedHbcLiveSession;
3use crate::live_session::{
4 InstrumentedInterpreterLiveSession, LiveSession, LiveSessionCapabilities, LiveSessionCommand,
5 LiveSessionError, LiveSessionReply, LiveSessionRequest, LiveSessionState, LiveSource,
6};
7
8#[derive(Default)]
9struct SessionLiveRegistry {
10 entries: HashMap<String, Box<dyn LiveSession>>,
11}
12
13impl SessionLiveRegistry {
14 fn dispose_all(&mut self) {
15 for live_session in self.entries.values_mut() {
16 let _ = live_session.dispatch_command(LiveSessionCommand::Dispose);
17 }
18 self.entries.clear();
19 }
20}
21
22impl Drop for SessionLiveRegistry {
23 fn drop(&mut self) {
24 self.dispose_all();
25 }
26}
27
28impl Session {
29 fn ensure_live_owner_active(&self) -> Result<(), LiveSessionError> {
30 self.ensure_active()
31 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))
32 }
33
34 fn ensure_live_session_identity_available(
35 &self,
36 live_session_id: &str,
37 ) -> Result<(), LiveSessionError> {
38 if self.live_sessions.entries.contains_key(live_session_id) {
39 Err(live_session_already_exists(live_session_id))
40 } else {
41 Ok(())
42 }
43 }
44
45 pub fn register_live_session(
49 &mut self,
50 mut live_session: Box<dyn LiveSession>,
51 ) -> Result<LiveSessionState, LiveSessionError> {
52 self.ensure_live_owner_active()?;
53 let state = live_session.state();
54 if state.session_id.trim().is_empty() {
55 let _ = live_session.dispatch_command(LiveSessionCommand::Dispose);
56 return Err(LiveSessionError::new(
57 "live-session/invalid-identity",
58 "live-session id must not be empty",
59 ));
60 }
61 if self.live_sessions.entries.contains_key(&state.session_id) {
62 let _ = live_session.dispatch_command(LiveSessionCommand::Dispose);
63 return Err(live_session_already_exists(&state.session_id));
64 }
65 self.live_sessions
66 .entries
67 .insert(state.session_id.clone(), live_session);
68 Ok(state)
69 }
70
71 pub fn start_interpreter_live_session(
74 &mut self,
75 live_session_id: impl Into<String>,
76 source: LiveSource,
77 ) -> Result<LiveSessionState, LiveSessionError> {
78 self.ensure_live_owner_active()?;
79 let live_session_id = live_session_id.into();
80 self.ensure_live_session_identity_available(&live_session_id)?;
81 let owner_session_id = self.name().to_owned();
82 let live_session = InstrumentedInterpreterLiveSession::start(
83 self.runtime()
84 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))?,
85 owner_session_id,
86 live_session_id,
87 source,
88 )?;
89 self.register_live_session(Box::new(live_session))
90 }
91
92 #[cfg(all(feature = "bytecode-observation", feature = "bytecode-instrumentation"))]
95 pub fn start_hbc_live_session(
96 &mut self,
97 live_session_id: impl Into<String>,
98 source: LiveSource,
99 ) -> Result<LiveSessionState, LiveSessionError> {
100 self.ensure_live_owner_active()?;
101 let live_session_id = live_session_id.into();
102 self.ensure_live_session_identity_available(&live_session_id)?;
103 let owner_session_id = self.name().to_owned();
104 let live_session = InstrumentedHbcLiveSession::start(
105 self.runtime()
106 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))?,
107 owner_session_id,
108 live_session_id,
109 source,
110 )?;
111 self.register_live_session(Box::new(live_session))
112 }
113
114 #[cfg(all(feature = "bytecode-observation", feature = "bytecode-instrumentation"))]
118 pub fn start_hbc_live_session_from_artifact(
119 &mut self,
120 live_session_id: impl Into<String>,
121 source: LiveSource,
122 artifact: &[u8],
123 ) -> Result<LiveSessionState, LiveSessionError> {
124 self.ensure_live_owner_active()?;
125 let live_session_id = live_session_id.into();
126 self.ensure_live_session_identity_available(&live_session_id)?;
127 let owner_session_id = self.name().to_owned();
128 let live_session = InstrumentedHbcLiveSession::start_from_artifact(
129 self.runtime()
130 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))?,
131 owner_session_id,
132 live_session_id,
133 source,
134 artifact,
135 )?;
136 self.register_live_session(Box::new(live_session))
137 }
138
139 #[cfg(all(feature = "whole-wasm", not(target_arch = "wasm32")))]
142 pub fn start_whole_wasm_live_session(
143 &mut self,
144 live_session_id: impl Into<String>,
145 source: LiveSource,
146 ) -> Result<LiveSessionState, LiveSessionError> {
147 self.ensure_live_owner_active()?;
148 let live_session_id = live_session_id.into();
149 self.ensure_live_session_identity_available(&live_session_id)?;
150 let owner_session_id = self.name().to_owned();
151 let runtime = self
152 .runtime()
153 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))?;
154 let live_session = crate::live_session::WholeWasmLiveSession::start(
155 runtime,
156 owner_session_id,
157 live_session_id,
158 source,
159 )?;
160 self.register_live_session(Box::new(live_session))
161 }
162
163 #[cfg(all(feature = "whole-wasm", not(target_arch = "wasm32")))]
166 pub fn start_whole_wasm_live_session_from_artifact(
167 &mut self,
168 live_session_id: impl Into<String>,
169 source: LiveSource,
170 artifact: &[u8],
171 ) -> Result<LiveSessionState, LiveSessionError> {
172 self.ensure_live_owner_active()?;
173 let live_session_id = live_session_id.into();
174 self.ensure_live_session_identity_available(&live_session_id)?;
175 let owner_session_id = self.name().to_owned();
176 let runtime = self
177 .runtime()
178 .map_err(|message| LiveSessionError::new("live-session/owner-closed", message))?;
179 let live_session = crate::live_session::WholeWasmLiveSession::from_artifact(
180 runtime,
181 owner_session_id,
182 live_session_id,
183 source,
184 artifact.to_vec(),
185 )?;
186 self.register_live_session(Box::new(live_session))
187 }
188
189 #[cfg(all(
192 feature = "bytecode-observation",
193 not(feature = "bytecode-instrumentation")
194 ))]
195 pub fn start_hbc_live_session(
196 &mut self,
197 live_session_id: impl Into<String>,
198 source: LiveSource,
199 ) -> Result<LiveSessionState, LiveSessionError> {
200 self.ensure_live_owner_active()?;
201 let live_session_id = live_session_id.into();
202 self.ensure_live_session_identity_available(&live_session_id)?;
203 let live_session =
204 crate::live_session::BytecodeLiveSession::compile(live_session_id, source)?;
205 self.register_live_session(Box::new(live_session))
206 }
207
208 #[cfg(all(
211 feature = "bytecode-observation",
212 not(feature = "bytecode-instrumentation")
213 ))]
214 pub fn start_hbc_live_session_from_artifact(
215 &mut self,
216 live_session_id: impl Into<String>,
217 source: LiveSource,
218 artifact: &[u8],
219 ) -> Result<LiveSessionState, LiveSessionError> {
220 self.ensure_live_owner_active()?;
221 let live_session_id = live_session_id.into();
222 self.ensure_live_session_identity_available(&live_session_id)?;
223 let live_session = crate::live_session::BytecodeLiveSession::from_artifact(
224 live_session_id,
225 source.source_id(),
226 source.revision(),
227 artifact,
228 )?;
229 self.register_live_session(Box::new(live_session))
230 }
231
232 pub fn live_session_ids(&self) -> Vec<String> {
233 let mut ids = self
234 .live_sessions
235 .entries
236 .keys()
237 .cloned()
238 .collect::<Vec<_>>();
239 ids.sort();
240 ids
241 }
242
243 pub fn live_session_count(&self) -> usize {
244 self.live_sessions.entries.len()
245 }
246
247 pub fn live_session_state(
248 &self,
249 live_session_id: &str,
250 ) -> Result<LiveSessionState, LiveSessionError> {
251 self.ensure_live_owner_active()?;
252 self.live_sessions
253 .entries
254 .get(live_session_id)
255 .map(|live_session| live_session.state())
256 .ok_or_else(|| live_session_not_found(live_session_id))
257 }
258
259 pub fn live_session_capabilities(
260 &self,
261 live_session_id: &str,
262 ) -> Result<LiveSessionCapabilities, LiveSessionError> {
263 self.ensure_live_owner_active()?;
264 self.live_sessions
265 .entries
266 .get(live_session_id)
267 .map(|live_session| live_session.capabilities())
268 .ok_or_else(|| live_session_not_found(live_session_id))
269 }
270
271 pub fn dispatch_live_session(
275 &mut self,
276 request: LiveSessionRequest,
277 ) -> Result<LiveSessionReply, LiveSessionError> {
278 self.ensure_live_owner_active()?;
279 let live_session_id = request.session_id.clone();
280 self.live_sessions
281 .entries
282 .get_mut(&live_session_id)
283 .ok_or_else(|| live_session_not_found(&live_session_id))?
284 .dispatch(request)
285 }
286}
287
288fn live_session_already_exists(live_session_id: &str) -> LiveSessionError {
289 LiveSessionError::new(
290 "live-session/already-exists",
291 format!("live session identity cannot be reused: {live_session_id}"),
292 )
293}
294
295fn live_session_not_found(live_session_id: &str) -> LiveSessionError {
296 LiveSessionError::new(
297 "live-session/not-found",
298 format!("unknown live session: {live_session_id}"),
299 )
300}
301
302fn private_sandbox_session(entry_namespace: &str, mut runtime: Runtime) -> Session {
303 runtime.use_namespace(entry_namespace);
304 let id = SessionId::parse("SANDBOX").expect("SANDBOX is a valid session identifier");
305 Session::open(SessionSpec::new(id, SessionAuthorityPolicy::ZERO), runtime)
306}
307
308#[cfg(not(target_arch = "wasm32"))]
312pub fn restricted_sandbox_session(entry_namespace: &str) -> Session {
313 private_sandbox_session(entry_namespace, Runtime::sandbox())
314}
315
316#[cfg(not(target_arch = "wasm32"))]
319pub fn restricted_sandbox_session_with_host(
320 entry_namespace: &str,
321 handler: Rc<dyn Fn(String, String, Vec<core::Value>) -> Result<core::Value, String>>,
322) -> Session {
323 private_sandbox_session(
324 entry_namespace,
325 restricted_sandbox_runtime_with_host(handler),
326 )
327}