1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-26 11:31:09 +00:00

refactor http actor handling

This commit is contained in:
Nikolay Kim 2017-11-29 10:31:24 -08:00
parent 6177d86d97
commit 6f833798c7
11 changed files with 131 additions and 211 deletions

View file

@ -80,35 +80,10 @@ impl Actor for MyWebSocket {
type Context = HttpContext<Self>; type Context = HttpContext<Self>;
} }
/// Http route handler
impl Route for MyWebSocket {
type State = ();
fn request(mut req: HttpRequest, mut ctx: HttpContext<Self>) -> Result<Reply>
{
// websocket handshake
let resp = ws::handshake(&req)?;
// send HttpResponse back to peer
ctx.start(resp);
// convert bytes stream to a stream of `ws::Message` and handle stream
ctx.add_stream(ws::WsStream::new(&mut req));
ctx.reply(MyWebSocket)
}
}
/// Standard actix's stream handler for a stream of `ws::Message` /// Standard actix's stream handler for a stream of `ws::Message`
impl StreamHandler<ws::Message> for MyWebSocket { impl StreamHandler<ws::Message> for MyWebSocket {}
fn started(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session openned");
}
fn finished(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session closed");
}
}
impl Handler<ws::Message> for MyWebSocket { impl Handler<ws::Message> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>) fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context)
-> Response<Self, ws::Message> -> Response<Self, ws::Message>
{ {
// process websocket messages // process websocket messages
@ -136,7 +111,7 @@ fn main() {
// enable logger // enable logger
.middleware(middlewares::Logger::default()) .middleware(middlewares::Logger::default())
// websocket route // websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>()) .resource("/ws/", |r| r.get(|req| ws::start(req, MyWebSocket)))
.route_handler("/", StaticFiles::new("examples/static/", true))) .route_handler("/", StaticFiles::new("examples/static/", true)))
.serve::<_, ()>("127.0.0.1:8080").unwrap(); .serve::<_, ()>("127.0.0.1:8080").unwrap();

View file

@ -19,6 +19,7 @@ struct AppState {
fn index(req: HttpRequest<AppState>) -> HttpResponse { fn index(req: HttpRequest<AppState>) -> HttpResponse {
println!("{:?}", req); println!("{:?}", req);
req.state().counter.set(req.state().counter.get() + 1); req.state().counter.set(req.state().counter.get() + 1);
httpcodes::HTTPOk.with_body( httpcodes::HTTPOk.with_body(
format!("Num of requests: {}", req.state().counter.get())) format!("Num of requests: {}", req.state().counter.get()))
} }
@ -30,25 +31,12 @@ struct MyWebSocket {
} }
impl Actor for MyWebSocket { impl Actor for MyWebSocket {
type Context = HttpContext<Self>; type Context = HttpContext<Self, AppState>;
}
impl Route for MyWebSocket {
/// Shared application state
type State = AppState;
fn request(mut req: HttpRequest<AppState>, mut ctx: HttpContext<Self>) -> Result<Reply>
{
let resp = ws::handshake(&req)?;
ctx.start(resp);
ctx.add_stream(ws::WsStream::new(&mut req));
ctx.reply(MyWebSocket{counter: 0})
}
} }
impl StreamHandler<ws::Message> for MyWebSocket {} impl StreamHandler<ws::Message> for MyWebSocket {}
impl Handler<ws::Message> for MyWebSocket { impl Handler<ws::Message> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>) fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context)
-> Response<Self, ws::Message> -> Response<Self, ws::Message>
{ {
self.counter += 1; self.counter += 1;
@ -76,7 +64,7 @@ fn main() {
// enable logger // enable logger
.middleware(middlewares::Logger::default()) .middleware(middlewares::Logger::default())
// websocket route // websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>()) .resource("/ws/", |r| r.get(|r| ws::start(r, MyWebSocket{counter: 0})))
// register simple handler, handle all methods // register simple handler, handle all methods
.handler("/", index)) .handler("/", index))
.serve::<_, ()>("127.0.0.1:8080").unwrap(); .serve::<_, ()>("127.0.0.1:8080").unwrap();

View file

@ -12,28 +12,19 @@ use actix::*;
use actix_web::*; use actix_web::*;
/// do websocket handshake and start `MyWebSocket` actor
fn ws_index(r: HttpRequest) -> Reply {
ws::start(r, MyWebSocket).into()
}
/// websocket connection is long running connection, it easier
/// to handle with an actor
struct MyWebSocket; struct MyWebSocket;
impl Actor for MyWebSocket { impl Actor for MyWebSocket {
type Context = HttpContext<Self>; type Context = HttpContext<Self>;
} }
/// Http route handler
impl Route for MyWebSocket {
type State = ();
fn request(mut req: HttpRequest, mut ctx: HttpContext<Self>) -> Result<Reply>
{
// websocket handshake
let resp = ws::handshake(&req)?;
// send HttpResponse back to peer
ctx.start(resp);
// convert bytes stream to a stream of `ws::Message` and register it
ctx.add_stream(ws::WsStream::new(&mut req));
ctx.reply(MyWebSocket)
}
}
/// Standard actix's stream handler for a stream of `ws::Message` /// Standard actix's stream handler for a stream of `ws::Message`
impl StreamHandler<ws::Message> for MyWebSocket { impl StreamHandler<ws::Message> for MyWebSocket {
fn started(&mut self, ctx: &mut Self::Context) { fn started(&mut self, ctx: &mut Self::Context) {
@ -74,7 +65,7 @@ fn main() {
// enable logger // enable logger
.middleware(middlewares::Logger::default()) .middleware(middlewares::Logger::default())
// websocket route // websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>()) .resource("/ws/", |r| r.get(ws_index))
.route_handler("/", StaticFiles::new("examples/static/", true))) .route_handler("/", StaticFiles::new("examples/static/", true)))
// start http server on 127.0.0.1:8080 // start http server on 127.0.0.1:8080
.serve::<_, ()>("127.0.0.1:8080").unwrap(); .serve::<_, ()>("127.0.0.1:8080").unwrap();

View file

@ -132,23 +132,10 @@ impl<S> ApplicationBuilder<S> where S: 'static {
/// use actix::*; /// use actix::*;
/// use actix_web::*; /// use actix_web::*;
/// ///
/// struct MyRoute;
///
/// impl Actor for MyRoute {
/// type Context = HttpContext<Self>;
/// }
///
/// impl Route for MyRoute {
/// type State = ();
///
/// fn request(req: HttpRequest, ctx: HttpContext<Self>) -> Result<Reply> {
/// Reply::reply(httpcodes::HTTPOk)
/// }
/// }
/// fn main() { /// fn main() {
/// let app = Application::default("/") /// let app = Application::default("/")
/// .resource("/test", |r| { /// .resource("/test", |r| {
/// r.get::<MyRoute>(); /// r.get(|req| httpcodes::HTTPOk);
/// r.handler(Method::HEAD, |req| httpcodes::HTTPMethodNotAllowed); /// r.handler(Method::HEAD, |req| httpcodes::HTTPMethodNotAllowed);
/// }) /// })
/// .finish(); /// .finish();

View file

@ -14,26 +14,27 @@ use actix::dev::{AsyncContextApi, ActorAddressCell, ActorItemsCell, ActorWaitCel
use task::{IoContext, DrainFut}; use task::{IoContext, DrainFut};
use body::Binary; use body::Binary;
use error::{Error, Result as ActixResult}; use error::Error;
use route::{Route, Frame, Reply}; use route::Frame;
use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
/// Http actor execution context /// Http actor execution context
pub struct HttpContext<A> where A: Actor<Context=HttpContext<A>> + Route, pub struct HttpContext<A, S=()> where A: Actor<Context=HttpContext<A, S>>,
{ {
act: Option<A>, act: A,
state: ActorState, state: ActorState,
modified: bool, modified: bool,
items: ActorItemsCell<A>, items: ActorItemsCell<A>,
address: ActorAddressCell<A>, address: ActorAddressCell<A>,
stream: VecDeque<Frame>, stream: VecDeque<Frame>,
wait: ActorWaitCell<A>, wait: ActorWaitCell<A>,
app_state: Rc<<A as Route>::State>, request: HttpRequest<S>,
disconnected: bool, disconnected: bool,
} }
impl<A> IoContext for HttpContext<A> where A: Actor<Context=Self> + Route { impl<A, S> IoContext for HttpContext<A, S> where A: Actor<Context=Self>, S: 'static {
fn disconnected(&mut self) { fn disconnected(&mut self) {
self.items.stop(); self.items.stop();
@ -44,7 +45,7 @@ impl<A> IoContext for HttpContext<A> where A: Actor<Context=Self> + Route {
} }
} }
impl<A> ActorContext for HttpContext<A> where A: Actor<Context=Self> + Route impl<A, S> ActorContext for HttpContext<A, S> where A: Actor<Context=Self>
{ {
/// Stop actor execution /// Stop actor execution
fn stop(&mut self) { fn stop(&mut self) {
@ -69,7 +70,7 @@ impl<A> ActorContext for HttpContext<A> where A: Actor<Context=Self> + Route
} }
} }
impl<A> AsyncContext<A> for HttpContext<A> where A: Actor<Context=Self> + Route impl<A, S> AsyncContext<A> for HttpContext<A, S> where A: Actor<Context=Self>
{ {
fn spawn<F>(&mut self, fut: F) -> SpawnHandle fn spawn<F>(&mut self, fut: F) -> SpawnHandle
where F: ActorFuture<Item=(), Error=(), Actor=A> + 'static where F: ActorFuture<Item=(), Error=(), Actor=A> + 'static
@ -96,41 +97,43 @@ impl<A> AsyncContext<A> for HttpContext<A> where A: Actor<Context=Self> + Route
} }
#[doc(hidden)] #[doc(hidden)]
impl<A> AsyncContextApi<A> for HttpContext<A> where A: Actor<Context=Self> + Route { impl<A, S> AsyncContextApi<A> for HttpContext<A, S> where A: Actor<Context=Self> {
fn address_cell(&mut self) -> &mut ActorAddressCell<A> { fn address_cell(&mut self) -> &mut ActorAddressCell<A> {
&mut self.address &mut self.address
} }
} }
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route { impl<A, S> HttpContext<A, S> where A: Actor<Context=Self> {
pub fn new(state: Rc<<A as Route>::State>) -> HttpContext<A> pub fn new(req: HttpRequest<S>, actor: A) -> HttpContext<A, S>
{ {
HttpContext { HttpContext {
act: None, act: actor,
state: ActorState::Started, state: ActorState::Started,
modified: false, modified: false,
items: ActorItemsCell::default(), items: ActorItemsCell::default(),
address: ActorAddressCell::default(), address: ActorAddressCell::default(),
wait: ActorWaitCell::default(), wait: ActorWaitCell::default(),
stream: VecDeque::new(), stream: VecDeque::new(),
app_state: state, request: req,
disconnected: false, disconnected: false,
} }
} }
pub(crate) fn set_actor(&mut self, act: A) {
self.act = Some(act)
}
} }
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route { impl<A, S> HttpContext<A, S> where A: Actor<Context=Self> {
/// Shared application state /// Shared application state
pub fn state(&self) -> &<A as Route>::State { pub fn state(&self) -> &S {
&self.app_state self.request.state()
} }
/// Incoming request
pub fn request(&mut self) -> &mut HttpRequest<S> {
&mut self.request
}
/// Start response processing /// Start response processing
pub fn start<R: Into<HttpResponse>>(&mut self, response: R) { pub fn start<R: Into<HttpResponse>>(&mut self, response: R) {
self.stream.push_back(Frame::Message(response.into())) self.stream.push_back(Frame::Message(response.into()))
@ -158,14 +161,9 @@ impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
pub fn connected(&self) -> bool { pub fn connected(&self) -> bool {
!self.disconnected !self.disconnected
} }
pub fn reply(mut self, actor: A) -> ActixResult<Reply> {
self.set_actor(actor);
Reply::async(self)
}
} }
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route { impl<A, S> HttpContext<A, S> where A: Actor<Context=Self> {
#[doc(hidden)] #[doc(hidden)]
pub fn subscriber<M>(&mut self) -> Box<Subscriber<M>> pub fn subscriber<M>(&mut self) -> Box<Subscriber<M>>
@ -187,20 +185,17 @@ impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
} }
#[doc(hidden)] #[doc(hidden)]
impl<A> Stream for HttpContext<A> where A: Actor<Context=Self> + Route impl<A, S> Stream for HttpContext<A, S> where A: Actor<Context=Self>
{ {
type Item = Frame; type Item = Frame;
type Error = Error; type Error = Error;
fn poll(&mut self) -> Poll<Option<Frame>, Error> { fn poll(&mut self) -> Poll<Option<Frame>, Error> {
if self.act.is_none() {
return Ok(Async::NotReady)
}
let act: &mut A = unsafe { let act: &mut A = unsafe {
std::mem::transmute(self.act.as_mut().unwrap() as &mut A) std::mem::transmute(&mut self.act as &mut A)
}; };
let ctx: &mut HttpContext<A> = unsafe { let ctx: &mut HttpContext<A, S> = unsafe {
std::mem::transmute(self as &mut HttpContext<A>) std::mem::transmute(self as &mut HttpContext<A, S>)
}; };
// update state // update state
@ -283,8 +278,8 @@ impl<A> Stream for HttpContext<A> where A: Actor<Context=Self> + Route
} }
} }
impl<A> ToEnvelope<A> for HttpContext<A> impl<A, S> ToEnvelope<A> for HttpContext<A, S>
where A: Actor<Context=HttpContext<A>> + Route, where A: Actor<Context=HttpContext<A, S>>,
{ {
fn pack<M>(msg: M, tx: Option<Sender<Result<M::Item, M::Error>>>) -> Envelope<A> fn pack<M>(msg: M, tx: Option<Sender<Result<M::Item, M::Error>>>) -> Envelope<A>
where A: Handler<M>, where A: Handler<M>,

View file

@ -11,7 +11,6 @@
// dev specific // dev specific
pub use task::Task; pub use task::Task;
pub use pipeline::Pipeline; pub use pipeline::Pipeline;
pub use route::RouteFactory;
pub use recognizer::RouteRecognizer; pub use recognizer::RouteRecognizer;
pub use channel::HttpChannel; pub use channel::HttpChannel;

View file

@ -95,11 +95,6 @@ impl<S> HttpRequest<S> {
&self.1 &self.1
} }
/// Clone application state
pub(crate) fn clone_state(&self) -> Rc<S> {
Rc::clone(&self.1)
}
/// Protocol extensions. /// Protocol extensions.
#[inline] #[inline]
pub fn extensions(&mut self) -> &mut Extensions { pub fn extensions(&mut self) -> &mut Extensions {

View file

@ -82,7 +82,7 @@ pub use application::Application;
pub use httprequest::{HttpRequest, UrlEncoded}; pub use httprequest::{HttpRequest, UrlEncoded};
pub use httpresponse::HttpResponse; pub use httpresponse::HttpResponse;
pub use payload::{Payload, PayloadItem}; pub use payload::{Payload, PayloadItem};
pub use route::{Frame, Route, RouteFactory, RouteHandler, Reply}; pub use route::{Frame, RouteHandler, Reply};
pub use resource::Resource; pub use resource::Resource;
pub use recognizer::Params; pub use recognizer::Params;
pub use server::HttpServer; pub use server::HttpServer;

View file

@ -1,14 +1,12 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::collections::HashMap; use std::collections::HashMap;
use actix::Actor;
use http::Method; use http::Method;
use futures::Stream; use futures::Stream;
use task::Task; use task::Task;
use error::Error; use error::Error;
use route::{Reply, Route, RouteHandler, Frame, FnHandler, StreamHandler}; use route::{Reply, RouteHandler, Frame, FnHandler, StreamHandler};
use context::HttpContext;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpcodes::{HTTPNotFound, HTTPMethodNotAllowed}; use httpcodes::{HTTPNotFound, HTTPMethodNotAllowed};
@ -92,31 +90,31 @@ impl<S> Resource<S> where S: 'static {
} }
/// Handler for `GET` method. /// Handler for `GET` method.
pub fn get<A>(&mut self) pub fn get<F, R>(&mut self, handler: F)
where A: Actor<Context=HttpContext<A>> + Route<State=S> where F: Fn(HttpRequest<S>) -> R + 'static,
{ R: Into<Reply> + 'static, {
self.route_handler(Method::GET, A::factory()); self.routes.insert(Method::GET, Box::new(FnHandler::new(handler)));
} }
/// Handler for `POST` method. /// Handler for `POST` method.
pub fn post<A>(&mut self) pub fn post<F, R>(&mut self, handler: F)
where A: Actor<Context=HttpContext<A>> + Route<State=S> where F: Fn(HttpRequest<S>) -> R + 'static,
{ R: Into<Reply> + 'static, {
self.route_handler(Method::POST, A::factory()); self.routes.insert(Method::POST, Box::new(FnHandler::new(handler)));
} }
/// Handler for `PUR` method. /// Handler for `PUT` method.
pub fn put<A>(&mut self) pub fn put<F, R>(&mut self, handler: F)
where A: Actor<Context=HttpContext<A>> + Route<State=S> where F: Fn(HttpRequest<S>) -> R + 'static,
{ R: Into<Reply> + 'static, {
self.route_handler(Method::PUT, A::factory()); self.routes.insert(Method::PUT, Box::new(FnHandler::new(handler)));
} }
/// Handler for `METHOD` method. /// Handler for `DELETE` method.
pub fn delete<A>(&mut self) pub fn delete<F, R>(&mut self, handler: F)
where A: Actor<Context=HttpContext<A>> + Route<State=S> where F: Fn(HttpRequest<S>) -> R + 'static,
{ R: Into<Reply> + 'static, {
self.route_handler(Method::DELETE, A::factory()); self.routes.insert(Method::DELETE, Box::new(FnHandler::new(handler)));
} }
} }

View file

@ -1,14 +1,15 @@
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::result::Result as StdResult;
use actix::Actor; use actix::Actor;
use http::{header, Version}; // use http::{header, Version};
use futures::Stream; use futures::Stream;
use task::{Task, DrainFut, IoContext}; use task::{Task, DrainFut, IoContext};
use body::Binary; use body::Binary;
use error::{Error, ExpectError, Result}; use error::{Error}; //, ExpectError, Result};
use context::HttpContext; use context::HttpContext;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -37,9 +38,10 @@ pub trait RouteHandler<S>: 'static {
fn set_prefix(&mut self, prefix: String) {} fn set_prefix(&mut self, prefix: String) {}
} }
/*
/// Actors with ability to handle http requests. /// Actors with ability to handle http requests.
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait Route: Actor { pub trait RouteState {
/// Shared state. State is shared with all routes within same application /// Shared state. State is shared with all routes within same application
/// and could be accessed with `HttpRequest::state()` method. /// and could be accessed with `HttpRequest::state()` method.
type State; type State;
@ -69,42 +71,13 @@ pub trait Route: Actor {
} }
} }
/// Handle incoming request. Route actor can return /// Handle incoming request with http actor.
/// result immediately with `Reply::reply`. fn handle(req: HttpRequest<Self::State>) -> Result<Reply>
/// Actor itself can be returned with `Reply::stream` for handling streaming where Self: Default, Self: Actor<Context=HttpContext<Self>>
/// request/response or websocket connection. {
/// In that case `HttpContext::start` and `HttpContext::write` has to be used Ok(HttpContext::new(req, Self::default()).into())
/// for writing response.
fn request(req: HttpRequest<Self::State>, ctx: Self::Context) -> Result<Reply>;
/// This method creates `RouteFactory` for this actor.
fn factory() -> RouteFactory<Self, Self::State> {
RouteFactory(PhantomData)
} }
} }*/
/// This is used for routes registration within `Resource`
pub struct RouteFactory<A: Route<State=S>, S>(PhantomData<A>);
impl<A, S> RouteHandler<S> for RouteFactory<A, S>
where A: Actor<Context=HttpContext<A>> + Route<State=S>,
S: 'static
{
fn handle(&self, mut req: HttpRequest<A::State>, task: &mut Task) {
let mut ctx = HttpContext::new(req.clone_state());
// handle EXPECT header
if req.headers().contains_key(header::EXPECT) {
if let Err(resp) = A::expect(&mut req, &mut ctx) {
task.reply(resp)
}
}
match A::request(req, ctx) {
Ok(reply) => reply.into(task),
Err(err) => task.reply(err),
}
}
}
/// Fn() route handler /// Fn() route handler
pub(crate) pub(crate)
@ -180,20 +153,22 @@ pub struct Reply(ReplyItem);
impl Reply impl Reply
{ {
/// Create actor response /// Create actor response
pub(crate) fn async<C: IoContext>(ctx: C) -> Result<Reply> { pub fn actor<A, S>(ctx: HttpContext<A, S>) -> Reply
Ok(Reply(ReplyItem::Actor(Box::new(ctx)))) where A: Actor<Context=HttpContext<A, S>>, S: 'static
{
Reply(ReplyItem::Actor(Box::new(ctx)))
} }
/// Create async response /// Create async response
pub fn stream<S>(stream: S) -> Result<Reply> pub fn stream<S>(stream: S) -> Reply
where S: Stream<Item=Frame, Error=Error> + 'static where S: Stream<Item=Frame, Error=Error> + 'static
{ {
Ok(Reply(ReplyItem::Stream(Box::new(stream)))) Reply(ReplyItem::Stream(Box::new(stream)))
} }
/// Send response /// Send response
pub fn reply<R: Into<HttpResponse>>(response: R) -> Result<Reply> { pub fn reply<R: Into<HttpResponse>>(response: R) -> Reply {
Ok(Reply(ReplyItem::Message(response.into()))) Reply(ReplyItem::Message(response.into()))
} }
pub fn into(self, task: &mut Task) pub fn into(self, task: &mut Task)
@ -218,3 +193,19 @@ impl<T: Into<HttpResponse>> From<T> for Reply
Reply(ReplyItem::Message(item.into())) Reply(ReplyItem::Message(item.into()))
} }
} }
impl<E: Into<Error>> From<StdResult<Reply, E>> for Reply {
fn from(res: StdResult<Reply, E>) -> Self {
match res {
Ok(val) => val,
Err(err) => err.into().into(),
}
}
}
impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> From<HttpContext<A, S>> for Reply
{
fn from(item: HttpContext<A, S>) -> Self {
Reply(ReplyItem::Actor(Box::new(item)))
}
}

