summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ws/src/communication.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/ws/src/communication.rs249
1 files changed, 249 insertions, 0 deletions
diff --git a/third_party/rust/ws/src/communication.rs b/third_party/rust/ws/src/communication.rs
new file mode 100644
index 0000000000..2b2822f03c
--- /dev/null
+++ b/third_party/rust/ws/src/communication.rs
@@ -0,0 +1,249 @@
+use std::borrow::Cow;
+use std::convert::Into;
+
+use mio;
+use mio::Token;
+use mio_extras::timer::Timeout;
+use url;
+
+use io::ALL;
+use message;
+use protocol::CloseCode;
+use result::{Error, Result};
+use std::cmp::PartialEq;
+use std::hash::{Hash, Hasher};
+use std::fmt;
+
+#[derive(Debug, Clone)]
+pub enum Signal {
+ Message(message::Message),
+ Close(CloseCode, Cow<'static, str>),
+ Ping(Vec<u8>),
+ Pong(Vec<u8>),
+ Connect(url::Url),
+ Shutdown,
+ Timeout { delay: u64, token: Token },
+ Cancel(Timeout),
+}
+
+#[derive(Debug, Clone)]
+pub struct Command {
+ token: Token,
+ signal: Signal,
+ connection_id: u32,
+}
+
+impl Command {
+ pub fn token(&self) -> Token {
+ self.token
+ }
+
+ pub fn into_signal(self) -> Signal {
+ self.signal
+ }
+
+ pub fn connection_id(&self) -> u32 {
+ self.connection_id
+ }
+}
+
+/// A representation of the output of the WebSocket connection. Use this to send messages to the
+/// other endpoint.
+#[derive(Clone)]
+pub struct Sender {
+ token: Token,
+ channel: mio::channel::SyncSender<Command>,
+ connection_id: u32,
+}
+
+impl fmt::Debug for Sender {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f,
+ "Sender {{ token: {:?}, channel: mio::channel::SyncSender<Command>, connection_id: {:?} }}",
+ self.token, self.connection_id)
+ }
+}
+
+impl PartialEq for Sender {
+ fn eq(&self, other: &Sender) -> bool {
+ self.token == other.token && self.connection_id == other.connection_id
+ }
+}
+
+impl Eq for Sender { }
+
+impl Hash for Sender {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.connection_id.hash(state);
+ self.token.hash(state);
+ }
+}
+
+
+impl Sender {
+ #[doc(hidden)]
+ #[inline]
+ pub fn new(
+ token: Token,
+ channel: mio::channel::SyncSender<Command>,
+ connection_id: u32,
+ ) -> Sender {
+ Sender {
+ token,
+ channel,
+ connection_id,
+ }
+ }
+
+ /// A Token identifying this sender within the WebSocket.
+ #[inline]
+ pub fn token(&self) -> Token {
+ self.token
+ }
+
+ /// A connection_id identifying this sender within the WebSocket.
+ #[inline]
+ pub fn connection_id(&self) -> u32 {
+ self.connection_id
+ }
+
+ /// Send a message over the connection.
+ #[inline]
+ pub fn send<M>(&self, msg: M) -> Result<()>
+ where
+ M: Into<message::Message>,
+ {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Message(msg.into()),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Send a message to the endpoints of all connections.
+ ///
+ /// Be careful with this method. It does not discriminate between client and server connections.
+ /// If your WebSocket is only functioning as a server, then usage is simple, this method will
+ /// send a copy of the message to each connected client. However, if you have a WebSocket that
+ /// is listening for connections and is also connected to another WebSocket, this method will
+ /// broadcast a copy of the message to all the clients connected and to that WebSocket server.
+ #[inline]
+ pub fn broadcast<M>(&self, msg: M) -> Result<()>
+ where
+ M: Into<message::Message>,
+ {
+ self.channel
+ .send(Command {
+ token: ALL,
+ signal: Signal::Message(msg.into()),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Send a close code to the other endpoint.
+ #[inline]
+ pub fn close(&self, code: CloseCode) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Close(code, "".into()),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Send a close code and provide a descriptive reason for closing.
+ #[inline]
+ pub fn close_with_reason<S>(&self, code: CloseCode, reason: S) -> Result<()>
+ where
+ S: Into<Cow<'static, str>>,
+ {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Close(code, reason.into()),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Send a ping to the other endpoint with the given test data.
+ #[inline]
+ pub fn ping(&self, data: Vec<u8>) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Ping(data),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Send a pong to the other endpoint responding with the given test data.
+ #[inline]
+ pub fn pong(&self, data: Vec<u8>) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Pong(data),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Queue a new connection on this WebSocket to the specified URL.
+ #[inline]
+ pub fn connect(&self, url: url::Url) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Connect(url),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Request that all connections terminate and that the WebSocket stop running.
+ #[inline]
+ pub fn shutdown(&self) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Shutdown,
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Schedule a `token` to be sent to the WebSocket Handler's `on_timeout` method
+ /// after `ms` milliseconds
+ #[inline]
+ pub fn timeout(&self, ms: u64, token: Token) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Timeout { delay: ms, token },
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+
+ /// Queue the cancellation of a previously scheduled timeout.
+ ///
+ /// This method is not guaranteed to prevent the timeout from occurring, because it is
+ /// possible to call this method after a timeout has already occurred. It is still necessary to
+ /// handle spurious timeouts.
+ #[inline]
+ pub fn cancel(&self, timeout: Timeout) -> Result<()> {
+ self.channel
+ .send(Command {
+ token: self.token,
+ signal: Signal::Cancel(timeout),
+ connection_id: self.connection_id,
+ })
+ .map_err(Error::from)
+ }
+}