1use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use uuid::Uuid;
8
9pub type InstanceId = Uuid;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct InstanceSnapshot {
17 #[serde(rename = "instanceId")]
18 pub instance_id: InstanceId,
19 #[serde(rename = "graphicId")]
20 pub graphic_id: String,
21 #[serde(default)]
22 pub data: Option<Value>,
23 #[serde(rename = "currentStep", default)]
24 pub current_step: Option<f64>,
25}
26
27pub type RenderTarget = Value;
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(tag = "type", rename_all = "camelCase")]
41pub enum ServerMessage {
42 Load {
43 #[serde(rename = "requestId")]
44 request_id: Uuid,
45 #[serde(rename = "instanceId")]
46 instance_id: InstanceId,
47 #[serde(rename = "graphicId")]
48 graphic_id: String,
49 data: Option<Value>,
50 },
51 PlayAction {
52 #[serde(rename = "requestId")]
53 request_id: Uuid,
54 #[serde(rename = "instanceId")]
55 instance_id: InstanceId,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 goto: Option<f64>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 delta: Option<f64>,
60 #[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
61 skip_animation: Option<bool>,
62 },
63 StopAction {
64 #[serde(rename = "requestId")]
65 request_id: Uuid,
66 #[serde(rename = "instanceId")]
67 instance_id: InstanceId,
68 #[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
69 skip_animation: Option<bool>,
70 },
71 UpdateAction {
72 #[serde(rename = "requestId")]
73 request_id: Uuid,
74 #[serde(rename = "instanceId")]
75 instance_id: InstanceId,
76 data: Value,
77 #[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
78 skip_animation: Option<bool>,
79 },
80 CustomAction {
81 #[serde(rename = "requestId")]
82 request_id: Uuid,
83 #[serde(rename = "instanceId")]
84 instance_id: InstanceId,
85 #[serde(rename = "actionId")]
86 action_id: String,
87 payload: Value,
88 #[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
89 skip_animation: Option<bool>,
90 },
91 RendererCustomAction {
93 #[serde(rename = "requestId")]
94 request_id: Uuid,
95 #[serde(rename = "actionId")]
96 action_id: String,
97 payload: Value,
98 #[serde(rename = "skipAnimation", skip_serializing_if = "Option::is_none")]
99 skip_animation: Option<bool>,
100 },
101 Clear {
102 #[serde(rename = "requestId")]
103 request_id: Uuid,
104 #[serde(rename = "instanceId")]
105 instance_id: InstanceId,
106 },
107}
108
109impl ServerMessage {
110 pub fn play_goto(
113 request_id: Uuid,
114 instance_id: InstanceId,
115 goto: f64,
116 skip_animation: Option<bool>,
117 ) -> Self {
118 ServerMessage::PlayAction {
119 request_id,
120 instance_id,
121 goto: Some(goto),
122 delta: None,
123 skip_animation,
124 }
125 }
126
127 pub fn play_delta(
130 request_id: Uuid,
131 instance_id: InstanceId,
132 delta: f64,
133 skip_animation: Option<bool>,
134 ) -> Self {
135 ServerMessage::PlayAction {
136 request_id,
137 instance_id,
138 goto: None,
139 delta: Some(delta),
140 skip_animation,
141 }
142 }
143
144 pub fn play_continue(
147 request_id: Uuid,
148 instance_id: InstanceId,
149 skip_animation: Option<bool>,
150 ) -> Self {
151 ServerMessage::PlayAction {
152 request_id,
153 instance_id,
154 goto: None,
155 delta: None,
156 skip_animation,
157 }
158 }
159}
160
161fn lenient_f64<'de, D>(deserializer: D) -> std::result::Result<f64, D::Error>
164where
165 D: serde::Deserializer<'de>,
166{
167 Ok(Value::deserialize(deserializer)?.as_f64().unwrap_or(0.0))
168}
169
170#[derive(Debug, Clone, Deserialize)]
172#[serde(tag = "type", rename_all = "camelCase")]
173pub enum RendererMessage {
174 Hello {
175 name: String,
176 #[serde(rename = "renderTarget")]
177 render_target: Value,
178 #[serde(default)]
179 capabilities: Value,
180 #[serde(default)]
184 instances: Option<Vec<InstanceSnapshot>>,
185 },
186 Ping,
187 LoadResult {
188 #[serde(rename = "requestId")]
189 request_id: Uuid,
190 #[serde(rename = "instanceId")]
191 instance_id: InstanceId,
192 #[serde(rename = "graphicId")]
193 graphic_id: String,
194 #[serde(default)]
195 data: Option<Value>,
196 #[serde(rename = "statusCode")]
197 status_code: u16,
198 #[serde(rename = "statusMessage", default)]
199 status_message: Option<String>,
200 },
201 PlayActionResult {
202 #[serde(rename = "requestId")]
203 request_id: Uuid,
204 #[serde(rename = "instanceId")]
205 instance_id: InstanceId,
206 #[serde(rename = "statusCode")]
207 status_code: u16,
208 #[serde(rename = "statusMessage", default)]
209 status_message: Option<String>,
210 #[serde(rename = "currentStep", default, deserialize_with = "lenient_f64")]
215 current_step: f64,
216 },
217 StopActionResult {
218 #[serde(rename = "requestId")]
219 request_id: Uuid,
220 #[serde(rename = "instanceId")]
221 instance_id: InstanceId,
222 #[serde(rename = "statusCode")]
223 status_code: u16,
224 #[serde(rename = "statusMessage", default)]
225 status_message: Option<String>,
226 },
227 UpdateActionResult {
228 #[serde(rename = "requestId")]
229 request_id: Uuid,
230 #[serde(rename = "instanceId")]
231 instance_id: InstanceId,
232 #[serde(default)]
233 data: Option<Value>,
234 #[serde(rename = "statusCode")]
235 status_code: u16,
236 #[serde(rename = "statusMessage", default)]
237 status_message: Option<String>,
238 },
239 CustomActionResult {
240 #[serde(rename = "requestId")]
241 request_id: Uuid,
242 #[serde(rename = "instanceId")]
243 instance_id: InstanceId,
244 #[serde(rename = "statusCode")]
245 status_code: u16,
246 #[serde(rename = "statusMessage", default)]
247 status_message: Option<String>,
248 },
249 RendererCustomActionResult {
250 #[serde(rename = "requestId")]
251 request_id: Uuid,
252 #[serde(rename = "statusCode")]
253 status_code: u16,
254 #[serde(rename = "statusMessage", default)]
255 status_message: Option<String>,
256 #[serde(default)]
257 result: Option<Value>,
258 },
259 ClearResult {
260 #[serde(rename = "requestId")]
261 request_id: Uuid,
262 #[serde(rename = "instanceId")]
263 instance_id: InstanceId,
264 #[serde(rename = "statusCode")]
265 status_code: u16,
266 #[serde(rename = "statusMessage", default)]
267 status_message: Option<String>,
268 },
269}
270
271impl RendererMessage {
272 pub fn request_id(&self) -> Option<Uuid> {
275 match self {
276 RendererMessage::LoadResult { request_id, .. }
277 | RendererMessage::PlayActionResult { request_id, .. }
278 | RendererMessage::StopActionResult { request_id, .. }
279 | RendererMessage::UpdateActionResult { request_id, .. }
280 | RendererMessage::CustomActionResult { request_id, .. }
281 | RendererMessage::RendererCustomActionResult { request_id, .. }
282 | RendererMessage::ClearResult { request_id, .. } => Some(*request_id),
283 RendererMessage::Hello { .. } | RendererMessage::Ping => None,
284 }
285 }
286
287 pub fn is_success(&self) -> bool {
290 match self {
291 RendererMessage::LoadResult { status_code, .. }
292 | RendererMessage::PlayActionResult { status_code, .. }
293 | RendererMessage::StopActionResult { status_code, .. }
294 | RendererMessage::UpdateActionResult { status_code, .. }
295 | RendererMessage::CustomActionResult { status_code, .. }
296 | RendererMessage::RendererCustomActionResult { status_code, .. }
297 | RendererMessage::ClearResult { status_code, .. } => *status_code < 400,
298 RendererMessage::Hello { .. } | RendererMessage::Ping => false,
299 }
300 }
301}