1
0
mirror of https://github.com/actix/examples synced 2024-11-27 07:52:57 +01:00

update more examples and rustfmt

This commit is contained in:
Nikolay Kim 2019-03-09 18:03:09 -08:00
parent f39a53ea3a
commit e2945b9b39
48 changed files with 485 additions and 801 deletions

View File

@ -7,7 +7,6 @@ members = [
"async_ex1",
"basics",
"cookie-auth",
"cookie-auth-full",
"cookie-session",
"diesel",
"error_handling",

View File

@ -3,30 +3,32 @@ extern crate actix_redis;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
#[macro_use] extern crate redis_async;
#[macro_use]
extern crate redis_async;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use]
extern crate serde_derive;
use std::sync::Arc;
use actix::prelude::*;
use actix_redis::{Command, RedisActor, Error as ARError};
use actix_web::{middleware, server, App, HttpRequest, HttpResponse, Json,
AsyncResponder, http::Method, Error as AWError};
use futures::future::{Future, join_all};
use actix_redis::{Command, Error as ARError, RedisActor};
use actix_web::{
http::Method, middleware, server, App, AsyncResponder, Error as AWError,
HttpRequest, HttpResponse, Json,
};
use futures::future::{join_all, Future};
use redis_async::resp::RespValue;
use std::sync::Arc;
#[derive(Deserialize)]
pub struct CacheInfo {
one: String,
two: String,
three: String
three: String,
}
fn cache_stuff((info, req): (Json<CacheInfo>, HttpRequest<AppState>))
-> impl Future<Item=HttpResponse, Error=AWError> {
fn cache_stuff(
(info, req): (Json<CacheInfo>, HttpRequest<AppState>),
) -> impl Future<Item = HttpResponse, Error = AWError> {
let info = info.into_inner();
let redis = req.state().redis_addr.clone();
@ -59,25 +61,33 @@ fn cache_stuff((info, req): (Json<CacheInfo>, HttpRequest<AppState>))
.responder()
}
fn del_stuff(req: HttpRequest<AppState>)
-> impl Future<Item=HttpResponse, Error=AWError> {
fn del_stuff(
req: HttpRequest<AppState>,
) -> impl Future<Item = HttpResponse, Error = AWError> {
let redis = req.state().redis_addr.clone();
redis.send(Command(resp_array!["DEL", "mydomain:one", "mydomain:two", "mydomain:three"]))
redis
.send(Command(resp_array![
"DEL",
"mydomain:one",
"mydomain:two",
"mydomain:three"
]))
.map_err(AWError::from)
.and_then(|res: Result<RespValue, ARError>|
match &res {
Ok(RespValue::Integer(x)) if x==&3 =>
Ok(HttpResponse::Ok().body("successfully deleted values")),
_ =>{println!("---->{:?}", res);
Ok(HttpResponse::InternalServerError().finish())}
.and_then(|res: Result<RespValue, ARError>| match &res {
Ok(RespValue::Integer(x)) if x == &3 => {
Ok(HttpResponse::Ok().body("successfully deleted values"))
}
_ => {
println!("---->{:?}", res);
Ok(HttpResponse::InternalServerError().finish())
}
})
.responder()
}
pub struct AppState {
pub redis_addr: Arc<Addr<RedisActor>>
pub redis_addr: Arc<Addr<RedisActor>>,
}
fn main() {
@ -92,12 +102,11 @@ fn main() {
App::with_state(app_state)
.middleware(middleware::Logger::default())
.resource("/stuff", |r| {
r.method(Method::POST)
.with_async(cache_stuff);
r.method(Method::DELETE)
.with_async(del_stuff)})
}).bind("0.0.0.0:8080")
r.method(Method::POST).with_async(cache_stuff);
r.method(Method::DELETE).with_async(del_stuff)
})
})
.bind("0.0.0.0:8080")
.unwrap()
.workers(1)
.start();

View File

