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