mirror of https://github.com/fafhrd91/actix-web
add `WsResponseBuilder` for building ws response
This commit is contained in:
parent
0c8196f8b0
commit
348e758b02
|
@ -29,6 +29,143 @@ use bytestring::ByteString;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use tokio::sync::oneshot::Sender;
|
use tokio::sync::oneshot::Sender;
|
||||||
|
|
||||||
|
/// Builder for Websocket Session response.
|
||||||
|
pub struct WsResponseBuilder<'a, A, T>
|
||||||
|
where
|
||||||
|
A: Actor<Context = WebsocketContext<A>>
|
||||||
|
+ StreamHandler<Result<Message, ProtocolError>>,
|
||||||
|
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
|
{
|
||||||
|
actor: A,
|
||||||
|
req: &'a HttpRequest,
|
||||||
|
stream: T,
|
||||||
|
protocols: Option<&'a [&'a str]>,
|
||||||
|
frame_size: Option<usize>,
|
||||||
|
codec: Option<Codec>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A, T> WsResponseBuilder<'a, A, T>
|
||||||
|
where
|
||||||
|
A: Actor<Context = WebsocketContext<A>>
|
||||||
|
+ StreamHandler<Result<Message, ProtocolError>>,
|
||||||
|
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub fn new(actor: A, req: &'a HttpRequest, stream: T) -> Self {
|
||||||
|
WsResponseBuilder {
|
||||||
|
actor,
|
||||||
|
req,
|
||||||
|
stream,
|
||||||
|
protocols: None,
|
||||||
|
frame_size: None,
|
||||||
|
codec: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn protocols(mut self, protocols: &'a [&'a str]) -> Self {
|
||||||
|
self.protocols = Some(protocols);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn frame_size(mut self, frame_size: usize) -> Self {
|
||||||
|
self.frame_size = Some(frame_size);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn codec(mut self, codec: Codec) -> Self {
|
||||||
|
self.codec = Some(codec);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn handshake_resp(&self) -> Result<HttpResponseBuilder, HandshakeError> {
|
||||||
|
match self.protocols {
|
||||||
|
Some(protocols) => handshake_with_protocols(self.req, protocols),
|
||||||
|
None => handshake(self.req),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_frame_size(&mut self) {
|
||||||
|
if let Some(frame_size) = self.frame_size {
|
||||||
|
match &mut self.codec {
|
||||||
|
// Modify existing Codec's size.
|
||||||
|
Some(codec) => {
|
||||||
|
codec.max_size(frame_size);
|
||||||
|
}
|
||||||
|
// Otherwise, create a new codec with the given size.
|
||||||
|
None => {
|
||||||
|
self.codec = Some(Codec::new().max_size(frame_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Perform WebSocket handshake and start actor.
|
||||||
|
///
|
||||||
|
/// `req` is an [`HttpRequest`] that should be requesting a websocket
|
||||||
|
/// protocol change. `stream` should be a [`Bytes`] stream (such as
|
||||||
|
/// `actix_web::web::Payload`) that contains a stream of the body request.
|
||||||
|
///
|
||||||
|
/// If there is a problem with the handshake, an error is returned.
|
||||||
|
///
|
||||||
|
/// If successful, consume the [`WsResponseBuilder`] and return a
|
||||||
|
/// [`HttpResponse`] wrapped in a [`Result`].
|
||||||
|
pub fn start(mut self) -> Result<HttpResponse, Error> {
|
||||||
|
let mut res = self.handshake_resp()?;
|
||||||
|
self.set_frame_size();
|
||||||
|
|
||||||
|
match self.codec {
|
||||||
|
Some(codec) => {
|
||||||
|
let out_stream =
|
||||||
|
WebsocketContext::with_codec(self.actor, self.stream, codec);
|
||||||
|
Ok(res.streaming(out_stream))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let out_stream = WebsocketContext::create(self.actor, self.stream);
|
||||||
|
Ok(res.streaming(out_stream))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Perform WebSocket handshake and start actor.
|
||||||
|
///
|
||||||
|
/// `req` is an [`HttpRequest`] that should be requesting a websocket
|
||||||
|
/// protocol change. `stream` should be a [`Bytes`] stream (such as
|
||||||
|
/// `actix_web::web::Payload`) that contains a stream of the body request.
|
||||||
|
///
|
||||||
|
/// If there is a problem with the handshake, an error is returned.
|
||||||
|
///
|
||||||
|
/// If successful, returns a pair where the first item is an address for the
|
||||||
|
/// created actor and the second item is the [`HttpResponse`] that should be
|
||||||
|
/// returned from the websocket request.
|
||||||
|
pub fn start_with_addr(mut self) -> Result<(Addr<A>, HttpResponse), Error> {
|
||||||
|
let mut res = self.handshake_resp()?;
|
||||||
|
self.set_frame_size();
|
||||||
|
|
||||||
|
match self.codec {
|
||||||
|
Some(codec) => {
|
||||||
|
let (addr, out_stream) = WebsocketContext::create_with_codec_addr(
|
||||||
|
self.actor,
|
||||||
|
self.stream,
|
||||||
|
codec,
|
||||||
|
);
|
||||||
|
Ok((addr, res.streaming(out_stream)))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let (addr, out_stream) =
|
||||||
|
WebsocketContext::create_with_addr(self.actor, self.stream);
|
||||||
|
Ok((addr, res.streaming(out_stream)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform WebSocket handshake and start actor.
|
/// Perform WebSocket handshake and start actor.
|
||||||
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
|
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
|
||||||
where
|
where
|
||||||
|
@ -279,6 +416,33 @@ where
|
||||||
(addr, WebsocketContextFut::new(ctx, actor, mb, Codec::new()))
|
(addr, WebsocketContextFut::new(ctx, actor, mb, Codec::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Create a new Websocket context from a request, an actor, and a codec.
|
||||||
|
///
|
||||||
|
/// Returns a pair, where the first item is an addr for the created actor,
|
||||||
|
/// and the second item is a stream intended to be set as part of the
|
||||||
|
/// response via `HttpResponseBuilder::streaming()`.
|
||||||
|
pub fn create_with_codec_addr<S>(
|
||||||
|
actor: A,
|
||||||
|
stream: S,
|
||||||
|
codec: Codec,
|
||||||
|
) -> (Addr<A>, impl Stream<Item = Result<Bytes, Error>>)
|
||||||
|
where
|
||||||
|
A: StreamHandler<Result<Message, ProtocolError>>,
|
||||||
|
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
|
{
|
||||||
|
let mb = Mailbox::default();
|
||||||
|
let mut ctx = WebsocketContext {
|
||||||
|
inner: ContextParts::new(mb.sender_producer()),
|
||||||
|
messages: VecDeque::new(),
|
||||||
|
};
|
||||||
|
ctx.add_stream(WsStream::new(stream, codec));
|
||||||
|
|
||||||
|
let addr = ctx.address();
|
||||||
|
|
||||||
|
(addr, WebsocketContextFut::new(ctx, actor, mb, codec))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Create a new Websocket context from a request, an actor, and a codec
|
/// Create a new Websocket context from a request, an actor, and a codec
|
||||||
pub fn with_codec<S>(
|
pub fn with_codec<S>(
|
||||||
|
|
Loading…
Reference in New Issue