pub struct ClientBuilder<'u> { /* private fields */ }
Expand description

Build clients with a builder-style API This makes it easy to create and configure a websocket connection:

The easiest way to connect is like this:

use websocket::ClientBuilder;

let client = ClientBuilder::new("ws://myapp.com")
    .unwrap()
    .connect_insecure()
    .unwrap();

But there are so many more possibilities:

use websocket::ClientBuilder;
use websocket::header::{Headers, Cookie};

let default_protos = vec!["ping", "chat"];
let mut my_headers = Headers::new();
my_headers.set(Cookie(vec!["userid=1".to_owned()]));

let mut builder = ClientBuilder::new("ws://myapp.com/room/discussion")
    .unwrap()
    .add_protocols(default_protos) // any IntoIterator
    .add_protocol("video-chat")
    .custom_headers(&my_headers);

// connect to a chat server with a user
let client = builder.connect_insecure().unwrap();

// clone the builder and take it with you
let not_logged_in = builder
    .clone()
    .clear_header::<Cookie>()
    .connect_insecure().unwrap();

You may have noticed we’re not using SSL, have no fear, SSL is included! This crate’s openssl dependency is optional (and included by default). One can use connect_secure to connect to an SSL service, or simply connect to choose either SSL or not based on the protocol (ws:// or wss://).

Implementations§

source§

impl<'u> ClientBuilder<'u>

source

pub fn from_url(address: &'u Url) -> Self

Create a client builder from an already parsed Url, because there is no need to parse this will never error.

use websocket::url::Url;

// the parsing error will be handled outside the constructor
let url = Url::parse("ws://bitcoins.pizza").unwrap();

let builder = ClientBuilder::from_url(&url);

The path of a URL is optional if no port is given then port 80 will be used in the case of ws:// and port 443 will be used in the case of wss://.

source

pub fn new(address: &str) -> Result<Self, ParseError>

Create a client builder from a URL string, this will attempt to parse the URL immediately and return a ParseError if the URL is invalid. URLs must be of the form: [ws or wss]://[domain]:[port]/[path] The path of a URL is optional if no port is given then port 80 will be used in the case of ws:// and port 443 will be used in the case of wss://.

let builder = ClientBuilder::new("wss://mycluster.club");
source

pub fn add_protocol<P>(self, protocol: P) -> Self
where P: Into<String>,

Adds a user-defined protocol to the handshake, the server will be given a list of these protocols and will send back the ones it accepts.

let builder = ClientBuilder::new("wss://my-twitch-clone.rs").unwrap()
    .add_protocol("my-chat-proto");

let protos = &builder.get_header::<WebSocketProtocol>().unwrap().0;
assert!(protos.contains(&"my-chat-proto".to_string()));
source

pub fn add_protocols<I, S>(self, protocols: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Adds a user-defined protocols to the handshake. This can take many kinds of iterators.

let builder = ClientBuilder::new("wss://my-twitch-clone.rs").unwrap()
    .add_protocols(vec!["pubsub", "sub.events"]);

let protos = &builder.get_header::<WebSocketProtocol>().unwrap().0;
assert!(protos.contains(&"pubsub".to_string()));
assert!(protos.contains(&"sub.events".to_string()));
source

pub fn clear_protocols(self) -> Self

Removes all the currently set protocols.

source

pub fn add_extension(self, extension: Extension) -> Self

Adds an extension to the connection. Unlike protocols, extensions can be below the application level (like compression). Currently no extensions are supported out-of-the-box but one can still use them by using their own implementation. Support is coming soon though.

let builder = ClientBuilder::new("wss://skype-for-linux-lol.com").unwrap()
    .add_extension(Extension {
        name: "permessage-deflate".to_string(),
        params: vec![],
    });

let exts = &builder.get_header::<WebSocketExtensions>().unwrap().0;
assert!(exts.first().unwrap().name == "permessage-deflate");
source

pub fn add_extensions<I>(self, extensions: I) -> Self
where I: IntoIterator<Item = Extension>,

Adds some extensions to the connection. Currently no extensions are supported out-of-the-box but one can still use them by using their own implementation. Support is coming soon though.

let builder = ClientBuilder::new("wss://moxie-chat.org").unwrap()
    .add_extensions(vec![
        Extension {
            name: "permessage-deflate".to_string(),
            params: vec![],
        },
        Extension {
            name: "crypt-omemo".to_string(),
            params: vec![],
        },
    ]);
source

pub fn clear_extensions(self) -> Self

Remove all the extensions added to the builder.

source

pub fn max_dataframe_size(self, value: usize) -> Self

Set maximum dataframe size. Client will abort connection with error if it is exceed. Values larger than u32::MAX are not supported.

source

pub fn max_message_size(self, value: usize) -> Self

Set maximum message size for which no more continuation dataframes are accepted. Client will abort connection with error if it is exceed. Values larger than u32::MAX are not supported.

source

pub fn key(self, key: [u8; 16]) -> Self

Add a custom Sec-WebSocket-Key header. Use this only if you know what you’re doing, and this almost never has to be used.

source

pub fn clear_key(self) -> Self

Remove the currently set Sec-WebSocket-Key header if any.

source

pub fn version(self, version: WebSocketVersion) -> Self

Set the version of the Websocket connection. Currently this library only supports version 13 (from RFC6455), but one could use this library to create the handshake then use an implementation of another websocket version.

source

pub fn clear_version(self) -> Self

Unset the websocket version to be the default (WebSocket 13).

source

pub fn origin(self, origin: String) -> Self

Sets the Origin header of the handshake. Normally in browsers this is used to protect against unauthorized cross-origin use of a WebSocket server, but it is rarely send by non-browser clients. Still, it can be useful.

source

pub fn clear_origin(self) -> Self

Remove the Origin header from the handshake.

source

pub fn custom_headers(self, custom_headers: &Headers) -> Self

This is a catch all to add random headers to your handshake, the process here is more manual.

let mut headers = Headers::new();
headers.set(Authorization("let me in".to_owned()));

let builder = ClientBuilder::new("ws://moz.illest").unwrap()
    .custom_headers(&headers);
source

pub fn clear_header<H>(self) -> Self
where H: Header + HeaderFormat,

Remove a type of header from the handshake, this is to be used with the catch all custom_headers.

source

pub fn get_header<H>(&self) -> Option<&H>
where H: Header + HeaderFormat,

Get a header to inspect it.

source

pub fn connect( &mut self, ssl_config: Option<TlsConnector> ) -> WebSocketResult<Client<Box<dyn NetworkStream + Send>>>

Connect to a server (finally)! This will use a Box<NetworkStream> to represent either an SSL connection or a normal TCP connection, what to use will be decided using the protocol of the URL passed in (e.g. ws:// or wss://)

If you have non-default SSL circumstances, you can use the ssl_config parameter to configure those.

let mut client = ClientBuilder::new("wss://supersecret.l33t").unwrap()
    .connect(None)
    .unwrap();

// send messages!
let message = Message::text("m337 47 7pm");
client.send_message(&message).unwrap();
source

pub fn connect_insecure(&mut self) -> WebSocketResult<Client<TcpStream>>

Create an insecure (plain TCP) connection to the client. In this case no Box will be used, you will just get a TcpStream, giving you the ability to split the stream into a reader and writer (since SSL streams cannot be cloned).

let mut client = ClientBuilder::new("wss://supersecret.l33t").unwrap()
    .connect_insecure()
    .unwrap();

// split into two (for some reason)!
let (receiver, sender) = client.split().unwrap();
source

pub fn connect_secure( &mut self, ssl_config: Option<TlsConnector> ) -> WebSocketResult<Client<TlsStream<TcpStream>>>

Create an SSL connection to the sever. This will only use an TlsStream, this is useful when you want to be sure to connect over SSL or when you want access to the TlsStream functions (without having to go through a Box).

source

pub fn connect_on<S>(&mut self, stream: S) -> WebSocketResult<Client<S>>
where S: Stream,

Connects to a websocket server on any stream you would like. Possible streams:

  • Unix Sockets
  • Logging Middle-ware
  • SSH
use websocket::sync::stream::ReadWritePair;
use std::io::Cursor;

let accept = b"HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r
\r\n";

let input = Cursor::new(&accept[..]);
let output = Cursor::new(Vec::new());

let client = ClientBuilder::new("wss://test.ws").unwrap()
    .key(b"the sample nonce".clone())
    .connect_on(ReadWritePair(input, output))
    .unwrap();

let text = (client.into_stream().0).1.into_inner();
let text = String::from_utf8(text).unwrap();
assert!(text.contains("dGhlIHNhbXBsZSBub25jZQ=="), "{}", text);
source

pub fn async_connect( self, ssl_config: Option<TlsConnector> ) -> ClientNew<Box<dyn Stream + Send>>

Connect to a websocket server asynchronously.

This will use a Box<AsyncRead + AsyncWrite + Send> to represent either an SSL connection or a normal TCP connection, what to use will be decided using the protocol of the URL passed in (e.g. ws:// or wss://)

If you have non-default SSL circumstances, you can use the ssl_config parameter to configure those.

Note that if URL contains a hostname (like in the example below), it uses only one of the resolved IP addresses, without “happy eyeballs”. This may lead to failures to connect to e.g. ws://localhost.

§Example
use websocket::ClientBuilder;
use websocket::futures::{Future, Stream, Sink};
use websocket::Message;
use tokio::runtime::Builder;

let mut runtime = Builder::new().build().unwrap();

// let's randomly do either SSL or plaintext
let url = if rand::thread_rng().gen() {
    "ws://echo.websocket.org"
} else {
    "wss://echo.websocket.org"
};

// send a message and hear it come back
let echo_future = ClientBuilder::new(url).unwrap()
    .async_connect(None)
    .and_then(|(s, _)| s.send(Message::text("hallo").into()))
    .and_then(|s| s.into_future().map_err(|e| e.0))
    .map(|(m, _)| {
        assert_eq!(m, Some(Message::text("hallo").into()))
    });

runtime.block_on(echo_future).unwrap();
source

pub fn async_connect_with_cb( self, ssl_config: Option<TlsConnector>, cb: impl FnOnce(SocketAddrs) -> Box<dyn Future<Item = TcpStreamNew, Error = WebSocketError> + Send> ) -> ClientNew<Box<dyn Stream + Send>>

Similar to [async_connect], but allowing to hook into getting tokio::TcpStream from an iterator of SocketAddrs, to allow implenting “happy eyeballs”.

source

pub fn async_connect_secure( self, ssl_config: Option<TlsConnector> ) -> ClientNew<TlsStream<TcpStream>>

Asynchronously create an SSL connection to a websocket sever.

This method will only try to connect over SSL and fail otherwise, useful when you want to be sure to connect over SSL or when you want access to the TlsStream functions (without having to go through a Box).

If you have non-default SSL circumstances, you can use the ssl_config parameter to configure those.

§Example
use websocket::ClientBuilder;
use websocket::futures::{Future, Stream, Sink};
use websocket::Message;

let mut runtime = tokio::runtime::Builder::new().build().unwrap();

// send a message and hear it come back
let echo_future = ClientBuilder::new("wss://echo.websocket.org").unwrap()
    .async_connect_secure(None)
    .and_then(|(s, _)| s.send(Message::text("hallo").into()))
    .and_then(|s| s.into_future().map_err(|e| e.0))
    .map(|(m, _)| {
        assert_eq!(m, Some(Message::text("hallo").into()))
    });

runtime.block_on(echo_future).unwrap();
source

pub fn async_connect_insecure(self) -> ClientNew<TcpStream>

Asynchronously create an insecure (plain TCP) connection to the client.

In this case no Box will be used, you will just get a TcpStream, giving you less allocations on the heap and direct access to TcpStream functions.

§Example
use websocket::ClientBuilder;
use websocket::futures::{Future, Stream, Sink};
use websocket::Message;

let mut runtime = tokio::runtime::Builder::new().build().unwrap();

// send a message and hear it come back
let echo_future = ClientBuilder::new("ws://echo.websocket.org").unwrap()
    .async_connect_insecure()
    .and_then(|(s, _)| s.send(Message::text("hallo").into()))
    .and_then(|s| s.into_future().map_err(|e| e.0))
    .map(|(m, _)| {
        assert_eq!(m, Some(Message::text("hallo").into()))
    });

runtime.block_on(echo_future).unwrap();
source

pub fn async_connect_on<S>(self, stream: S) -> ClientNew<S>
where S: Stream + Send + 'static,

Asynchronously connects to a websocket server on any stream you would like. Possible streams:

  • Unix Sockets
  • Bluetooth
  • Logging Middle-ware
  • SSH

The stream must be AsyncRead + AsyncWrite + Send + 'static.

§Example
use websocket::header::WebSocketProtocol;
use websocket::ClientBuilder;
use websocket::sync::stream::ReadWritePair;
use websocket::futures::Future;

let mut runtime = tokio::runtime::Builder::new().build().unwrap();

let accept = b"\
HTTP/1.1 101 Switching Protocols\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Protocol: proto-metheus\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\
\r\n";

let input = Cursor::new(&accept[..]);
let output = Cursor::new(Vec::new());

let client = ClientBuilder::new("wss://test.ws").unwrap()
    .key(b"the sample nonce".clone())
    .async_connect_on(ReadWritePair(input, output))
    .map(|(_, headers)| {
        let proto: &WebSocketProtocol = headers.get().unwrap();
        assert_eq!(proto.0.first().unwrap(), "proto-metheus")
    });

runtime.block_on(client).unwrap();

Trait Implementations§

source§

impl<'u> Clone for ClientBuilder<'u>

source§

fn clone(&self) -> ClientBuilder<'u>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'u> Debug for ClientBuilder<'u>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'u> Freeze for ClientBuilder<'u>

§

impl<'u> !RefUnwindSafe for ClientBuilder<'u>

§

impl<'u> Send for ClientBuilder<'u>

§

impl<'u> !Sync for ClientBuilder<'u>

§

impl<'u> Unpin for ClientBuilder<'u>

§

impl<'u> !UnwindSafe for ClientBuilder<'u>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> Typeable for T
where T: Any,

source§

fn get_type(&self) -> TypeId

Get the TypeId of this object.