reown_relay_rpc/
rpc.rs

1//! The crate exports common types used when interacting with messages between
2//! clients. This also includes communication over HTTP between relays.
3
4use {
5    crate::domain::{DidKey, MessageId, SubscriptionId, Topic},
6    serde::{de::DeserializeOwned, Deserialize, Serialize},
7    std::{fmt::Debug, sync::Arc},
8};
9pub use {error::*, watch::*};
10
11pub mod error;
12pub mod msg_id;
13#[cfg(test)]
14mod tests;
15pub mod watch;
16
17/// Version of the WalletConnect protocol that we're implementing.
18pub const JSON_RPC_VERSION_STR: &str = "2.0";
19
20pub static JSON_RPC_VERSION: once_cell::sync::Lazy<Arc<str>> =
21    once_cell::sync::Lazy::new(|| Arc::from(JSON_RPC_VERSION_STR));
22
23/// The maximum number of topics allowed for a batch subscribe request.
24///
25/// See <https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/specs/servers/relay/relay-server-rpc.md>
26pub const MAX_SUBSCRIPTION_BATCH_SIZE: usize = 500;
27
28/// The maximum number of topics allowed for a batch fetch request.
29///
30/// See <https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/specs/servers/relay/relay-server-rpc.md>
31pub const MAX_FETCH_BATCH_SIZE: usize = 500;
32
33/// The maximum number of receipts allowed for a batch receive request.
34///
35/// See <https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/specs/servers/relay/relay-server-rpc.md>
36pub const MAX_RECEIVE_BATCH_SIZE: usize = 500;
37
38pub trait Serializable:
39    Debug + Clone + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync + 'static
40{
41}
42impl<T> Serializable for T where
43    T: Debug + Clone + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync + 'static
44{
45}
46
47/// Trait that adds validation capabilities and strong typing to errors and
48/// successful responses. Implemented for all possible RPC request types.
49pub trait ServiceRequest: Serializable {
50    /// The error representing a failed request.
51    type Error: ServiceError;
52
53    /// The type of a successful response.
54    type Response: Serializable;
55
56    /// Validates the request parameters.
57    fn validate(&self) -> Result<(), PayloadError> {
58        Ok(())
59    }
60
61    fn into_params(self) -> Params;
62}
63
64/// Enum representing a JSON RPC payload.
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(untagged)]
67pub enum Payload {
68    /// An inbound request.
69    Request(Request),
70
71    /// An outbound response.
72    Response(Response),
73}
74
75impl Payload {
76    /// Returns the message ID contained within the payload.
77    pub fn id(&self) -> MessageId {
78        match self {
79            Self::Request(req) => req.id,
80            Self::Response(Response::Success(r)) => r.id,
81            Self::Response(Response::Error(r)) => r.id,
82        }
83    }
84
85    pub fn validate(&self) -> Result<(), PayloadError> {
86        match self {
87            Self::Request(request) => request.validate(),
88            Self::Response(response) => response.validate(),
89        }
90    }
91}
92
93impl<T> From<T> for Payload
94where
95    T: Into<ErrorResponse>,
96{
97    fn from(value: T) -> Self {
98        Self::Response(Response::Error(value.into()))
99    }
100}
101
102/// Enum representing a JSON RPC response.
103#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(untagged)]
105pub enum Response {
106    /// A response with a result.
107    Success(SuccessfulResponse),
108
109    /// A response for a failed request.
110    Error(ErrorResponse),
111}
112
113impl Response {
114    pub fn id(&self) -> MessageId {
115        match self {
116            Self::Success(response) => response.id,
117            Self::Error(response) => response.id,
118        }
119    }
120
121    /// Validates the response parameters.
122    pub fn validate(&self) -> Result<(), PayloadError> {
123        match self {
124            Self::Success(response) => response.validate(),
125            Self::Error(response) => response.validate(),
126        }
127    }
128}
129
130/// Data structure representing a successful JSON RPC response.
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
132pub struct SuccessfulResponse {
133    /// ID this message corresponds to.
134    pub id: MessageId,
135
136    /// RPC version.
137    pub jsonrpc: Arc<str>,
138
139    /// The result for the message.
140    pub result: serde_json::Value,
141}
142
143impl SuccessfulResponse {
144    /// Create a new instance.
145    pub fn new(id: MessageId, result: serde_json::Value) -> Self {
146        Self {
147            id,
148            jsonrpc: JSON_RPC_VERSION.clone(),
149            result,
150        }
151    }
152
153    /// Validates the parameters.
154    pub fn validate(&self) -> Result<(), PayloadError> {
155        if self.jsonrpc.as_ref() != JSON_RPC_VERSION_STR {
156            Err(PayloadError::InvalidJsonRpcVersion)
157        } else {
158            // We can't really validate `serde_json::Value` without knowing the expected
159            // value type.
160            Ok(())
161        }
162    }
163}
164
165/// Data structure representing a JSON RPC error response.
166#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167pub struct ErrorResponse {
168    /// ID this message corresponds to.
169    pub id: MessageId,
170
171    /// RPC version.
172    pub jsonrpc: Arc<str>,
173
174    /// The ErrorResponse corresponding to this message.
175    pub error: ErrorData,
176}
177
178impl ErrorResponse {
179    /// Create a new instance.
180    pub fn new(id: MessageId, error: impl Into<ErrorData>) -> Self {
181        Self {
182            id,
183            jsonrpc: JSON_RPC_VERSION.clone(),
184            error: error.into(),
185        }
186    }
187
188    /// Validates the parameters.
189    pub fn validate(&self) -> Result<(), PayloadError> {
190        if self.jsonrpc.as_ref() != JSON_RPC_VERSION_STR {
191            Err(PayloadError::InvalidJsonRpcVersion)
192        } else {
193            Ok(())
194        }
195    }
196}
197
198/// Data structure representing error response params.
199#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
200pub struct ErrorData {
201    /// Error code.
202    pub code: i32,
203
204    /// Error message.
205    pub message: String,
206
207    /// Error data, if any.
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub data: Option<String>,
210}
211
212#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
213pub enum SubscriptionError {
214    #[error("Subscriber limit exceeded")]
215    SubscriberLimitExceeded,
216}
217
218/// Subscription request parameters. This request does not require the
219/// subscription to be fully processed, and returns as soon as the server
220/// receives it.
221#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
222pub struct Subscribe {
223    /// The topic to subscribe to.
224    pub topic: Topic,
225}
226
227impl ServiceRequest for Subscribe {
228    type Error = SubscriptionError;
229    type Response = SubscriptionId;
230
231    fn validate(&self) -> Result<(), PayloadError> {
232        self.topic
233            .decode()
234            .map_err(|_| PayloadError::InvalidTopic)?;
235
236        Ok(())
237    }
238
239    fn into_params(self) -> Params {
240        Params::Subscribe(self)
241    }
242}
243
244/// Subscription request parameters. This request awaits the subscription to be
245/// fully processed and returns possible errors.
246#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
247pub struct SubscribeBlocking {
248    /// The topic to subscribe to.
249    pub topic: Topic,
250}
251
252impl ServiceRequest for SubscribeBlocking {
253    type Error = SubscriptionError;
254    type Response = SubscriptionId;
255
256    fn validate(&self) -> Result<(), PayloadError> {
257        self.topic
258            .decode()
259            .map_err(|_| PayloadError::InvalidTopic)?;
260
261        Ok(())
262    }
263
264    fn into_params(self) -> Params {
265        Params::SubscribeBlocking(self)
266    }
267}
268
269/// Data structure representing unsubscribe request params.
270#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
271pub struct Unsubscribe {
272    /// The topic to unsubscribe from.
273    pub topic: Topic,
274}
275
276impl ServiceRequest for Unsubscribe {
277    type Error = SubscriptionError;
278    type Response = bool;
279
280    fn validate(&self) -> Result<(), PayloadError> {
281        self.topic
282            .decode()
283            .map_err(|_| PayloadError::InvalidTopic)?;
284
285        // FIXME: Subscription ID validation is currently disabled, since SDKs do not
286        // use the actual IDs generated by the relay, and instead send some randomized
287        // values. We should either fix SDKs to ensure they properly utilize the IDs, or
288        // just remove it from the payload.
289
290        // self.subscription_id
291        //     .decode()
292        //     .map_err(ValidationError::SubscriptionIdDecoding)?;
293
294        Ok(())
295    }
296
297    fn into_params(self) -> Params {
298        Params::Unsubscribe(self)
299    }
300}
301
302/// Data structure representing fetch request params.
303#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
304pub struct FetchMessages {
305    /// The topic of the messages to fetch.
306    pub topic: Topic,
307}
308
309impl ServiceRequest for FetchMessages {
310    type Error = GenericError;
311    type Response = FetchResponse;
312
313    fn validate(&self) -> Result<(), PayloadError> {
314        self.topic
315            .decode()
316            .map_err(|_| PayloadError::InvalidTopic)?;
317
318        Ok(())
319    }
320
321    fn into_params(self) -> Params {
322        Params::FetchMessages(self)
323    }
324}
325
326/// Data structure representing fetch response.
327#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
328#[serde(rename_all = "camelCase")]
329pub struct FetchResponse {
330    /// Array of messages fetched from the mailbox.
331    pub messages: Vec<SubscriptionData>,
332
333    /// Flag that indicates whether the client should keep fetching the
334    /// messages.
335    pub has_more: bool,
336}
337
338/// Multi-topic subscription request parameters. This request does not require
339/// all subscriptions to be fully processed, and returns as soon as the server
340/// receives it.
341#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
342pub struct BatchSubscribe {
343    /// The topics to subscribe to.
344    pub topics: Vec<Topic>,
345}
346
347impl BatchSubscribe {
348    fn validate_topics(topics: &[Topic]) -> Result<(), PayloadError> {
349        let batch_size = topics.len();
350
351        if batch_size == 0 {
352            return Err(PayloadError::BatchEmpty);
353        }
354
355        if batch_size > MAX_SUBSCRIPTION_BATCH_SIZE {
356            return Err(PayloadError::BatchLimitExceeded);
357        }
358
359        for topic in topics {
360            topic.decode().map_err(|_| PayloadError::InvalidTopic)?;
361        }
362
363        Ok(())
364    }
365}
366
367impl ServiceRequest for BatchSubscribe {
368    type Error = SubscriptionError;
369    type Response = Vec<SubscriptionId>;
370
371    fn validate(&self) -> Result<(), PayloadError> {
372        Self::validate_topics(&self.topics)
373    }
374
375    fn into_params(self) -> Params {
376        Params::BatchSubscribe(self)
377    }
378}
379
380/// Multi-topic subscription request parameters. This request awaits all
381/// subscriptions to be fully processed and returns possible errors per topic.
382#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
383pub struct BatchSubscribeBlocking {
384    /// The topics to subscribe to.
385    pub topics: Vec<Topic>,
386}
387
388#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
389#[serde(rename_all = "camelCase")]
390pub enum SubscriptionResult {
391    Id(SubscriptionId),
392    Error(ErrorData),
393}
394
395impl ServiceRequest for BatchSubscribeBlocking {
396    type Error = SubscriptionError;
397    type Response = Vec<SubscriptionResult>;
398
399    fn validate(&self) -> Result<(), PayloadError> {
400        BatchSubscribe::validate_topics(&self.topics)
401    }
402
403    fn into_params(self) -> Params {
404        Params::BatchSubscribeBlocking(self)
405    }
406}
407
408/// Multi-topic unsubscription request parameters.
409#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
410pub struct BatchUnsubscribe {
411    /// The subscriptions to unsubscribe from.
412    pub subscriptions: Vec<Unsubscribe>,
413}
414
415impl ServiceRequest for BatchUnsubscribe {
416    type Error = SubscriptionError;
417    type Response = bool;
418
419    fn validate(&self) -> Result<(), PayloadError> {
420        let batch_size = self.subscriptions.len();
421
422        if batch_size == 0 {
423            return Err(PayloadError::BatchEmpty);
424        }
425
426        if batch_size > MAX_SUBSCRIPTION_BATCH_SIZE {
427            return Err(PayloadError::BatchLimitExceeded);
428        }
429
430        for sub in &self.subscriptions {
431            sub.validate()?;
432        }
433
434        Ok(())
435    }
436
437    fn into_params(self) -> Params {
438        Params::BatchUnsubscribe(self)
439    }
440}
441
442/// Data structure representing batch fetch request params.
443#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
444pub struct BatchFetchMessages {
445    /// The topics of the messages to fetch.
446    pub topics: Vec<Topic>,
447}
448
449impl ServiceRequest for BatchFetchMessages {
450    type Error = GenericError;
451    type Response = FetchResponse;
452
453    fn validate(&self) -> Result<(), PayloadError> {
454        let batch_size = self.topics.len();
455
456        if batch_size == 0 {
457            return Err(PayloadError::BatchEmpty);
458        }
459
460        if batch_size > MAX_FETCH_BATCH_SIZE {
461            return Err(PayloadError::BatchLimitExceeded);
462        }
463
464        for topic in &self.topics {
465            topic.decode().map_err(|_| PayloadError::InvalidTopic)?;
466        }
467
468        Ok(())
469    }
470
471    fn into_params(self) -> Params {
472        Params::BatchFetchMessages(self)
473    }
474}
475
476/// Represents a message receipt.
477#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
478pub struct Receipt {
479    /// The topic of the message to acknowledge.
480    pub topic: Topic,
481
482    /// The ID of the message to acknowledge.
483    pub message_id: MessageId,
484}
485
486/// Data structure representing publish request params.
487#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
488pub struct BatchReceiveMessages {
489    /// The receipts to acknowledge.
490    pub receipts: Vec<Receipt>,
491}
492
493impl ServiceRequest for BatchReceiveMessages {
494    type Error = GenericError;
495    type Response = bool;
496
497    fn validate(&self) -> Result<(), PayloadError> {
498        let batch_size = self.receipts.len();
499
500        if batch_size == 0 {
501            return Err(PayloadError::BatchEmpty);
502        }
503
504        if batch_size > MAX_RECEIVE_BATCH_SIZE {
505            return Err(PayloadError::BatchLimitExceeded);
506        }
507
508        for receipt in &self.receipts {
509            receipt
510                .topic
511                .decode()
512                .map_err(|_| PayloadError::InvalidTopic)?;
513        }
514
515        Ok(())
516    }
517
518    fn into_params(self) -> Params {
519        Params::BatchReceiveMessages(self)
520    }
521}
522
523/// Data structure representing publish request params.
524#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
525pub struct Publish {
526    /// Topic to publish to.
527    pub topic: Topic,
528
529    /// Message to publish.
530    pub message: Arc<str>,
531
532    #[serde(default, skip_serializing_if = "is_default")]
533    pub attestation: Option<Arc<str>>,
534
535    /// Duration for which the message should be kept in the mailbox if it can't
536    /// be delivered, in seconds.
537    #[serde(rename = "ttl")]
538    pub ttl_secs: u32,
539
540    /// A label that identifies what type of message is sent based on the RPC
541    /// method used.
542    pub tag: u32,
543
544    /// A flag that identifies whether the server should trigger a notification
545    /// webhook to a client through a push server.
546    #[serde(default, skip_serializing_if = "is_default")]
547    pub prompt: bool,
548}
549
550impl Publish {
551    /// Converts these publish params into subscription params.
552    pub fn as_subscription(
553        &self,
554        subscription_id: SubscriptionId,
555        published_at: i64,
556    ) -> Subscription {
557        Subscription {
558            id: subscription_id,
559            data: SubscriptionData {
560                topic: self.topic.clone(),
561                message: self.message.clone(),
562                attestation: self.attestation.clone(),
563                published_at,
564                tag: self.tag,
565            },
566        }
567    }
568
569    /// Creates a subscription request from these publish params.
570    pub fn as_subscription_request(
571        &self,
572        message_id: MessageId,
573        subscription_id: SubscriptionId,
574        published_at: i64,
575    ) -> Request {
576        Request {
577            id: message_id,
578            jsonrpc: JSON_RPC_VERSION.clone(),
579            params: Params::Subscription(self.as_subscription(subscription_id, published_at)),
580        }
581    }
582}
583
584#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
585pub enum PublishError {
586    #[error("TTL too short")]
587    TtlTooShort,
588
589    #[error("TTL too long")]
590    TtlTooLong,
591
592    #[error("Mailbox limit exceeded")]
593    MailboxLimitExceeded,
594}
595
596impl ServiceRequest for Publish {
597    type Error = PublishError;
598    type Response = bool;
599
600    fn validate(&self) -> Result<(), PayloadError> {
601        self.topic
602            .decode()
603            .map_err(|_| PayloadError::InvalidTopic)?;
604
605        Ok(())
606    }
607
608    fn into_params(self) -> Params {
609        Params::Publish(self)
610    }
611}
612
613fn is_default<T>(x: &T) -> bool
614where
615    T: Default + PartialEq + 'static,
616{
617    *x == Default::default()
618}
619
620#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
621pub enum GenericError {
622    #[error("Unknown error")]
623    Unknown,
624}
625
626#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
627pub enum WatchError {
628    #[error("Invalid TTL")]
629    InvalidTtl,
630
631    #[error("Service URL is invalid or too long")]
632    InvalidServiceUrl,
633
634    #[error("Webhook URL is invalid or too long")]
635    InvalidWebhookUrl,
636
637    #[error("Invalid action")]
638    InvalidAction,
639
640    #[error("Invalid JWT")]
641    InvalidJwt,
642}
643
644#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
645#[serde(rename_all = "camelCase")]
646pub struct WatchRegisterResponse {
647    /// The Relay's public key (did:key).
648    pub relay_id: DidKey,
649}
650
651/// Data structure representing watch registration request params.
652#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
653#[serde(rename_all = "camelCase")]
654pub struct WatchRegister {
655    /// JWT with [`watch::WatchRegisterClaims`] payload.
656    pub register_auth: String,
657}
658
659impl ServiceRequest for WatchRegister {
660    type Error = WatchError;
661    type Response = WatchRegisterResponse;
662
663    fn validate(&self) -> Result<(), PayloadError> {
664        Ok(())
665    }
666
667    fn into_params(self) -> Params {
668        Params::WatchRegister(self)
669    }
670}
671
672/// Data structure representing watch unregistration request params.
673#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
674#[serde(rename_all = "camelCase")]
675pub struct WatchUnregister {
676    /// JWT with [`watch::WatchUnregisterClaims`] payload.
677    pub unregister_auth: String,
678}
679
680impl ServiceRequest for WatchUnregister {
681    type Error = WatchError;
682    type Response = bool;
683
684    fn validate(&self) -> Result<(), PayloadError> {
685        Ok(())
686    }
687
688    fn into_params(self) -> Params {
689        Params::WatchUnregister(self)
690    }
691}
692
693/// Data structure representing subscription request params.
694#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
695pub struct Subscription {
696    /// The id of the subscription.
697    pub id: SubscriptionId,
698
699    /// The published data.
700    pub data: SubscriptionData,
701}
702
703impl ServiceRequest for Subscription {
704    type Error = GenericError;
705    type Response = bool;
706
707    fn validate(&self) -> Result<(), PayloadError> {
708        self.id
709            .decode()
710            .map_err(|_| PayloadError::InvalidSubscriptionId)?;
711
712        self.data
713            .topic
714            .decode()
715            .map_err(|_| PayloadError::InvalidTopic)?;
716
717        Ok(())
718    }
719
720    fn into_params(self) -> Params {
721        Params::Subscription(self)
722    }
723}
724
725/// Data structure representing subscription message params.
726#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
727#[serde(rename_all = "camelCase")]
728pub struct SubscriptionData {
729    /// The topic of the subscription.
730    pub topic: Topic,
731
732    /// The message for the subscription.
733    pub message: Arc<str>,
734
735    #[serde(default, skip_serializing_if = "is_default")]
736    pub attestation: Option<Arc<str>>,
737
738    /// Message publish timestamp in UTC milliseconds.
739    pub published_at: i64,
740
741    /// A label that identifies what type of message is sent based on the RPC
742    /// method used.
743    #[serde(default, skip_serializing_if = "is_default")]
744    pub tag: u32,
745}
746
747/// Enum representing parameters of all possible RPC requests.
748#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
749#[serde(tag = "method", content = "params")]
750pub enum Params {
751    /// Parameters to subscribe.
752    #[serde(rename = "irn_subscribe", alias = "iridium_subscribe")]
753    Subscribe(Subscribe),
754
755    /// Parameters to blocking subscribe.
756    #[serde(rename = "irn_subscribeBlocking", alias = "iridium_subscribeBlocking")]
757    SubscribeBlocking(SubscribeBlocking),
758
759    /// Parameters to unsubscribe.
760    #[serde(rename = "irn_unsubscribe", alias = "iridium_unsubscribe")]
761    Unsubscribe(Unsubscribe),
762
763    /// Parameters to fetch.
764    #[serde(rename = "irn_fetchMessages", alias = "iridium_fetchMessages")]
765    FetchMessages(FetchMessages),
766
767    /// Parameters to batch subscribe.
768    #[serde(rename = "irn_batchSubscribe", alias = "iridium_batchSubscribe")]
769    BatchSubscribe(BatchSubscribe),
770
771    /// Parameters to blocking batch subscribe.
772    #[serde(
773        rename = "irn_batchSubscribeBlocking",
774        alias = "iridium_batchSubscribeBlocking"
775    )]
776    BatchSubscribeBlocking(BatchSubscribeBlocking),
777
778    /// Parameters to batch unsubscribe.
779    #[serde(rename = "irn_batchUnsubscribe", alias = "iridium_batchUnsubscribe")]
780    BatchUnsubscribe(BatchUnsubscribe),
781
782    /// Parameters to batch fetch.
783    #[serde(
784        rename = "irn_batchFetchMessages",
785        alias = "iridium_batchFetchMessages"
786    )]
787    BatchFetchMessages(BatchFetchMessages),
788
789    /// Parameters to publish.
790    #[serde(rename = "irn_publish", alias = "iridium_publish")]
791    Publish(Publish),
792
793    /// Parameters to batch receive.
794    #[serde(rename = "irn_batchReceive", alias = "iridium_batchReceive")]
795    BatchReceiveMessages(BatchReceiveMessages),
796
797    /// Parameters to watch register.
798    #[serde(rename = "irn_watchRegister", alias = "iridium_watchRegister")]
799    WatchRegister(WatchRegister),
800
801    /// Parameters to watch unregister.
802    #[serde(rename = "irn_watchUnregister", alias = "iridium_watchUnregister")]
803    WatchUnregister(WatchUnregister),
804
805    /// Parameters for a subscription. The messages for any given topic sent to
806    /// clients are wrapped into this format. A `publish` message to a topic
807    /// results in a `subscription` message to each client subscribed to the
808    /// topic the data is published for.
809    #[serde(rename = "irn_subscription", alias = "iridium_subscription")]
810    Subscription(Subscription),
811}
812
813/// Data structure representing a JSON RPC request.
814#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
815pub struct Request {
816    /// ID this message corresponds to.
817    pub id: MessageId,
818
819    /// The JSON RPC version.
820    pub jsonrpc: Arc<str>,
821
822    /// The parameters required to fulfill this request.
823    #[serde(flatten)]
824    pub params: Params,
825}
826
827impl Request {
828    /// Create a new instance.
829    pub fn new(id: MessageId, params: Params) -> Self {
830        Self {
831            id,
832            jsonrpc: JSON_RPC_VERSION_STR.into(),
833            params,
834        }
835    }
836
837    /// Validates the request payload.
838    pub fn validate(&self) -> Result<(), PayloadError> {
839        if !self.id.validate() {
840            return Err(PayloadError::InvalidRequestId);
841        }
842
843        if self.jsonrpc.as_ref() != JSON_RPC_VERSION_STR {
844            return Err(PayloadError::InvalidJsonRpcVersion);
845        }
846
847        match &self.params {
848            Params::Subscribe(params) => params.validate(),
849            Params::SubscribeBlocking(params) => params.validate(),
850            Params::Unsubscribe(params) => params.validate(),
851            Params::FetchMessages(params) => params.validate(),
852            Params::BatchSubscribe(params) => params.validate(),
853            Params::BatchSubscribeBlocking(params) => params.validate(),
854            Params::BatchUnsubscribe(params) => params.validate(),
855            Params::BatchFetchMessages(params) => params.validate(),
856            Params::Publish(params) => params.validate(),
857            Params::BatchReceiveMessages(params) => params.validate(),
858            Params::WatchRegister(params) => params.validate(),
859            Params::WatchUnregister(params) => params.validate(),
860            Params::Subscription(params) => params.validate(),
861        }
862    }
863}