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:
parent
f39a53ea3a
commit
e2945b9b39
@ -7,7 +7,6 @@ members = [
|
||||
"async_ex1",
|
||||
"basics",
|
||||
"cookie-auth",
|
||||
"cookie-auth-full",
|
||||
"cookie-session",
|
||||
"diesel",
|
||||
"error_handling",
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 = "../"
|
||||
|
||||
[dependencies]
|
||||
actix = "0.7"
|
||||
actix-web = "0.7"
|
||||
actix-web = { git="https://github.com/actix/actix-web.git" }
|
||||
env_logger = "0.5"
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,5 +35,3 @@ impl Handler<CreateInvitation> for DbExecutor {
|
||||
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 app::AppState;
|
||||
@ -18,5 +20,6 @@ pub fn register_email(
|
||||
Ok(HttpResponse::Ok().into())
|
||||
}
|
||||
Err(err) => Ok(err.error_response()),
|
||||
}).responder()
|
||||
})
|
||||
.responder()
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -14,7 +14,4 @@ table! {
|
||||
}
|
||||
}
|
||||
|
||||
allow_tables_to_appear_in_same_query!(
|
||||
invitations,
|
||||
users,
|
||||
);
|
||||
allow_tables_to_appear_in_same_query!(invitations, users,);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -39,7 +39,8 @@ fn main() {
|
||||
})
|
||||
.register()
|
||||
})
|
||||
}).bind("127.0.0.1:8000")
|
||||
})
|
||||
.bind("127.0.0.1:8000")
|
||||
.unwrap()
|
||||
.shutdown_timeout(2)
|
||||
.start();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user