1use serde::{Deserialize, Serialize};
3use serde_json::{Map, Value};
4use std::collections::BTreeMap;
5use uuid::Uuid;
6
7pub type Metadata = Map<String, Value>;
9
10#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
11#[serde(rename_all = "snake_case")]
12pub enum ActorType {
13 Carbon,
14 Silicon,
15}
16
17#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
18pub struct Actor {
19 #[serde(rename = "type")]
20 pub actor_type: ActorType,
21 pub id: String,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct Attachment {
26 pub permanent_url: url::Url,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub name: Option<String>,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub content_type: Option<String>,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub size: Option<u64>,
33}
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub struct VoiceAttachment {
36 #[serde(flatten)]
37 pub attachment: Attachment,
38 pub duration_milliseconds: Option<u64>,
40}
41#[derive(Clone, Debug, Serialize, Deserialize)]
42pub struct Gif {
43 pub provider_id: String,
44 pub url: url::Url,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub preview_url: Option<url::Url>,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub title: Option<String>,
49}
50#[derive(Clone, Debug, Default, Serialize, Deserialize)]
51pub struct MessageCreate {
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub sender_id: Option<String>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub text: Option<String>,
56 #[serde(default)]
57 pub attachments: Vec<Attachment>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub voice: Option<VoiceAttachment>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub voice_transcript: Option<String>,
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub gif: Option<Gif>,
64 #[serde(default)]
65 pub metadata: Metadata,
66 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub reply_to_message_id: Option<Uuid>,
68}
69#[derive(Clone, Debug, Serialize, Deserialize)]
70#[serde(rename_all = "snake_case")]
71pub enum MessageStatus {
72 Waiting,
73 Sent,
74 Delivered,
75 Read,
76 Failed,
77}
78#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80pub enum ReceiptStatus {
81 Delivered,
82 Read,
83}
84#[derive(Clone, Debug, Serialize, Deserialize)]
85pub struct Message {
86 pub id: Uuid,
87 pub conversation_id: Uuid,
88 pub sender: Actor,
89 pub sequence: i64,
90 pub status: MessageStatus,
91 #[serde(flatten)]
92 pub content: MessageCreate,
93 pub created_at: String,
94 #[serde(default)]
95 pub delivered_at: Option<String>,
96 #[serde(default)]
97 pub read_at: Option<String>,
98 #[serde(default)]
99 pub failure_reason: Option<String>,
100 #[serde(default)]
101 pub bundle: Option<BundleRef>,
102 #[serde(default)]
103 pub version: Option<i64>,
104 #[serde(default)]
105 pub updated_at: Option<String>,
106 #[serde(default)]
107 pub deleted_at: Option<String>,
108}
109#[derive(Clone, Debug, Serialize, Deserialize)]
110pub struct BundleRef {
111 pub id: Uuid,
112 pub role: String,
113}
114#[derive(Clone, Debug, Serialize, Deserialize)]
115pub struct Conversation {
116 pub id: Uuid,
117 pub org_id: String,
118 pub participants: Vec<Actor>,
119 pub last_message: Option<Message>,
120 pub created_at: String,
121 pub updated_at: String,
122}
123#[derive(Clone, Debug, Default, Serialize, Deserialize)]
124pub struct PageRequest {
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub cursor: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub limit: Option<u16>,
129}
130#[derive(Clone, Debug, Serialize, Deserialize)]
131pub struct Page<T> {
132 pub items: Vec<T>,
133 #[serde(default)]
134 pub next_cursor: Option<String>,
135}
136#[derive(Clone, Debug, Default, Serialize, Deserialize)]
137pub struct DraftInput {
138 #[serde(default, skip_serializing_if = "Option::is_none")]
139 pub message_content: Option<String>,
140 #[serde(default)]
141 pub attachments: Vec<Attachment>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub voice: Option<VoiceAttachment>,
144 #[serde(default, skip_serializing_if = "Option::is_none")]
145 pub voice_transcript: Option<String>,
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub gif: Option<Gif>,
148 #[serde(default)]
149 pub metadata: Metadata,
150 #[serde(default, skip_serializing_if = "Option::is_none")]
151 pub reply_to_message_id: Option<Uuid>,
152}
153#[derive(Clone, Debug, Serialize, Deserialize)]
154pub struct Draft {
155 pub conversation_id: Uuid,
156 pub actor_id: String,
157 pub version: i64,
158 #[serde(flatten)]
159 pub content: DraftInput,
160 pub updated_at: String,
161}
162#[derive(Clone, Debug, Serialize, Deserialize)]
163pub struct BundleCreate {
164 pub message_ids: Vec<Uuid>,
165 pub display_message: MessageCreate,
166}
167#[derive(Clone, Debug, Serialize, Deserialize)]
168pub struct Bundle {
169 pub id: Uuid,
170 pub conversation_id: Uuid,
171 pub original_message_ids: Vec<Uuid>,
172 pub display_message: Message,
173 pub created_by: Actor,
174 pub created_at: String,
175 #[serde(default)]
176 pub original_messages: Vec<Message>,
177}
178#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
179#[serde(rename_all = "snake_case")]
180pub enum Activity {
181 Typing,
182 RecordingVoice,
183 TranscribingVoice,
184 UploadingFile,
185 SearchingGifs,
186}
187#[derive(Clone, Debug, Serialize, Deserialize)]
188pub struct Presence {
189 pub actor_id: String,
190 pub availability: String,
191 pub activity: Option<Activity>,
192 pub last_seen_at: Option<String>,
193}
194#[derive(Clone, Serialize, Deserialize)]
196pub struct Tokens {
197 pub access_token: String,
198 pub refresh_token: String,
199 pub token_type: String,
200 pub expires_in: i64,
201 pub scope: String,
202 pub actor: Actor,
203 pub organization_id: String,
204}
205#[derive(Clone, Debug, Serialize, Deserialize)]
206pub struct Identity {
207 pub actor: Actor,
208 pub organization_id: String,
209 pub principal_id: String,
210 pub session_id: Option<String>,
211 pub org_role: Option<String>,
212 pub capabilities: Vec<String>,
213}
214#[derive(Clone, Serialize, Deserialize)]
216pub struct TestEnvironmentCreate {
217 pub name: String,
218 pub description: Option<String>,
219 pub iam_environment_id: Uuid,
220 pub iam_environment_key: String,
221 pub iam_app_id: String,
222 pub iam_app_secret: String,
223 #[serde(default, skip_serializing_if = "Option::is_none")]
224 pub iam_webhook_secret: Option<String>,
225 #[serde(default, skip_serializing_if = "Option::is_none")]
226 pub iam_webhook_key_version: Option<i64>,
227}
228#[derive(Clone, Debug, Default, Serialize, Deserialize)]
229pub struct TestEnvironmentUpdate {
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub name: Option<String>,
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub description: Option<String>,
234}
235#[derive(Clone, Serialize, Deserialize)]
236pub struct TestEnvironment {
237 pub environment_id: Uuid,
238 pub organization_id: String,
239 pub creator_actor_id: String,
240 pub creator_actor_kind: String,
241 pub iam_app_id: String,
242 pub version: i64,
243 pub name: String,
244 pub description: Option<String>,
245 pub status: String,
246 pub iam_environment_id: Uuid,
247 pub created_at: String,
248 pub last_activity_at: String,
249 pub deleted_at: Option<String>,
250 pub purge_after: Option<String>,
251 #[serde(default, skip_serializing_if = "Option::is_none")]
252 pub root_key: Option<String>,
253}
254#[derive(Clone, Serialize, Deserialize)]
255pub struct TestEnvironmentKey {
256 pub environment_id: Uuid,
257 pub root_key: String,
258}
259
260#[derive(Clone, Debug, Serialize, Deserialize)]
261#[serde(tag = "type", rename_all = "snake_case")]
262pub enum ClientFrame {
263 Pong {
264 ping_id: String,
265 },
266 Ack {
267 actor_id: String,
268 through_sequence: i64,
269 },
270 Resume {
271 actor_id: String,
272 after_sequence: i64,
273 },
274 Presence {
275 actor_id: String,
276 activity: Option<Activity>,
277 },
278 Receipt {
279 actor_id: String,
280 conversation_id: Uuid,
281 message_id: Uuid,
282 status: ReceiptStatus,
283 device_id: String,
284 },
285 SendMessage {
286 actor_id: String,
287 org_id: String,
288 conversation_id: Uuid,
289 idempotency_key: String,
290 message: Box<MessageCreate>,
291 },
292}
293#[derive(Clone, Debug, Serialize, Deserialize)]
294#[serde(tag = "type", rename_all = "snake_case")]
295pub enum ServerFrame {
296 Ready {
297 protocol_version: u16,
298 connection_id: Uuid,
299 actors: Vec<String>,
300 acknowledged_through: BTreeMap<String, i64>,
301 #[serde(default)]
302 testing_generation: Option<i64>,
303 },
304 Ping {
305 ping_id: String,
306 },
307 MessageAccepted {
308 idempotency_key: String,
309 message: Box<Message>,
310 },
311 ReceiptRecorded {
312 message_id: Uuid,
313 status: ReceiptStatus,
314 },
315 Message {
316 delivery_id: Uuid,
317 actor_id: String,
318 delivery_sequence: i64,
319 message: Box<Message>,
320 },
321 Receipt {
322 delivery_id: Uuid,
323 actor_id: String,
324 delivery_sequence: i64,
325 message_id: Uuid,
326 status: MessageStatus,
327 },
328 Error {
329 code: String,
330 message: String,
331 recoverable: bool,
332 },
333}
334impl ServerFrame {
335 pub fn delivery_position(&self) -> Option<(Uuid, &str, i64)> {
336 match self {
337 Self::Message {
338 delivery_id,
339 actor_id,
340 delivery_sequence,
341 ..
342 }
343 | Self::Receipt {
344 delivery_id,
345 actor_id,
346 delivery_sequence,
347 ..
348 } => Some((*delivery_id, actor_id, *delivery_sequence)),
349 _ => None,
350 }
351 }
352}