reifydb_remote_proxy/
lib.rs1#![cfg_attr(not(debug_assertions), deny(clippy::disallowed_methods))]
11#![cfg_attr(debug_assertions, warn(clippy::disallowed_methods))]
12#![cfg_attr(not(debug_assertions), deny(warnings))]
13
14use std::fmt;
15
16use reifydb_client::{GrpcClient, GrpcSubscription, RawChangePayload, SubscriptionConfig, WireFormat};
17use tokio::{
18 select,
19 sync::{mpsc, watch},
20};
21
22#[derive(Debug)]
23pub enum RemoteSubscriptionError {
24 Connect(String),
25 Subscribe(String),
26}
27
28impl fmt::Display for RemoteSubscriptionError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Self::Connect(e) => write!(f, "Failed to connect to remote: {}", e),
32 Self::Subscribe(e) => write!(f, "Remote subscribe failed: {}", e),
33 }
34 }
35}
36
37pub struct RemoteSubscription {
38 inner: GrpcSubscription,
39 subscription_id: String,
40}
41
42impl RemoteSubscription {
43 pub fn subscription_id(&self) -> &str {
44 &self.subscription_id
45 }
46}
47
48pub async fn connect_remote(
49 address: &str,
50 body: &str,
51 config: SubscriptionConfig,
52 token: Option<&str>,
53 wire_format: WireFormat,
54) -> Result<RemoteSubscription, RemoteSubscriptionError> {
55 let mut client = GrpcClient::connect(address, wire_format)
56 .await
57 .map_err(|e| RemoteSubscriptionError::Connect(e.to_string()))?;
58 if let Some(t) = token {
59 client.authenticate(t);
60 }
61 let sub =
62 client.subscribe(body, config).await.map_err(|e| RemoteSubscriptionError::Subscribe(e.to_string()))?;
63 let subscription_id = sub.subscription_id().to_string();
64 Ok(RemoteSubscription {
65 inner: sub,
66 subscription_id,
67 })
68}
69
70pub async fn proxy_remote<T, F>(
71 mut remote_sub: RemoteSubscription,
72 sender: mpsc::UnboundedSender<T>,
73 mut shutdown: watch::Receiver<bool>,
74 convert: F,
75) where
76 T: Send + 'static,
77 F: Fn(RawChangePayload) -> T,
78{
79 loop {
80 select! {
81 payload = remote_sub.inner.recv_raw() => {
82 match payload {
83 Some(payload) => {
84 if sender.send(convert(payload)).is_err() {
85 break;
86 }
87 }
88 None => break,
89 }
90 }
91 _ = sender.closed() => break,
92 _ = shutdown.changed() => break,
93 }
94 }
95}
96
97pub async fn proxy_remote_to_sink<F>(
98 mut remote_sub: RemoteSubscription,
99 mut shutdown: watch::Receiver<bool>,
100 mut sink: F,
101) where
102 F: FnMut(RawChangePayload) -> bool + Send + 'static,
103{
104 loop {
105 select! {
106 payload = remote_sub.inner.recv_raw() => {
107 match payload {
108 Some(payload) => {
109 if !sink(payload) {
110 break;
111 }
112 }
113 None => break,
114 }
115 }
116 _ = shutdown.changed() => break,
117 }
118 }
119}