use std::sync::Arc;
#[cfg(feature = "mint")]
use cashu::nut17::ws::JSON_RPC_VERSION;
use cashu::nut17::{self};
#[cfg(feature = "mint")]
use cashu::quote_id::QuoteId;
#[cfg(feature = "mint")]
use cashu::NotificationPayload;
type SubId = Arc<crate::subscription::SubId>;
pub type WsUnsubscribeRequest = nut17::ws::WsUnsubscribeRequest<SubId>;
pub type WsNotification = nut17::ws::WsNotification<SubId>;
pub type WsResponseResult = nut17::ws::WsResponseResult<SubId>;
pub type WsRequest = nut17::ws::WsRequest<SubId>;
pub type WsResponse = nut17::ws::WsResponse<SubId>;
pub type WsMethodRequest = nut17::ws::WsMethodRequest<SubId>;
pub type WsErrorBody = nut17::ws::WsErrorBody;
pub type WsMessageOrResponse = nut17::ws::WsMessageOrResponse<SubId>;
pub type RawNotificationInner = nut17::ws::RawNotificationInner<SubId>;
pub type RawWsMessageOrResponse = nut17::ws::RawWsMessageOrResponse<SubId>;
pub type NotificationInner<T> = nut17::ws::NotificationInner<T, SubId>;
#[cfg(feature = "mint")]
pub fn notification_uuid_to_notification_string(
notification: NotificationInner<QuoteId>,
) -> NotificationInner<String> {
nut17::ws::NotificationInner {
sub_id: notification.sub_id,
payload: match notification.payload {
NotificationPayload::ProofState(pk) => NotificationPayload::ProofState(pk),
NotificationPayload::MeltQuoteBolt11Response(quote) => {
NotificationPayload::MeltQuoteBolt11Response(quote.to_string_id())
}
NotificationPayload::MintQuoteBolt11Response(quote) => {
NotificationPayload::MintQuoteBolt11Response(quote.to_string_id())
}
NotificationPayload::MintQuoteBolt12Response(quote) => {
NotificationPayload::MintQuoteBolt12Response(quote.to_string_id())
}
NotificationPayload::MeltQuoteBolt12Response(quote) => {
NotificationPayload::MeltQuoteBolt12Response(quote.to_string_id())
}
NotificationPayload::CustomMintQuoteResponse(method, quote) => {
NotificationPayload::CustomMintQuoteResponse(method, quote.to_string_id())
}
NotificationPayload::CustomMeltQuoteResponse(method, quote) => {
NotificationPayload::CustomMeltQuoteResponse(method, quote.to_string_id())
}
NotificationPayload::MeltQuoteOnchainResponse(quote) => {
NotificationPayload::MeltQuoteOnchainResponse(quote.to_string_id())
}
NotificationPayload::MintQuoteOnchainResponse(quote) => {
NotificationPayload::MintQuoteOnchainResponse(quote.to_string_id())
}
},
}
}
#[cfg(feature = "mint")]
pub fn notification_to_ws_message(notification: NotificationInner<QuoteId>) -> WsMessageOrResponse {
nut17::ws::WsMessageOrResponse::Notification(Box::new(nut17::ws::WsNotification {
jsonrpc: JSON_RPC_VERSION.to_owned(),
method: "subscribe".to_string(),
params: notification_uuid_to_notification_string(notification),
}))
}
#[cfg(test)]
mod tests {
use cashu::nut17::MAX_SUBSCRIPTION_ID_LEN;
use serde_json::json;
use super::*;
#[test]
fn websocket_requests_reject_oversized_subscription_ids() {
let oversized_id = "a".repeat(MAX_SUBSCRIPTION_ID_LEN + 1);
let subscribe = json!({
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"kind": "bolt11_mint_quote",
"filters": [],
"subId": oversized_id,
},
"id": 1,
});
assert!(serde_json::from_value::<WsRequest>(subscribe).is_err());
let unsubscribe = json!({
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"subId": "a".repeat(MAX_SUBSCRIPTION_ID_LEN + 1),
},
"id": 2,
});
assert!(serde_json::from_value::<WsRequest>(unsubscribe).is_err());
}
}