Skip to content

Commit

Permalink
Allow binary-only and text-only websocket connects (#389)
Browse files Browse the repository at this point in the history
This allows the various formats (e.g., CBOR) that can't be converted
in or out of Text to be used in a websocket by specifying you want to
use a binary-only connection.  A text-only connection is provided for
symmetry.
  • Loading branch information
ctm committed Jan 7, 2020
1 parent 5d27094 commit 6bf5cb3
Showing 1 changed file with 89 additions and 13 deletions.
102 changes: 89 additions & 13 deletions src/services/websocket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,58 @@ impl WebSocketService {
where
OUT: From<Text> + From<Binary>,
{
let ws = self.connect_common(url, &notification)?;
ws.add_event_listener(move |event: SocketMessageEvent| {
process_both(&event, &callback);
});
Ok(WebSocketTask { ws, notification })
}

/// Connects to a server by a websocket connection, like connect,
/// but only processes binary frames. Text frames are silently
/// ignored. Needs two functions to generate data and notification
/// messages.
pub fn connect_binary<OUT: 'static>(
&mut self,
url: &str,
callback: Callback<OUT>,
notification: Callback<WebSocketStatus>,
) -> Result<WebSocketTask, &str>
where
OUT: From<Binary>,
{
let ws = self.connect_common(url, &notification)?;
ws.add_event_listener(move |event: SocketMessageEvent| {
did_process_binary(&event, &callback);
});
Ok(WebSocketTask { ws, notification })
}

/// Connects to a server by a websocket connection, like connect,
/// but only processes text frames. Binary frames are silently
/// ignored. Needs two functions to generate data and notification
/// messages.
pub fn connect_text<OUT: 'static>(
&mut self,
url: &str,
callback: Callback<OUT>,
notification: Callback<WebSocketStatus>,
) -> Result<WebSocketTask, &str>
where
OUT: From<Text>,
{
let ws = self.connect_common(url, &notification)?;
ws.add_event_listener(move |event: SocketMessageEvent| {
process_text(&event, &callback);
});
Ok(WebSocketTask { ws, notification })
}

fn connect_common(
&mut self,
url: &str,
notification: &Callback<WebSocketStatus>,
) -> Result<WebSocket, &str> {
let ws = WebSocket::new(url);
if ws.is_err() {
return Err("Failed to created websocket with given URL");
Expand All @@ -73,19 +125,43 @@ impl WebSocketService {
ws.add_event_listener(move |_: SocketErrorEvent| {
notify.emit(WebSocketStatus::Error);
});
ws.add_event_listener(move |event: SocketMessageEvent| {
if let Some(bytes) = event.data().into_array_buffer() {
let bytes: Vec<u8> = bytes.into();
let data = Ok(bytes);
let out = OUT::from(data);
callback.emit(out);
} else if let Some(text) = event.data().into_text() {
let data = Ok(text);
let out = OUT::from(data);
callback.emit(out);
}
});
Ok(WebSocketTask { ws, notification })
Ok(ws)
}
}

fn did_process_binary<OUT: 'static>(event: &SocketMessageEvent, callback: &Callback<OUT>) -> bool
where
OUT: From<Binary>,
{
match event.data().into_array_buffer() {
None => false,
Some(bytes) => {
let bytes: Vec<u8> = bytes.into();
let data = Ok(bytes);
let out = OUT::from(data);
callback.emit(out);
true
}
}
}

fn process_text<OUT: 'static>(event: &SocketMessageEvent, callback: &Callback<OUT>)
where
OUT: From<Text>,
{
if let Some(text) = event.data().into_text() {
let data = Ok(text);
let out = OUT::from(data);
callback.emit(out);
}
}

fn process_both<OUT: 'static>(event: &SocketMessageEvent, callback: &Callback<OUT>)
where
OUT: From<Text> + From<Binary>,
{
if !did_process_binary(event, callback) {
process_text(event, callback);
}
}

Expand Down

0 comments on commit 6bf5cb3

Please sign in to comment.