@ -32,7 +32,8 @@ pub fn index(req: HttpRequest<AppState>) -> FutureResponse<HttpResponse> {
session::clear_flash(&req);
}
let rendered = req.state()
let rendered = req
.state()
.template
.render("index.html.tera", &context)
.map_err(|e| {
@ -61,7 +62,8 @@ pub fn create(
FlashMessage::error("Description cannot be empty"),
)?;
Ok(redirect_to("/"))
}).responder()
})
.responder()
} else {
req.state()
.db

View File

@ -3,7 +3,8 @@ use diesel::pg::PgConnection;
use diesel::prelude::*;
use schema::{
tasks, tasks::dsl::{completed as task_completed, tasks as all_tasks},
tasks,
tasks::dsl::{completed as task_completed, tasks as all_tasks},
};
#[derive(Debug, Insertable)]

View File

@ -2,10 +2,13 @@
name = "awc_examples"
version = "0.1.0"
authors = ["dowwie <dkcdkg@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix = "0.7"
actix-web = { version="0.7.3", features=["rust-tls"] }
actix-rt = "0.2"
actix-http = { git="https://github.com/actix/actix-http.git", features=["ssl"] }
actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0", features=["ssl"] }
futures = "0.1"
serde = "1.0.43"

View File

@ -15,25 +15,17 @@
// There are 2 versions in this example, one that uses Boxed Futures and the
// other that uses Impl Future, available since rustc v1.26.
extern crate actix;
extern crate actix_web;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate validator_derive;
extern crate env_logger;
extern crate futures;
extern crate validator;
#[macro_use]
extern crate serde_derive;
use actix_web::{
client, http::Method, server, App, AsyncResponder, Error, HttpMessage, HttpResponse,
Json,
};
use futures::{future::ok as fut_ok, Future};
use std::collections::HashMap;
use std::time::Duration;
use std::io;
use actix_http::client;
use actix_web::{web, App, Error, HttpMessage, HttpResponse, HttpServer};
use futures::future::{ok, Future};
use validator::Validate;
#[derive(Debug, Validate, Deserialize, Serialize)]
@ -62,28 +54,30 @@ struct HttpBinResponse {
/// post json to httpbin, get it back in the response body, return deserialized
fn step_x_v1(data: SomeData) -> Box<Future<Item = SomeData, Error = Error>> {
let mut connector = client::Connector::default().service();
Box::new(
client::ClientRequest::post("https://httpbin.org/post")
.json(data).unwrap()
.send()
.conn_timeout(Duration::from_secs(10))
.json(data)
.unwrap()
.send(&mut connector)
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
.and_then(|mut resp| {
resp.body() // <- this is MessageBody type, resolves to complete body
.from_err() // <- convert PayloadError to an Error
.and_then(|body| {
let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap();
fut_ok(resp.json)
let resp: HttpBinResponse =
serde_json::from_slice(&body).unwrap();
ok(resp.json)
})
),
}),
)
}
fn create_something_v1(
some_data: Json<SomeData>,
some_data: web::Json<SomeData>,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
step_x_v1(some_data.into_inner())
.and_then(|some_data_2| {
Box::new(step_x_v1(some_data.into_inner()).and_then(|some_data_2| {
step_x_v1(some_data_2).and_then(|some_data_3| {
step_x_v1(some_data_3).and_then(|d| {
Ok(HttpResponse::Ok()
@ -92,8 +86,7 @@ fn create_something_v1(
.into())
})
})
})
.responder()
}))
}
// ---------------------------------------------------------------
@ -102,23 +95,25 @@ fn create_something_v1(
/// post json to httpbin, get it back in the response body, return deserialized
fn step_x_v2(data: SomeData) -> impl Future<Item = SomeData, Error = Error> {
let mut connector = client::Connector::default().service();
client::ClientRequest::post("https://httpbin.org/post")
.json(data).unwrap()
.send()
.conn_timeout(Duration::from_secs(10))
.json(data)
.unwrap()
.send(&mut connector)
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
.and_then(|mut resp| {
resp.body() // <- this is MessageBody type, resolves to complete body
.from_err() // <- convert PayloadError to an Error
.and_then(|body| {
let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap();
fut_ok(resp.json)
ok(resp.json)
})
})
)
}
fn create_something_v2(
some_data: Json<SomeData>,
some_data: web::Json<SomeData>,
) -> impl Future<Item = HttpResponse, Error = Error> {
step_x_v2(some_data.into_inner()).and_then(|some_data_2| {
step_x_v2(some_data_2).and_then(|some_data_3| {
@ -132,23 +127,21 @@ fn create_something_v2(
})
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("asyncio_example");
server::new(move || {
HttpServer::new(|| {
App::new()
.resource("/something_v1", |r| {
r.method(Method::POST).with(create_something_v1)
.service(
web::resource("/something_v1")
.route(web::post().to(create_something_v1)),
)
.service(
web::resource("/something_v2")
.route(web::post().to_async(create_something_v2)),
)
})
.resource("/something_v2", |r| {
r.method(Method::POST).with_async(create_something_v2)
})
}).bind("127.0.0.1:8088")
.unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
let _ = sys.run();
.bind("127.0.0.1:8088")?
.run()
}

View File

@ -1,14 +0,0 @@
[package]
name = "cookie-auth-full"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../"
[dependencies]
actix = "0.7"
actix-web = "0.7"
cookie = { version="0.11", features=["percent-encode", "secure"] }
futures = "0.1"
time = "0.1"
env_logger = "0.5"

View File

@ -1,274 +0,0 @@
#![allow(dead_code)]
use std::rc::Rc;
use cookie::{Cookie, CookieJar, Key};
use futures::future::{err as FutErr, ok as FutOk, FutureResult};
use futures::Future;
use time::Duration;
use actix_web::http::header::{self, HeaderValue};
use actix_web::middleware::{Middleware, Response, Started};
use actix_web::{Error, HttpRequest, HttpResponse, Result};
/// Trait provides identity service for the request.
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(&self) -> Option<String>;
/// Remember identity.
fn remember(&self, identity: String);
/// This method is used to 'forget' the current identity on subsequent
/// requests.
fn forget(&self);
}
impl<S> RequestIdentity for HttpRequest<S> {
fn identity(&self) -> Option<String> {
if let Some(id) = self.extensions().get::<IdentityBox>() {
return id.0.identity().map(|s| s.to_owned());
}
None
}
fn remember(&self, identity: String) {
if let Some(id) = self.extensions_mut().get_mut::<IdentityBox>() {
return id.0.as_mut().remember(identity);
}
}
fn forget(&self) {
if let Some(id) = self.extensions_mut().get_mut::<IdentityBox>() {
return id.0.forget();
}
}
}
/// An identity
pub trait Identity: 'static {
fn identity(&self) -> Option<&str>;
fn remember(&mut self, key: String);
fn forget(&mut self);
/// Write session to storage backend.
fn write(&mut self, resp: HttpResponse) -> Result<Response>;
}
/// Identity policy definition.
pub trait IdentityPolicy<S>: Sized + 'static {
type Identity: Identity;
type Future: Future<Item = Self::Identity, Error = Error>;
/// Parse the session from request and load data from a service identity.
fn from_request(&self, request: &mut HttpRequest<S>) -> Self::Future;
}
/// Middleware that implements identity service
pub struct IdentityService<T> {
backend: T,
}
impl<T> IdentityService<T> {
/// Create new identity service with specified backend.
pub fn new(backend: T) -> Self {
IdentityService { backend }
}
}
struct IdentityBox(Box<Identity>);
#[doc(hidden)]
unsafe impl Send for IdentityBox {}
#[doc(hidden)]
unsafe impl Sync for IdentityBox {}
impl<S: 'static, T: IdentityPolicy<S>> Middleware<S> for IdentityService<T> {
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
let mut req = req.clone();
let fut = self
.backend
.from_request(&mut req)
.then(move |res| match res {
Ok(id) => {
req.extensions_mut().insert(IdentityBox(Box::new(id)));
FutOk(None)
}
Err(err) => FutErr(err),
});
Ok(Started::Future(Box::new(fut)))
}
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 {
Ok(Response::Done(resp))
}
}
}
/// Identity that uses private cookies as identity storage
pub struct CookieIdentity {
changed: bool,
identity: Option<String>,
inner: Rc<CookieIdentityInner>,
}
impl Identity for CookieIdentity {
fn identity(&self) -> Option<&str> {
self.identity.as_ref().map(|s| s.as_ref())
}
fn remember(&mut self, value: String) {
self.changed = true;
self.identity = Some(value);
}
fn forget(&mut self) {
self.changed = true;
self.identity = None;
}
fn write(&mut self, mut resp: HttpResponse) -> Result<Response> {
if self.changed {
let _ = self.inner.set_cookie(&mut resp, self.identity.take());
}
Ok(Response::Done(resp))
}
}
struct CookieIdentityInner {
key: Key,
name: String,
path: String,
domain: Option<String>,
secure: bool,
max_age: Option<Duration>,
}
impl CookieIdentityInner {
fn new(key: &[u8]) -> CookieIdentityInner {
CookieIdentityInner {
key: Key::from_master(key),
name: "actix-identity".to_owned(),
path: "/".to_owned(),
domain: None,
secure: true,
max_age: None,
}
}
fn set_cookie(&self, resp: &mut HttpResponse, id: Option<String>) -> Result<()> {
let some = id.is_some();
{
let id = id.unwrap_or_else(|| String::new());
let mut cookie = Cookie::new(self.name.clone(), id);
cookie.set_path(self.path.clone());
cookie.set_secure(self.secure);
cookie.set_http_only(true);
if let Some(ref domain) = self.domain {
cookie.set_domain(domain.clone());
}
if let Some(max_age) = self.max_age {
cookie.set_max_age(max_age);
}
let mut jar = CookieJar::new();
if some {
jar.private(&self.key).add(cookie);
} else {
jar.add_original(cookie.clone());
jar.private(&self.key).remove(cookie);
}
for cookie in jar.delta() {
let val = HeaderValue::from_str(&cookie.to_string())?;
resp.headers_mut().append(header::SET_COOKIE, val);
}
}
Ok(())
}
fn load<S>(&self, req: &mut HttpRequest<S>) -> Option<String> {
if let Ok(cookies) = req.cookies() {
for cookie in cookies.iter() {
if cookie.name() == self.name {
let mut jar = CookieJar::new();
jar.add_original(cookie.clone());
let cookie_opt = jar.private(&self.key).get(&self.name);
if let Some(cookie) = cookie_opt {
return Some(cookie.value().into());
}
}
}
}
None
}
}
/// Use cookies for request identity.
pub struct CookieIdentityPolicy(Rc<CookieIdentityInner>);
impl CookieIdentityPolicy {
/// Construct new `CookieIdentityPolicy` instance.
///
/// Panics if key length is less than 32 bytes.
pub fn new(key: &[u8]) -> CookieIdentityPolicy {
CookieIdentityPolicy(Rc::new(CookieIdentityInner::new(key)))
}
/// Sets the `path` field in the session cookie being built.
pub fn path<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
Rc::get_mut(&mut self.0).unwrap().path = value.into();
self
}
/// Sets the `name` field in the session cookie being built.
pub fn name<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
Rc::get_mut(&mut self.0).unwrap().name = value.into();
self
}
/// Sets the `domain` field in the session cookie being built.
pub fn domain<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
self
}
/// Sets the `secure` field in the session cookie being built.
///
/// If the `secure` field is set, a cookie will only be transmitted when the
/// connection is secure - i.e. `https`
pub fn secure(mut self, value: bool) -> CookieIdentityPolicy {
Rc::get_mut(&mut self.0).unwrap().secure = value;
self
}
/// Sets the `max-age` field in the session cookie being built.
pub fn max_age(mut self, value: Duration) -> CookieIdentityPolicy {
Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
self
}
}
impl<S> IdentityPolicy<S> for CookieIdentityPolicy {
type Identity = CookieIdentity;
type Future = FutureResult<CookieIdentity, Error>;
fn from_request(&self, req: &mut HttpRequest<S>) -> Self::Future {
let identity = self.0.load(req);
FutOk(CookieIdentity {
identity,
changed: false,
inner: Rc::clone(&self.0),
})
}
}

