misskey_websocket/client/
builder.rs

1use std::convert::TryInto;
2use std::result::Result as StdResult;
3use std::time::Duration;
4
5use crate::broker::{ReconnectCondition, ReconnectConfig};
6use crate::client::WebSocketClient;
7use crate::error::{Error, Result};
8
9use url::Url;
10
11#[derive(Debug, Clone)]
12struct WebSocketClientBuilderInner {
13    url: Url,
14    reconnect: ReconnectConfig,
15}
16
17/// Builder for [`WebSocketClient`].
18#[derive(Debug, Clone)]
19pub struct WebSocketClientBuilder {
20    inner: Result<WebSocketClientBuilderInner>,
21}
22
23trait ResultExt<T, E> {
24    fn and_then_mut<F>(&mut self, op: F)
25    where
26        F: FnOnce(&mut T) -> StdResult<(), E>;
27}
28
29impl<T, E> ResultExt<T, E> for StdResult<T, E> {
30    fn and_then_mut<F>(&mut self, f: F)
31    where
32        F: FnOnce(&mut T) -> StdResult<(), E>,
33    {
34        if let Ok(x) = self {
35            if let Err(e) = f(x) {
36                *self = Err(e);
37            }
38        }
39    }
40}
41
42impl WebSocketClientBuilder {
43    /// Creates a new builder instance with `url`.
44    ///
45    /// All configurations are set to default.
46    pub fn new<T>(url: T) -> Self
47    where
48        T: TryInto<Url>,
49        T::Error: Into<Error>,
50    {
51        let inner = url
52            .try_into()
53            .map_err(Into::into)
54            .map(|url| WebSocketClientBuilderInner {
55                url,
56                reconnect: ReconnectConfig::default(),
57            });
58
59        WebSocketClientBuilder { inner }
60    }
61
62    /// Creates a new builder instance with the given host name `host`.
63    ///
64    /// This method configures the builder with a URL of the form `wss://{host}/streaming`.
65    /// All other configurations are set to default.
66    pub fn with_host<S>(host: S) -> Self
67    where
68        S: AsRef<str>,
69    {
70        let url = format!("wss://{}/streaming", host.as_ref());
71        WebSocketClientBuilder::new(url.as_str())
72    }
73
74    /// Sets an API token.
75    ///
76    /// This method appends the given token as the `i` query parameter to the URL.
77    pub fn token<S>(&mut self, token: S) -> &mut Self
78    where
79        S: AsRef<str>,
80    {
81        self.query("i", token)
82    }
83
84    /// Specifies additional query parameters for the URL.
85    pub fn query<S1, S2>(&mut self, key: S1, value: S2) -> &mut Self
86    where
87        S1: AsRef<str>,
88        S2: AsRef<str>,
89    {
90        self.inner.and_then_mut(|inner| {
91            inner
92                .url
93                .query_pairs_mut()
94                .append_pair(key.as_ref(), value.as_ref());
95            Ok(())
96        });
97        self
98    }
99
100    /// Sets whether or not to enable automatic reconnection.
101    ///
102    /// Automatic reconnection is enabled by default (as per [`Default`][default] implementation for
103    /// [`ReconnectConfig`]), and you can disable it with `.auto_reconnect(false)`.
104    ///
105    /// [default]: std::default::Default
106    pub fn auto_reconnect(&mut self, enable: bool) -> &mut Self {
107        if enable {
108            self.reconnect_condition(ReconnectCondition::unexpected_reset())
109        } else {
110            self.reconnect_condition(ReconnectCondition::never())
111        }
112    }
113
114    /// Sets an interval duration of automatic reconnection in seconds.
115    pub fn reconnect_secs(&mut self, secs: u64) -> &mut Self {
116        self.inner.and_then_mut(|inner| {
117            inner.reconnect.interval = Duration::from_secs(secs);
118            Ok(())
119        });
120        self
121    }
122
123    /// Sets an interval duration of automatic reconnection.
124    pub fn reconnect_interval(&mut self, interval: Duration) -> &mut Self {
125        self.inner.and_then_mut(|inner| {
126            inner.reconnect.interval = interval;
127            Ok(())
128        });
129        self
130    }
131
132    /// Specifies the condition for reconnecting.
133    pub fn reconnect_condition(&mut self, condition: ReconnectCondition) -> &mut Self {
134        self.inner.and_then_mut(|inner| {
135            inner.reconnect.condition = condition;
136            Ok(())
137        });
138        self
139    }
140
141    /// Specifies whether to re-send messages that may have failed to be sent when reconnecting.
142    pub fn reconnect_retry_send(&mut self, enable: bool) -> &mut Self {
143        self.inner.and_then_mut(|inner| {
144            inner.reconnect.retry_send = enable;
145            Ok(())
146        });
147        self
148    }
149
150    /// Finish this builder instance and connect to Misskey using this configuration.
151    pub async fn connect(&self) -> Result<WebSocketClient> {
152        let WebSocketClientBuilderInner { url, reconnect } = match self.inner.clone() {
153            Err(e) => return Err(e),
154            Ok(inner) => inner,
155        };
156
157        WebSocketClient::connect_with_config(url, reconnect).await
158    }
159}