1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! # Rust-engineio-client
//!
//! An implementation of a engine.io client written in the rust programming language. This implementation currently
//! supports revision 4 of the engine.io protocol. If you have any connection issues with this client,
//! make sure the server uses at least revision 4 of the engine.io protocol.
//!
//! ## Example usage
//!
//! ``` rust
//! use rust_engineio::{ClientBuilder, Client, packet::{Packet, PacketId}};
//! use url::Url;
//! use bytes::Bytes;
//!
//! // get a client with an `on_open` callback
//! let client: Client = ClientBuilder::new(Url::parse("http://localhost:4201").unwrap())
//!      .on_open(|_| println!("Connection opened!"))
//!      .build()
//!      .expect("Creating client failed");
//!
//! // connect to the server
//! client.connect().expect("Connection failed");
//!
//! // create a packet, in this case a message packet and emit it
//! let packet = Packet::new(PacketId::Message, Bytes::from_static(b"Hello World"));
//! client.emit(packet).expect("Server unreachable");
//!
//! // disconnect from the server
//! client.disconnect().expect("Disconnect failed")
//! ```
//!
//! The main entry point for using this crate is the [`ClientBuilder`] which provides
//! the opportunity to define how you want to connect to a certain endpoint.
//! The following connection methods are available:
//! * `build`: Build websocket if allowed, if not fall back to polling. Standard configuration.
//! * `build_polling`: enforces a `polling` transport.
//! * `build_websocket_with_upgrade`: Build socket with a polling transport then upgrade to websocket transport (if possible).
//! * `build_websocket`: Build socket with only a websocket transport, crashes when websockets are not allowed.
//!
//!
//! ## Current features
//!
//! This implementation now supports all of the features of the engine.io protocol mentioned [here](https://github.com/socketio/engine.io-protocol).
//! This includes various transport options, the possibility of sending engine.io packets and registering the
//! commmon engine.io event callbacks:
//! * on_open
//! * on_close
//! * on_data
//! * on_error
//! * on_packet
//!
//! It is also possible to pass in custom tls configurations via the `TlsConnector` as well
//! as custom headers for the opening request.
//!
#![allow(clippy::rc_buffer)]
#![warn(clippy::complexity)]
#![warn(clippy::style)]
#![warn(clippy::perf)]
#![warn(clippy::correctness)]
/// A small macro that spawns a scoped thread. Used for calling the callback
/// functions.
macro_rules! spawn_scoped {
    ($e:expr) => {
        crossbeam_utils::thread::scope(|s| {
            s.spawn(|_| $e);
        })
        .unwrap();
    };
}
mod callback;
pub mod client;
/// Generic header map
pub mod header;
pub mod packet;
pub(self) mod socket;
pub mod transport;
pub mod transports;

pub const ENGINE_IO_VERSION: i32 = 4;

/// Contains the error type which will be returned with every result in this
/// crate. Handles all kinds of errors.
pub mod error;

pub use client::{Client, ClientBuilder};
pub use error::Error;
pub use packet::{Packet, PacketId};

#[cfg(test)]
pub(crate) mod test {
    use super::*;
    use native_tls::TlsConnector;
    const CERT_PATH: &str = "../ci/cert/ca.crt";
    use native_tls::Certificate;
    use std::fs::File;
    use std::io::Read;

    pub(crate) fn tls_connector() -> error::Result<TlsConnector> {
        let cert_path = std::env::var("CA_CERT_PATH").unwrap_or_else(|_| CERT_PATH.to_owned());
        let mut cert_file = File::open(cert_path)?;
        let mut buf = vec![];
        cert_file.read_to_end(&mut buf)?;
        let cert: Certificate = Certificate::from_pem(&buf[..]).unwrap();
        Ok(TlsConnector::builder()
            // ONLY USE FOR TESTING!
            .danger_accept_invalid_hostnames(true)
            .add_root_certificate(cert)
            .build()
            .unwrap())
    }
    /// The `engine.io` server for testing runs on port 4201
    const SERVER_URL: &str = "http://localhost:4201";
    /// The `engine.io` server that refuses upgrades runs on port 4203
    const SERVER_POLLING_URL: &str = "http://localhost:4203";
    const SERVER_URL_SECURE: &str = "https://localhost:4202";
    use url::Url;

    pub(crate) fn engine_io_server() -> crate::error::Result<Url> {
        let url = std::env::var("ENGINE_IO_SERVER").unwrap_or_else(|_| SERVER_URL.to_owned());
        Ok(Url::parse(&url)?)
    }

    pub(crate) fn engine_io_polling_server() -> crate::error::Result<Url> {
        let url = std::env::var("ENGINE_IO_POLLING_SERVER")
            .unwrap_or_else(|_| SERVER_POLLING_URL.to_owned());
        Ok(Url::parse(&url)?)
    }

    pub(crate) fn engine_io_server_secure() -> crate::error::Result<Url> {
        let url = std::env::var("ENGINE_IO_SECURE_SERVER")
            .unwrap_or_else(|_| SERVER_URL_SECURE.to_owned());
        Ok(Url::parse(&url)?)
    }
}