cdk_ffi/types/
subscription.rs1use std::sync::Arc;
3
4use cdk::event::MintEvent;
5use serde::{Deserialize, Serialize};
6
7use super::proof::ProofStateUpdate;
8use super::quote::{
9 MeltQuoteBolt11Response, MeltQuoteOnchainResponse, MintQuoteBolt11Response,
10 MintQuoteOnchainResponse,
11};
12use crate::error::FfiError;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
16pub enum SubscriptionKind {
17 Bolt11MeltQuote,
19 Bolt11MintQuote,
21 Bolt12MintQuote,
23 Bolt12MeltQuote,
25 OnchainMintQuote,
27 OnchainMeltQuote,
29 ProofState,
31}
32
33impl From<SubscriptionKind> for cdk::nuts::nut17::Kind {
34 fn from(kind: SubscriptionKind) -> Self {
35 match kind {
36 SubscriptionKind::Bolt11MeltQuote => cdk::nuts::nut17::Kind::Bolt11MeltQuote,
37 SubscriptionKind::Bolt11MintQuote => cdk::nuts::nut17::Kind::Bolt11MintQuote,
38 SubscriptionKind::Bolt12MintQuote => cdk::nuts::nut17::Kind::Bolt12MintQuote,
39 SubscriptionKind::Bolt12MeltQuote => cdk::nuts::nut17::Kind::Bolt12MeltQuote,
40 SubscriptionKind::OnchainMintQuote => cdk::nuts::nut17::Kind::OnchainMintQuote,
41 SubscriptionKind::OnchainMeltQuote => cdk::nuts::nut17::Kind::OnchainMeltQuote,
42 SubscriptionKind::ProofState => cdk::nuts::nut17::Kind::ProofState,
43 }
44 }
45}
46
47impl From<cdk::nuts::nut17::Kind> for SubscriptionKind {
48 fn from(kind: cdk::nuts::nut17::Kind) -> Self {
49 match kind {
50 cdk::nuts::nut17::Kind::Bolt11MeltQuote => SubscriptionKind::Bolt11MeltQuote,
51 cdk::nuts::nut17::Kind::Bolt11MintQuote => SubscriptionKind::Bolt11MintQuote,
52 cdk::nuts::nut17::Kind::Bolt12MintQuote => SubscriptionKind::Bolt12MintQuote,
53 cdk::nuts::nut17::Kind::Bolt12MeltQuote => SubscriptionKind::Bolt12MeltQuote,
54 cdk::nuts::nut17::Kind::OnchainMintQuote => SubscriptionKind::OnchainMintQuote,
55 cdk::nuts::nut17::Kind::OnchainMeltQuote => SubscriptionKind::OnchainMeltQuote,
56 cdk::nuts::nut17::Kind::Custom(_) => {
57 panic!("Custom subscription kind not supported in FFI")
58 }
59 cdk::nuts::nut17::Kind::ProofState => SubscriptionKind::ProofState,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
66pub struct SubscribeParams {
67 pub kind: SubscriptionKind,
69 pub filters: Vec<String>,
71 pub id: Option<String>,
73}
74
75impl From<SubscribeParams> for cdk::nuts::nut17::Params<Arc<String>> {
76 fn from(params: SubscribeParams) -> Self {
77 let sub_id = params.id.unwrap_or_else(|| {
78 uuid::Uuid::new_v4().to_string()
80 });
81
82 cdk::nuts::nut17::Params {
83 kind: params.kind.into(),
84 filters: params.filters,
85 id: Arc::new(sub_id),
86 }
87 }
88}
89
90impl SubscribeParams {
91 pub fn to_json(&self) -> Result<String, FfiError> {
93 Ok(serde_json::to_string(self)?)
94 }
95}
96
97#[uniffi::export]
99pub fn decode_subscribe_params(json: String) -> Result<SubscribeParams, FfiError> {
100 Ok(serde_json::from_str(&json)?)
101}
102
103#[uniffi::export]
105pub fn encode_subscribe_params(params: SubscribeParams) -> Result<String, FfiError> {
106 Ok(serde_json::to_string(¶ms)?)
107}
108
109#[derive(uniffi::Object)]
111pub struct ActiveSubscription {
112 inner: std::sync::Arc<tokio::sync::Mutex<cdk::wallet::subscription::ActiveSubscription>>,
113 pub sub_id: String,
114}
115
116impl ActiveSubscription {
117 pub(crate) fn new(
118 inner: cdk::wallet::subscription::ActiveSubscription,
119 sub_id: String,
120 ) -> Self {
121 Self {
122 inner: std::sync::Arc::new(tokio::sync::Mutex::new(inner)),
123 sub_id,
124 }
125 }
126}
127
128#[uniffi::export(async_runtime = "tokio")]
129impl ActiveSubscription {
130 pub fn id(&self) -> String {
132 self.sub_id.clone()
133 }
134
135 pub async fn recv(&self) -> Result<NotificationPayload, FfiError> {
137 let mut guard = self.inner.lock().await;
138 guard
139 .recv()
140 .await
141 .ok_or_else(|| FfiError::internal("Subscription closed"))
142 .map(Into::into)
143 }
144
145 pub async fn try_recv(&self) -> Result<Option<NotificationPayload>, FfiError> {
147 let mut guard = self.inner.lock().await;
148 Ok(guard.try_recv().map(Into::into))
149 }
150}
151
152#[derive(Debug, Clone, uniffi::Enum)]
154pub enum NotificationPayload {
155 ProofState { proof_states: Vec<ProofStateUpdate> },
157 MintQuoteUpdate { quote: MintQuoteBolt11Response },
159 MeltQuoteUpdate { quote: MeltQuoteBolt11Response },
161 MintQuoteOnchainUpdate { quote: MintQuoteOnchainResponse },
163 MeltQuoteOnchainUpdate { quote: MeltQuoteOnchainResponse },
165}
166
167impl From<MintEvent<String>> for NotificationPayload {
168 fn from(payload: MintEvent<String>) -> Self {
169 match payload.into() {
170 cdk::nuts::NotificationPayload::ProofState(states) => NotificationPayload::ProofState {
171 proof_states: vec![states.into()],
172 },
173 cdk::nuts::NotificationPayload::MintQuoteBolt11Response(quote_resp) => {
174 NotificationPayload::MintQuoteUpdate {
175 quote: quote_resp.into(),
176 }
177 }
178 cdk::nuts::NotificationPayload::MeltQuoteBolt11Response(quote_resp) => {
179 NotificationPayload::MeltQuoteUpdate {
180 quote: quote_resp.into(),
181 }
182 }
183 cdk::nuts::NotificationPayload::MintQuoteOnchainResponse(quote_resp) => {
184 NotificationPayload::MintQuoteOnchainUpdate {
185 quote: quote_resp.into(),
186 }
187 }
188 cdk::nuts::NotificationPayload::MeltQuoteOnchainResponse(quote_resp) => {
189 NotificationPayload::MeltQuoteOnchainUpdate {
190 quote: quote_resp.into(),
191 }
192 }
193 _ => {
194 NotificationPayload::ProofState {
196 proof_states: vec![],
197 }
198 }
199 }
200 }
201}