mirror of
https://github.com/actix/examples
synced 2024-11-23 22:41:07 +01:00
update more examples and rustfmt
This commit is contained in:
parent
f39a53ea3a
commit
e2945b9b39
@ -7,7 +7,6 @@ members = [
|
|||||||
"async_ex1",
|
"async_ex1",
|
||||||
"basics",
|
"basics",
|
||||||
"cookie-auth",
|
"cookie-auth",
|
||||||
"cookie-auth-full",
|
|
||||||
"cookie-session",
|
"cookie-session",
|
||||||
"diesel",
|
"diesel",
|
||||||
"error_handling",
|
"error_handling",
|
||||||
|
@ -3,30 +3,32 @@ extern crate actix_redis;
|
|||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
#[macro_use] extern crate redis_async;
|
#[macro_use]
|
||||||
|
extern crate redis_async;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use] extern crate serde_derive;
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use actix_redis::{Command, RedisActor, Error as ARError};
|
use actix_redis::{Command, Error as ARError, RedisActor};
|
||||||
use actix_web::{middleware, server, App, HttpRequest, HttpResponse, Json,
|
use actix_web::{
|
||||||
AsyncResponder, http::Method, Error as AWError};
|
http::Method, middleware, server, App, AsyncResponder, Error as AWError,
|
||||||
use futures::future::{Future, join_all};
|
HttpRequest, HttpResponse, Json,
|
||||||
|
};
|
||||||
|
use futures::future::{join_all, Future};
|
||||||
use redis_async::resp::RespValue;
|
use redis_async::resp::RespValue;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CacheInfo {
|
pub struct CacheInfo {
|
||||||
one: String,
|
one: String,
|
||||||
two: String,
|
two: String,
|
||||||
three: String
|
three: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cache_stuff(
|
||||||
fn cache_stuff((info, req): (Json<CacheInfo>, HttpRequest<AppState>))
|
(info, req): (Json<CacheInfo>, HttpRequest<AppState>),
|
||||||
-> impl Future<Item=HttpResponse, Error=AWError> {
|
) -> impl Future<Item = HttpResponse, Error = AWError> {
|
||||||
let info = info.into_inner();
|
let info = info.into_inner();
|
||||||
let redis = req.state().redis_addr.clone();
|
let redis = req.state().redis_addr.clone();
|
||||||
|
|
||||||
@ -59,25 +61,33 @@ fn cache_stuff((info, req): (Json<CacheInfo>, HttpRequest<AppState>))
|
|||||||
.responder()
|
.responder()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn del_stuff(req: HttpRequest<AppState>)
|
fn del_stuff(
|
||||||
-> impl Future<Item=HttpResponse, Error=AWError> {
|
req: HttpRequest<AppState>,
|
||||||
|
) -> impl Future<Item = HttpResponse, Error = AWError> {
|
||||||
let redis = req.state().redis_addr.clone();
|
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)
|
.map_err(AWError::from)
|
||||||
.and_then(|res: Result<RespValue, ARError>|
|
.and_then(|res: Result<RespValue, ARError>| match &res {
|
||||||
match &res {
|
Ok(RespValue::Integer(x)) if x == &3 => {
|
||||||
Ok(RespValue::Integer(x)) if x==&3 =>
|
Ok(HttpResponse::Ok().body("successfully deleted values"))
|
||||||
Ok(HttpResponse::Ok().body("successfully deleted values")),
|
}
|
||||||
_ =>{println!("---->{:?}", res);
|
_ => {
|
||||||
Ok(HttpResponse::InternalServerError().finish())}
|
println!("---->{:?}", res);
|
||||||
|
Ok(HttpResponse::InternalServerError().finish())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.responder()
|
.responder()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub redis_addr: Arc<Addr<RedisActor>>
|
pub redis_addr: Arc<Addr<RedisActor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -92,12 +102,11 @@ fn main() {
|
|||||||
App::with_state(app_state)
|
App::with_state(app_state)
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/stuff", |r| {
|
.resource("/stuff", |r| {
|
||||||
r.method(Method::POST)
|
r.method(Method::POST).with_async(cache_stuff);
|
||||||
.with_async(cache_stuff);
|
r.method(Method::DELETE).with_async(del_stuff)
|
||||||
r.method(Method::DELETE)
|
})
|
||||||
.with_async(del_stuff)})
|
})
|
||||||
|
.bind("0.0.0.0:8080")
|
||||||
}).bind("0.0.0.0:8080")
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.workers(1)
|
.workers(1)
|
||||||
.start();
|
.start();
|
||||||
|
@ -32,7 +32,8 @@ pub fn index(req: HttpRequest<AppState>) -> FutureResponse<HttpResponse> {
|
|||||||
session::clear_flash(&req);
|
session::clear_flash(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = req.state()
|
let rendered = req
|
||||||
|
.state()
|
||||||
.template
|
.template
|
||||||
.render("index.html.tera", &context)
|
.render("index.html.tera", &context)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@ -61,7 +62,8 @@ pub fn create(
|
|||||||
FlashMessage::error("Description cannot be empty"),
|
FlashMessage::error("Description cannot be empty"),
|
||||||
)?;
|
)?;
|
||||||
Ok(redirect_to("/"))
|
Ok(redirect_to("/"))
|
||||||
}).responder()
|
})
|
||||||
|
.responder()
|
||||||
} else {
|
} else {
|
||||||
req.state()
|
req.state()
|
||||||
.db
|
.db
|
||||||
|
@ -3,7 +3,8 @@ use diesel::pg::PgConnection;
|
|||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use schema::{
|
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)]
|
#[derive(Debug, Insertable)]
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
name = "awc_examples"
|
name = "awc_examples"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["dowwie <dkcdkg@gmail.com>"]
|
authors = ["dowwie <dkcdkg@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
workspace = ".."
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "0.7"
|
actix-rt = "0.2"
|
||||||
actix-web = { version="0.7.3", features=["rust-tls"] }
|
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"
|
futures = "0.1"
|
||||||
serde = "1.0.43"
|
serde = "1.0.43"
|
||||||
|
@ -15,25 +15,17 @@
|
|||||||
// There are 2 versions in this example, one that uses Boxed Futures and the
|
// There are 2 versions in this example, one that uses Boxed Futures and the
|
||||||
// other that uses Impl Future, available since rustc v1.26.
|
// 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]
|
#[macro_use]
|
||||||
extern crate validator_derive;
|
extern crate validator_derive;
|
||||||
extern crate env_logger;
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate serde_derive;
|
||||||
extern crate validator;
|
|
||||||
|
|
||||||
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::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;
|
use validator::Validate;
|
||||||
|
|
||||||
#[derive(Debug, Validate, Deserialize, Serialize)]
|
#[derive(Debug, Validate, Deserialize, Serialize)]
|
||||||
@ -62,28 +54,30 @@ struct HttpBinResponse {
|
|||||||
|
|
||||||
/// post json to httpbin, get it back in the response body, return deserialized
|
/// 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>> {
|
fn step_x_v1(data: SomeData) -> Box<Future<Item = SomeData, Error = Error>> {
|
||||||
|
let mut connector = client::Connector::default().service();
|
||||||
|
|
||||||
Box::new(
|
Box::new(
|
||||||
client::ClientRequest::post("https://httpbin.org/post")
|
client::ClientRequest::post("https://httpbin.org/post")
|
||||||
.json(data).unwrap()
|
.json(data)
|
||||||
.send()
|
.unwrap()
|
||||||
.conn_timeout(Duration::from_secs(10))
|
.send(&mut connector)
|
||||||
.map_err(Error::from) // <- convert SendRequestError to an Error
|
.map_err(Error::from) // <- convert SendRequestError to an Error
|
||||||
.and_then(
|
.and_then(|mut resp| {
|
||||||
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
|
resp.body() // <- this is MessageBody type, resolves to complete body
|
||||||
.from_err() // <- convert PayloadError to an Error
|
.from_err() // <- convert PayloadError to an Error
|
||||||
.and_then(|body| {
|
.and_then(|body| {
|
||||||
let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap();
|
let resp: HttpBinResponse =
|
||||||
fut_ok(resp.json)
|
serde_json::from_slice(&body).unwrap();
|
||||||
|
ok(resp.json)
|
||||||
})
|
})
|
||||||
),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_something_v1(
|
fn create_something_v1(
|
||||||
some_data: Json<SomeData>,
|
some_data: web::Json<SomeData>,
|
||||||
) -> Box<Future<Item = HttpResponse, Error = Error>> {
|
) -> Box<Future<Item = HttpResponse, Error = Error>> {
|
||||||
step_x_v1(some_data.into_inner())
|
Box::new(step_x_v1(some_data.into_inner()).and_then(|some_data_2| {
|
||||||
.and_then(|some_data_2| {
|
|
||||||
step_x_v1(some_data_2).and_then(|some_data_3| {
|
step_x_v1(some_data_2).and_then(|some_data_3| {
|
||||||
step_x_v1(some_data_3).and_then(|d| {
|
step_x_v1(some_data_3).and_then(|d| {
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
@ -92,8 +86,7 @@ fn create_something_v1(
|
|||||||
.into())
|
.into())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}))
|
||||||
.responder()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
@ -102,23 +95,25 @@ fn create_something_v1(
|
|||||||
|
|
||||||
/// post json to httpbin, get it back in the response body, return deserialized
|
/// 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> {
|
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")
|
client::ClientRequest::post("https://httpbin.org/post")
|
||||||
.json(data).unwrap()
|
.json(data)
|
||||||
.send()
|
.unwrap()
|
||||||
.conn_timeout(Duration::from_secs(10))
|
.send(&mut connector)
|
||||||
.map_err(Error::from) // <- convert SendRequestError to an Error
|
.map_err(Error::from) // <- convert SendRequestError to an Error
|
||||||
.and_then(
|
.and_then(|mut resp| {
|
||||||
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
|
resp.body() // <- this is MessageBody type, resolves to complete body
|
||||||
.from_err() // <- convert PayloadError to an Error
|
.from_err() // <- convert PayloadError to an Error
|
||||||
.and_then(|body| {
|
.and_then(|body| {
|
||||||
let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap();
|
let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap();
|
||||||
fut_ok(resp.json)
|
ok(resp.json)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_something_v2(
|
fn create_something_v2(
|
||||||
some_data: Json<SomeData>,
|
some_data: web::Json<SomeData>,
|
||||||
) -> impl Future<Item = HttpResponse, Error = Error> {
|
) -> impl Future<Item = HttpResponse, Error = Error> {
|
||||||
step_x_v2(some_data.into_inner()).and_then(|some_data_2| {
|
step_x_v2(some_data.into_inner()).and_then(|some_data_2| {
|
||||||
step_x_v2(some_data_2).and_then(|some_data_3| {
|
step_x_v2(some_data_2).and_then(|some_data_3| {
|
||||||
@ -132,23 +127,21 @@ fn create_something_v2(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> io::Result<()> {
|
||||||
::std::env::set_var("RUST_LOG", "actix_web=info");
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let sys = actix::System::new("asyncio_example");
|
|
||||||
|
|
||||||
server::new(move || {
|
HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
.resource("/something_v1", |r| {
|
.service(
|
||||||
r.method(Method::POST).with(create_something_v1)
|
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| {
|
.bind("127.0.0.1:8088")?
|
||||||
r.method(Method::POST).with_async(create_something_v2)
|
.run()
|
||||||
})
|
|
||||||
}).bind("127.0.0.1:8088")
|
|
||||||
.unwrap()
|
|
||||||
.start();
|
|
||||||
|
|
||||||
println!("Started http server: 127.0.0.1:8088");
|
|
||||||
let _ = sys.run();
|
|
||||||
}
|
}
|
||||||
|
@ -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"
|
|
@ -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),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
@ -5,6 +5,5 @@ authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
|||||||
workspace = "../"
|
workspace = "../"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "0.7"
|
actix-web = { git="https://github.com/actix/actix-web.git" }
|
||||||
actix-web = "0.7"
|
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
|
@ -2,9 +2,9 @@ extern crate actix;
|
|||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
|
|
||||||
use actix_web::middleware::identity::RequestIdentity;
|
use actix_web::middleware::identity::RequestIdentity;
|
||||||
use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
|
use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
|
||||||
|
use actix_web::{middleware, server, App, HttpRequest, HttpResponse};
|
||||||
|
|
||||||
fn index(req: &HttpRequest) -> String {
|
fn index(req: &HttpRequest) -> String {
|
||||||
format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned()))
|
format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned()))
|
||||||
@ -36,7 +36,8 @@ fn main() {
|
|||||||
.resource("/login", |r| r.f(login))
|
.resource("/login", |r| r.f(login))
|
||||||
.resource("/logout", |r| r.f(logout))
|
.resource("/logout", |r| r.f(logout))
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
name = "cookie-session"
|
name = "cookie-session"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
workspace = "../"
|
workspace = ".."
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "0.7"
|
actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
|
||||||
actix-web = "^0.7"
|
actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
|
||||||
|
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
env_logger = "0.5"
|
env_logger = "0.6"
|
||||||
|
@ -5,50 +5,38 @@
|
|||||||
//!
|
//!
|
||||||
//! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions)
|
//! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions)
|
||||||
|
|
||||||
extern crate actix;
|
use actix_session::{CookieSession, Session};
|
||||||
extern crate actix_web;
|
use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result};
|
||||||
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;
|
|
||||||
|
|
||||||
/// simple index handler with session
|
/// simple index handler with session
|
||||||
fn index(req: &HttpRequest) -> Result<&'static str> {
|
fn index(session: Session, req: HttpRequest) -> Result<&'static str> {
|
||||||
println!("{:?}", req);
|
println!("{:?}", req);
|
||||||
|
|
||||||
// RequestSession trait is used for session access
|
// RequestSession trait is used for session access
|
||||||
let mut counter = 1;
|
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);
|
println!("SESSION value: {}", count);
|
||||||
counter = count + 1;
|
counter = count + 1;
|
||||||
req.session().set("counter", counter)?;
|
session.set("counter", counter)?;
|
||||||
} else {
|
} else {
|
||||||
req.session().set("counter", counter)?;
|
session.set("counter", counter)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok("welcome!")
|
Ok("welcome!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
env::set_var("RUST_LOG", "actix_web=info");
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let sys = actix::System::new("session-example");
|
|
||||||
|
|
||||||
server::new(|| {
|
HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(Logger::default())
|
||||||
// cookie session middleware
|
// cookie session middleware
|
||||||
.middleware(session::SessionStorage::new(
|
.middleware(CookieSession::signed(&[0; 32]).secure(false))
|
||||||
session::CookieSessionBackend::signed(&[0; 32]).secure(false)
|
.service(web::resource("/").to(index))
|
||||||
))
|
})
|
||||||
.resource("/", |r| r.f(index))
|
.bind("127.0.0.1:8080")?
|
||||||
}).bind("127.0.0.1:8080")
|
.run()
|
||||||
.expect("Can not bind to 127.0.0.1:8080")
|
|
||||||
.start();
|
|
||||||
|
|
||||||
println!("Starting http server: 127.0.0.1:8080");
|
|
||||||
let _ = sys.run();
|
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
name = "error_handling"
|
name = "error_handling"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["dowwie <dkcdkg@gmail.com>"]
|
authors = ["dowwie <dkcdkg@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
workspace = ".."
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "0.7.3"
|
actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" }
|
||||||
actix-web = "0.7.3"
|
|
||||||
failure = "0.1.2"
|
derive_more = "0.14.0"
|
||||||
futures = "0.1.23"
|
futures = "0.1.23"
|
||||||
rand = "0.5.4"
|
rand = "0.5.4"
|
||||||
env_logger = "0.5.12"
|
env_logger = "0.6"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
The goal of this example is to show how to propagate a custom error type, derived
|
The goal of this example is to show how to propagate a custom error type,
|
||||||
from the Fail trait, to a web handler that will evaluate the type of error that
|
to a web handler that will evaluate the type of error that
|
||||||
was raised and return an appropriate HTTPResponse.
|
was raised and return an appropriate HTTPResponse.
|
||||||
|
|
||||||
This example uses a 50/50 chance of returning 200 Ok, otherwise one of four possible
|
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:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use actix_web::{web, App, Error, HttpResponse, HttpServer, ResponseError};
|
||||||
extern crate actix;
|
use derive_more::Display; // naming it clearly for illustration purposes
|
||||||
extern crate actix_web;
|
use futures::future::{err, ok, Future};
|
||||||
extern crate env_logger;
|
use rand::{
|
||||||
#[macro_use] extern crate failure;
|
distributions::{Distribution, Standard},
|
||||||
extern crate futures;
|
thread_rng, Rng,
|
||||||
extern crate rand;
|
|
||||||
|
|
||||||
|
|
||||||
use actix_web::{
|
|
||||||
http::Method, server, App, AsyncResponder, Error as ActixWebError,
|
|
||||||
HttpResponse, HttpRequest
|
|
||||||
};
|
};
|
||||||
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(Debug, Display)]
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
|
||||||
pub enum CustomError {
|
pub enum CustomError {
|
||||||
#[fail(display = "Custom Error 1")]
|
#[display(fmt = "Custom Error 1")]
|
||||||
CustomOne,
|
CustomOne,
|
||||||
#[fail(display = "Custom Error 2")]
|
#[display(fmt = "Custom Error 2")]
|
||||||
CustomTwo,
|
CustomTwo,
|
||||||
#[fail(display = "Custom Error 3")]
|
#[display(fmt = "Custom Error 3")]
|
||||||
CustomThree,
|
CustomThree,
|
||||||
#[fail(display = "Custom Error 4")]
|
#[display(fmt = "Custom Error 4")]
|
||||||
CustomFour
|
CustomFour,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Distribution<CustomError> for Standard {
|
impl Distribution<CustomError> for Standard {
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> CustomError {
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> CustomError {
|
||||||
match rng.gen_range(0, 4) {
|
match rng.gen_range(0, 4) {
|
||||||
0 => CustomError::CustomOne,
|
0 => CustomError::CustomOne,
|
||||||
1 => CustomError::CustomTwo,
|
1 => CustomError::CustomTwo,
|
||||||
2 => CustomError::CustomThree,
|
2 => CustomError::CustomThree,
|
||||||
_ => CustomError::CustomFour
|
_ => CustomError::CustomFour,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Actix web uses `ResponseError` for conversion of errors to a response
|
||||||
impl ResponseError for CustomError {
|
impl ResponseError for CustomError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
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
|
/// 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> {
|
fn do_something_random() -> impl Future<Item = (), Error = CustomError> {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
// 20% chance that () will be returned by this function
|
// 20% chance that () will be returned by this function
|
||||||
if rng.gen_bool(2.0 / 10.0) {
|
if rng.gen_bool(2.0 / 10.0) {
|
||||||
return fut_ok(())
|
ok(())
|
||||||
}
|
} else {
|
||||||
|
err(rand::random::<CustomError>())
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::io::Result<()> {
|
||||||
fn main() {
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||||
::std::env::set_var("RUST_LOG", "actix_web=info");
|
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let sys = actix::System::new("error_handling_example");
|
|
||||||
|
|
||||||
server::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new().service(
|
||||||
.resource("/something", |r|
|
web::resource("/something").route(web::get().to_async(do_something)),
|
||||||
r.method(Method::GET)
|
)
|
||||||
.with_async(do_something))
|
})
|
||||||
}).bind("127.0.0.1:8088")
|
.bind("127.0.0.1:8088")?
|
||||||
.unwrap()
|
.run()
|
||||||
.start();
|
|
||||||
|
|
||||||
println!("Started http server: 127.0.0.1:8088");
|
|
||||||
let _ = sys.run();
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ fn main() {
|
|||||||
let _addr = server::new(|| {
|
let _addr = server::new(|| {
|
||||||
App::with_state(AppState {
|
App::with_state(AppState {
|
||||||
foo: "bar".to_string(),
|
foo: "bar".to_string(),
|
||||||
}).middleware(middleware::Logger::default())
|
})
|
||||||
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/", |r| {
|
.resource("/", |r| {
|
||||||
r.method(http::Method::GET).with(index);
|
r.method(http::Method::GET).with(index);
|
||||||
})
|
})
|
||||||
@ -31,7 +32,8 @@ fn main() {
|
|||||||
.resource("/post3", |r| {
|
.resource("/post3", |r| {
|
||||||
r.method(http::Method::POST).with(handle_post_3)
|
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")
|
.expect("Can not bind to 127.0.0.1:8080")
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ fn main() {
|
|||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -87,25 +87,29 @@ fn main() {
|
|||||||
.value_name("LISTEN ADDR")
|
.value_name("LISTEN ADDR")
|
||||||
.index(1)
|
.index(1)
|
||||||
.required(true),
|
.required(true),
|
||||||
).arg(
|
)
|
||||||
|
.arg(
|
||||||
Arg::with_name("listen_port")
|
Arg::with_name("listen_port")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("LISTEN PORT")
|
.value_name("LISTEN PORT")
|
||||||
.index(2)
|
.index(2)
|
||||||
.required(true),
|
.required(true),
|
||||||
).arg(
|
)
|
||||||
|
.arg(
|
||||||
Arg::with_name("forward_addr")
|
Arg::with_name("forward_addr")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("FWD ADDR")
|
.value_name("FWD ADDR")
|
||||||
.index(3)
|
.index(3)
|
||||||
.required(true),
|
.required(true),
|
||||||
).arg(
|
)
|
||||||
|
.arg(
|
||||||
Arg::with_name("forward_port")
|
Arg::with_name("forward_port")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("FWD PORT")
|
.value_name("FWD PORT")
|
||||||
.index(4)
|
.index(4)
|
||||||
.required(true),
|
.required(true),
|
||||||
).get_matches();
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
let listen_addr = matches.value_of("listen_addr").unwrap();
|
let listen_addr = matches.value_of("listen_addr").unwrap();
|
||||||
let listen_port = value_t!(matches, "listen_port", u16).unwrap_or_else(|e| e.exit());
|
let listen_port = value_t!(matches, "listen_port", u16).unwrap_or_else(|e| e.exit());
|
||||||
@ -121,13 +125,15 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
)).unwrap();
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
server::new(move || {
|
server::new(move || {
|
||||||
App::with_state(AppState::init(forward_url.clone())).default_resource(|r| {
|
App::with_state(AppState::init(forward_url.clone())).default_resource(|r| {
|
||||||
r.f(forward);
|
r.f(forward);
|
||||||
})
|
})
|
||||||
}).workers(32)
|
})
|
||||||
|
.workers(32)
|
||||||
.bind((listen_addr, listen_port))
|
.bind((listen_addr, listen_port))
|
||||||
.expect("Cannot bind listening port")
|
.expect("Cannot bind listening port")
|
||||||
.system_exit()
|
.system_exit()
|
||||||
|
@ -12,15 +12,18 @@ use futures::{Future, Stream};
|
|||||||
/// Stream client request response and then send body to a server response
|
/// 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/")
|
client::ClientRequest::get("http://127.0.0.1:8081/")
|
||||||
.finish().unwrap()
|
.finish()
|
||||||
|
.unwrap()
|
||||||
.send()
|
.send()
|
||||||
.map_err(Error::from) // <- convert SendRequestError to an Error
|
.map_err(Error::from) // <- convert SendRequestError to an Error
|
||||||
.and_then(
|
.and_then(|resp| {
|
||||||
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
|
resp.body() // <- this is MessageBody type, resolves to complete body
|
||||||
.from_err() // <- convert PayloadError to an Error
|
.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))
|
Ok(HttpResponse::Ok().body(body))
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
.responder()
|
.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>> {
|
fn streaming(_req: &HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
|
||||||
// send client request
|
// send client request
|
||||||
client::ClientRequest::get("https://www.rust-lang.org/en-US/")
|
client::ClientRequest::get("https://www.rust-lang.org/en-US/")
|
||||||
.finish().unwrap()
|
.finish()
|
||||||
|
.unwrap()
|
||||||
.send() // <- connect to host and send request
|
.send() // <- connect to host and send request
|
||||||
.map_err(Error::from) // <- convert SendRequestError to an Error
|
.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()
|
Ok(HttpResponse::Ok()
|
||||||
// read one chunk from client response and send this chunk to a server response
|
// read one chunk from client response and send this chunk to a server response
|
||||||
// .from_err() converts PayloadError to an Error
|
// .from_err() converts PayloadError to an Error
|
||||||
@ -50,7 +55,8 @@ fn main() {
|
|||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/streaming", |r| r.f(streaming))
|
.resource("/streaming", |r| r.f(streaming))
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).workers(1)
|
})
|
||||||
|
.workers(1)
|
||||||
.bind("127.0.0.1:8080")
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
@ -24,7 +24,8 @@ fn main() {
|
|||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).workers(1)
|
})
|
||||||
|
.workers(1)
|
||||||
.bind("127.0.0.1:8081")
|
.bind("127.0.0.1:8081")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
@ -93,12 +93,15 @@ fn main() {
|
|||||||
|
|
||||||
// Start http server
|
// Start http server
|
||||||
server::new(move || {
|
server::new(move || {
|
||||||
App::with_state(AppState{executor: addr.clone()})
|
App::with_state(AppState {
|
||||||
|
executor: addr.clone(),
|
||||||
|
})
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/graphql", |r| r.method(http::Method::POST).with(graphql))
|
.resource("/graphql", |r| r.method(http::Method::POST).with(graphql))
|
||||||
.resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))
|
.resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -16,12 +16,15 @@ fn main() {
|
|||||||
.middleware(simple::SayHi)
|
.middleware(simple::SayHi)
|
||||||
// .middleware(redirect::CheckLogin)
|
// .middleware(redirect::CheckLogin)
|
||||||
.resource("/login", |r| {
|
.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| {
|
.resource("/", |r| {
|
||||||
r.f(|_| "Hello, middleware! Check the console where the server is run.")
|
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()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -101,12 +101,14 @@ fn main() {
|
|||||||
server::new(|| {
|
server::new(|| {
|
||||||
App::with_state(AppState {
|
App::with_state(AppState {
|
||||||
counter: Cell::new(0),
|
counter: Cell::new(0),
|
||||||
}).middleware(middleware::Logger::default())
|
})
|
||||||
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/", |r| {
|
.resource("/", |r| {
|
||||||
r.method(http::Method::GET).with(index);
|
r.method(http::Method::GET).with(index);
|
||||||
r.method(http::Method::POST).with(upload);
|
r.method(http::Method::POST).with(upload);
|
||||||
})
|
})
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ fn main() {
|
|||||||
App::new()
|
App::new()
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/", |r| r.method(http::Method::POST).f(index))
|
.resource("/", |r| r.method(http::Method::POST).f(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.shutdown_timeout(1)
|
.shutdown_timeout(1)
|
||||||
.start();
|
.start();
|
||||||
|
@ -35,12 +35,14 @@ fn main() {
|
|||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
// redis session middleware
|
// redis session middleware
|
||||||
.middleware(SessionStorage::new(
|
.middleware(SessionStorage::new(RedisSessionBackend::new(
|
||||||
RedisSessionBackend::new("127.0.0.1:6379", &[0; 32])
|
"127.0.0.1:6379",
|
||||||
))
|
&[0; 32],
|
||||||
|
)))
|
||||||
// register simple route, handle all methods
|
// register simple route, handle all methods
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -49,13 +49,16 @@ fn main() {
|
|||||||
// register simple handler, handle all methods
|
// register simple handler, handle all methods
|
||||||
.resource("/index.html", |r| r.f(index))
|
.resource("/index.html", |r| r.f(index))
|
||||||
// with path parameters
|
// with path parameters
|
||||||
.resource("/", |r| r.method(http::Method::GET).f(|_| {
|
.resource("/", |r| {
|
||||||
|
r.method(http::Method::GET).f(|_| {
|
||||||
HttpResponse::Found()
|
HttpResponse::Found()
|
||||||
.header("LOCATION", "/index.html")
|
.header("LOCATION", "/index.html")
|
||||||
.finish()
|
.finish()
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
.handler("/static", StaticFiles::new("static").unwrap())
|
.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()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@ pub struct AppState {
|
|||||||
/// creates and returns the app after mounting all routes/resources
|
/// creates and returns the app after mounting all routes/resources
|
||||||
pub fn create_app(db: Addr<DbExecutor>) -> App<AppState> {
|
pub fn create_app(db: Addr<DbExecutor>) -> App<AppState> {
|
||||||
// secret is a random minimum 32 bytes long base 64 string
|
// 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 secret: String =
|
||||||
let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_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 })
|
App::with_state(AppState { db })
|
||||||
.middleware(Logger::default())
|
.middleware(Logger::default())
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use actix::{Handler, Message};
|
use actix::{Handler, Message};
|
||||||
|
use actix_web::{middleware::identity::RequestIdentity, FromRequest, HttpRequest};
|
||||||
|
use bcrypt::verify;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use errors::ServiceError;
|
use errors::ServiceError;
|
||||||
use models::{DbExecutor, User, SlimUser};
|
use models::{DbExecutor, SlimUser, User};
|
||||||
use bcrypt::verify;
|
|
||||||
use actix_web::{FromRequest, HttpRequest, middleware::identity::RequestIdentity};
|
|
||||||
use utils::decode_token;
|
use utils::decode_token;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -19,22 +19,24 @@ impl Message for AuthData {
|
|||||||
impl Handler<AuthData> for DbExecutor {
|
impl Handler<AuthData> for DbExecutor {
|
||||||
type Result = Result<SlimUser, ServiceError>;
|
type Result = Result<SlimUser, ServiceError>;
|
||||||
fn handle(&mut self, msg: AuthData, _: &mut Self::Context) -> Self::Result {
|
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 conn: &PgConnection = &self.0.get().unwrap();
|
||||||
|
|
||||||
let mut items = users
|
let mut items = users.filter(email.eq(&msg.email)).load::<User>(conn)?;
|
||||||
.filter(email.eq(&msg.email))
|
|
||||||
.load::<User>(conn)?;
|
|
||||||
|
|
||||||
if let Some(user) = items.pop() {
|
if let Some(user) = items.pop() {
|
||||||
match verify(&msg.password, &user.password) {
|
match verify(&msg.password, &user.password) {
|
||||||
Ok(matching) => if matching {
|
Ok(matching) => {
|
||||||
|
if matching {
|
||||||
return Ok(user.into());
|
return Ok(user.into());
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ServiceError::BadRequest("Username and Password don't match".into()))
|
Err(ServiceError::BadRequest(
|
||||||
|
"Username and Password don't match".into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
use actix_web::{AsyncResponder, FutureResponse, HttpResponse, HttpRequest, ResponseError, Json};
|
|
||||||
use actix_web::middleware::identity::RequestIdentity;
|
use actix_web::middleware::identity::RequestIdentity;
|
||||||
|
use actix_web::{
|
||||||
|
AsyncResponder, FutureResponse, HttpRequest, HttpResponse, Json, ResponseError,
|
||||||
|
};
|
||||||
use futures::future::Future;
|
use futures::future::Future;
|
||||||
use utils::create_token;
|
use utils::create_token;
|
||||||
|
|
||||||
use app::AppState;
|
use app::AppState;
|
||||||
use auth_handler::{AuthData, LoggedUser};
|
use auth_handler::{AuthData, LoggedUser};
|
||||||
|
|
||||||
pub fn login((auth_data, req): (Json<AuthData>, HttpRequest<AppState>))
|
pub fn login(
|
||||||
-> FutureResponse<HttpResponse> {
|
(auth_data, req): (Json<AuthData>, HttpRequest<AppState>),
|
||||||
|
) -> FutureResponse<HttpResponse> {
|
||||||
req.state()
|
req.state()
|
||||||
.db
|
.db
|
||||||
.send(auth_data.into_inner())
|
.send(auth_data.into_inner())
|
||||||
@ -19,7 +22,8 @@ pub fn login((auth_data, req): (Json<AuthData>, HttpRequest<AppState>))
|
|||||||
Ok(HttpResponse::Ok().into())
|
Ok(HttpResponse::Ok().into())
|
||||||
}
|
}
|
||||||
Err(err) => Ok(err.error_response()),
|
Err(err) => Ok(err.error_response()),
|
||||||
}).responder()
|
})
|
||||||
|
.responder()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logout(req: HttpRequest<AppState>) -> HttpResponse {
|
pub fn logout(req: HttpRequest<AppState>) -> HttpResponse {
|
||||||
|
@ -9,8 +9,8 @@ fn get_api_key() -> String {
|
|||||||
|
|
||||||
pub fn send_invitation(invitation: &Invitation) {
|
pub fn send_invitation(invitation: &Invitation) {
|
||||||
let tm = Transmission::new_eu(get_api_key());
|
let tm = Transmission::new_eu(get_api_key());
|
||||||
let sending_email =
|
let sending_email = std::env::var("SENDING_EMAIL_ADDRESS")
|
||||||
std::env::var("SENDING_EMAIL_ADDRESS").expect("SENDING_EMAIL_ADDRESS must be set");
|
.expect("SENDING_EMAIL_ADDRESS must be set");
|
||||||
// new email message with sender name and email
|
// new email message with sender name and email
|
||||||
let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise"));
|
let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise"));
|
||||||
|
|
||||||
@ -39,7 +39,6 @@ pub fn send_invitation(invitation: &Invitation) {
|
|||||||
.to_string()
|
.to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// complete the email message with details
|
// complete the email message with details
|
||||||
email
|
email
|
||||||
.add_recipient(recipient)
|
.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
|
// Note that we only print out the error response from email api
|
||||||
match result {
|
match result {
|
||||||
Ok(res) => {
|
Ok(res) => match res {
|
||||||
match res {
|
|
||||||
TransmissionResponse::ApiResponse(api_res) => {
|
TransmissionResponse::ApiResponse(api_res) => {
|
||||||
println!("API Response: \n {:#?}", api_res);
|
println!("API Response: \n {:#?}", api_res);
|
||||||
}
|
}
|
||||||
TransmissionResponse::ApiError(errors) => {
|
TransmissionResponse::ApiError(errors) => {
|
||||||
println!("Response Errors: \n {:#?}", &errors);
|
println!("Response Errors: \n {:#?}", &errors);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
println!("error \n {:#?}", error);
|
println!("error \n {:#?}", error);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use actix_web::{error::ResponseError, HttpResponse};
|
use actix_web::{error::ResponseError, HttpResponse};
|
||||||
use std::convert::From;
|
|
||||||
use diesel::result::{DatabaseErrorKind, Error};
|
use diesel::result::{DatabaseErrorKind, Error};
|
||||||
|
use std::convert::From;
|
||||||
use uuid::ParseError;
|
use uuid::ParseError;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub enum ServiceError {
|
pub enum ServiceError {
|
||||||
#[fail(display = "Internal Server Error")]
|
#[fail(display = "Internal Server Error")]
|
||||||
@ -20,9 +19,14 @@ pub enum ServiceError {
|
|||||||
impl ResponseError for ServiceError {
|
impl ResponseError for ServiceError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match *self {
|
match *self {
|
||||||
ServiceError::InternalServerError => HttpResponse::InternalServerError().json("Internal Server Error, Please try later"),
|
ServiceError::InternalServerError => HttpResponse::InternalServerError()
|
||||||
ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message),
|
.json("Internal Server Error, Please try later"),
|
||||||
ServiceError::Unauthorized => HttpResponse::Unauthorized().json("Unauthorized")
|
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 {
|
match error {
|
||||||
Error::DatabaseError(kind, info) => {
|
Error::DatabaseError(kind, info) => {
|
||||||
if let DatabaseErrorKind::UniqueViolation = kind {
|
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);
|
return ServiceError::BadRequest(message);
|
||||||
}
|
}
|
||||||
ServiceError::InternalServerError
|
ServiceError::InternalServerError
|
||||||
}
|
}
|
||||||
_ => ServiceError::InternalServerError
|
_ => ServiceError::InternalServerError,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,5 +35,3 @@ impl Handler<CreateInvitation> for DbExecutor {
|
|||||||
Ok(inserted_invitation)
|
Ok(inserted_invitation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 futures::future::Future;
|
||||||
|
|
||||||
use app::AppState;
|
use app::AppState;
|
||||||
@ -18,5 +20,6 @@ pub fn register_email(
|
|||||||
Ok(HttpResponse::Ok().into())
|
Ok(HttpResponse::Ok().into())
|
||||||
}
|
}
|
||||||
Err(err) => Ok(err.error_response()),
|
Err(err) => Ok(err.error_response()),
|
||||||
}).responder()
|
})
|
||||||
|
.responder()
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
// to avoid the warning from diesel macros
|
// to avoid the warning from diesel macros
|
||||||
#![allow(proc_macro_derive_resolution_fallback)]
|
#![allow(proc_macro_derive_resolution_fallback)]
|
||||||
|
|
||||||
extern crate bcrypt;
|
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate env_logger;
|
extern crate bcrypt;
|
||||||
extern crate serde;
|
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
extern crate dotenv;
|
extern crate dotenv;
|
||||||
|
extern crate env_logger;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate r2d2;
|
|
||||||
extern crate uuid;
|
|
||||||
extern crate jsonwebtoken as jwt;
|
extern crate jsonwebtoken as jwt;
|
||||||
|
extern crate r2d2;
|
||||||
|
extern crate serde;
|
||||||
extern crate sparkpost;
|
extern crate sparkpost;
|
||||||
|
extern crate uuid;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -21,26 +21,25 @@ extern crate serde_derive;
|
|||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod models;
|
|
||||||
mod schema;
|
|
||||||
mod errors;
|
|
||||||
mod auth_handler;
|
mod auth_handler;
|
||||||
mod auth_routes;
|
mod auth_routes;
|
||||||
|
mod email_service;
|
||||||
|
mod errors;
|
||||||
mod invitation_handler;
|
mod invitation_handler;
|
||||||
mod invitation_routes;
|
mod invitation_routes;
|
||||||
|
mod models;
|
||||||
mod register_handler;
|
mod register_handler;
|
||||||
mod register_routes;
|
mod register_routes;
|
||||||
|
mod schema;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod email_service;
|
|
||||||
|
|
||||||
use models::DbExecutor;
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use actix_web::server;
|
use actix_web::server;
|
||||||
use diesel::{r2d2::ConnectionManager, PgConnection};
|
use diesel::{r2d2::ConnectionManager, PgConnection};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use models::DbExecutor;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
std::env::set_var("RUST_LOG", "simple-auth-server=debug,actix_web=info");
|
std::env::set_var("RUST_LOG", "simple-auth-server=debug,actix_web=info");
|
||||||
@ -55,7 +54,8 @@ fn main() {
|
|||||||
.build(manager)
|
.build(manager)
|
||||||
.expect("Failed to create pool.");
|
.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()))
|
server::new(move || app::create_app(address.clone()))
|
||||||
.bind("127.0.0.1:3000")
|
.bind("127.0.0.1:3000")
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use actix::{Actor, SyncContext};
|
use actix::{Actor, SyncContext};
|
||||||
|
use chrono::{Local, NaiveDateTime};
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
use diesel::r2d2::{ConnectionManager, Pool};
|
use diesel::r2d2::{ConnectionManager, Pool};
|
||||||
use chrono::{NaiveDateTime, Local};
|
|
||||||
use uuid::Uuid;
|
|
||||||
use std::convert::From;
|
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
|
/// This is db executor actor. can be run in parallel
|
||||||
pub struct DbExecutor(pub Pool<ConnectionManager<PgConnection>>);
|
pub struct DbExecutor(pub Pool<ConnectionManager<PgConnection>>);
|
||||||
@ -51,8 +51,6 @@ pub struct SlimUser {
|
|||||||
|
|
||||||
impl From<User> for SlimUser {
|
impl From<User> for SlimUser {
|
||||||
fn from(user: User) -> Self {
|
fn from(user: User) -> Self {
|
||||||
SlimUser {
|
SlimUser { email: user.email }
|
||||||
email: user.email
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ use actix::{Handler, Message};
|
|||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use errors::ServiceError;
|
use errors::ServiceError;
|
||||||
use models::{DbExecutor, Invitation, User, SlimUser};
|
use models::{DbExecutor, Invitation, SlimUser, User};
|
||||||
use uuid::Uuid;
|
|
||||||
use utils::hash_password;
|
use utils::hash_password;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
// UserData is used to extract data from a post request by the client
|
// UserData is used to extract data from a post request by the client
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -23,11 +23,10 @@ impl Message for RegisterUser {
|
|||||||
type Result = Result<SlimUser, ServiceError>;
|
type Result = Result<SlimUser, ServiceError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Handler<RegisterUser> for DbExecutor {
|
impl Handler<RegisterUser> for DbExecutor {
|
||||||
type Result = Result<SlimUser, ServiceError>;
|
type Result = Result<SlimUser, ServiceError>;
|
||||||
fn handle(&mut self, msg: RegisterUser, _: &mut Self::Context) -> Self::Result {
|
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;
|
use schema::users::dsl::users;
|
||||||
let conn: &PgConnection = &self.0.get().unwrap();
|
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
|
// return early with error that will be converted to ServiceError
|
||||||
let invitation_id = Uuid::parse_str(&msg.invitation_id)?;
|
let invitation_id = Uuid::parse_str(&msg.invitation_id)?;
|
||||||
|
|
||||||
invitations.filter(id.eq(invitation_id))
|
invitations
|
||||||
|
.filter(id.eq(invitation_id))
|
||||||
.load::<Invitation>(conn)
|
.load::<Invitation>(conn)
|
||||||
.map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into()))
|
.map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into()))
|
||||||
.and_then(|mut result| {
|
.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
|
// try hashing the password, else return the error that will be converted to ServiceError
|
||||||
let password: String = hash_password(&msg.password)?;
|
let password: String = hash_password(&msg.password)?;
|
||||||
let user = User::with_details(invitation.email, password);
|
let user = User::with_details(invitation.email, password);
|
||||||
let inserted_user: User = diesel::insert_into(users)
|
let inserted_user: User =
|
||||||
.values(&user)
|
diesel::insert_into(users).values(&user).get_result(conn)?;
|
||||||
.get_result(conn)?;
|
|
||||||
|
|
||||||
return Ok(inserted_user.into());
|
return Ok(inserted_user.into());
|
||||||
}
|
}
|
||||||
@ -56,5 +55,3 @@ impl Handler<RegisterUser> for DbExecutor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 futures::future::Future;
|
||||||
|
|
||||||
use app::AppState;
|
use app::AppState;
|
||||||
use register_handler::{RegisterUser, UserData};
|
use register_handler::{RegisterUser, UserData};
|
||||||
|
|
||||||
|
pub fn register_user(
|
||||||
pub fn register_user((invitation_id, user_data, state): (Path<String>, Json<UserData>, State<AppState>))
|
(invitation_id, user_data, state): (Path<String>, Json<UserData>, State<AppState>),
|
||||||
-> FutureResponse<HttpResponse> {
|
) -> FutureResponse<HttpResponse> {
|
||||||
let msg = RegisterUser {
|
let msg = RegisterUser {
|
||||||
// into_inner() returns the inner string value from Path
|
// into_inner() returns the inner string value from Path
|
||||||
invitation_id: invitation_id.into_inner(),
|
invitation_id: invitation_id.into_inner(),
|
||||||
password: user_data.password.clone(),
|
password: user_data.password.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
state.db.send(msg)
|
state
|
||||||
|
.db
|
||||||
|
.send(msg)
|
||||||
.from_err()
|
.from_err()
|
||||||
.and_then(|db_response| match db_response {
|
.and_then(|db_response| match db_response {
|
||||||
Ok(slim_user) => Ok(HttpResponse::Ok().json(slim_user)),
|
Ok(slim_user) => Ok(HttpResponse::Ok().json(slim_user)),
|
||||||
Err(service_error) => Ok(service_error.error_response()),
|
Err(service_error) => Ok(service_error.error_response()),
|
||||||
}).responder()
|
})
|
||||||
|
.responder()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,4 @@ table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(invitations, users,);
|
||||||
invitations,
|
|
||||||
users,
|
|
||||||
);
|
|
||||||
|
@ -17,9 +17,12 @@ fn main() {
|
|||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.handler(
|
.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")
|
.expect("Can not start server on given IP/Port")
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -24,7 +24,8 @@ fn index(query: Query<HashMap<String, String>>) -> Result<HttpResponse> {
|
|||||||
UserTemplate {
|
UserTemplate {
|
||||||
name: name,
|
name: name,
|
||||||
text: "Welcome!",
|
text: "Welcome!",
|
||||||
}.render()
|
}
|
||||||
|
.render()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
Index.render().unwrap()
|
Index.render().unwrap()
|
||||||
@ -38,7 +39,8 @@ fn main() {
|
|||||||
// start http server
|
// start http server
|
||||||
server::new(move || {
|
server::new(move || {
|
||||||
App::new().resource("/", |r| r.method(http::Method::GET).with(index))
|
App::new().resource("/", |r| r.method(http::Method::GET).with(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ fn main() {
|
|||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/", |r| r.method(http::Method::GET).with(index))
|
.resource("/", |r| r.method(http::Method::GET).with(index))
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ fn main() {
|
|||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
.resource("/index.html", |r| r.f(|_| "Hello world!"))
|
||||||
.resource("/", |r| r.f(index))
|
.resource("/", |r| r.f(index))
|
||||||
}).start_incoming(listener.incoming(), false);
|
})
|
||||||
|
.start_incoming(listener.incoming(), false);
|
||||||
|
|
||||||
println!("Started http server: /tmp/actix-uds.socket");
|
println!("Started http server: /tmp/actix-uds.socket");
|
||||||
let _ = sys.run();
|
let _ = sys.run();
|
||||||
|
@ -39,7 +39,8 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.register()
|
.register()
|
||||||
})
|
})
|
||||||
}).bind("127.0.0.1:8000")
|
})
|
||||||
|
.bind("127.0.0.1:8000")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.shutdown_timeout(2)
|
.shutdown_timeout(2)
|
||||||
.start();
|
.start();
|
||||||
|
@ -52,7 +52,8 @@ impl WsChatSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fut::ok(())
|
fut::ok(())
|
||||||
}).spawn(ctx);
|
})
|
||||||
|
.spawn(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_rooms(&mut self, ctx: &mut ws::WebsocketContext<Self>) {
|
fn list_rooms(&mut self, ctx: &mut ws::WebsocketContext<Self>) {
|
||||||
@ -66,7 +67,8 @@ impl WsChatSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fut::ok(())
|
fut::ok(())
|
||||||
}).spawn(ctx);
|
})
|
||||||
|
.spawn(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_msg(&self, msg: &str) {
|
fn send_msg(&self, msg: &str) {
|
||||||
@ -158,7 +160,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.index_file("index.html"),
|
.index_file("index.html"),
|
||||||
)
|
)
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ extern crate tokio_io;
|
|||||||
extern crate actix;
|
extern crate actix;
|
||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
|
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use actix::*;
|
use actix::*;
|
||||||
use actix_web::server::HttpServer;
|
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::Binary(bin) => println!("Unexpected binary"),
|
||||||
ws::Message::Close(_) => {
|
ws::Message::Close(_) => {
|
||||||
ctx.stop();
|
ctx.stop();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,9 +202,7 @@ impl WsChatSession {
|
|||||||
println!("Websocket Client heartbeat failed, disconnecting!");
|
println!("Websocket Client heartbeat failed, disconnecting!");
|
||||||
|
|
||||||
// notify chat server
|
// notify chat server
|
||||||
ctx.state()
|
ctx.state().addr.do_send(server::Disconnect { id: act.id });
|
||||||
.addr
|
|
||||||
.do_send(server::Disconnect { id: act.id });
|
|
||||||
|
|
||||||
// stop actor
|
// stop actor
|
||||||
ctx.stop();
|
ctx.stop();
|
||||||
@ -234,16 +232,19 @@ fn main() {
|
|||||||
|
|
||||||
App::with_state(state)
|
App::with_state(state)
|
||||||
// redirect to websocket.html
|
// redirect to websocket.html
|
||||||
.resource("/", |r| r.method(http::Method::GET).f(|_| {
|
.resource("/", |r| {
|
||||||
|
r.method(http::Method::GET).f(|_| {
|
||||||
HttpResponse::Found()
|
HttpResponse::Found()
|
||||||
.header("LOCATION", "/static/websocket.html")
|
.header("LOCATION", "/static/websocket.html")
|
||||||
.finish()
|
.finish()
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
// websocket
|
// websocket
|
||||||
.resource("/ws/", |r| r.route().f(chat_route))
|
.resource("/ws/", |r| r.route().f(chat_route))
|
||||||
// static resources
|
// static resources
|
||||||
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
|
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -65,7 +65,9 @@ impl Encoder for ChatCodec {
|
|||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn encode(
|
fn encode(
|
||||||
&mut self, msg: ChatResponse, dst: &mut BytesMut,
|
&mut self,
|
||||||
|
msg: ChatResponse,
|
||||||
|
dst: &mut BytesMut,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let msg = json::to_string(&msg).unwrap();
|
let msg = json::to_string(&msg).unwrap();
|
||||||
let msg_ref: &[u8] = msg.as_ref();
|
let msg_ref: &[u8] = msg.as_ref();
|
||||||
@ -108,7 +110,9 @@ impl Encoder for ClientChatCodec {
|
|||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn encode(
|
fn encode(
|
||||||
&mut self, msg: ChatRequest, dst: &mut BytesMut,
|
&mut self,
|
||||||
|
msg: ChatRequest,
|
||||||
|
dst: &mut BytesMut,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let msg = json::to_string(&msg).unwrap();
|
let msg = json::to_string(&msg).unwrap();
|
||||||
let msg_ref: &[u8] = msg.as_ref();
|
let msg_ref: &[u8] = msg.as_ref();
|
||||||
|
@ -19,7 +19,7 @@ extern crate actix_web;
|
|||||||
use actix::*;
|
use actix::*;
|
||||||
use actix_web::server::HttpServer;
|
use actix_web::server::HttpServer;
|
||||||
use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse};
|
use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse};
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
mod codec;
|
mod codec;
|
||||||
mod server;
|
mod server;
|
||||||
@ -191,7 +191,7 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for WsChatSession {
|
|||||||
ws::Message::Binary(bin) => println!("Unexpected binary"),
|
ws::Message::Binary(bin) => println!("Unexpected binary"),
|
||||||
ws::Message::Close(_) => {
|
ws::Message::Close(_) => {
|
||||||
ctx.stop();
|
ctx.stop();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,9 +208,7 @@ impl WsChatSession {
|
|||||||
println!("Websocket Client heartbeat failed, disconnecting!");
|
println!("Websocket Client heartbeat failed, disconnecting!");
|
||||||
|
|
||||||
// notify chat server
|
// notify chat server
|
||||||
ctx.state()
|
ctx.state().addr.do_send(server::Disconnect { id: act.id });
|
||||||
.addr
|
|
||||||
.do_send(server::Disconnect { id: act.id });
|
|
||||||
|
|
||||||
// stop actor
|
// stop actor
|
||||||
ctx.stop();
|
ctx.stop();
|
||||||
@ -247,16 +245,19 @@ fn main() {
|
|||||||
|
|
||||||
App::with_state(state)
|
App::with_state(state)
|
||||||
// redirect to websocket.html
|
// redirect to websocket.html
|
||||||
.resource("/", |r| r.method(http::Method::GET).f(|_| {
|
.resource("/", |r| {
|
||||||
|
r.method(http::Method::GET).f(|_| {
|
||||||
HttpResponse::Found()
|
HttpResponse::Found()
|
||||||
.header("LOCATION", "/static/websocket.html")
|
.header("LOCATION", "/static/websocket.html")
|
||||||
.finish()
|
.finish()
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
// websocket
|
// websocket
|
||||||
.resource("/ws/", |r| r.route().f(chat_route))
|
.resource("/ws/", |r| r.route().f(chat_route))
|
||||||
// static resources
|
// static resources
|
||||||
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
|
.handler("/static/", fs::StaticFiles::new("static/").unwrap())
|
||||||
}).bind("127.0.0.1:8080")
|
})
|
||||||
|
.bind("127.0.0.1:8080")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ extern crate actix;
|
|||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
@ -96,18 +96,23 @@ fn main() {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
let sys = actix::System::new("ws-example");
|
let sys = actix::System::new("ws-example");
|
||||||
|
|
||||||
server::new(
|
server::new(|| {
|
||||||
|| App::new()
|
App::new()
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
// websocket route
|
// websocket route
|
||||||
.resource("/ws/", |r| r.method(http::Method::GET).f(ws_index))
|
.resource("/ws/", |r| r.method(http::Method::GET).f(ws_index))
|
||||||
// static files
|
// static files
|
||||||
.handler("/", fs::StaticFiles::new("static/")
|
.handler(
|
||||||
|
"/",
|
||||||
|
fs::StaticFiles::new("static/")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.index_file("index.html")))
|
.index_file("index.html"),
|
||||||
|
)
|
||||||
|
})
|
||||||
// start http server on 127.0.0.1:8080
|
// start http server on 127.0.0.1:8080
|
||||||
.bind("127.0.0.1:8080").unwrap()
|
.bind("127.0.0.1:8080")
|
||||||
|
.unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
println!("Started http server: 127.0.0.1:8080");
|
println!("Started http server: 127.0.0.1:8080");
|
||||||
|
Loading…
Reference in New Issue
Block a user