hawk_ws/
communication.rs

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