use crate::action::ActionEnvelope;
use crate::async_runtime::{
JobRef, JobRequestPayload, JobSpec, ResourceExecutionContext, ServiceBindings,
ServiceCommandPayload, ServiceSpec, ServiceStartPayload, ServiceStopPayload, ServiceType,
};
use crate::capability::CapabilityInvocationPayload;
use crate::capability::{CapabilityType, OperationCapability};
use fission_ir::NodeId;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ReqId(pub u64);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ResourceId(pub u64);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RuntimeEffect {
Cancel { req_id: u64 },
ReleaseResource { resource_id: u64 },
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum Effect {
Runtime(RuntimeEffect),
Capability(CapabilityInvocationPayload),
Job(JobRequestPayload),
StartService(ServiceStartPayload),
ServiceCommand(ServiceCommandPayload),
StopService(ServiceStopPayload),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct EffectEnvelope {
pub req_id: u64,
pub effect: Effect,
pub on_ok: Option<ActionEnvelope>,
pub on_err: Option<ActionEnvelope>,
pub service_bindings: Option<ServiceBindings>,
pub resource: Option<ResourceExecutionContext>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ActionInput {
None,
JobOk {
job_name: String,
req_id: u64,
payload: Vec<u8>,
},
JobErr {
job_name: String,
req_id: u64,
payload: Option<Vec<u8>>,
message: Option<String>,
},
ServiceStarted {
service_name: String,
slot_key: String,
instance_id: u64,
},
ServiceStartFailed {
service_name: String,
slot_key: String,
payload: Option<Vec<u8>>,
message: Option<String>,
},
ServiceEvent {
service_name: String,
slot_key: String,
instance_id: u64,
payload: Vec<u8>,
},
ServiceStopped {
service_name: String,
slot_key: String,
instance_id: u64,
},
ServiceCommandOk {
service_name: String,
slot_key: String,
instance_id: u64,
req_id: u64,
payload: Option<Vec<u8>>,
},
ServiceCommandErr {
service_name: String,
slot_key: String,
instance_id: u64,
req_id: u64,
payload: Option<Vec<u8>>,
message: Option<String>,
},
CapabilityOk {
capability: String,
req_id: u64,
payload: Vec<u8>,
},
CapabilityErr {
capability: String,
req_id: u64,
payload: Option<Vec<u8>>,
message: Option<String>,
},
TimerTick { payload: Vec<u8> },
Pointer {
x: f32,
y: f32,
delta_x: f32,
delta_y: f32,
},
Drop { paths: Vec<String>, x: f32, y: f32 },
InternalDrop { payload: Vec<u8>, x: f32, y: f32 },
ScopedRaw {
scope_id: u128,
target: NodeId,
input: Box<ActionInput>,
},
}
impl ActionInput {
pub fn scoped_raw(scope_id: u128, target: NodeId, input: ActionInput) -> Self {
Self::ScopedRaw {
scope_id,
target,
input: Box::new(input),
}
}
pub fn action_scope_id(&self) -> Option<u128> {
match self {
ActionInput::ScopedRaw { scope_id, .. } => Some(*scope_id),
_ => None,
}
}
pub fn scoped_target(&self) -> Option<NodeId> {
match self {
ActionInput::ScopedRaw { target, .. } => Some(*target),
_ => None,
}
}
pub fn unscoped(&self) -> &ActionInput {
match self {
ActionInput::ScopedRaw { input, .. } => input.unscoped(),
_ => self,
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self.unscoped() {
ActionInput::JobOk { payload, .. } => Some(payload),
ActionInput::CapabilityOk { payload, .. } => Some(payload),
ActionInput::TimerTick { payload } => Some(payload),
ActionInput::InternalDrop { payload, .. } => Some(payload),
_ => None,
}
}
pub fn as_pointer(&self) -> Option<(f32, f32, f32, f32)> {
match self.unscoped() {
ActionInput::Pointer {
x,
y,
delta_x,
delta_y,
} => Some((*x, *y, *delta_x, *delta_y)),
ActionInput::Drop { x, y, .. } => Some((*x, *y, 0.0, 0.0)),
ActionInput::InternalDrop { x, y, .. } => Some((*x, *y, 0.0, 0.0)),
_ => None,
}
}
pub fn as_drop_paths(&self) -> Option<&[String]> {
match self.unscoped() {
ActionInput::Drop { paths, .. } => Some(paths),
_ => None,
}
}
pub fn as_internal_drop(&self) -> Option<&[u8]> {
match self.unscoped() {
ActionInput::InternalDrop { payload, .. } => Some(payload),
_ => None,
}
}
pub fn job_ok<J: JobSpec>(&self, job: JobRef<J>) -> Option<J::Ok> {
match self.unscoped() {
ActionInput::JobOk {
job_name, payload, ..
} if job_name == job.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn job_err<J: JobSpec>(&self, job: JobRef<J>) -> Option<J::Err> {
match self.unscoped() {
ActionInput::JobErr {
job_name,
payload: Some(payload),
..
} if job_name == job.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn job_error_message<J: JobSpec>(&self, job: JobRef<J>) -> Option<&str> {
match self.unscoped() {
ActionInput::JobErr {
job_name,
message: Some(message),
..
} if job_name == job.name => Some(message.as_str()),
_ => None,
}
}
pub fn capability_ok<C: OperationCapability>(
&self,
capability: CapabilityType<C>,
) -> Option<C::Ok> {
match self.unscoped() {
ActionInput::CapabilityOk {
capability: actual,
payload,
..
} if actual == capability.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn capability_error<C: OperationCapability>(
&self,
capability: CapabilityType<C>,
) -> Option<C::Err> {
match self.unscoped() {
ActionInput::CapabilityErr {
capability: actual,
payload: Some(payload),
..
} if actual == capability.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn capability_error_message<C: OperationCapability>(
&self,
capability: CapabilityType<C>,
) -> Option<&str> {
match self.unscoped() {
ActionInput::CapabilityErr {
capability: actual,
message: Some(message),
..
} if actual == capability.name => Some(message),
_ => None,
}
}
pub fn service_event<S: ServiceSpec>(&self, service: ServiceType<S>) -> Option<S::Event> {
match self.unscoped() {
ActionInput::ServiceEvent {
service_name,
payload,
..
} if service_name == service.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn service_start_err<S: ServiceSpec>(
&self,
service: ServiceType<S>,
) -> Option<S::StartErr> {
match self.unscoped() {
ActionInput::ServiceStartFailed {
service_name,
payload: Some(payload),
..
} if service_name == service.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn service_start_error_message<S: ServiceSpec>(
&self,
service: ServiceType<S>,
) -> Option<&str> {
match self.unscoped() {
ActionInput::ServiceStartFailed {
service_name,
message: Some(message),
..
} if service_name == service.name => Some(message.as_str()),
_ => None,
}
}
pub fn service_command_ok<S: ServiceSpec>(
&self,
service: ServiceType<S>,
) -> Option<S::CommandOk> {
match self.unscoped() {
ActionInput::ServiceCommandOk {
service_name,
payload: Some(payload),
..
} if service_name == service.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn service_command_err<S: ServiceSpec>(
&self,
service: ServiceType<S>,
) -> Option<S::CommandErr> {
match self.unscoped() {
ActionInput::ServiceCommandErr {
service_name,
payload: Some(payload),
..
} if service_name == service.name => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn timer_tick<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
match self.unscoped() {
ActionInput::TimerTick { payload } => serde_json::from_slice(payload).ok(),
_ => None,
}
}
pub fn service_slot_key(&self) -> Option<&str> {
match self.unscoped() {
ActionInput::ServiceStarted { slot_key, .. }
| ActionInput::ServiceStartFailed { slot_key, .. }
| ActionInput::ServiceEvent { slot_key, .. }
| ActionInput::ServiceStopped { slot_key, .. }
| ActionInput::ServiceCommandOk { slot_key, .. }
| ActionInput::ServiceCommandErr { slot_key, .. } => Some(slot_key.as_str()),
_ => None,
}
}
pub fn service_instance_id(&self) -> Option<u64> {
match self.unscoped() {
ActionInput::ServiceStarted { instance_id, .. }
| ActionInput::ServiceEvent { instance_id, .. }
| ActionInput::ServiceStopped { instance_id, .. }
| ActionInput::ServiceCommandOk { instance_id, .. }
| ActionInput::ServiceCommandErr { instance_id, .. } => Some(*instance_id),
_ => None,
}
}
}