razer_ws/
communication.rs

1use std::borrow::Cow;
2use std::convert::Into;
3
4use mio;
5use mio::Token;
6use mio_extras::timer::Timeout;
7use url;
8
9use io::ALL;
10use message;
11use protocol::CloseCode;
12use result::{Error, Result};
13use std::cmp::PartialEq;
14use std::hash::{Hash, Hasher};
15use std::fmt;
16
17#[derive(Debug, Clone)]
18pub enum Signal {
19    Message(message::Message),
20    Close(CloseCode, Cow<'static, str>),
21    Ping(Vec<u8>),
22    Pong(Vec<u8>),
23    Connect(url::Url),
24    Shutdown,
25    Timeout { delay: u64, token: Token },
26    Cancel(Timeout),
27}
28
29#[derive(Debug, Clone)]
30pub struct Command {
31    token: Token,
32    signal: Signal,
33    connection_id: u32,
34}
35
36impl Command {
37    pub fn token(&self) -> Token {
38        self.token
39    }
40
41    pub fn into_signal(self) -> Signal {
42        self.signal
43    }
44
45    pub fn connection_id(&self) -> u32 {
46        self.connection_id
47    }
48}
49
50/// A representation of the output of the WebSocket connection. Use this to send messages to the
51/// other endpoint.
52#[derive(Clone)]
53pub struct Sender {
54    token: Token,
55    channel: mio::channel::SyncSender<Command>,
56    connection_id: u32,
57}
58
59impl fmt::Debug for Sender {
60    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61        write!(f,
62            "Sender {{ token: {:?}, channel: mio::channel::SyncSender<Command>, connection_id: {:?} }}",
63            self.token, self.connection_id)
64    }
65}
66
67impl PartialEq for Sender {
68    fn eq(&self, other: &Sender) -> bool {
69        self.token == other.token && self.connection_id == other.connection_id
70    }
71}
72
73impl Eq for Sender { }
74
75impl Hash for Sender {
76    fn hash<H: Hasher>(&self, state: &mut H) {
77        self.connection_id.hash(state);
78        self.token.hash(state);
79    }
80}
81
82
83impl Sender {
84    #[doc(hidden)]
85    #[inline]
86    pub fn new(
87        token: Token,
88        channel: mio::channel::SyncSender<Command>,
89        connection_id: u32,
90    ) -> Sender {
91        Sender {
92            token,
93            channel,
94            connection_id,
95        }
96    }
97
98    /// A Token identifying this sender within the WebSocket.
99    #[inline]
100    pub fn token(&self) -> Token {
101        self.token
102    }
103
104    /// A connection_id identifying this sender within the WebSocket.
105    #[inline]
106    pub fn connection_id(&self) -> u32 {
107        self.connection_id
108    }
109
110    /// Changes the token
111    #[inline]
112    pub fn change_token(
113        &mut self,
114        token: Token,
115        id: u32
116    ) {
117        self.token = token;
118        self.connection_id = id;
119    }
120
121    /// Send a message over the connection.
122    #[inline]
123    pub fn send<M>(&self, msg: M) -> Result<()>
124    where
125        M: Into<message::Message>,
126    {
127        self.channel
128            .send(Command {
129                token: self.token,
130                signal: Signal::Message(msg.into()),
131                connection_id: self.connection_id,
132            })
133            .map_err(Error::from)
134    }
135
136    /// Send a message to the endpoints of all connections.
137    ///
138    /// Be careful with this method. It does not discriminate between client and server connections.
139    /// If your WebSocket is only functioning as a server, then usage is simple, this method will
140    /// send a copy of the message to each connected client. However, if you have a WebSocket that
141    /// is listening for connections and is also connected to another WebSocket, this method will
142    /// broadcast a copy of the message to all the clients connected and to that WebSocket server.
143    #[inline]
144    pub fn broadcast<M>(&self, msg: M) -> Result<()>
145    where
146        M: Into<message::Message>,
147    {
148        self.channel
149            .send(Command {
150                token: ALL,
151                signal: Signal::Message(msg.into()),
152                connection_id: self.connection_id,
153            })
154            .map_err(Error::from)
155    }
156
157    /// Send a close code to the other endpoint.
158    #[inline]
159    pub fn close(&self, code: CloseCode) -> Result<()> {
160        self.channel
161            .send(Command {
162                token: self.token,
163                signal: Signal::Close(code, "".into()),
164                connection_id: self.connection_id,
165            })
166            .map_err(Error::from)
167    }
168
169    /// Send a close code and provide a descriptive reason for closing.
170    #[inline]
171    pub fn close_with_reason<S>(&self, code: CloseCode, reason: S) -> Result<()>
172    where
173        S: Into<Cow<'static, str>>,
174    {
175        self.channel
176            .send(Command {
177                token: self.token,
178                signal: Signal::Close(code, reason.into()),
179                connection_id: self.connection_id,
180            })
181            .map_err(Error::from)
182    }
183
184    /// Send a ping to the other endpoint with the given test data.
185    #[inline]
186    pub fn ping(&self, data: Vec<u8>) -> Result<()> {
187        self.channel
188            .send(Command {
189                token: self.token,
190                signal: Signal::Ping(data),
191                connection_id: self.connection_id,
192            })
193            .map_err(Error::from)
194    }
195
196    /// Send a pong to the other endpoint responding with the given test data.
197    #[inline]
198    pub fn pong(&self, data: Vec<u8>) -> Result<()> {
199        self.channel
200            .send(Command {
201                token: self.token,
202                signal: Signal::Pong(data),
203                connection_id: self.connection_id,
204            })
205            .map_err(Error::from)
206    }
207
208    /// Queue a new connection on this WebSocket to the specified URL.
209    #[inline]
210    pub fn connect(&self, url: url::Url) -> Result<()> {
211        self.channel
212            .send(Command {
213                token: self.token,
214                signal: Signal::Connect(url),
215                connection_id: self.connection_id,
216            })
217            .map_err(Error::from)
218    }
219
220    /// Request that all connections terminate and that the WebSocket stop running.
221    #[inline]
222    pub fn shutdown(&self) -> Result<()> {
223        self.channel
224            .send(Command {
225                token: self.token,
226                signal: Signal::Shutdown,
227                connection_id: self.connection_id,
228            })
229            .map_err(Error::from)
230    }
231
232    /// Schedule a `token` to be sent to the WebSocket Handler's `on_timeout` method
233    /// after `ms` milliseconds
234    #[inline]
235    pub fn timeout(&self, ms: u64, token: Token) -> Result<()> {
236        self.channel
237            .send(Command {
238                token: self.token,
239                signal: Signal::Timeout { delay: ms, token },
240                connection_id: self.connection_id,
241            })
242            .map_err(Error::from)
243    }
244
245    /// Queue the cancellation of a previously scheduled timeout.
246    ///
247    /// This method is not guaranteed to prevent the timeout from occurring, because it is
248    /// possible to call this method after a timeout has already occurred. It is still necessary to
249    /// handle spurious timeouts.
250    #[inline]
251    pub fn cancel(&self, timeout: Timeout) -> Result<()> {
252        self.channel
253            .send(Command {
254                token: self.token,
255                signal: Signal::Cancel(timeout),
256                connection_id: self.connection_id,
257            })
258            .map_err(Error::from)
259    }
260}