cdk_common/
subscription.rs

1//! Subscription types and traits
2use std::ops::Deref;
3use std::str::FromStr;
4use std::sync::Arc;
5
6use cashu::nut17::{self, Kind, NotificationId};
7use cashu::quote_id::QuoteId;
8use cashu::PublicKey;
9use serde::{Deserialize, Serialize};
10
11use crate::pub_sub::{Error, SubscriptionRequest};
12
13/// CDK/Mint Subscription parameters.
14///
15/// This is a concrete type alias for `nut17::Params<SubId>`.
16pub type Params = nut17::Params<Arc<SubId>>;
17
18impl SubscriptionRequest for Params {
19    type Topic = NotificationId<QuoteId>;
20
21    type SubscriptionId = SubId;
22
23    fn subscription_name(&self) -> Arc<Self::SubscriptionId> {
24        self.id.clone()
25    }
26
27    fn try_get_topics(&self) -> Result<Vec<Self::Topic>, Error> {
28        self.filters
29            .iter()
30            .map(|filter| match self.kind {
31                Kind::Bolt11MeltQuote => QuoteId::from_str(filter)
32                    .map(NotificationId::MeltQuoteBolt11)
33                    .map_err(|_| Error::ParsingError(filter.to_owned())),
34                Kind::Bolt11MintQuote => QuoteId::from_str(filter)
35                    .map(NotificationId::MintQuoteBolt11)
36                    .map_err(|_| Error::ParsingError(filter.to_owned())),
37                Kind::ProofState => PublicKey::from_str(filter)
38                    .map(NotificationId::ProofState)
39                    .map_err(|_| Error::ParsingError(filter.to_owned())),
40
41                Kind::Bolt12MintQuote => QuoteId::from_str(filter)
42                    .map(NotificationId::MintQuoteBolt12)
43                    .map_err(|_| Error::ParsingError(filter.to_owned())),
44            })
45            .collect::<Result<Vec<_>, _>>()
46    }
47}
48
49/// Subscriptions parameters for the wallet
50///
51/// This is because the Wallet can subscribe to non CDK quotes, where IDs are not constraint to
52/// QuoteId
53pub type WalletParams = nut17::Params<Arc<String>>;
54
55impl SubscriptionRequest for WalletParams {
56    type Topic = NotificationId<String>;
57
58    type SubscriptionId = String;
59
60    fn subscription_name(&self) -> Arc<Self::SubscriptionId> {
61        self.id.clone()
62    }
63
64    fn try_get_topics(&self) -> Result<Vec<Self::Topic>, Error> {
65        self.filters
66            .iter()
67            .map(|filter| {
68                Ok(match self.kind {
69                    Kind::Bolt11MeltQuote => NotificationId::MeltQuoteBolt11(filter.to_owned()),
70                    Kind::Bolt11MintQuote => NotificationId::MintQuoteBolt11(filter.to_owned()),
71                    Kind::ProofState => PublicKey::from_str(filter)
72                        .map(NotificationId::ProofState)
73                        .map_err(|_| Error::ParsingError(filter.to_owned()))?,
74
75                    Kind::Bolt12MintQuote => NotificationId::MintQuoteBolt12(filter.to_owned()),
76                })
77            })
78            .collect::<Result<Vec<_>, _>>()
79    }
80}
81
82/// Subscription Id wrapper
83///
84/// This is the place to add some sane default (like a max length) to the
85/// subscription ID
86#[derive(Debug, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
87pub struct SubId(String);
88
89impl From<&str> for SubId {
90    fn from(s: &str) -> Self {
91        Self(s.to_string())
92    }
93}
94
95impl From<String> for SubId {
96    fn from(s: String) -> Self {
97        Self(s)
98    }
99}
100
101impl FromStr for SubId {
102    type Err = ();
103
104    fn from_str(s: &str) -> Result<Self, Self::Err> {
105        Ok(Self(s.to_string()))
106    }
107}
108
109impl Deref for SubId {
110    type Target = String;
111
112    fn deref(&self) -> &Self::Target {
113        &self.0
114    }
115}