use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
pub type InstanceId = Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InstanceSnapshot {
#[serde(rename = "instanceId")]
pub instance_id: InstanceId,
#[serde(rename = "graphicId")]
pub graphic_id: String,
#[serde(default)]
pub data: Option<Value>,
#[serde(rename = "currentStep", default)]
pub current_step: Option<f64>,
}
pub type RenderTarget = Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum ServerMessage {
Load {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "graphicId")]
graphic_id: String,
data: Option<Value>,
},
PlayAction {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(skip_serializing_if = "Option::is_none")]
goto: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
delta: Option<f64>,
#[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
skip_animation: Option<bool>,
},
StopAction {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
skip_animation: Option<bool>,
},
UpdateAction {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
data: Value,
#[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
skip_animation: Option<bool>,
},
CustomAction {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "actionId")]
action_id: String,
payload: Value,
#[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
skip_animation: Option<bool>,
},
RendererCustomAction {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "actionId")]
action_id: String,
payload: Value,
#[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
skip_animation: Option<bool>,
},
Clear {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
},
}
impl ServerMessage {
pub fn play_goto(
request_id: Uuid,
instance_id: InstanceId,
goto: f64,
skip_animation: Option<bool>,
) -> Self {
ServerMessage::PlayAction {
request_id,
instance_id,
goto: Some(goto),
delta: None,
skip_animation,
}
}
pub fn play_delta(
request_id: Uuid,
instance_id: InstanceId,
delta: f64,
skip_animation: Option<bool>,
) -> Self {
ServerMessage::PlayAction {
request_id,
instance_id,
goto: None,
delta: Some(delta),
skip_animation,
}
}
pub fn play_continue(
request_id: Uuid,
instance_id: InstanceId,
skip_animation: Option<bool>,
) -> Self {
ServerMessage::PlayAction {
request_id,
instance_id,
goto: None,
delta: None,
skip_animation,
}
}
}
fn lenient_f64<'de, D>(deserializer: D) -> std::result::Result<f64, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Value::deserialize(deserializer)?.as_f64().unwrap_or(0.0))
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum RendererMessage {
Hello {
name: String,
#[serde(rename = "renderTarget")]
render_target: Value,
#[serde(default)]
capabilities: Value,
#[serde(default)]
instances: Option<Vec<InstanceSnapshot>>,
},
Ping,
LoadResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "graphicId")]
graphic_id: String,
#[serde(default)]
data: Option<Value>,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
},
PlayActionResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
#[serde(rename = "currentStep", default, deserialize_with = "lenient_f64")]
current_step: f64,
},
StopActionResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
},
UpdateActionResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(default)]
data: Option<Value>,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
},
CustomActionResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
},
RendererCustomActionResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
#[serde(default)]
result: Option<Value>,
},
ClearResult {
#[serde(rename = "requestId")]
request_id: Uuid,
#[serde(rename = "instanceId")]
instance_id: InstanceId,
#[serde(rename = "statusCode")]
status_code: u16,
#[serde(rename = "statusMessage", default)]
status_message: Option<String>,
},
}
impl RendererMessage {
pub fn request_id(&self) -> Option<Uuid> {
match self {
RendererMessage::LoadResult { request_id, .. }
| RendererMessage::PlayActionResult { request_id, .. }
| RendererMessage::StopActionResult { request_id, .. }
| RendererMessage::UpdateActionResult { request_id, .. }
| RendererMessage::CustomActionResult { request_id, .. }
| RendererMessage::RendererCustomActionResult { request_id, .. }
| RendererMessage::ClearResult { request_id, .. } => Some(*request_id),
RendererMessage::Hello { .. } | RendererMessage::Ping => None,
}
}
pub fn is_success(&self) -> bool {
match self {
RendererMessage::LoadResult { status_code, .. }
| RendererMessage::PlayActionResult { status_code, .. }
| RendererMessage::StopActionResult { status_code, .. }
| RendererMessage::UpdateActionResult { status_code, .. }
| RendererMessage::CustomActionResult { status_code, .. }
| RendererMessage::RendererCustomActionResult { status_code, .. }
| RendererMessage::ClearResult { status_code, .. } => *status_code < 400,
RendererMessage::Hello { .. } | RendererMessage::Ping => false,
}
}
}