1#![cfg(native)]
2
3use super::error::SignalError;
36use super::signal::Signal;
37use parking_lot::RwLock;
38use serde::{Deserialize, Serialize, de::DeserializeOwned};
39use std::collections::HashMap;
40use std::fmt;
41use std::marker::PhantomData;
42use std::sync::Arc;
43use tokio::sync::broadcast;
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct SubscriptionEvent<T> {
58 pub subscription_name: String,
60 pub data: T,
62 pub timestamp: u64,
64}
65
66impl<T> SubscriptionEvent<T> {
67 pub fn new(subscription_name: impl Into<String>, data: T) -> Self {
79 use std::time::{SystemTime, UNIX_EPOCH};
80
81 let timestamp = SystemTime::now()
82 .duration_since(UNIX_EPOCH)
83 .unwrap_or_default()
84 .as_millis() as u64;
85
86 Self {
87 subscription_name: subscription_name.into(),
88 data,
89 timestamp,
90 }
91 }
92}
93
94type SubscriptionStream = broadcast::Sender<String>;
98
99pub struct GraphQLSubscriptionBridge {
112 streams: Arc<RwLock<HashMap<String, SubscriptionStream>>>,
113}
114
115impl GraphQLSubscriptionBridge {
116 pub fn new() -> Self {
126 Self {
127 streams: Arc::new(RwLock::new(HashMap::new())),
128 }
129 }
130
131 pub fn get_or_create_stream(&self, subscription_name: &str) -> SubscriptionStream {
142 let mut streams = self.streams.write();
143 streams
144 .entry(subscription_name.to_string())
145 .or_insert_with(|| {
146 let (tx, _) = broadcast::channel(100);
147 tx
148 })
149 .clone()
150 }
151
152 pub async fn subscribe(
165 &self,
166 subscription_name: impl Into<String>,
167 ) -> broadcast::Receiver<String> {
168 let name = subscription_name.into();
169 let stream = self.get_or_create_stream(&name);
170 stream.subscribe()
171 }
172
173 pub async fn publish(
186 &self,
187 subscription_name: impl Into<String>,
188 message: String,
189 ) -> Result<(), SignalError> {
190 let stream = self.get_or_create_stream(&subscription_name.into());
191 stream
192 .send(message)
193 .map_err(|e| SignalError::new(format!("Failed to publish: {}", e)))?;
194 Ok(())
195 }
196
197 pub fn subscription_count(&self) -> usize {
208 self.streams.read().len()
209 }
210
211 pub fn receiver_count(&self, subscription_name: &str) -> usize {
225 self.streams
226 .read()
227 .get(subscription_name)
228 .map(|s| s.receiver_count())
229 .unwrap_or(0)
230 }
231
232 pub async fn connect_signal<T, F, E>(
259 &self,
260 signal: Signal<T>,
261 subscription_name: impl Into<String>,
262 transform: F,
263 ) where
264 T: Send + Sync + 'static,
265 F: Fn(Arc<T>) -> E + Send + Sync + 'static,
266 E: Serialize + Send + Sync + 'static,
267 {
268 let streams = Arc::clone(&self.streams);
269 let subscription_name = subscription_name.into();
270 let transform = Arc::new(transform);
271
272 signal.connect(move |instance| {
273 let streams = Arc::clone(&streams);
274 let subscription_name = subscription_name.clone();
275 let transform = Arc::clone(&transform);
276
277 async move {
278 let event = transform(instance);
279 let json = serde_json::to_string(&event)
280 .map_err(|e| SignalError::new(format!("Serialization error: {}", e)))?;
281
282 let streams_read = streams.read();
283 if let Some(stream) = streams_read.get(&subscription_name)
284 && let Err(e) = stream.send(json)
285 {
286 eprintln!("Failed to send GraphQL subscription event: {}", e);
287 }
288
289 Ok(())
290 }
291 });
292 }
293
294 pub fn remove_stream(&self, subscription_name: &str) {
309 self.streams.write().remove(subscription_name);
310 }
311}
312
313impl Default for GraphQLSubscriptionBridge {
314 fn default() -> Self {
315 Self::new()
316 }
317}
318
319impl Clone for GraphQLSubscriptionBridge {
320 fn clone(&self) -> Self {
321 Self {
322 streams: Arc::clone(&self.streams),
323 }
324 }
325}
326
327impl fmt::Debug for GraphQLSubscriptionBridge {
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 f.debug_struct("GraphQLSubscriptionBridge")
330 .field("subscription_count", &self.subscription_count())
331 .finish()
332 }
333}
334
335pub struct TypedSubscription<T>
348where
349 T: Serialize + DeserializeOwned + Send + Sync + 'static,
350{
351 bridge: GraphQLSubscriptionBridge,
352 subscription_name: String,
353 _phantom: PhantomData<T>,
354}
355
356impl<T> TypedSubscription<T>
357where
358 T: Serialize + DeserializeOwned + Send + Sync + 'static,
359{
360 pub fn new(bridge: GraphQLSubscriptionBridge, subscription_name: impl Into<String>) -> Self {
371 Self {
372 bridge,
373 subscription_name: subscription_name.into(),
374 _phantom: PhantomData,
375 }
376 }
377
378 pub async fn subscribe(&self) -> broadcast::Receiver<String> {
397 self.bridge.subscribe(&self.subscription_name).await
398 }
399
400 pub async fn publish(&self, event: SubscriptionEvent<T>) -> Result<(), SignalError> {
416 let json = serde_json::to_string(&event)
417 .map_err(|e| SignalError::new(format!("Serialization error: {}", e)))?;
418
419 self.bridge.publish(&self.subscription_name, json).await
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
428 struct TestData {
429 id: i32,
430 message: String,
431 }
432
433 #[test]
434 fn test_subscription_event_creation() {
435 let event = SubscriptionEvent::new("test", "data");
436 assert_eq!(event.subscription_name, "test");
437 assert_eq!(event.data, "data");
438 assert!(event.timestamp > 0);
439 }
440
441 #[tokio::test]
442 async fn test_graphql_bridge_subscribe() {
443 let bridge = GraphQLSubscriptionBridge::new();
444 let mut receiver = bridge.subscribe("test").await;
445
446 bridge.publish("test", "message".to_string()).await.unwrap();
447
448 let result = receiver.recv().await.unwrap();
449 assert_eq!(result, "message");
450 }
451
452 #[tokio::test]
453 async fn test_graphql_bridge_multiple_subscribers() {
454 let bridge = GraphQLSubscriptionBridge::new();
455 let mut receiver1 = bridge.subscribe("event").await;
456 let mut receiver2 = bridge.subscribe("event").await;
457
458 assert_eq!(bridge.receiver_count("event"), 2);
459
460 bridge.publish("event", "data".to_string()).await.unwrap();
461
462 let msg1 = receiver1.recv().await.unwrap();
463 let msg2 = receiver2.recv().await.unwrap();
464
465 assert_eq!(msg1, "data");
466 assert_eq!(msg2, "data");
467 }
468
469 #[tokio::test]
470 async fn test_graphql_bridge_connect_signal() {
471 let bridge = GraphQLSubscriptionBridge::new();
472 let mut receiver = bridge.subscribe("user_event").await;
473
474 let signal = Signal::<String>::new(crate::signals::SignalName::custom("test"));
475
476 bridge
477 .connect_signal(signal.clone(), "user_event", |data| {
478 SubscriptionEvent::new("user_event", (*data).clone())
479 })
480 .await;
481
482 signal.send("test data".to_string()).await.unwrap();
483
484 let result = receiver.recv().await.unwrap();
485 let parsed: SubscriptionEvent<String> = serde_json::from_str(&result).unwrap();
486 assert_eq!(parsed.subscription_name, "user_event");
487 assert_eq!(parsed.data, "test data");
488 }
489
490 #[tokio::test]
491 async fn test_graphql_bridge_subscription_count() {
492 let bridge = GraphQLSubscriptionBridge::new();
493 assert_eq!(bridge.subscription_count(), 0);
494
495 bridge.get_or_create_stream("sub1");
496 assert_eq!(bridge.subscription_count(), 1);
497
498 bridge.get_or_create_stream("sub2");
499 assert_eq!(bridge.subscription_count(), 2);
500 }
501
502 #[tokio::test]
503 async fn test_graphql_bridge_remove_stream() {
504 let bridge = GraphQLSubscriptionBridge::new();
505
506 bridge.get_or_create_stream("test");
507 assert_eq!(bridge.subscription_count(), 1);
508
509 bridge.remove_stream("test");
510 assert_eq!(bridge.subscription_count(), 0);
511 }
512
513 #[tokio::test]
514 async fn test_typed_subscription() {
515 let bridge = GraphQLSubscriptionBridge::new();
516 let subscription = TypedSubscription::<TestData>::new(bridge, "typed_test");
517
518 let mut receiver = subscription.subscribe().await;
519
520 let event = SubscriptionEvent::new(
521 "typed_test",
522 TestData {
523 id: 1,
524 message: "Hello".to_string(),
525 },
526 );
527
528 subscription.publish(event.clone()).await.unwrap();
529
530 let result = receiver.recv().await.unwrap();
531 let parsed: SubscriptionEvent<TestData> = serde_json::from_str(&result).unwrap();
532
533 assert_eq!(parsed.subscription_name, "typed_test");
534 assert_eq!(parsed.data, event.data);
535 }
536
537 #[tokio::test]
538 async fn test_graphql_bridge_receiver_count() {
539 let bridge = GraphQLSubscriptionBridge::new();
540
541 let _r1 = bridge.subscribe("test").await;
542 assert_eq!(bridge.receiver_count("test"), 1);
543
544 let _r2 = bridge.subscribe("test").await;
545 assert_eq!(bridge.receiver_count("test"), 2);
546
547 drop(_r1);
548 }
550
551 #[tokio::test]
552 async fn test_graphql_bridge_multiple_subscriptions() {
553 let bridge = GraphQLSubscriptionBridge::new();
554
555 let mut r1 = bridge.subscribe("sub1").await;
556 let mut r2 = bridge.subscribe("sub2").await;
557
558 bridge.publish("sub1", "msg1".to_string()).await.unwrap();
559 bridge.publish("sub2", "msg2".to_string()).await.unwrap();
560
561 let result1 = r1.recv().await.unwrap();
562 let result2 = r2.recv().await.unwrap();
563
564 assert_eq!(result1, "msg1");
565 assert_eq!(result2, "msg2");
566 }
567}