View file

@ -12,6 +12,10 @@
//! use actix::*; //! use actix::*;
//! use actix_web::*; //! use actix_web::*;
//! //!
//! fn ws_index(req: HttpRequest) -> Result<Reply> {
//! ws::start(req, WsRoute)
//! }
//!
//! // WebSocket Route //! // WebSocket Route
//! struct WsRoute; //! struct WsRoute;
//! //!
@ -19,22 +23,6 @@
//! type Context = HttpContext<Self>; //! type Context = HttpContext<Self>;
//! } //! }
//! //!
//! impl Route for WsRoute {
//! type State = ();
//!
//! fn request(mut req: HttpRequest, mut ctx: HttpContext<Self>) -> Result<Reply>
//! {
//! // WebSocket handshake
//! let resp = ws::handshake(&req)?;
//! // Send handshake response to peer
//! ctx.start(resp);
//! // Map Payload into WsStream
//! ctx.add_stream(ws::WsStream::new(&mut req));
//! // Start ws messages processing
//! ctx.reply(WsRoute)
//! }
//! }
//!
//! // Define Handler for ws::Message message //! // Define Handler for ws::Message message
//! impl StreamHandler<ws::Message> for WsRoute {} //! impl StreamHandler<ws::Message> for WsRoute {}
//! //!
@ -59,13 +47,13 @@ use http::{Method, StatusCode, header};
use bytes::BytesMut; use bytes::BytesMut;
use futures::{Async, Poll, Stream}; use futures::{Async, Poll, Stream};
use actix::{Actor, ResponseType}; use actix::{Actor, AsyncContext, ResponseType, StreamHandler};
use body::Body; use body::Body;
use context::HttpContext; use context::HttpContext;
use route::Route; use route::Reply;
use payload::Payload; use payload::Payload;
use error::WsHandshakeError; use error::{Error, WsHandshakeError};
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::{ConnectionType, HttpResponse}; use httpresponse::{ConnectionType, HttpResponse};
@ -100,6 +88,19 @@ impl ResponseType for Message {
type Error = (); type Error = ();
} }
pub fn start<A, S>(mut req: HttpRequest<S>, actor: A) -> Result<Reply, Error>
where A: Actor<Context=HttpContext<A, S>> + StreamHandler<Message>,
S: 'static
{
let resp = handshake(&req)?;
let stream = WsStream::new(&mut req);
let mut ctx = HttpContext::new(req, actor);
ctx.start(resp);
ctx.add_stream(stream);
Ok(ctx.into())
}
/// Prepare `WebSocket` handshake response. /// Prepare `WebSocket` handshake response.
/// ///
/// This function returns handshake `HttpResponse`, ready to send to peer. /// This function returns handshake `HttpResponse`, ready to send to peer.
@ -271,8 +272,8 @@ pub struct WsWriter;
impl WsWriter { impl WsWriter {
/// Send text frame /// Send text frame
pub fn text<A>(ctx: &mut HttpContext<A>, text: &str) pub fn text<A, S>(ctx: &mut HttpContext<A, S>, text: &str)
where A: Actor<Context=HttpContext<A>> + Route where A: Actor<Context=HttpContext<A, S>>
{ {
let mut frame = wsframe::Frame::message(Vec::from(text), OpCode::Text, true); let mut frame = wsframe::Frame::message(Vec::from(text), OpCode::Text, true);
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -282,8 +283,8 @@ impl WsWriter {
} }
/// Send binary frame /// Send binary frame
pub fn binary<A>(ctx: &mut HttpContext<A>, data: Vec<u8>) pub fn binary<A, S>(ctx: &mut HttpContext<A, S>, data: Vec<u8>)
where A: Actor<Context=HttpContext<A>> + Route where A: Actor<Context=HttpContext<A, S>>
{ {
let mut frame = wsframe::Frame::message(data, OpCode::Binary, true); let mut frame = wsframe::Frame::message(data, OpCode::Binary, true);
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -293,8 +294,8 @@ impl WsWriter {
} }
/// Send ping frame /// Send ping frame
pub fn ping<A>(ctx: &mut HttpContext<A>, message: &str) pub fn ping<A, S>(ctx: &mut HttpContext<A, S>, message: &str)
where A: Actor<Context=HttpContext<A>> + Route where A: Actor<Context=HttpContext<A, S>>
{ {
let mut frame = wsframe::Frame::message(Vec::from(message), OpCode::Ping, true); let mut frame = wsframe::Frame::message(Vec::from(message), OpCode::Ping, true);
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -304,8 +305,8 @@ impl WsWriter {
} }
/// Send pong frame /// Send pong frame
pub fn pong<A>(ctx: &mut HttpContext<A>, message: &str) pub fn pong<A, S>(ctx: &mut HttpContext<A, S>, message: &str)
where A: Actor<Context=HttpContext<A>> + Route where A: Actor<Context=HttpContext<A, S>>
{ {
let mut frame = wsframe::Frame::message(Vec::from(message), OpCode::Pong, true); let mut frame = wsframe::Frame::message(Vec::from(message), OpCode::Pong, true);
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -315,8 +316,8 @@ impl WsWriter {
} }
/// Send close frame /// Send close frame
pub fn close<A>(ctx: &mut HttpContext<A>, code: CloseCode, reason: &str) pub fn close<A, S>(ctx: &mut HttpContext<A, S>, code: CloseCode, reason: &str)
where A: Actor<Context=HttpContext<A>> + Route where A: Actor<Context=HttpContext<A, S>>
{ {
let mut frame = wsframe::Frame::close(code, reason); let mut frame = wsframe::Frame::close(code, reason);
let mut buf = Vec::new(); let mut buf = Vec::new();