enigma_node_types/
relay.rs1use base64::engine::general_purpose::STANDARD;
2use base64::Engine;
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6use crate::error::{EnigmaNodeTypesError, Result};
7use crate::user_id::UserId;
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10#[serde(deny_unknown_fields)]
11pub struct RelayEnvelope {
12 pub id: Uuid,
13 pub to: UserId,
14 pub from: Option<UserId>,
15 pub created_at_ms: u64,
16 pub expires_at_ms: Option<u64>,
17 pub kind: RelayKind,
18}
19
20impl RelayEnvelope {
21 pub fn validate(&self) -> Result<()> {
22 if self.created_at_ms == 0 {
23 return Err(EnigmaNodeTypesError::InvalidField("created_at_ms"));
24 }
25 if let Some(expires) = self.expires_at_ms {
26 if expires <= self.created_at_ms {
27 return Err(EnigmaNodeTypesError::InvalidField("expires_at_ms"));
28 }
29 }
30 match &self.kind {
31 RelayKind::OpaqueMessage(message) => {
32 validate_blob(&message.blob_b64)?;
33 if let Some(ct) = &message.content_type {
34 if ct.len() > 128 {
35 return Err(EnigmaNodeTypesError::InvalidField("content_type"));
36 }
37 }
38 }
39 RelayKind::OpaqueSignaling(signaling) => {
40 validate_blob(&signaling.blob_b64)?;
41 }
42 RelayKind::OpaqueAttachmentChunk(chunk) => {
43 validate_blob(&chunk.blob_b64)?;
44 }
45 }
46 Ok(())
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
51pub enum RelayKind {
52 OpaqueMessage(OpaqueMessage),
53 OpaqueSignaling(OpaqueSignaling),
54 OpaqueAttachmentChunk(OpaqueAttachmentChunk),
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
58#[serde(deny_unknown_fields)]
59pub struct OpaqueMessage {
60 pub blob_b64: String,
61 pub content_type: Option<String>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
65#[serde(deny_unknown_fields)]
66pub struct OpaqueSignaling {
67 pub blob_b64: String,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
71#[serde(deny_unknown_fields)]
72pub struct OpaqueAttachmentChunk {
73 pub blob_b64: String,
74 pub attachment_id: Uuid,
75 pub index: u32,
76 pub total: Option<u32>,
77}
78
79fn validate_blob(blob_b64: &str) -> Result<()> {
80 let decoded = STANDARD.decode(blob_b64.as_bytes())?;
81 if decoded.is_empty() {
82 return Err(EnigmaNodeTypesError::InvalidBase64);
83 }
84 Ok(())
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
88#[serde(deny_unknown_fields)]
89pub struct RelayPushRequest {
90 pub envelopes: Vec<RelayEnvelope>,
91}
92
93impl RelayPushRequest {
94 pub fn validate(&self) -> Result<()> {
95 for envelope in &self.envelopes {
96 envelope.validate()?;
97 }
98 Ok(())
99 }
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103#[serde(deny_unknown_fields)]
104pub struct RelayPushResponse {
105 pub accepted: usize,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
109#[serde(deny_unknown_fields)]
110pub struct RelayPullResponse {
111 pub envelopes: Vec<RelayEnvelope>,
112 pub next_cursor: Option<String>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
116#[serde(deny_unknown_fields)]
117pub struct RelayAckRequest {
118 pub ids: Vec<Uuid>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
122#[serde(deny_unknown_fields)]
123pub struct RelayAckResponse {
124 pub removed: usize,
125}