use std::sync::Arc;
use cdk::event::MintEvent;
use serde::{Deserialize, Serialize};
use super::proof::ProofStateUpdate;
use super::quote::{
MeltQuoteBolt11Response, MeltQuoteOnchainResponse, MintQuoteBolt11Response,
MintQuoteOnchainResponse,
};
use crate::error::FfiError;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
pub enum SubscriptionKind {
Bolt11MeltQuote,
Bolt11MintQuote,
Bolt12MintQuote,
Bolt12MeltQuote,
OnchainMintQuote,
OnchainMeltQuote,
ProofState,
}
impl From<SubscriptionKind> for cdk::nuts::nut17::Kind {
fn from(kind: SubscriptionKind) -> Self {
match kind {
SubscriptionKind::Bolt11MeltQuote => cdk::nuts::nut17::Kind::Bolt11MeltQuote,
SubscriptionKind::Bolt11MintQuote => cdk::nuts::nut17::Kind::Bolt11MintQuote,
SubscriptionKind::Bolt12MintQuote => cdk::nuts::nut17::Kind::Bolt12MintQuote,
SubscriptionKind::Bolt12MeltQuote => cdk::nuts::nut17::Kind::Bolt12MeltQuote,
SubscriptionKind::OnchainMintQuote => cdk::nuts::nut17::Kind::OnchainMintQuote,
SubscriptionKind::OnchainMeltQuote => cdk::nuts::nut17::Kind::OnchainMeltQuote,
SubscriptionKind::ProofState => cdk::nuts::nut17::Kind::ProofState,
}
}
}
impl From<cdk::nuts::nut17::Kind> for SubscriptionKind {
fn from(kind: cdk::nuts::nut17::Kind) -> Self {
match kind {
cdk::nuts::nut17::Kind::Bolt11MeltQuote => SubscriptionKind::Bolt11MeltQuote,
cdk::nuts::nut17::Kind::Bolt11MintQuote => SubscriptionKind::Bolt11MintQuote,
cdk::nuts::nut17::Kind::Bolt12MintQuote => SubscriptionKind::Bolt12MintQuote,
cdk::nuts::nut17::Kind::Bolt12MeltQuote => SubscriptionKind::Bolt12MeltQuote,
cdk::nuts::nut17::Kind::OnchainMintQuote => SubscriptionKind::OnchainMintQuote,
cdk::nuts::nut17::Kind::OnchainMeltQuote => SubscriptionKind::OnchainMeltQuote,
cdk::nuts::nut17::Kind::Custom(_) => {
panic!("Custom subscription kind not supported in FFI")
}
cdk::nuts::nut17::Kind::ProofState => SubscriptionKind::ProofState,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
pub struct SubscribeParams {
pub kind: SubscriptionKind,
pub filters: Vec<String>,
pub id: Option<String>,
}
impl From<SubscribeParams> for cdk::nuts::nut17::Params<Arc<String>> {
fn from(params: SubscribeParams) -> Self {
let sub_id = params.id.unwrap_or_else(|| {
uuid::Uuid::new_v4().to_string()
});
cdk::nuts::nut17::Params {
kind: params.kind.into(),
filters: params.filters,
id: Arc::new(sub_id),
}
}
}
impl SubscribeParams {
pub fn to_json(&self) -> Result<String, FfiError> {
Ok(serde_json::to_string(self)?)
}
}
#[uniffi::export]
pub fn decode_subscribe_params(json: String) -> Result<SubscribeParams, FfiError> {
Ok(serde_json::from_str(&json)?)
}
#[uniffi::export]
pub fn encode_subscribe_params(params: SubscribeParams) -> Result<String, FfiError> {
Ok(serde_json::to_string(¶ms)?)
}
#[derive(uniffi::Object)]
pub struct ActiveSubscription {
inner: std::sync::Arc<tokio::sync::Mutex<cdk::wallet::subscription::ActiveSubscription>>,
pub sub_id: String,
}
impl ActiveSubscription {
pub(crate) fn new(
inner: cdk::wallet::subscription::ActiveSubscription,
sub_id: String,
) -> Self {
Self {
inner: std::sync::Arc::new(tokio::sync::Mutex::new(inner)),
sub_id,
}
}
}
#[uniffi::export(async_runtime = "tokio")]
impl ActiveSubscription {
pub fn id(&self) -> String {
self.sub_id.clone()
}
pub async fn recv(&self) -> Result<NotificationPayload, FfiError> {
let mut guard = self.inner.lock().await;
guard
.recv()
.await
.ok_or_else(|| FfiError::internal("Subscription closed"))
.map(Into::into)
}
pub async fn try_recv(&self) -> Result<Option<NotificationPayload>, FfiError> {
let mut guard = self.inner.lock().await;
Ok(guard.try_recv().map(Into::into))
}
}
#[derive(Debug, Clone, uniffi::Enum)]
pub enum NotificationPayload {
ProofState { proof_states: Vec<ProofStateUpdate> },
MintQuoteUpdate { quote: MintQuoteBolt11Response },
MeltQuoteUpdate { quote: MeltQuoteBolt11Response },
MintQuoteOnchainUpdate { quote: MintQuoteOnchainResponse },
MeltQuoteOnchainUpdate { quote: MeltQuoteOnchainResponse },
}
impl From<MintEvent<String>> for NotificationPayload {
fn from(payload: MintEvent<String>) -> Self {
match payload.into() {
cdk::nuts::NotificationPayload::ProofState(states) => NotificationPayload::ProofState {
proof_states: vec![states.into()],
},
cdk::nuts::NotificationPayload::MintQuoteBolt11Response(quote_resp) => {
NotificationPayload::MintQuoteUpdate {
quote: quote_resp.into(),
}
}
cdk::nuts::NotificationPayload::MeltQuoteBolt11Response(quote_resp) => {
NotificationPayload::MeltQuoteUpdate {
quote: quote_resp.into(),
}
}
cdk::nuts::NotificationPayload::MintQuoteOnchainResponse(quote_resp) => {
NotificationPayload::MintQuoteOnchainUpdate {
quote: quote_resp.into(),
}
}
cdk::nuts::NotificationPayload::MeltQuoteOnchainResponse(quote_resp) => {
NotificationPayload::MeltQuoteOnchainUpdate {
quote: quote_resp.into(),
}
}
_ => {
NotificationPayload::ProofState {
proof_states: vec![],
}
}
}
}
}