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