#![cfg_attr(finchers_inject_extern_prelude, feature(extern_prelude))]
#![doc(html_root_url = "https://docs.rs/finchers-tungstenite/0.2.0")]
#![warn(
missing_docs,
missing_debug_implementations,
nonstandard_style,
rust_2018_idioms,
unused,
)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, doc(test(attr(deny(warnings)))))]
extern crate base64;
#[macro_use]
extern crate failure;
extern crate finchers;
extern crate futures;
extern crate http;
extern crate sha1;
extern crate tokio_tungstenite;
pub extern crate tungstenite;
mod handshake;
pub use self::handshake::{HandshakeError, HandshakeErrorKind};
pub use self::imp::{ws, Ws, WsEndpoint, WsTransport};
#[doc(no_inline)]
pub use tungstenite::error::Error as WsError;
#[doc(no_inline)]
pub use tungstenite::protocol::{Message, WebSocketConfig};
mod imp {
use finchers;
use finchers::endpoint::{ApplyContext, ApplyResult, Endpoint};
use finchers::endpoints::upgrade::{Builder, UpgradedIo};
use finchers::output::Output;
use tungstenite::protocol::{Role, WebSocketConfig};
use futures::{Async, Future, Poll};
use http::header;
use tokio_tungstenite::WebSocketStream;
use handshake::{handshake, Accept};
#[allow(missing_docs)]
pub type WsTransport = WebSocketStream<UpgradedIo>;
pub fn ws() -> WsEndpoint {
(WsEndpoint { _priv: () }).with_output::<(Ws,)>()
}
#[derive(Debug, Copy, Clone)]
pub struct WsEndpoint {
_priv: (),
}
impl<'a> Endpoint<'a> for WsEndpoint {
type Output = (Ws,);
type Future = WsFuture;
fn apply(&'a self, _: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
Ok(WsFuture { _priv: () })
}
}
#[derive(Debug)]
pub struct WsFuture {
_priv: (),
}
impl Future for WsFuture {
type Item = (Ws,);
type Error = finchers::error::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let accept = finchers::endpoint::with_get_cx(|cx| handshake(cx))?;
Ok(Async::Ready((Ws {
builder: Builder::new(),
accept,
config: None,
},)))
}
}
#[derive(Debug)]
pub struct Ws {
builder: Builder,
accept: Accept,
config: Option<WebSocketConfig>,
}
impl Ws {
pub fn config(self, config: WebSocketConfig) -> Ws {
Ws {
config: Some(config),
..self
}
}
pub fn on_upgrade<F, R>(self, upgrade: F) -> impl Output
where
F: FnOnce(WsTransport) -> R + Send + 'static,
R: Future<Item = (), Error = ()> + Send + 'static,
{
let Self {
builder,
accept,
config,
} = self;
builder
.header(header::CONNECTION, "upgrade")
.header(header::UPGRADE, "websocket")
.header(header::SEC_WEBSOCKET_ACCEPT, &*accept.hash)
.finish(move |upgraded| {
let ws_stream =
WebSocketStream::from_raw_socket(upgraded, Role::Server, config);
upgrade(ws_stream)
})
}
}
}