karyon_jsonrpc/client/
subscriptions.rs1use std::{collections::HashMap, sync::Arc};
2
3use async_channel::{Receiver, Sender};
4#[cfg(feature = "quic")]
5use log::debug;
6use serde_json::{from_value, json, Value};
7
8use karyon_core::async_runtime::lock::RwLock;
9
10use crate::{
11 error::{Error, Result},
12 message::{Notification, NotificationResult, SubscriptionID},
13};
14
15pub type NotificationDecoder = fn(Notification) -> Result<NotificationResult>;
18
19pub(super) fn default_notification_decoder(nt: Notification) -> Result<NotificationResult> {
21 match nt.params {
22 Some(p) => Ok(from_value(p)?),
23 None => Err(Error::InvalidMsg("Invalid notification msg".to_string())),
24 }
25}
26
27#[cfg(feature = "quic")]
29pub(super) fn decode_notification(
30 decoder: NotificationDecoder,
31 msg: Value,
32) -> Result<NotificationResult> {
33 let nt: Notification = from_value(msg)?;
34 debug!("<-- {nt}");
35 decoder(nt)
36}
37
38pub struct Subscription {
40 id: SubscriptionID,
41 rx: Receiver<Value>,
42 tx: Sender<Value>,
43}
44
45impl Subscription {
46 fn new(id: SubscriptionID, buffer_size: usize) -> Arc<Self> {
47 let (tx, rx) = async_channel::bounded(buffer_size);
48 Arc::new(Self { tx, id, rx })
49 }
50
51 pub async fn recv(&self) -> Result<Value> {
52 self.rx.recv().await.map_err(|_| Error::SubscriptionClosed)
53 }
54
55 pub fn id(&self) -> SubscriptionID {
56 self.id
57 }
58
59 pub(crate) async fn notify(&self, val: Value) -> Result<()> {
60 if self.tx.is_full() {
61 return Err(Error::SubscriptionBufferFull);
62 }
63 self.tx.send(val).await?;
64 Ok(())
65 }
66
67 fn close(&self) {
68 self.tx.close();
69 }
70}
71
72pub(crate) struct Subscriptions {
74 subs: RwLock<HashMap<SubscriptionID, Arc<Subscription>>>,
75 sub_buffer_size: usize,
76}
77
78impl Subscriptions {
79 pub(super) fn new(sub_buffer_size: usize) -> Arc<Self> {
81 Arc::new(Self {
82 subs: RwLock::new(HashMap::new()),
83 sub_buffer_size,
84 })
85 }
86
87 pub(super) async fn subscribe(&self, id: SubscriptionID) -> Arc<Subscription> {
89 let sub = Subscription::new(id, self.sub_buffer_size);
90 self.subs.write().await.insert(id, sub.clone());
91 sub
92 }
93
94 pub(super) async fn clear(&self) {
96 let mut subs = self.subs.write().await;
97 for sub in subs.values() {
98 sub.close();
99 }
100 subs.clear();
101 }
102
103 pub(super) async fn unsubscribe(&self, id: &SubscriptionID) {
105 if let Some(sub) = self.subs.write().await.remove(id) {
106 sub.close();
107 }
108 }
109
110 pub(super) async fn notify(&self, nt_res: NotificationResult) -> Result<()> {
112 match self.subs.read().await.get(&nt_res.subscription) {
113 Some(s) => s.notify(nt_res.result.unwrap_or(json!(""))).await?,
114 None => {
115 return Err(Error::InvalidMsg("Unknown notification".to_string()));
116 }
117 }
118
119 Ok(())
120 }
121}