1
0
mirror of https://github.com/actix/examples synced 2024-11-23 14:31:07 +01:00

upgrade example to actix-web 0.7

This commit is contained in:
Nikolay Kim 2018-07-16 12:36:53 +06:00
parent 0b52c7850e
commit 2cc1b23761
57 changed files with 913 additions and 693 deletions

946
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,10 @@ version = "0.1.0"
authors = ["Darin Gordon <dkcdkg@gmail.com>"]
[dependencies]
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
dotenv = "0.10"
env_logger = "0.5"
failure = "0.1.1"

View File

@ -1,31 +1,28 @@
use actix::prelude::*;
use std::{time::Duration, thread::sleep};
use failure::Error;
use r2d2;
use r2d2_sqlite;
use std::{thread::sleep, time::Duration};
pub type Pool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>;
pub type Connection = r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
pub struct DbExecutor(pub Pool);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
#[derive(Debug, Serialize, Deserialize)]
pub enum WeatherAgg {
AnnualAgg {year: i32, total: f64},
MonthAgg {year: i32, month: i32, total: f64}
AnnualAgg { year: i32, total: f64 },
MonthAgg { year: i32, month: i32, total: f64 },
}
pub enum Queries {
GetTopTenHottestYears,
GetTopTenColdestYears,
GetTopTenHottestMonths,
GetTopTenColdestMonths
GetTopTenColdestMonths,
}
//pub struct GetTopTenHottestYears;
@ -41,7 +38,7 @@ impl Handler<Queries> for DbExecutor {
match msg {
Queries::GetTopTenHottestYears => get_hottest_years(conn),
Queries::GetTopTenColdestYears => get_coldest_years(conn),
Queries::GetTopTenHottestMonths =>get_hottest_months(conn),
Queries::GetTopTenHottestMonths => get_hottest_months(conn),
Queries::GetTopTenColdestMonths => get_coldest_months(conn),
}
}
@ -56,13 +53,17 @@ fn get_hottest_years(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
GROUP BY theyear
ORDER BY total DESC LIMIT 10;";
let mut prep_stmt = conn.prepare(stmt)?;
let annuals = prep_stmt.query_map(&[], |row| {
WeatherAgg::AnnualAgg{year: row.get(0),
total: row.get(1)}})
.and_then(|mapped_rows|
Ok(mapped_rows.map(|row| row.unwrap()).collect::<Vec<WeatherAgg>>()))?;
let annuals = prep_stmt
.query_map(&[], |row| WeatherAgg::AnnualAgg {
year: row.get(0),
total: row.get(1),
})
.and_then(|mapped_rows| {
Ok(mapped_rows
.map(|row| row.unwrap())
.collect::<Vec<WeatherAgg>>())
})?;
sleep(Duration::from_secs(2));
@ -79,11 +80,16 @@ fn get_coldest_years(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
ORDER BY total ASC LIMIT 10;";
let mut prep_stmt = conn.prepare(stmt)?;
let annuals = prep_stmt.query_map(&[], |row| {
WeatherAgg::AnnualAgg{year: row.get(0),
total: row.get(1)}})
.and_then(|mapped_rows|
Ok(mapped_rows.map(|row| row.unwrap()).collect::<Vec<WeatherAgg>>()))?;
let annuals = prep_stmt
.query_map(&[], |row| WeatherAgg::AnnualAgg {
year: row.get(0),
total: row.get(1),
})
.and_then(|mapped_rows| {
Ok(mapped_rows
.map(|row| row.unwrap())
.collect::<Vec<WeatherAgg>>())
})?;
sleep(Duration::from_secs(2));
@ -91,8 +97,7 @@ fn get_coldest_years(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
}
fn get_hottest_months(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
let stmt =
"SELECT cast(strftime('%Y', date) as int) as theyear,
let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear,
cast(strftime('%m', date) as int) as themonth,
sum(tmax) as total
FROM nyc_weather
@ -101,20 +106,24 @@ fn get_hottest_months(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
ORDER BY total DESC LIMIT 10;";
let mut prep_stmt = conn.prepare(stmt)?;
let annuals = prep_stmt.query_map(&[], |row| {
WeatherAgg::MonthAgg{year: row.get(0),
let annuals = prep_stmt
.query_map(&[], |row| WeatherAgg::MonthAgg {
year: row.get(0),
month: row.get(1),
total: row.get(2)}})
.and_then(|mapped_rows|
Ok(mapped_rows.map(|row| row.unwrap()).collect::<Vec<WeatherAgg>>()))?;
total: row.get(2),
})
.and_then(|mapped_rows| {
Ok(mapped_rows
.map(|row| row.unwrap())
.collect::<Vec<WeatherAgg>>())
})?;
sleep(Duration::from_secs(2));
Ok(annuals)
}
fn get_coldest_months(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
let stmt =
"SELECT cast(strftime('%Y', date) as int) as theyear,
let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear,
cast(strftime('%m', date) as int) as themonth,
sum(tmax) as total
FROM nyc_weather
@ -123,12 +132,17 @@ fn get_coldest_months(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {
ORDER BY total ASC LIMIT 10;";
let mut prep_stmt = conn.prepare(stmt)?;
let annuals = prep_stmt.query_map(&[], |row| {
WeatherAgg::MonthAgg{year: row.get(0),
let annuals = prep_stmt
.query_map(&[], |row| WeatherAgg::MonthAgg {
year: row.get(0),
month: row.get(1),
total: row.get(2)}})
.and_then(|mapped_rows|
Ok(mapped_rows.map(|row| row.unwrap()).collect::<Vec<WeatherAgg>>()))?;
total: row.get(2),
})
.and_then(|mapped_rows| {
Ok(mapped_rows
.map(|row| row.unwrap())
.collect::<Vec<WeatherAgg>>())
})?;
sleep(Duration::from_secs(2));
Ok(annuals)

View File

@ -10,7 +10,7 @@ This project illustrates two examples:
*/
#[macro_use] extern crate actix;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate failure;
@ -19,42 +19,52 @@ extern crate num_cpus;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use actix::prelude::*;
use actix_web::{
http, middleware, server, App, AsyncResponder, FutureResponse, HttpResponse,
State, Error as AWError
http, middleware, server, App, AsyncResponder, Error as AWError, FutureResponse,
HttpResponse, State,
};
use std::error::Error as StdError;
use failure::Error;
use futures::future::{Future, join_all, ok as fut_ok, err as fut_err};
use futures::future::{join_all, ok as fut_ok, Future};
use r2d2_sqlite::SqliteConnectionManager;
mod db;
use db::{DbExecutor, Queries, WeatherAgg, Pool};
use db::{DbExecutor, Pool, Queries, WeatherAgg};
/// State with DbExecutor address
struct AppState {
db: Addr<Syn, DbExecutor>,
db: Addr<DbExecutor>,
}
/// Version 1: Calls 4 queries in sequential order, as an asynchronous handler
fn asyncio_weather(state: State<AppState>) -> FutureResponse<HttpResponse> {
let mut result: Vec<Vec<WeatherAgg>> = vec![];
state.db.send(Queries::GetTopTenHottestYears).from_err()
state
.db
.send(Queries::GetTopTenHottestYears)
.from_err()
.and_then(move |res| {
result.push(res.unwrap());
state.db.send(Queries::GetTopTenColdestYears).from_err()
state
.db
.send(Queries::GetTopTenColdestYears)
.from_err()
.and_then(move |res| {
result.push(res.unwrap());
state.db.send(Queries::GetTopTenHottestMonths).from_err()
state
.db
.send(Queries::GetTopTenHottestMonths)
.from_err()
.and_then(move |res| {
result.push(res.unwrap());
state.db.send(Queries::GetTopTenColdestMonths).from_err()
state
.db
.send(Queries::GetTopTenColdestMonths)
.from_err()
.and_then(move |res| {
result.push(res.unwrap());
fut_ok(result)
@ -73,7 +83,8 @@ fn parallel_weather(state: State<AppState>) -> FutureResponse<HttpResponse> {
Box::new(state.db.send(Queries::GetTopTenHottestYears)),
Box::new(state.db.send(Queries::GetTopTenColdestYears)),
Box::new(state.db.send(Queries::GetTopTenHottestMonths)),
Box::new(state.db.send(Queries::GetTopTenColdestMonths))];
Box::new(state.db.send(Queries::GetTopTenColdestMonths)),
];
join_all(fut_result)
.map_err(AWError::from)

View File

@ -4,8 +4,10 @@ version = "0.1.0"
authors = ["dowwie <dkcdkg@gmail.com>"]
[dependencies]
actix = "0.5.6"
actix-web = { version = "^0.6", features=["alpn"] }
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
serde = "1.0.43"
serde_derive = "1.0.43"

View File

@ -5,8 +5,10 @@ authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../"
[dependencies]
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
bytes = "0.4"

View File

@ -21,21 +21,14 @@ use futures::future::{result, FutureResult};
use std::{env, io};
/// favicon handler
fn favicon(req: HttpRequest) -> Result<fs::NamedFile> {
fn favicon(req: &HttpRequest) -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/favicon.ico")?)
}
/// simple index handler
fn welcome(mut req: HttpRequest) -> Result<HttpResponse> {
fn welcome(req: &HttpRequest) -> Result<HttpResponse> {
println!("{:?}", req);
// example of ...
if let Ok(ch) = req.poll() {
if let futures::Async::Ready(Some(d)) = ch {
println!("{}", String::from_utf8_lossy(d.as_ref()));
}
}
// session
let mut counter = 1;
if let Some(count) = req.session().get::<i32>("counter")? {
@ -53,12 +46,12 @@ fn welcome(mut req: HttpRequest) -> Result<HttpResponse> {
}
/// 404 handler
fn p404(req: HttpRequest) -> Result<fs::NamedFile> {
fn p404(req: &HttpRequest) -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/404.html")?.set_status_code(StatusCode::NOT_FOUND))
}
/// async handler
fn index_async(req: HttpRequest) -> FutureResult<HttpResponse, Error> {
fn index_async(req: &HttpRequest) -> FutureResult<HttpResponse, Error> {
println!("{:?}", req);
result(Ok(HttpResponse::Ok().content_type("text/html").body(
@ -78,7 +71,7 @@ fn index_async_body(path: Path<String>) -> HttpResponse {
}
/// handler with path parameters like `/user/{name}/`
fn with_param(req: HttpRequest) -> HttpResponse {
fn with_param(req: &HttpRequest) -> HttpResponse {
println!("{:?}", req);
HttpResponse::Ok()
@ -122,7 +115,7 @@ fn main() {
io::Error::new(io::ErrorKind::Other, "test"), StatusCode::INTERNAL_SERVER_ERROR)
}))
// static files
.handler("/static", fs::StaticFiles::new("static"))
.handler("/static", fs::StaticFiles::new("static").unwrap())
// redirect
.resource("/", |r| r.method(Method::GET).f(|req| {
println!("{:?}", req);

View File

@ -5,8 +5,10 @@ authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../"
[dependencies]
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
cookie = { version="0.10", features=["percent-encode", "secure"] }
futures = "0.1"
time = "0.1"

View File

@ -14,31 +14,31 @@ use actix_web::{Error, HttpRequest, HttpResponse, Result};
pub trait RequestIdentity {
/// Return the claimed identity of the user associated request or
/// ``None`` if no identity can be found associated with the request.
fn identity(&mut self) -> Option<&str>;
fn identity(&self) -> Option<String>;
/// Remember identity.
fn remember(&mut self, identity: String);
fn remember(&self, identity: String);
/// This method is used to 'forget' the current identity on subsequent
/// requests.
fn forget(&mut self);
fn forget(&self);
}
impl<S> RequestIdentity for HttpRequest<S> {
fn identity(&mut self) -> Option<&str> {
fn identity(&self) -> Option<String> {
if let Some(id) = self.extensions().get::<IdentityBox>() {
return id.0.identity();
return id.0.identity().map(|s| s.to_owned());
}
None
}
fn remember(&mut self, identity: String) {
fn remember(&self, identity: String) {
if let Some(id) = self.extensions_mut().get_mut::<IdentityBox>() {
return id.0.remember(identity);
return id.0.as_mut().remember(identity);
}
}
fn forget(&mut self) {
fn forget(&self) {
if let Some(id) = self.extensions_mut().get_mut::<IdentityBox>() {
return id.0.forget();
}
@ -86,7 +86,7 @@ unsafe impl Send for IdentityBox {}
unsafe impl Sync for IdentityBox {}
impl<S: 'static, T: IdentityPolicy<S>> Middleware<S> for IdentityService<T> {
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
let mut req = req.clone();
let fut = self
@ -102,9 +102,7 @@ impl<S: 'static, T: IdentityPolicy<S>> Middleware<S> for IdentityService<T> {
Ok(Started::Future(Box::new(fut)))
}
fn response(
&self, req: &mut HttpRequest<S>, resp: HttpResponse,
) -> Result<Response> {
fn response(&self, req: &HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
if let Some(mut id) = req.extensions_mut().remove::<IdentityBox>() {
id.0.write(resp)
} else {
@ -200,7 +198,7 @@ impl CookieIdentityInner {
fn load<S>(&self, req: &mut HttpRequest<S>) -> Option<String> {
if let Ok(cookies) = req.cookies() {
for cookie in cookies {
for cookie in cookies.iter() {
if cookie.name() == self.name {
let mut jar = CookieJar::new();
jar.add_original(cookie.clone());

View File

@ -10,16 +10,16 @@ use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
mod auth;
use auth::{CookieIdentityPolicy, IdentityService, RequestIdentity};
fn index(mut req: HttpRequest) -> String {
format!("Hello {}", req.identity().unwrap_or("Anonymous"))
fn index(req: &HttpRequest) -> String {
format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned()))
}
fn login(mut req: HttpRequest) -> HttpResponse {
fn login(req: &HttpRequest) -> HttpResponse {
req.remember("user1".to_owned());
HttpResponse::Found().header("location", "/").finish()
}
fn logout(mut req: HttpRequest) -> HttpResponse {
fn logout(req: &HttpRequest) -> HttpResponse {
req.forget();
HttpResponse::Found().header("location", "/").finish()
}

View File

@ -5,8 +5,10 @@ authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../"
[dependencies]
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
time = "0.1"
env_logger = "0.5"

View File

@ -15,7 +15,7 @@ use actix_web::{middleware, server, App, HttpRequest, Result};
use std::env;
/// simple index handler with session
fn index(req: HttpRequest) -> Result<&'static str> {
fn index(req: &HttpRequest) -> Result<&'static str> {
println!("{:?}", req);
// RequestSession trait is used for session access

View File

@ -6,8 +6,10 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
uuid = { version = "0.5", features = ["serde", "v4"] }

View File

@ -35,7 +35,7 @@ use db::{CreateUser, DbExecutor};
/// State with DbExecutor address
struct AppState {
db: Addr<Syn, DbExecutor>,
db: Addr<DbExecutor>,
}
/// Async request handler

View File

@ -4,7 +4,9 @@ version = "0.1.0"
authors = ["Gorm Casper <gcasper@gmail.com>"]
[dependencies]
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
serde = "1.0"
serde_derive = "1.0"

View File

@ -6,5 +6,7 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -4,7 +4,7 @@ extern crate env_logger;
use actix_web::{middleware, server, App, HttpRequest};
fn index(_req: HttpRequest) -> &'static str {
fn index(_req: &HttpRequest) -> &'static str {
"Hello world!"
}

View File

@ -15,5 +15,7 @@ path = "src/server.rs"
[dependencies]
env_logger = "0.5"
futures = "0.1"
actix = "0.5"
actix-web = { version = "^0.6", features=["alpn"] }
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -10,7 +10,7 @@ use actix_web::{
use futures::{Future, Stream};
/// Stream client request response and then send body to a server response
fn index(_req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
fn index(_req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
client::ClientRequest::get("http://127.0.0.1:8081/")
.finish().unwrap()
.send()
@ -25,7 +25,7 @@ fn index(_req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
}
/// streaming client request to a streaming server response
fn streaming(_req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
fn streaming(_req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
// send client request
client::ClientRequest::get("https://www.rust-lang.org/en-US/")
.finish().unwrap()
@ -35,7 +35,7 @@ fn streaming(_req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error
Ok(HttpResponse::Ok()
// read one chunk from client response and send this chunk to a server response
// .from_err() converts PayloadError to an Error
.body(Body::Streaming(Box::new(resp.from_err()))))
.body(Body::Streaming(Box::new(resp.payload().from_err()))))
})
.responder()
}

View File

@ -6,7 +6,7 @@ extern crate futures;
use actix_web::*;
use futures::Future;
fn index(req: HttpRequest) -> FutureResponse<HttpResponse> {
fn index(req: &HttpRequest) -> FutureResponse<HttpResponse> {
req.body()
.from_err()
.map(|bytes| HttpResponse::Ok().body(bytes))

View File

@ -14,5 +14,6 @@ serde_json = "1.0"
serde_derive = "1.0"
json = "*"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -25,7 +25,7 @@ struct MyObj {
}
/// This handler uses `HttpRequest::json()` for loading json object.
fn index(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
fn index(req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
req.json()
.from_err() // convert all errors into `Error`
.and_then(|val: MyObj| {
@ -50,9 +50,9 @@ fn extract_item_limit((item, _req): (Json<MyObj>, HttpRequest)) -> HttpResponse
const MAX_SIZE: usize = 262_144; // max payload size is 256k
/// This handler manually load request payload and parse json object
fn index_manual(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
// HttpRequest is stream of Bytes objects
req
fn index_manual(req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
// HttpRequest::payload() is stream of Bytes objects
req.payload()
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
@ -79,8 +79,11 @@ fn index_manual(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Err
}
/// This handler manually load request payload and parse json-rust
fn index_mjsonrust(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
req.concat2()
fn index_mjsonrust(
req: &HttpRequest,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
req.payload()
.concat2()
.from_err()
.and_then(|body| {
// body is loaded, now we can deserialize json-rust
@ -107,13 +110,15 @@ fn main() {
.middleware(middleware::Logger::default())
.resource("/extractor", |r| {
r.method(http::Method::POST)
.with(extract_item)
.limit(4096); // <- limit size of the payload
.with_config(extract_item, |cfg| {
cfg.limit(4096); // <- limit size of the payload
})
})
.resource("/extractor2", |r| {
r.method(http::Method::POST)
.with(extract_item_limit)
.0.limit(4096); // <- limit size of the payload
.with_config(extract_item_limit, |cfg| {
cfg.0.limit(4096); // <- limit size of the payload
})
})
.resource("/manual", |r| r.method(http::Method::POST).f(index_manual))
.resource("/mjsonrust", |r| r.method(http::Method::POST).f(index_mjsonrust))

View File

@ -6,8 +6,10 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
serde = "1.0"

View File

@ -27,7 +27,7 @@ use schema::create_schema;
use schema::Schema;
struct AppState {
executor: Addr<Syn, GraphQLExecutor>,
executor: Addr<GraphQLExecutor>,
}
#[derive(Serialize, Deserialize)]
@ -61,7 +61,7 @@ impl Handler<GraphQLData> for GraphQLExecutor {
}
}
fn graphiql(_req: HttpRequest<AppState>) -> Result<HttpResponse, Error> {
fn graphiql(_req: &HttpRequest<AppState>) -> Result<HttpResponse, Error> {
let html = graphiql_source("http://127.0.0.1:8080/graphql");
Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8")

View File

@ -4,5 +4,6 @@ version = "0.1.0"
authors = ["Gorm Casper <gcasper@gmail.com>"]
[dependencies]
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -7,7 +7,7 @@ pub struct CheckLogin;
impl<S> Middleware<S> for CheckLogin {
// We only need to hook into the `start` for this middleware.
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
let is_logged_in = false; // Change this to see the change in outcome in the browser
if is_logged_in {

View File

@ -8,21 +8,17 @@ use actix_web::{HttpRequest, HttpResponse, Result};
pub struct SayHi;
impl<S> Middleware<S> for SayHi {
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
println!("Hi from start. You requested: {}", req.path());
Ok(Started::Done)
}
fn response(
&self,
_req: &mut HttpRequest<S>,
resp: HttpResponse,
) -> Result<Response> {
fn response(&self, _req: &HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
println!("Hi from response");
Ok(Response::Done(resp))
}
fn finish(&self, _req: &mut HttpRequest<S>, _resp: &HttpResponse) -> Finished {
fn finish(&self, _req: &HttpRequest<S>, _resp: &HttpResponse) -> Finished {
println!("Hi from finish");
Finished::Done
}

View File

@ -11,5 +11,7 @@ path = "src/main.rs"
[dependencies]
env_logger = "*"
futures = "0.1"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -4,13 +4,13 @@ extern crate actix_web;
extern crate env_logger;
extern crate futures;
use std::cell::Cell;
use std::fs;
use std::io::Write;
use std::cell::Cell;
use actix_web::{
error, http, middleware, multipart, server, App, Error, FutureResponse, HttpMessage,
HttpRequest, HttpResponse,
dev, error, http, middleware, multipart, server, App, Error, FutureResponse,
HttpMessage, HttpRequest, HttpResponse,
};
use futures::future;
@ -20,7 +20,9 @@ pub struct AppState {
pub counter: Cell<usize>,
}
pub fn save_file( field: multipart::Field<HttpRequest<AppState>>) -> Box<Future<Item = i64, Error = Error>> {
pub fn save_file(
field: multipart::Field<dev::Payload>,
) -> Box<Future<Item = i64, Error = Error>> {
let file_path_string = "upload.png";
let mut file = match fs::File::create(file_path_string) {
Ok(file) => file,
@ -45,7 +47,9 @@ pub fn save_file( field: multipart::Field<HttpRequest<AppState>>) -> Box<Future<
)
}
pub fn handle_multipart_item( item: multipart::MultipartItem<HttpRequest<AppState>>) -> Box<Stream<Item = i64, Error = Error>> {
pub fn handle_multipart_item(
item: multipart::MultipartItem<dev::Payload>,
) -> Box<Stream<Item = i64, Error = Error>> {
match item {
multipart::MultipartItem::Field(field) => {
Box::new(save_file(field).into_stream())
@ -62,8 +66,7 @@ pub fn upload(req: HttpRequest<AppState>) -> FutureResponse<HttpResponse> {
req.state().counter.set(req.state().counter.get() + 1);
println!("{:?}", req.state().counter.get());
Box::new(
req.clone()
.multipart()
req.multipart()
.map_err(error::ErrorInternalServerError)
.map(handle_multipart_item)
.flatten()
@ -96,8 +99,9 @@ fn main() {
let sys = actix::System::new("multipart-example");
server::new(|| {
App::with_state(AppState{counter: Cell::new(0)})
.middleware(middleware::Logger::default())
App::with_state(AppState {
counter: Cell::new(0),
}).middleware(middleware::Logger::default())
.resource("/", |r| {
r.method(http::Method::GET).with(index);
r.method(http::Method::POST).with(upload);

View File

@ -13,5 +13,6 @@ env_logger = "*"
prost = "0.2.0"
prost-derive = "0.2.0"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -26,7 +26,7 @@ pub struct MyObj {
}
/// This handler uses `ProtoBufMessage` for loading protobuf object.
fn index(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
fn index(req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
protobuf::ProtoBufMessage::new(req)
.from_err() // convert all errors into `Error`
.and_then(|val: MyObj| {

View File

@ -1,4 +1,4 @@
use bytes::{Bytes, BytesMut};
use bytes::BytesMut;
use futures::{Future, Poll, Stream};
use bytes::IntoBuf;
@ -8,7 +8,7 @@ use prost::Message;
use actix_web::dev::HttpResponseBuilder;
use actix_web::error::{Error, PayloadError, ResponseError};
use actix_web::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
use actix_web::http::header::CONTENT_TYPE;
use actix_web::{HttpMessage, HttpRequest, HttpResponse, Responder};
#[derive(Fail, Debug)]
@ -72,84 +72,32 @@ impl<T: Message> Responder for ProtoBuf<T> {
}
}
pub struct ProtoBufMessage<T, U: Message + Default> {
limit: usize,
ct: &'static str,
req: Option<T>,
fut: Option<Box<Future<Item = U, Error = ProtoBufPayloadError>>>,
pub struct ProtoBufMessage<U: Message + Default> {
fut: Box<Future<Item = U, Error = ProtoBufPayloadError>>,
}
impl<T, U: Message + Default> ProtoBufMessage<T, U> {
impl<U: Message + Default + 'static> ProtoBufMessage<U> {
/// Create `ProtoBufMessage` for request.
pub fn new(req: T) -> Self {
ProtoBufMessage {
limit: 262_144,
req: Some(req),
fut: None,
ct: "application/protobuf",
}
}
pub fn new(req: &HttpRequest) -> Self {
let fut = req
.payload()
.map_err(|e| ProtoBufPayloadError::Payload(e))
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, ProtoBufPayloadError>(body)
})
.and_then(|body| Ok(<U>::decode(&mut body.into_buf())?));
/// Change max size of payload. By default max size is 256Kb
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
/// Set allowed content type.
///
/// By default *application/protobuf* content type is used. Set content type
/// to empty string if you want to disable content type check.
pub fn content_type(mut self, ct: &'static str) -> Self {
self.ct = ct;
self
ProtoBufMessage { fut: Box::new(fut) }
}
}
impl<T, U: Message + Default + 'static> Future for ProtoBufMessage<T, U>
where
T: HttpMessage + Stream<Item = Bytes, Error = PayloadError> + 'static,
{
impl<U: Message + Default + 'static> Future for ProtoBufMessage<U> where {
type Item = U;
type Error = ProtoBufPayloadError;
fn poll(&mut self) -> Poll<U, ProtoBufPayloadError> {
if let Some(req) = self.req.take() {
if let Some(len) = req.headers().get(CONTENT_LENGTH) {
if let Ok(s) = len.to_str() {
if let Ok(len) = s.parse::<usize>() {
if len > self.limit {
return Err(ProtoBufPayloadError::Overflow);
}
} else {
return Err(ProtoBufPayloadError::Overflow);
}
}
}
// check content-type
if !self.ct.is_empty() && req.content_type() != self.ct {
return Err(ProtoBufPayloadError::ContentType);
}
let limit = self.limit;
let fut = req
.from_err()
.fold(BytesMut::new(), move |mut body, chunk| {
if (body.len() + chunk.len()) > limit {
Err(ProtoBufPayloadError::Overflow)
} else {
body.extend_from_slice(&chunk);
Ok(body)
}
})
.and_then(|body| Ok(<U>::decode(&mut body.into_buf())?));
self.fut = Some(Box::new(fut));
}
self.fut
.as_mut()
.expect("ProtoBufBody could not be used second time")
.poll()
self.fut.poll()
}
}

View File

@ -6,8 +6,10 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
futures = "0.1"
uuid = { version = "0.5", features = ["serde", "v4"] }

View File

@ -22,11 +22,11 @@ use db::{CreateUser, DbExecutor};
/// State with DbExecutor address
struct State {
db: Addr<Syn, DbExecutor>,
db: Addr<DbExecutor>,
}
/// Async request handler
fn index(req: HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Error>> {
fn index(req: &HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Error>> {
let name = &req.match_info()["name"];
req.state()

View File

@ -7,5 +7,7 @@ workspace = "../"
[dependencies]
futures = "0.1"
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -25,7 +25,7 @@ struct AppState {
}
/// simple handle
fn index(req: HttpRequest<AppState>) -> HttpResponse {
fn index(req: &HttpRequest<AppState>) -> HttpResponse {
println!("{:?}", req);
req.state().counter.set(req.state().counter.get() + 1);

View File

@ -7,5 +7,7 @@ workspace = "../"
[dependencies]
futures = "0.1"
env_logger = "0.5"
actix = "0.5"
actix-web = "0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -17,7 +17,7 @@ fn main() {
.middleware(middleware::Logger::default())
.handler(
"/",
fs::StaticFiles::new("./static/").index_file("index.html")
fs::StaticFiles::new("./static/").unwrap().index_file("index.html")
)
}).bind("127.0.0.1:8080")
.expect("Can not start server on given IP/Port")

View File

@ -6,9 +6,11 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
askama = "0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
[build-dependencies]
askama = "0.6"

View File

@ -6,6 +6,7 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
tera = "*"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -10,6 +10,7 @@ path = "src/main.rs"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { version = "^0.6", features=["alpn"] }
openssl = { version="0.10" }
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -8,7 +8,7 @@ use actix_web::{http, middleware, server, App, Error, HttpRequest, HttpResponse}
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
/// simple handle
fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
fn index(req: &HttpRequest) -> Result<HttpResponse, Error> {
println!("{:?}", req);
Ok(HttpResponse::Ok()
.content_type("text/plain")

View File

@ -6,6 +6,8 @@ workspace = "../"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "^0.6"
tokio-uds = "0.1"
tokio-uds = "0.2"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -7,7 +7,7 @@ use actix::*;
use actix_web::{middleware, server, App, HttpRequest};
use tokio_uds::UnixListener;
fn index(_req: HttpRequest) -> &'static str {
fn index(_req: &HttpRequest) -> &'static str {
"Hello world!"
}
@ -16,8 +16,7 @@ fn main() {
env_logger::init();
let sys = actix::System::new("unix-socket");
let listener = UnixListener::bind("/tmp/actix-uds.socket", Arbiter::handle())
.expect("bind failed");
let listener = UnixListener::bind("/tmp/actix-uds.socket").expect("bind failed");
server::new(|| {
App::new()
// enable logger

View File

@ -10,8 +10,10 @@ serde_derive = "1.0"
serde_json = "1.0"
http = "0.1"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }
dotenv = "0.10"
env_logger = "0.5"
futures = "0.1"

View File

@ -8,7 +8,10 @@ extern crate serde;
extern crate serde_json;
use actix_web::{
http::{header, Method}, middleware, middleware::cors::Cors, server, App,
http::{header, Method},
middleware,
middleware::cors::Cors,
server, App,
};
use std::env;

View File

@ -20,5 +20,6 @@ env_logger = "*"
serde = "1.0"
serde_json = "1.0"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -24,11 +24,11 @@ mod server;
/// This is our websocket route state, this state is shared with all route
/// instances via `HttpContext::state()`
struct WsChatSessionState {
addr: Addr<Syn, server::ChatServer>,
addr: Addr<server::ChatServer>,
}
/// Entry point for our route
fn chat_route(req: HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
fn chat_route(req: &HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
ws::start(
req,
WsChatSession {
@ -63,7 +63,7 @@ impl Actor for WsChatSession {
// before processing any other events.
// HttpContext::state() is instance of WsChatSessionState, state is shared
// across all routes within application
let addr: Addr<Syn, _> = ctx.address();
let addr = ctx.address();
ctx.state()
.addr
.send(server::Connect {
@ -183,7 +183,7 @@ fn main() {
let sys = actix::System::new("websocket-example");
// Start chat server actor in separate thread
let server: Addr<Syn, _> = Arbiter::start(|_| server::ChatServer::default());
let server = Arbiter::start(|_| server::ChatServer::default());
// Create Http server with websocket support
HttpServer::new(move || {
@ -202,7 +202,7 @@ fn main() {
// websocket
.resource("/ws/", |r| r.route().f(chat_route))
// static resources
.handler("/static/", fs::StaticFiles::new("static/"))
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
}).bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -17,7 +17,7 @@ pub struct Message(pub String);
#[derive(Message)]
#[rtype(usize)]
pub struct Connect {
pub addr: Recipient<Syn, Message>,
pub addr: Recipient<Message>,
}
/// Session is disconnected
@ -56,7 +56,7 @@ pub struct Join {
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session. implementation is super primitive
pub struct ChatServer {
sessions: HashMap<usize, Recipient<Syn, Message>>,
sessions: HashMap<usize, Recipient<Message>>,
rooms: HashMap<String, HashSet<usize>>,
rng: RefCell<ThreadRng>,
}

View File

@ -18,12 +18,14 @@ bytes = "0.4"
byteorder = "1.1"
futures = "0.1"
tokio-io = "0.1"
tokio-core = "0.1"
tokio-tcp = "0.1"
tokio-codec = "0.1"
env_logger = "*"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -5,8 +5,9 @@ extern crate bytes;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_codec;
extern crate tokio_io;
extern crate tokio_tcp;
#[macro_use]
extern crate serde_derive;
@ -15,10 +16,10 @@ use futures::Future;
use std::str::FromStr;
use std::time::Duration;
use std::{io, net, process, thread};
use tokio_core::net::TcpStream;
use tokio_io::codec::FramedRead;
use tokio_codec::FramedRead;
use tokio_io::io::WriteHalf;
use tokio_io::AsyncRead;
use tokio_tcp::TcpStream;
mod codec;
@ -27,10 +28,10 @@ fn main() {
// Connect to server
let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap();
Arbiter::handle().spawn(
TcpStream::connect(&addr, Arbiter::handle())
Arbiter::spawn(
TcpStream::connect(&addr)
.and_then(|stream| {
let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
let addr = ChatClient::create(|ctx| {
let (r, w) = stream.split();
ChatClient::add_stream(
FramedRead::new(r, codec::ClientChatCodec),
@ -87,7 +88,7 @@ impl Actor for ChatClient {
println!("Disconnected");
// Stop application on disconnect
Arbiter::system().do_send(actix::msgs::SystemExit(0));
System::current().stop();
}
}

View File

@ -6,8 +6,9 @@ extern crate futures;
extern crate rand;
extern crate serde;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_codec;
extern crate tokio_io;
extern crate tokio_tcp;
#[macro_use]
extern crate serde_derive;
@ -28,11 +29,11 @@ mod session;
/// This is our websocket route state, this state is shared with all route
/// instances via `HttpContext::state()`
struct WsChatSessionState {
addr: Addr<Syn, server::ChatServer>,
addr: Addr<server::ChatServer>,
}
/// Entry point for our route
fn chat_route(req: HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
fn chat_route(req: &HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
ws::start(
req,
WsChatSession {
@ -67,7 +68,7 @@ impl Actor for WsChatSession {
// before processing any other events.
// HttpContext::state() is instance of WsChatSessionState, state is shared
// across all routes within application
let addr: Addr<Syn, _> = ctx.address();
let addr = ctx.address();
ctx.state()
.addr
.send(server::Connect {
@ -187,7 +188,7 @@ fn main() {
let sys = actix::System::new("websocket-example");
// Start chat server actor in separate thread
let server: Addr<Syn, _> = Arbiter::start(|_| server::ChatServer::default());
let server = Arbiter::start(|_| server::ChatServer::default());
// Start tcp server in separate thread
let srv = server.clone();
@ -213,7 +214,7 @@ fn main() {
// websocket
.resource("/ws/", |r| r.route().f(chat_route))
// static resources
.handler("/static/", fs::StaticFiles::new("static/"))
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
}).bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -15,7 +15,7 @@ use session;
#[derive(Message)]
#[rtype(usize)]
pub struct Connect {
pub addr: Recipient<Syn, session::Message>,
pub addr: Recipient<session::Message>,
}
/// Session is disconnected
@ -54,7 +54,7 @@ pub struct Join {
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session. implementation is super primitive
pub struct ChatServer {
sessions: HashMap<usize, Recipient<Syn, session::Message>>,
sessions: HashMap<usize, Recipient<session::Message>>,
rooms: HashMap<String, HashSet<usize>>,
rng: RefCell<ThreadRng>,
}

View File

@ -4,10 +4,10 @@ use futures::Stream;
use std::str::FromStr;
use std::time::{Duration, Instant};
use std::{io, net};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_io::codec::FramedRead;
use tokio_codec::FramedRead;
use tokio_io::io::WriteHalf;
use tokio_io::AsyncRead;
use tokio_tcp::{TcpListener, TcpStream};
use actix::prelude::*;
@ -23,7 +23,7 @@ pub struct ChatSession {
/// unique session id
id: usize,
/// this is address of chat server
addr: Addr<Syn, ChatServer>,
addr: Addr<ChatServer>,
/// Client must send ping at least once per 10 seconds, otherwise we drop
/// connection.
hb: Instant,
@ -45,7 +45,7 @@ impl Actor for ChatSession {
// register self in chat server. `AsyncContext::wait` register
// future within context, but context waits until this future resolves
// before processing any other events.
let addr: Addr<Syn, _> = ctx.address();
let addr = ctx.address();
self.addr
.send(server::Connect {
addr: addr.recipient(),
@ -133,7 +133,7 @@ impl Handler<Message> for ChatSession {
/// Helper methods
impl ChatSession {
pub fn new(
addr: Addr<Syn, ChatServer>,
addr: Addr<ChatServer>,
framed: actix::io::FramedWrite<WriteHalf<TcpStream>, ChatCodec>,
) -> ChatSession {
ChatSession {
@ -172,14 +172,14 @@ impl ChatSession {
/// Define tcp server that will accept incoming tcp connection and create
/// chat actors.
pub struct TcpServer {
chat: Addr<Syn, ChatServer>,
chat: Addr<ChatServer>,
}
impl TcpServer {
pub fn new(s: &str, chat: Addr<Syn, ChatServer>) {
pub fn new(s: &str, chat: Addr<ChatServer>) {
// Create server listener
let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap();
let listener = TcpListener::bind(&addr, Arbiter::handle()).unwrap();
let listener = TcpListener::bind(&addr).unwrap();
// Our chat server `Server` is an actor, first we need to start it
// and then add stream on incoming tcp connections to it.
@ -187,12 +187,9 @@ impl TcpServer {
// items So to be able to handle this events `Server` actor has to
// implement stream handler `StreamHandler<(TcpStream,
// net::SocketAddr), io::Error>`
let _: () = TcpServer::create(|ctx| {
TcpServer::create(|ctx| {
ctx.add_message_stream(
listener
.incoming()
.map_err(|_| ())
.map(|(t, a)| TcpConnect(t, a)),
listener.incoming().map_err(|_| ()).map(|s| TcpConnect(s)),
);
TcpServer { chat: chat }
});
@ -206,7 +203,7 @@ impl Actor for TcpServer {
}
#[derive(Message)]
struct TcpConnect(TcpStream, net::SocketAddr);
struct TcpConnect(TcpStream);
/// Handle stream of TcpStream's
impl Handler<TcpConnect> for TcpServer {
@ -216,7 +213,7 @@ impl Handler<TcpConnect> for TcpServer {
// For each incoming connection we create `ChatSession` actor
// with out chat server address.
let server = self.chat.clone();
let _: () = ChatSession::create(|ctx| {
ChatSession::create(|ctx| {
let (r, w) = msg.0.split();
ChatSession::add_stream(FramedRead::new(r, ChatCodec), ctx);
ChatSession::new(server, actix::io::FramedWrite::new(w, ChatCodec, ctx))

View File

@ -15,6 +15,7 @@ path = "src/client.rs"
[dependencies]
env_logger = "*"
futures = "0.1"
tokio-core = "0.1"
actix = "0.5"
actix-web = "^0.6"
actix = "0.7"
#actix-web = "^0.7"
actix-web = { git = "https://github.com/actix/actix-web.git" }

View File

@ -5,13 +5,11 @@ extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;
use std::time::Duration;
use std::{io, thread};
use actix::*;
use actix_web::ws::WsWriter;
use actix_web::ws::{Client, ClientWriter, Message, ProtocolError};
use futures::Future;
@ -20,7 +18,7 @@ fn main() {
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
Arbiter::handle().spawn(
Arbiter::spawn(
Client::new("http://127.0.0.1:8080/ws/")
.connect()
.map_err(|e| {
@ -28,7 +26,7 @@ fn main() {
()
})
.map(|(reader, writer)| {
let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
let addr = ChatClient::create(|ctx| {
ChatClient::add_stream(reader, ctx);
ChatClient(writer)
});
@ -67,7 +65,7 @@ impl Actor for ChatClient {
println!("Disconnected");
// Stop application on disconnect
Arbiter::system().do_send(actix::msgs::SystemExit(0));
System::current().stop();
}
}

View File

@ -14,7 +14,7 @@ use actix_web::{
};
/// do websocket handshake and start `MyWebSocket` actor
fn ws_index(r: HttpRequest) -> Result<HttpResponse, Error> {
fn ws_index(r: &HttpRequest) -> Result<HttpResponse, Error> {
ws::start(r, MyWebSocket)
}
@ -56,6 +56,7 @@ fn main() {
.resource("/ws/", |r| r.method(http::Method::GET).f(ws_index))
// static files
.handler("/", fs::StaticFiles::new("static/")
.unwrap()
.index_file("index.html")))
// start http server on 127.0.0.1:8080
.bind("127.0.0.1:8080").unwrap()