1use std::time::Duration;
2
3use super::{
4 CancellationToken, EventCapability, InvocationContext, ModuleEventDependencyHandle,
5 NativeAppRuntime, NativeEndpointBinding, NativeEventHandle, NativeRequestHandle,
6 NativeStreamEndpointBinding, NativeStreamHandle, Rc, RefCell, StreamCapability, Weak,
7};
8
9pub trait RequestCapability: 'static {
10 type Request: 'static;
12 type Response: 'static;
14 type DomainError: 'static;
16 const ID: &'static str;
18 const DESCRIPTOR_VERSION: &'static str;
20}
21
22pub type RequestId = u64;
24
25#[derive(Clone, Debug, Eq, PartialEq)]
27pub enum RuntimeFailure {
28 Unavailable { capability: &'static str },
30 UnknownOperation {
32 capability: &'static str,
33 operation: String,
34 },
35 AmbiguousBinding {
37 capability: &'static str,
38 providers: usize,
39 },
40 ProtocolViolation { capability: &'static str },
42 MissingModuleFactory {
44 instance: String,
45 package_id: String,
46 },
47 UnavailableExecutionClass {
49 instance_key: String,
50 execution_class: String,
51 },
52 InvalidResolvedPlan { detail: String },
54 AdmissionClosed,
56 ResourceExhausted {
58 capability: &'static str,
59 operation: String,
60 },
61 DeadlineExceeded { request_id: RequestId },
63 Cancelled { request_id: RequestId },
65 Internal { detail: String },
67 ModuleFailure { detail: String },
69 ModuleRestartExhausted { instance: String, attempts: usize },
71}
72
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
75pub enum ModuleLifecyclePhase {
76 Prepare,
78 Activate,
80 Ready,
82 Deactivate,
84}
85
86#[derive(Clone, Debug)]
88pub struct ModuleDependency {
89 pub(super) capability_id: String,
90 pub(super) provider_instance: String,
91 pub(super) provider_order: usize,
92 pub(super) handle: Option<ModuleDependencyHandle>,
93 pub(super) stream_handle: Option<ModuleStreamDependencyHandle>,
94 pub(super) event_handle: Option<ModuleEventDependencyHandle>,
95}
96
97impl ModuleDependency {
98 pub(super) fn new(
99 capability_id: impl Into<String>,
100 provider_instance: impl Into<String>,
101 provider_order: usize,
102 handle: Option<ModuleDependencyHandle>,
103 stream_handle: Option<ModuleStreamDependencyHandle>,
104 event_handle: Option<ModuleEventDependencyHandle>,
105 ) -> Self {
106 Self {
107 capability_id: capability_id.into(),
108 provider_instance: provider_instance.into(),
109 provider_order,
110 handle,
111 stream_handle,
112 event_handle,
113 }
114 }
115
116 pub fn capability_id(&self) -> &str {
118 &self.capability_id
119 }
120
121 pub fn provider_instance(&self) -> &str {
123 &self.provider_instance
124 }
125
126 pub const fn provider_order(&self) -> usize {
128 self.provider_order
129 }
130
131 pub fn handle(&self) -> Option<ModuleDependencyHandle> {
133 self.handle.clone()
134 }
135
136 pub fn stream_handle(&self) -> Option<ModuleStreamDependencyHandle> {
138 self.stream_handle.clone()
139 }
140
141 pub fn event_handle(&self) -> Option<ModuleEventDependencyHandle> {
143 self.event_handle.clone()
144 }
145}
146
147#[derive(Clone, Debug)]
149pub struct ModuleDependencyHandle {
150 pub(super) binding: NativeEndpointBinding,
151 pub(super) caller_instance: String,
152 pub(super) runtime: Rc<RefCell<Weak<NativeAppRuntime>>>,
153}
154
155#[derive(Clone, Debug)]
157pub struct ModuleStreamDependencyHandle {
158 pub(super) binding: NativeStreamEndpointBinding,
159 pub(super) caller_instance: String,
160 pub(super) runtime: Rc<RefCell<Weak<NativeAppRuntime>>>,
161}
162
163impl ModuleStreamDependencyHandle {
164 pub fn capability_id(&self) -> &'static str {
166 self.binding.state.capability_id
167 }
168
169 pub fn descriptor_version(&self) -> &'static str {
171 self.binding.state.descriptor_version
172 }
173
174 pub fn operations(&self) -> &'static [&'static str] {
176 self.binding.state.operations
177 }
178
179 pub fn typed<C: StreamCapability>(&self) -> Result<NativeStreamHandle<C>, RuntimeFailure> {
181 if self.capability_id() != C::ID || self.descriptor_version() != C::DESCRIPTOR_VERSION {
182 return Err(RuntimeFailure::ProtocolViolation { capability: C::ID });
183 }
184 let runtime = self
185 .runtime
186 .borrow()
187 .upgrade()
188 .ok_or(RuntimeFailure::AdmissionClosed)?;
189 Ok(NativeStreamHandle::from_endpoints(
190 std::slice::from_ref(&self.binding),
191 runtime,
192 &self.caller_instance,
193 true,
194 ))
195 }
196}
197
198impl ModuleDependencyHandle {
199 pub fn capability_id(&self) -> &'static str {
201 self.binding.state.capability_id
202 }
203
204 pub fn descriptor_version(&self) -> &'static str {
206 self.binding.state.descriptor_version
207 }
208
209 pub fn operations(&self) -> &'static [&'static str] {
211 self.binding.state.operations
212 }
213
214 pub fn typed<C: RequestCapability>(&self) -> Result<NativeRequestHandle<C>, RuntimeFailure> {
216 if self.capability_id() != C::ID || self.descriptor_version() != C::DESCRIPTOR_VERSION {
217 return Err(RuntimeFailure::ProtocolViolation { capability: C::ID });
218 }
219 let runtime = self
220 .runtime
221 .borrow()
222 .upgrade()
223 .ok_or(RuntimeFailure::AdmissionClosed)?;
224 Ok(NativeRequestHandle::from_endpoints(
225 std::slice::from_ref(&self.binding),
226 runtime,
227 &self.caller_instance,
228 true,
229 ))
230 }
231}
232
233#[derive(Clone, Debug, Default)]
235pub struct ModuleDependencies {
236 pub(super) bindings: Vec<ModuleDependency>,
237 pub(super) caller_instance: String,
238 pub(super) runtime: Rc<RefCell<Weak<NativeAppRuntime>>>,
239}
240
241impl ModuleDependencies {
242 pub(super) fn new(
243 caller_instance: impl Into<String>,
244 runtime: Rc<RefCell<Weak<NativeAppRuntime>>>,
245 ) -> Self {
246 Self {
247 bindings: Vec::new(),
248 caller_instance: caller_instance.into(),
249 runtime,
250 }
251 }
252
253 pub fn bindings(&self) -> &[ModuleDependency] {
255 &self.bindings
256 }
257
258 pub fn len(&self) -> usize {
260 self.bindings.len()
261 }
262
263 pub fn is_empty(&self) -> bool {
265 self.bindings.is_empty()
266 }
267
268 pub fn invocation_context(
274 &self,
275 deadline: Option<Duration>,
276 cancellation: CancellationToken,
277 ) -> Result<InvocationContext, RuntimeFailure> {
278 let runtime = self
279 .runtime
280 .borrow()
281 .upgrade()
282 .ok_or(RuntimeFailure::AdmissionClosed)?;
283 let request_id = runtime.request_ids.get();
284 runtime.request_ids.set(request_id.saturating_add(1));
285 Ok(InvocationContext::new(request_id, deadline, cancellation)
286 .with_caller_instance(self.caller_instance.clone()))
287 }
288
289 pub fn invocation_context_after(
291 &self,
292 timeout: Duration,
293 cancellation: CancellationToken,
294 ) -> Result<InvocationContext, RuntimeFailure> {
295 let runtime = self
296 .runtime
297 .borrow()
298 .upgrade()
299 .ok_or(RuntimeFailure::AdmissionClosed)?;
300 let deadline = (runtime.driver.now)().saturating_add(timeout);
301 drop(runtime);
302 self.invocation_context(Some(deadline), cancellation)
303 }
304
305 pub fn one<C: RequestCapability>(&self) -> Result<NativeRequestHandle<C>, RuntimeFailure> {
307 let handles: Vec<_> = self
308 .bindings
309 .iter()
310 .filter(|binding| binding.capability_id() == C::ID)
311 .filter_map(ModuleDependency::handle)
312 .collect();
313 match handles.as_slice() {
314 [handle] => handle.typed::<C>(),
315 [] => Err(RuntimeFailure::Unavailable { capability: C::ID }),
316 handles => Err(RuntimeFailure::AmbiguousBinding {
317 capability: C::ID,
318 providers: handles.len(),
319 }),
320 }
321 }
322
323 pub fn optional<C: RequestCapability>(
325 &self,
326 ) -> Result<Option<NativeRequestHandle<C>>, RuntimeFailure> {
327 match self
328 .bindings
329 .iter()
330 .filter(|binding| binding.capability_id() == C::ID)
331 .filter_map(ModuleDependency::handle)
332 .collect::<Vec<_>>()
333 .as_slice()
334 {
335 [] => Ok(None),
336 [handle] => handle.typed::<C>().map(Some),
337 handles => Err(RuntimeFailure::AmbiguousBinding {
338 capability: C::ID,
339 providers: handles.len(),
340 }),
341 }
342 }
343
344 pub fn many<C: RequestCapability>(
346 &self,
347 ) -> Result<Vec<NativeRequestHandle<C>>, RuntimeFailure> {
348 self.bindings
349 .iter()
350 .filter(|binding| binding.capability_id() == C::ID)
351 .filter_map(ModuleDependency::handle)
352 .map(|handle| handle.typed::<C>())
353 .collect()
354 }
355
356 pub fn one_stream<C: StreamCapability>(&self) -> Result<NativeStreamHandle<C>, RuntimeFailure> {
358 let handles: Vec<_> = self
359 .bindings
360 .iter()
361 .filter(|binding| binding.capability_id() == C::ID)
362 .filter_map(ModuleDependency::stream_handle)
363 .collect();
364 match handles.as_slice() {
365 [handle] => handle.typed::<C>(),
366 [] => Err(RuntimeFailure::Unavailable { capability: C::ID }),
367 handles => Err(RuntimeFailure::AmbiguousBinding {
368 capability: C::ID,
369 providers: handles.len(),
370 }),
371 }
372 }
373
374 pub fn optional_stream<C: StreamCapability>(
376 &self,
377 ) -> Result<Option<NativeStreamHandle<C>>, RuntimeFailure> {
378 match self
379 .bindings
380 .iter()
381 .filter(|binding| binding.capability_id() == C::ID)
382 .filter_map(ModuleDependency::stream_handle)
383 .collect::<Vec<_>>()
384 .as_slice()
385 {
386 [] => Ok(None),
387 [handle] => handle.typed::<C>().map(Some),
388 handles => Err(RuntimeFailure::AmbiguousBinding {
389 capability: C::ID,
390 providers: handles.len(),
391 }),
392 }
393 }
394
395 pub fn many_stream<C: StreamCapability>(
397 &self,
398 ) -> Result<Vec<NativeStreamHandle<C>>, RuntimeFailure> {
399 self.bindings
400 .iter()
401 .filter(|binding| binding.capability_id() == C::ID)
402 .filter_map(ModuleDependency::stream_handle)
403 .map(|handle| handle.typed::<C>())
404 .collect()
405 }
406
407 pub fn many_event<C: EventCapability>(&self) -> Result<NativeEventHandle<C>, RuntimeFailure> {
409 let handles: Vec<_> = self
410 .bindings
411 .iter()
412 .filter(|binding| binding.capability_id() == C::ID)
413 .filter_map(ModuleDependency::event_handle)
414 .collect();
415 if handles.iter().any(|handle| {
416 handle.capability_id() != C::ID || handle.descriptor_version() != C::DESCRIPTOR_VERSION
417 }) {
418 return Err(RuntimeFailure::ProtocolViolation { capability: C::ID });
419 }
420 let runtime = self
421 .runtime
422 .borrow()
423 .upgrade()
424 .ok_or(RuntimeFailure::AdmissionClosed)?;
425 let endpoints = handles
426 .iter()
427 .map(|handle| handle.binding.clone())
428 .collect::<Vec<_>>();
429 Ok(NativeEventHandle::from_endpoints(
430 &endpoints,
431 runtime,
432 &self.caller_instance,
433 true,
434 ))
435 }
436
437 pub fn one_event<C: EventCapability>(&self) -> Result<NativeEventHandle<C>, RuntimeFailure> {
439 match self
440 .bindings
441 .iter()
442 .filter(|binding| binding.capability_id() == C::ID)
443 .filter_map(ModuleDependency::event_handle)
444 .collect::<Vec<_>>()
445 .as_slice()
446 {
447 [handle] => handle.typed::<C>(),
448 [] => Err(RuntimeFailure::Unavailable { capability: C::ID }),
449 handles => Err(RuntimeFailure::AmbiguousBinding {
450 capability: C::ID,
451 providers: handles.len(),
452 }),
453 }
454 }
455
456 pub fn optional_event<C: EventCapability>(
458 &self,
459 ) -> Result<Option<NativeEventHandle<C>>, RuntimeFailure> {
460 match self
461 .bindings
462 .iter()
463 .filter(|binding| binding.capability_id() == C::ID)
464 .filter_map(ModuleDependency::event_handle)
465 .collect::<Vec<_>>()
466 .as_slice()
467 {
468 [] => Ok(None),
469 [handle] => handle.typed::<C>().map(Some),
470 handles => Err(RuntimeFailure::AmbiguousBinding {
471 capability: C::ID,
472 providers: handles.len(),
473 }),
474 }
475 }
476}