View File

@ -1,49 +0,0 @@
extern crate actix;
extern crate actix_web;
extern crate cookie;
extern crate env_logger;
extern crate futures;
extern crate time;
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
mod auth;
use auth::{CookieIdentityPolicy, IdentityService, RequestIdentity};
fn index(req: &HttpRequest) -> String {
format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned()))
}
fn login(req: &HttpRequest) -> HttpResponse {
req.remember("user1".to_owned());
HttpResponse::Found().header("location", "/").finish()
}
fn logout(req: &HttpRequest) -> HttpResponse {
req.forget();
HttpResponse::Found().header("location", "/").finish()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("cookie-auth");
server::new(|| {
App::new()
.middleware(middleware::Logger::default())
.middleware(IdentityService::new(
CookieIdentityPolicy::new(&[0; 32])
.name("auth-example")
.secure(false),
))
.resource("/login", |r| r.f(login))
.resource("/logout", |r| r.f(logout))
.resource("/", |r| r.f(index))
}).bind("127.0.0.1:8080")
.unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -5,6 +5,5 @@ 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" }
env_logger = "0.5"

View File

@ -2,9 +2,9 @@ extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
use actix_web::middleware::identity::RequestIdentity;
use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
fn index(req: &HttpRequest) -> String {
format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned()))
@ -36,7 +36,8 @@ fn main() {
.resource("/login", |r| r.f(login))
.resource("/logout", |r| r.f(logout))
.resource("/", |r| r.f(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -2,12 +2,13 @@
name = "cookie-session"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../"
workspace = ".."
edition = "2018"
[dependencies]
actix = "0.7"
actix-web = "^0.7"
actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
futures = "0.1"
time = "0.1"
env_logger = "0.5"
env_logger = "0.6"

View File

@ -5,50 +5,38 @@
//!
//! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions)
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
use actix_web::middleware::session::{self, RequestSession};
use actix_web::{middleware, server, App, HttpRequest, Result};
use std::env;
use actix_session::{CookieSession, Session};
use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result};
/// simple index handler with session
fn index(req: &HttpRequest) -> Result<&'static str> {
fn index(session: Session, req: HttpRequest) -> Result<&'static str> {
println!("{:?}", req);
// RequestSession trait is used for session access
let mut counter = 1;
if let Some(count) = req.session().get::<i32>("counter")? {
if let Some(count) = session.get::<i32>("counter")? {
println!("SESSION value: {}", count);
counter = count + 1;
req.session().set("counter", counter)?;
session.set("counter", counter)?;
} else {
req.session().set("counter", counter)?;
session.set("counter", counter)?;
}
Ok("welcome!")
}
fn main() {
env::set_var("RUST_LOG", "actix_web=info");
fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("session-example");
server::new(|| {
HttpServer::new(|| {
App::new()
// enable logger
.middleware(middleware::Logger::default())
.middleware(Logger::default())
// cookie session middleware
.middleware(session::SessionStorage::new(
session::CookieSessionBackend::signed(&[0; 32]).secure(false)
))
.resource("/", |r| r.f(index))
}).bind("127.0.0.1:8080")
.expect("Can not bind to 127.0.0.1:8080")
.start();
println!("Starting http server: 127.0.0.1:8080");
let _ = sys.run();
.middleware(CookieSession::signed(&[0; 32]).secure(false))
.service(web::resource("/").to(index))
})
.bind("127.0.0.1:8080")?
.run()
}

View File

@ -2,11 +2,13 @@
name = "error_handling"
version = "0.1.0"
authors = ["dowwie <dkcdkg@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix = "0.7.3"
actix-web = "0.7.3"
failure = "0.1.2"
actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
derive_more = "0.14.0"
futures = "0.1.23"
rand = "0.5.4"
env_logger = "0.5.12"
env_logger = "0.6"

View File

@ -1,6 +1,6 @@
/*
The goal of this example is to show how to propagate a custom error type, derived
from the Fail trait, to a web handler that will evaluate the type of error that
The goal of this example is to show how to propagate a custom error type,
to a web handler that will evaluate the type of error that
was raised and return an appropriate HTTPResponse.
This example uses a 50/50 chance of returning 200 Ok, otherwise one of four possible
@ -12,128 +12,91 @@ http errors will be chosen, each with an equal chance of being selected:
*/
extern crate actix;
extern crate actix_web;
extern crate env_logger;
#[macro_use] extern crate failure;
extern crate futures;
extern crate rand;
use actix_web::{
http::Method, server, App, AsyncResponder, Error as ActixWebError,
HttpResponse, HttpRequest
use actix_web::{web, App, Error, HttpResponse, HttpServer, ResponseError};
use derive_more::Display; // naming it clearly for illustration purposes
use futures::future::{err, ok, Future};
use rand::{
distributions::{Distribution, Standard},
thread_rng, Rng,
};
use failure::Error as FailureError; // naming it clearly for illustration purposes
use futures::{
future::{
ok as fut_ok,
err as fut_err
},
Future
};
use rand::{thread_rng, Rng, distributions::{Distribution, Standard}};
#[derive(Fail, Debug)]
#[derive(Debug, Display)]
pub enum CustomError {
#[fail(display = "Custom Error 1")]
#[display(fmt = "Custom Error 1")]
CustomOne,
#[fail(display = "Custom Error 2")]
#[display(fmt = "Custom Error 2")]
CustomTwo,
#[fail(display = "Custom Error 3")]
#[display(fmt = "Custom Error 3")]
CustomThree,
#[fail(display = "Custom Error 4")]
CustomFour
#[display(fmt = "Custom Error 4")]
CustomFour,
}
impl Distribution<CustomError> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> CustomError {
match rng.gen_range(0, 4) {
0 => CustomError::CustomOne,
1 => CustomError::CustomTwo,
2 => CustomError::CustomThree,
_ => CustomError::CustomFour
_ => CustomError::CustomFour,
}
}
}
/*
/// Actix web uses `ResponseError` for conversion of errors to a response
impl ResponseError for CustomError {
fn error_response(&self) -> HttpResponse {
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
match self {
CustomError::CustomOne => {
println!("do some stuff related to CustomOne error");
HttpResponse::Forbidden().finish()
}
}
*/
CustomError::CustomTwo => {
println!("do some stuff related to CustomTwo error");
HttpResponse::Unauthorized().finish()
}
CustomError::CustomThree => {
println!("do some stuff related to CustomThree error");
HttpResponse::InternalServerError().finish()
}
_ => {
println!("do some stuff related to CustomFour error");
HttpResponse::BadRequest().finish()
}
}
}
}
/// randomly returns either () or one of the 4 CustomError variants
//fn do_something_random() -> impl Future<Item = Result<(), FailureError>,
// Error = ActixWebError> {
fn do_something_random() -> impl Future<Item = (), Error = CustomError> {
let mut rng = thread_rng();
// 20% chance that () will be returned by this function
if rng.gen_bool(2.0 / 10.0) {
return fut_ok(())
}
let err: CustomError = rand::random();
return fut_err(err)
}
fn do_something(_req: HttpRequest)
-> impl Future<Item = HttpResponse, Error = ActixWebError> {
do_something_random()
.then(|result| match result {
Ok(_) => Ok(HttpResponse::Ok()
.body("Nothing interesting happened. Try again.")),
Err(err) => match err {
CustomError::CustomOne => {
println!("do some stuff related to CustomOne error");
Ok(HttpResponse::Forbidden().finish())
},
CustomError::CustomTwo => {
println!("do some stuff related to CustomTwo error");
Ok(HttpResponse::Unauthorized().finish())
},
CustomError::CustomThree => {
println!("do some stuff related to CustomThree error");
Ok(HttpResponse::InternalServerError().finish())
},
_ => {
println!("do some stuff related to CustomFour error");
Ok(HttpResponse::BadRequest().finish())
ok(())
} else {
err(rand::random::<CustomError>())
}
}
fn do_something() -> impl Future<Item = HttpResponse, Error = Error> {
do_something_random().from_err().and_then(|_| {
HttpResponse::Ok().body("Nothing interesting happened. Try again.")
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("error_handling_example");
server::new(move || {
App::new()
.resource("/something", |r|
r.method(Method::GET)
.with_async(do_something))
}).bind("127.0.0.1:8088")
.unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
let _ = sys.run();
HttpServer::new(move || {
App::new().service(
web::resource("/something").route(web::get().to_async(do_something)),
)
})
.bind("127.0.0.1:8088")?
.run()
}

View File

@ -18,7 +18,8 @@ fn main() {
let _addr = server::new(|| {
App::with_state(AppState {
foo: "bar".to_string(),
}).middleware(middleware::Logger::default())
})
.middleware(middleware::Logger::default())
.resource("/", |r| {
r.method(http::Method::GET).with(index);
})
@ -31,7 +32,8 @@ fn main() {
.resource("/post3", |r| {
r.method(http::Method::POST).with(handle_post_3)
})
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.expect("Can not bind to 127.0.0.1:8080")
.start();

View File

@ -19,7 +19,8 @@ fn main() {
.middleware(middleware::Logger::default())
.resource("/index.html", |r| r.f(|_| "Hello world!"))
.resource("/", |r| r.f(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -87,25 +87,29 @@ fn main() {
.value_name("LISTEN ADDR")
.index(1)
.required(true),
).arg(
)
.arg(
Arg::with_name("listen_port")
.takes_value(true)
.value_name("LISTEN PORT")
.index(2)
.required(true),
).arg(
)
.arg(
Arg::with_name("forward_addr")
.takes_value(true)
.value_name("FWD ADDR")
.index(3)
.required(true),
).arg(
)
.arg(
Arg::with_name("forward_port")
.takes_value(true)
.value_name("FWD PORT")
.index(4)
.required(true),
).get_matches();
)
.get_matches();
let listen_addr = matches.value_of("listen_addr").unwrap();
let listen_port = value_t!(matches, "listen_port", u16).unwrap_or_else(|e| e.exit());
@ -121,13 +125,15 @@ fn main() {
.unwrap()
.next()
.unwrap()
)).unwrap();
))
.unwrap();
server::new(move || {
App::with_state(AppState::init(forward_url.clone())).default_resource(|r| {
r.f(forward);
})
}).workers(32)
})
.workers(32)
.bind((listen_addr, listen_port))
.expect("Cannot bind listening port")
.system_exit()

View File

@ -12,15 +12,18 @@ 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>> {
client::ClientRequest::get("http://127.0.0.1:8081/")
.finish().unwrap()
.finish()
.unwrap()
.send()
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
.and_then(|resp| {
resp.body() // <- this is MessageBody type, resolves to complete body
.from_err() // <- convert PayloadError to an Error
.and_then(|body| { // <- we got complete body, now send as server response
.and_then(|body| {
// <- we got complete body, now send as server response
Ok(HttpResponse::Ok().body(body))
}))
})
})
.responder()
}
@ -28,10 +31,12 @@ fn index(_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()
.finish()
.unwrap()
.send() // <- connect to host and send request
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(|resp| { // <- we received client response
.and_then(|resp| {
// <- we received client response
Ok(HttpResponse::Ok()
// read one chunk from client response and send this chunk to a server response
// .from_err() converts PayloadError to an Error
@ -50,7 +55,8 @@ fn main() {
.middleware(middleware::Logger::default())
.resource("/streaming", |r| r.f(streaming))
.resource("/", |r| r.f(index))
}).workers(1)
})
.workers(1)
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -24,7 +24,8 @@ fn main() {
.middleware(middleware::Logger::default())
.resource("/index.html", |r| r.f(|_| "Hello world!"))
.resource("/", |r| r.f(index))
}).workers(1)
})
.workers(1)
.bind("127.0.0.1:8081")
.unwrap()
.start();

View File

@ -93,12 +93,15 @@ fn main() {
// Start http server
server::new(move || {
App::with_state(AppState{executor: addr.clone()})
App::with_state(AppState {
executor: addr.clone(),
})
// enable logger
.middleware(middleware::Logger::default())
.resource("/graphql", |r| r.method(http::Method::POST).with(graphql))
.resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -16,12 +16,15 @@ fn main() {
.middleware(simple::SayHi)
// .middleware(redirect::CheckLogin)
.resource("/login", |r| {
r.f(|_| "You are on /login. Go to src/redirect.rs to change this behavior.")
r.f(|_| {
"You are on /login. Go to src/redirect.rs to change this behavior."
})
})
.resource("/", |r| {
r.f(|_| "Hello, middleware! Check the console where the server is run.")
})
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -101,12 +101,14 @@ fn main() {
server::new(|| {
App::with_state(AppState {
counter: Cell::new(0),
}).middleware(middleware::Logger::default())
})
.middleware(middleware::Logger::default())
.resource("/", |r| {
r.method(http::Method::GET).with(index);
r.method(http::Method::POST).with(upload);
})
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -45,7 +45,8 @@ fn main() {
App::new()
.middleware(middleware::Logger::default())
.resource("/", |r| r.method(http::Method::POST).f(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.shutdown_timeout(1)
.start();

View File

@ -35,12 +35,14 @@ fn main() {
// enable logger
.middleware(middleware::Logger::default())
// redis session middleware
.middleware(SessionStorage::new(
RedisSessionBackend::new("127.0.0.1:6379", &[0; 32])
))
.middleware(SessionStorage::new(RedisSessionBackend::new(
"127.0.0.1:6379",
&[0; 32],
)))
// register simple route, handle all methods
.resource("/", |r| r.f(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -49,13 +49,16 @@ fn main() {
// register simple handler, handle all methods
.resource("/index.html", |r| r.f(index))
// with path parameters
.resource("/", |r| r.method(http::Method::GET).f(|_| {
.resource("/", |r| {
r.method(http::Method::GET).f(|_| {
HttpResponse::Found()
.header("LOCATION", "/index.html")
.finish()
}))
})
})
.handler("/static", StaticFiles::new("static").unwrap())
}).bind_with("127.0.0.1:8443", move || acceptor.clone())
})
.bind_with("127.0.0.1:8443", move || acceptor.clone())
.unwrap()
.start();

View File

@ -14,8 +14,10 @@ pub struct AppState {
/// creates and returns the app after mounting all routes/resources
pub fn create_app(db: Addr<DbExecutor>) -> App<AppState> {
// secret is a random minimum 32 bytes long base 64 string
let secret: String = std::env::var("SECRET_KEY").unwrap_or_else(|_| "0123".repeat(8));
let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string());
let secret: String =
std::env::var("SECRET_KEY").unwrap_or_else(|_| "0123".repeat(8));
let domain: String =
std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string());
App::with_state(AppState { db })
.middleware(Logger::default())

View File

@ -1,9 +1,9 @@
use actix::{Handler, Message};
use actix_web::{middleware::identity::RequestIdentity, FromRequest, HttpRequest};
use bcrypt::verify;
use diesel::prelude::*;
use errors::ServiceError;
use models::{DbExecutor, User, SlimUser};
use bcrypt::verify;
use actix_web::{FromRequest, HttpRequest, middleware::identity::RequestIdentity};
use models::{DbExecutor, SlimUser, User};
use utils::decode_token;
#[derive(Debug, Deserialize)]
@ -19,22 +19,24 @@ impl Message for AuthData {
impl Handler<AuthData> for DbExecutor {
type Result = Result<SlimUser, ServiceError>;
fn handle(&mut self, msg: AuthData, _: &mut Self::Context) -> Self::Result {
use schema::users::dsl::{users, email};
use schema::users::dsl::{email, users};
let conn: &PgConnection = &self.0.get().unwrap();
let mut items = users
.filter(email.eq(&msg.email))
.load::<User>(conn)?;
let mut items = users.filter(email.eq(&msg.email)).load::<User>(conn)?;
if let Some(user) = items.pop() {
match verify(&msg.password, &user.password) {
Ok(matching) => if matching {
Ok(matching) => {
if matching {
return Ok(user.into());
},
}
}
Err(_) => (),
}
}
Err(ServiceError::BadRequest("Username and Password don't match".into()))
Err(ServiceError::BadRequest(
"Username and Password don't match".into(),
))
}
}

View File

@ -1,13 +1,16 @@
use actix_web::{AsyncResponder, FutureResponse, HttpResponse, HttpRequest, ResponseError, Json};
use actix_web::middleware::identity::RequestIdentity;
use actix_web::{
AsyncResponder, FutureResponse, HttpRequest, HttpResponse, Json, ResponseError,
};
use futures::future::Future;
use utils::create_token;
use app::AppState;
use auth_handler::{AuthData, LoggedUser};
pub fn login((auth_data, req): (Json<AuthData>, HttpRequest<AppState>))
-> FutureResponse<HttpResponse> {
pub fn login(
(auth_data, req): (Json<AuthData>, HttpRequest<AppState>),
) -> FutureResponse<HttpResponse> {
req.state()
.db
.send(auth_data.into_inner())
@ -19,7 +22,8 @@ pub fn login((auth_data, req): (Json<AuthData>, HttpRequest<AppState>))
Ok(HttpResponse::Ok().into())
}
Err(err) => Ok(err.error_response()),
}).responder()
})
.responder()
}
pub fn logout(req: HttpRequest<AppState>) -> HttpResponse {

View File

@ -9,8 +9,8 @@ fn get_api_key() -> String {
pub fn send_invitation(invitation: &Invitation) {
let tm = Transmission::new_eu(get_api_key());
let sending_email =
std::env::var("SENDING_EMAIL_ADDRESS").expect("SENDING_EMAIL_ADDRESS must be set");
let sending_email = std::env::var("SENDING_EMAIL_ADDRESS")
.expect("SENDING_EMAIL_ADDRESS must be set");
// new email message with sender name and email
let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise"));
@ -39,7 +39,6 @@ pub fn send_invitation(invitation: &Invitation) {
.to_string()
);
// complete the email message with details
email
.add_recipient(recipient)
@ -51,16 +50,14 @@ pub fn send_invitation(invitation: &Invitation) {
// Note that we only print out the error response from email api
match result {
Ok(res) => {
match res {
Ok(res) => match res {
TransmissionResponse::ApiResponse(api_res) => {
println!("API Response: \n {:#?}", api_res);
}
TransmissionResponse::ApiError(errors) => {
println!("Response Errors: \n {:#?}", &errors);
}
}
}
},
Err(error) => {
println!("error \n {:#?}", error);
}

View File

@ -1,9 +1,8 @@
use actix_web::{error::ResponseError, HttpResponse};
use std::convert::From;
use diesel::result::{DatabaseErrorKind, Error};
use std::convert::From;
use uuid::ParseError;
#[derive(Fail, Debug)]
pub enum ServiceError {
#[fail(display = "Internal Server Error")]
@ -20,9 +19,14 @@ pub enum ServiceError {
impl ResponseError for ServiceError {
fn error_response(&self) -> HttpResponse {
match *self {
ServiceError::InternalServerError => HttpResponse::InternalServerError().json("Internal Server Error, Please try later"),
ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message),
ServiceError::Unauthorized => HttpResponse::Unauthorized().json("Unauthorized")
ServiceError::InternalServerError => HttpResponse::InternalServerError()
.json("Internal Server Error, Please try later"),
ServiceError::BadRequest(ref message) => {
HttpResponse::BadRequest().json(message)
}
ServiceError::Unauthorized => {
HttpResponse::Unauthorized().json("Unauthorized")
}
}
}
}
@ -42,12 +46,13 @@ impl From<Error> for ServiceError {
match error {
Error::DatabaseError(kind, info) => {
if let DatabaseErrorKind::UniqueViolation = kind {
let message = info.details().unwrap_or_else(|| info.message()).to_string();
let message =
info.details().unwrap_or_else(|| info.message()).to_string();
return ServiceError::BadRequest(message);
}
ServiceError::InternalServerError
}
_ => ServiceError::InternalServerError
_ => ServiceError::InternalServerError,
}
}
}

View File

@ -35,5 +35,3 @@ impl Handler<CreateInvitation> for DbExecutor {
Ok(inserted_invitation)
}
}

View File

@ -1,4 +1,6 @@
use actix_web::{AsyncResponder, FutureResponse, HttpResponse, Json, ResponseError, State};
use actix_web::{
AsyncResponder, FutureResponse, HttpResponse, Json, ResponseError, State,
};
use futures::future::Future;
use app::AppState;
@ -18,5 +20,6 @@ pub fn register_email(
Ok(HttpResponse::Ok().into())
}
Err(err) => Ok(err.error_response()),
}).responder()
})
.responder()
}

View File

@ -1,18 +1,18 @@
// to avoid the warning from diesel macros
#![allow(proc_macro_derive_resolution_fallback)]
extern crate bcrypt;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate serde;
extern crate bcrypt;
extern crate chrono;
extern crate dotenv;
extern crate env_logger;
extern crate futures;
extern crate r2d2;
extern crate uuid;
extern crate jsonwebtoken as jwt;
extern crate r2d2;
extern crate serde;
extern crate sparkpost;
extern crate uuid;
#[macro_use]
extern crate diesel;
#[macro_use]
@ -21,26 +21,25 @@ extern crate serde_derive;
extern crate failure;
mod app;
mod models;
mod schema;
mod errors;
mod auth_handler;
mod auth_routes;
mod email_service;
mod errors;
mod invitation_handler;
mod invitation_routes;
mod models;
mod register_handler;
mod register_routes;
mod schema;
mod utils;
mod email_service;
use models::DbExecutor;
use actix::prelude::*;
use actix_web::server;
use diesel::{r2d2::ConnectionManager, PgConnection};
use dotenv::dotenv;
use models::DbExecutor;
use std::env;
fn main() {
dotenv().ok();
std::env::set_var("RUST_LOG", "simple-auth-server=debug,actix_web=info");
@ -55,7 +54,8 @@ fn main() {
.build(manager)
.expect("Failed to create pool.");
let address: Addr<DbExecutor> = SyncArbiter::start(4, move || DbExecutor(pool.clone()));
let address: Addr<DbExecutor> =
SyncArbiter::start(4, move || DbExecutor(pool.clone()));
server::new(move || app::create_app(address.clone()))
.bind("127.0.0.1:3000")

View File

@ -1,11 +1,11 @@
use actix::{Actor, SyncContext};
use chrono::{Local, NaiveDateTime};
use diesel::pg::PgConnection;
use diesel::r2d2::{ConnectionManager, Pool};
use chrono::{NaiveDateTime, Local};
use uuid::Uuid;
use std::convert::From;
use uuid::Uuid;
use schema::{users, invitations};
use schema::{invitations, users};
/// This is db executor actor. can be run in parallel
pub struct DbExecutor(pub Pool<ConnectionManager<PgConnection>>);
@ -51,8 +51,6 @@ pub struct SlimUser {
impl From<User> for SlimUser {
fn from(user: User) -> Self {
SlimUser {
email: user.email
}
SlimUser { email: user.email }
}
}

View File

@ -2,9 +2,9 @@ use actix::{Handler, Message};
use chrono::Local;
use diesel::prelude::*;
use errors::ServiceError;
use models::{DbExecutor, Invitation, User, SlimUser};
use uuid::Uuid;
use models::{DbExecutor, Invitation, SlimUser, User};
use utils::hash_password;
use uuid::Uuid;
// UserData is used to extract data from a post request by the client
#[derive(Debug, Deserialize)]
@ -23,11 +23,10 @@ impl Message for RegisterUser {
type Result = Result<SlimUser, ServiceError>;
}
impl Handler<RegisterUser> for DbExecutor {
type Result = Result<SlimUser, ServiceError>;
fn handle(&mut self, msg: RegisterUser, _: &mut Self::Context) -> Self::Result {
use schema::invitations::dsl::{invitations, id};
use schema::invitations::dsl::{id, invitations};
use schema::users::dsl::users;
let conn: &PgConnection = &self.0.get().unwrap();
@ -35,7 +34,8 @@ impl Handler<RegisterUser> for DbExecutor {
// return early with error that will be converted to ServiceError
let invitation_id = Uuid::parse_str(&msg.invitation_id)?;
invitations.filter(id.eq(invitation_id))
invitations
.filter(id.eq(invitation_id))
.load::<Invitation>(conn)
.map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into()))
.and_then(|mut result| {
@ -45,9 +45,8 @@ impl Handler<RegisterUser> for DbExecutor {
// try hashing the password, else return the error that will be converted to ServiceError
let password: String = hash_password(&msg.password)?;
let user = User::with_details(invitation.email, password);
let inserted_user: User = diesel::insert_into(users)
.values(&user)
.get_result(conn)?;
let inserted_user: User =
diesel::insert_into(users).values(&user).get_result(conn)?;
return Ok(inserted_user.into());
}
@ -56,5 +55,3 @@ impl Handler<RegisterUser> for DbExecutor {
})
}
}

View File

@ -1,22 +1,27 @@
use actix_web::{AsyncResponder, FutureResponse, HttpResponse, ResponseError, State, Json, Path};
use actix_web::{
AsyncResponder, FutureResponse, HttpResponse, Json, Path, ResponseError, State,
};
use futures::future::Future;
use app::AppState;
use register_handler::{RegisterUser, UserData};
pub fn register_user((invitation_id, user_data, state): (Path<String>, Json<UserData>, State<AppState>))
-> FutureResponse<HttpResponse> {
pub fn register_user(
(invitation_id, user_data, state): (Path<String>, Json<UserData>, State<AppState>),
) -> FutureResponse<HttpResponse> {
let msg = RegisterUser {
// into_inner() returns the inner string value from Path
invitation_id: invitation_id.into_inner(),
password: user_data.password.clone(),
};
state.db.send(msg)
state
.db
.send(msg)
.from_err()
.and_then(|db_response| match db_response {
Ok(slim_user) => Ok(HttpResponse::Ok().json(slim_user)),
Err(service_error) => Ok(service_error.error_response()),
}).responder()
})
.responder()
}

View File

@ -14,7 +14,4 @@ table! {
}
}
allow_tables_to_appear_in_same_query!(
invitations,
users,
);
allow_tables_to_appear_in_same_query!(invitations, users,);

View File

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

View File

@ -24,7 +24,8 @@ fn index(query: Query<HashMap<String, String>>) -> Result<HttpResponse> {
UserTemplate {
name: name,
text: "Welcome!",
}.render()
}
.render()
.unwrap()
} else {
Index.render().unwrap()
@ -38,7 +39,8 @@ fn main() {
// start http server
server::new(move || {
App::new().resource("/", |r| r.method(http::Method::GET).with(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -48,7 +48,8 @@ fn main() {
// enable logger
.middleware(middleware::Logger::default())
.resource("/", |r| r.method(http::Method::GET).with(index))
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -23,7 +23,8 @@ fn main() {
.middleware(middleware::Logger::default())
.resource("/index.html", |r| r.f(|_| "Hello world!"))
.resource("/", |r| r.f(index))
}).start_incoming(listener.incoming(), false);
})
.start_incoming(listener.incoming(), false);
println!("Started http server: /tmp/actix-uds.socket");
let _ = sys.run();

View File

@ -39,7 +39,8 @@ fn main() {
})
.register()
})
}).bind("127.0.0.1:8000")
})
.bind("127.0.0.1:8000")
.unwrap()
.shutdown_timeout(2)
.start();

View File

@ -52,7 +52,8 @@ impl WsChatSession {
}
fut::ok(())
}).spawn(ctx);
})
.spawn(ctx);
}
fn list_rooms(&mut self, ctx: &mut ws::WebsocketContext<Self>) {
@ -66,7 +67,8 @@ impl WsChatSession {
}
}
fut::ok(())
}).spawn(ctx);
})
.spawn(ctx);
}
fn send_msg(&self, msg: &str) {
@ -158,7 +160,8 @@ fn main() {
.unwrap()
.index_file("index.html"),
)
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -12,7 +12,7 @@ extern crate tokio_io;
extern crate actix;
extern crate actix_web;
use std::time::{Instant, Duration};
use std::time::{Duration, Instant};
use actix::*;
use actix_web::server::HttpServer;
@ -185,7 +185,7 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for WsChatSession {
ws::Message::Binary(bin) => println!("Unexpected binary"),
ws::Message::Close(_) => {
ctx.stop();
},
}
}
}
}
@ -202,9 +202,7 @@ impl WsChatSession {
println!("Websocket Client heartbeat failed, disconnecting!");
// notify chat server
ctx.state()
.addr
.do_send(server::Disconnect { id: act.id });
ctx.state().addr.do_send(server::Disconnect { id: act.id });
// stop actor
ctx.stop();
@ -234,16 +232,19 @@ fn main() {
App::with_state(state)
// redirect to websocket.html
.resource("/", |r| r.method(http::Method::GET).f(|_| {
.resource("/", |r| {
r.method(http::Method::GET).f(|_| {
HttpResponse::Found()
.header("LOCATION", "/static/websocket.html")
.finish()
}))
})
})
// websocket
.resource("/ws/", |r| r.route().f(chat_route))
// static resources
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -65,7 +65,9 @@ impl Encoder for ChatCodec {
type Error = io::Error;
fn encode(
&mut self, msg: ChatResponse, dst: &mut BytesMut,
&mut self,
msg: ChatResponse,
dst: &mut BytesMut,
) -> Result<(), Self::Error> {
let msg = json::to_string(&msg).unwrap();
let msg_ref: &[u8] = msg.as_ref();
@ -108,7 +110,9 @@ impl Encoder for ClientChatCodec {
type Error = io::Error;
fn encode(
&mut self, msg: ChatRequest, dst: &mut BytesMut,
&mut self,
msg: ChatRequest,
dst: &mut BytesMut,
) -> Result<(), Self::Error> {
let msg = json::to_string(&msg).unwrap();
let msg_ref: &[u8] = msg.as_ref();

View File

@ -19,7 +19,7 @@ extern crate actix_web;
use actix::*;
use actix_web::server::HttpServer;
use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse};
use std::time::{Instant, Duration};
use std::time::{Duration, Instant};
mod codec;
mod server;
@ -191,7 +191,7 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for WsChatSession {
ws::Message::Binary(bin) => println!("Unexpected binary"),
ws::Message::Close(_) => {
ctx.stop();
},
}
}
}
}
@ -208,9 +208,7 @@ impl WsChatSession {
println!("Websocket Client heartbeat failed, disconnecting!");
// notify chat server
ctx.state()
.addr
.do_send(server::Disconnect { id: act.id });
ctx.state().addr.do_send(server::Disconnect { id: act.id });
// stop actor
ctx.stop();
@ -247,16 +245,19 @@ fn main() {
App::with_state(state)
// redirect to websocket.html
.resource("/", |r| r.method(http::Method::GET).f(|_| {
.resource("/", |r| {
r.method(http::Method::GET).f(|_| {
HttpResponse::Found()
.header("LOCATION", "/static/websocket.html")
.finish()
}))
})
})
// websocket
.resource("/ws/", |r| r.route().f(chat_route))
// static resources
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
}).bind("127.0.0.1:8080")
})
.bind("127.0.0.1:8080")
.unwrap()
.start();

View File

@ -8,7 +8,7 @@ extern crate actix;
extern crate actix_web;
extern crate env_logger;
use std::time::{Instant, Duration};
use std::time::{Duration, Instant};
use actix::prelude::*;
use actix_web::{
@ -96,18 +96,23 @@ fn main() {
env_logger::init();
let sys = actix::System::new("ws-example");
server::new(
|| App::new()
server::new(|| {
App::new()
// enable logger
.middleware(middleware::Logger::default())
// websocket route
.resource("/ws/", |r| r.method(http::Method::GET).f(ws_index))
// static files
.handler("/", fs::StaticFiles::new("static/")
.handler(
"/",
fs::StaticFiles::new("static/")
.unwrap()
.index_file("index.html")))
.index_file("index.html"),
)
})
// start http server on 127.0.0.1:8080
.bind("127.0.0.1:8080").unwrap()
.bind("127.0.0.1:8080")
.unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");