1use crate::action::ActionEnvelope;
10use crate::async_runtime::{
11 JobRef, JobRequestPayload, JobSpec, ResourceExecutionContext, ServiceBindings,
12 ServiceCommandPayload, ServiceSpec, ServiceStartPayload, ServiceStopPayload, ServiceType,
13};
14use crate::capability::CapabilityInvocationPayload;
15use crate::capability::{CapabilityType, OperationCapability};
16use fission_ir::NodeId;
17use serde::{Deserialize, Serialize};
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
24pub struct ReqId(pub u64);
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub struct ResourceId(pub u64);
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub enum RuntimeEffect {
36 Cancel { req_id: u64 },
38 ReleaseResource { resource_id: u64 },
40}
41
42#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
47pub enum Effect {
48 Runtime(RuntimeEffect),
50 Capability(CapabilityInvocationPayload),
52 Job(JobRequestPayload),
54 StartService(ServiceStartPayload),
56 ServiceCommand(ServiceCommandPayload),
58 StopService(ServiceStopPayload),
60}
61
62#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
77pub struct EffectEnvelope {
78 pub req_id: u64,
80 pub effect: Effect,
82 pub on_ok: Option<ActionEnvelope>,
84 pub on_err: Option<ActionEnvelope>,
86 pub service_bindings: Option<ServiceBindings>,
88 pub resource: Option<ResourceExecutionContext>,
90}
91
92#[derive(Clone, Debug, PartialEq)]
112pub enum ActionInput {
113 None,
115 JobOk {
117 job_name: String,
118 req_id: u64,
119 payload: Vec<u8>,
120 },
121 JobErr {
123 job_name: String,
124 req_id: u64,
125 payload: Option<Vec<u8>>,
126 message: Option<String>,
127 },
128 ServiceStarted {
130 service_name: String,
131 slot_key: String,
132 instance_id: u64,
133 },
134 ServiceStartFailed {
136 service_name: String,
137 slot_key: String,
138 payload: Option<Vec<u8>>,
139 message: Option<String>,
140 },
141 ServiceEvent {
143 service_name: String,
144 slot_key: String,
145 instance_id: u64,
146 payload: Vec<u8>,
147 },
148 ServiceStopped {
150 service_name: String,
151 slot_key: String,
152 instance_id: u64,
153 },
154 ServiceCommandOk {
156 service_name: String,
157 slot_key: String,
158 instance_id: u64,
159 req_id: u64,
160 payload: Option<Vec<u8>>,
161 },
162 ServiceCommandErr {
164 service_name: String,
165 slot_key: String,
166 instance_id: u64,
167 req_id: u64,
168 payload: Option<Vec<u8>>,
169 message: Option<String>,
170 },
171 CapabilityOk {
173 capability: String,
174 req_id: u64,
175 payload: Vec<u8>,
176 },
177 CapabilityErr {
179 capability: String,
180 req_id: u64,
181 payload: Option<Vec<u8>>,
182 message: Option<String>,
183 },
184 TimerTick { payload: Vec<u8> },
186 Pointer {
188 x: f32,
189 y: f32,
190 delta_x: f32,
191 delta_y: f32,
192 },
193 Drop { paths: Vec<String>, x: f32, y: f32 },
195 InternalDrop { payload: Vec<u8>, x: f32, y: f32 },
197 ScopedRaw {
199 scope_id: u128,
200 target: NodeId,
201 input: Box<ActionInput>,
202 },
203}
204
205impl ActionInput {
206 pub fn scoped_raw(scope_id: u128, target: NodeId, input: ActionInput) -> Self {
207 Self::ScopedRaw {
208 scope_id,
209 target,
210 input: Box::new(input),
211 }
212 }
213
214 pub fn action_scope_id(&self) -> Option<u128> {
215 match self {
216 ActionInput::ScopedRaw { scope_id, .. } => Some(*scope_id),
217 _ => None,
218 }
219 }
220
221 pub fn scoped_target(&self) -> Option<NodeId> {
222 match self {
223 ActionInput::ScopedRaw { target, .. } => Some(*target),
224 _ => None,
225 }
226 }
227
228 pub fn unscoped(&self) -> &ActionInput {
229 match self {
230 ActionInput::ScopedRaw { input, .. } => input.unscoped(),
231 _ => self,
232 }
233 }
234
235 pub fn as_bytes(&self) -> Option<&[u8]> {
236 match self.unscoped() {
237 ActionInput::JobOk { payload, .. } => Some(payload),
238 ActionInput::CapabilityOk { payload, .. } => Some(payload),
239 ActionInput::TimerTick { payload } => Some(payload),
240 ActionInput::InternalDrop { payload, .. } => Some(payload),
241 _ => None,
242 }
243 }
244
245 pub fn as_pointer(&self) -> Option<(f32, f32, f32, f32)> {
246 match self.unscoped() {
247 ActionInput::Pointer {
248 x,
249 y,
250 delta_x,
251 delta_y,
252 } => Some((*x, *y, *delta_x, *delta_y)),
253 ActionInput::Drop { x, y, .. } => Some((*x, *y, 0.0, 0.0)),
254 ActionInput::InternalDrop { x, y, .. } => Some((*x, *y, 0.0, 0.0)),
255 _ => None,
256 }
257 }
258
259 pub fn as_drop_paths(&self) -> Option<&[String]> {
260 match self.unscoped() {
261 ActionInput::Drop { paths, .. } => Some(paths),
262 _ => None,
263 }
264 }
265
266 pub fn as_internal_drop(&self) -> Option<&[u8]> {
267 match self.unscoped() {
268 ActionInput::InternalDrop { payload, .. } => Some(payload),
269 _ => None,
270 }
271 }
272
273 pub fn job_ok<J: JobSpec>(&self, job: JobRef<J>) -> Option<J::Ok> {
274 match self.unscoped() {
275 ActionInput::JobOk {
276 job_name, payload, ..
277 } if job_name == job.name => serde_json::from_slice(payload).ok(),
278 _ => None,
279 }
280 }
281
282 pub fn job_err<J: JobSpec>(&self, job: JobRef<J>) -> Option<J::Err> {
283 match self.unscoped() {
284 ActionInput::JobErr {
285 job_name,
286 payload: Some(payload),
287 ..
288 } if job_name == job.name => serde_json::from_slice(payload).ok(),
289 _ => None,
290 }
291 }
292
293 pub fn job_error_message<J: JobSpec>(&self, job: JobRef<J>) -> Option<&str> {
294 match self.unscoped() {
295 ActionInput::JobErr {
296 job_name,
297 message: Some(message),
298 ..
299 } if job_name == job.name => Some(message.as_str()),
300 _ => None,
301 }
302 }
303
304 pub fn capability_ok<C: OperationCapability>(
305 &self,
306 capability: CapabilityType<C>,
307 ) -> Option<C::Ok> {
308 match self.unscoped() {
309 ActionInput::CapabilityOk {
310 capability: actual,
311 payload,
312 ..
313 } if actual == capability.name => serde_json::from_slice(payload).ok(),
314 _ => None,
315 }
316 }
317
318 pub fn capability_error<C: OperationCapability>(
319 &self,
320 capability: CapabilityType<C>,
321 ) -> Option<C::Err> {
322 match self.unscoped() {
323 ActionInput::CapabilityErr {
324 capability: actual,
325 payload: Some(payload),
326 ..
327 } if actual == capability.name => serde_json::from_slice(payload).ok(),
328 _ => None,
329 }
330 }
331
332 pub fn capability_error_message<C: OperationCapability>(
333 &self,
334 capability: CapabilityType<C>,
335 ) -> Option<&str> {
336 match self.unscoped() {
337 ActionInput::CapabilityErr {
338 capability: actual,
339 message: Some(message),
340 ..
341 } if actual == capability.name => Some(message),
342 _ => None,
343 }
344 }
345
346 pub fn service_event<S: ServiceSpec>(&self, service: ServiceType<S>) -> Option<S::Event> {
347 match self.unscoped() {
348 ActionInput::ServiceEvent {
349 service_name,
350 payload,
351 ..
352 } if service_name == service.name => serde_json::from_slice(payload).ok(),
353 _ => None,
354 }
355 }
356
357 pub fn service_start_err<S: ServiceSpec>(
358 &self,
359 service: ServiceType<S>,
360 ) -> Option<S::StartErr> {
361 match self.unscoped() {
362 ActionInput::ServiceStartFailed {
363 service_name,
364 payload: Some(payload),
365 ..
366 } if service_name == service.name => serde_json::from_slice(payload).ok(),
367 _ => None,
368 }
369 }
370
371 pub fn service_start_error_message<S: ServiceSpec>(
372 &self,
373 service: ServiceType<S>,
374 ) -> Option<&str> {
375 match self.unscoped() {
376 ActionInput::ServiceStartFailed {
377 service_name,
378 message: Some(message),
379 ..
380 } if service_name == service.name => Some(message.as_str()),
381 _ => None,
382 }
383 }
384
385 pub fn service_command_ok<S: ServiceSpec>(
386 &self,
387 service: ServiceType<S>,
388 ) -> Option<S::CommandOk> {
389 match self.unscoped() {
390 ActionInput::ServiceCommandOk {
391 service_name,
392 payload: Some(payload),
393 ..
394 } if service_name == service.name => serde_json::from_slice(payload).ok(),
395 _ => None,
396 }
397 }
398
399 pub fn service_command_err<S: ServiceSpec>(
400 &self,
401 service: ServiceType<S>,
402 ) -> Option<S::CommandErr> {
403 match self.unscoped() {
404 ActionInput::ServiceCommandErr {
405 service_name,
406 payload: Some(payload),
407 ..
408 } if service_name == service.name => serde_json::from_slice(payload).ok(),
409 _ => None,
410 }
411 }
412
413 pub fn timer_tick<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
414 match self.unscoped() {
415 ActionInput::TimerTick { payload } => serde_json::from_slice(payload).ok(),
416 _ => None,
417 }
418 }
419
420 pub fn service_slot_key(&self) -> Option<&str> {
421 match self.unscoped() {
422 ActionInput::ServiceStarted { slot_key, .. }
423 | ActionInput::ServiceStartFailed { slot_key, .. }
424 | ActionInput::ServiceEvent { slot_key, .. }
425 | ActionInput::ServiceStopped { slot_key, .. }
426 | ActionInput::ServiceCommandOk { slot_key, .. }
427 | ActionInput::ServiceCommandErr { slot_key, .. } => Some(slot_key.as_str()),
428 _ => None,
429 }
430 }
431
432 pub fn service_instance_id(&self) -> Option<u64> {
433 match self.unscoped() {
434 ActionInput::ServiceStarted { instance_id, .. }
435 | ActionInput::ServiceEvent { instance_id, .. }
436 | ActionInput::ServiceStopped { instance_id, .. }
437 | ActionInput::ServiceCommandOk { instance_id, .. }
438 | ActionInput::ServiceCommandErr { instance_id, .. } => Some(*instance_id),
439 _ => None,
440 }
441 }
442}