From 71e83fb87c75ebaa7d9ee52c19b2823db278eed6 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 5 Mar 2019 22:16:42 -0800 Subject: [PATCH 001/111] update basic example --- async_db/Cargo.toml | 2 +- basics/Cargo.toml | 11 ++-- basics/src/main.rs | 141 ++++++++++++++++++++++---------------------- 3 files changed, 79 insertions(+), 75 deletions(-) diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 55105f57..56e97c2f 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -11,7 +11,7 @@ dotenv = "0.10" env_logger = "0.5" failure = "0.1.1" futures = "0.1" -num_cpus = "1.8.0" +num_cpus = "1.10.0" r2d2 = "0.8.2" r2d2_sqlite = "0.5.0" serde = "1.0" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 2db8e75a..b13337c7 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "basics" -version = "0.1.0" +version = "1.0.0" authors = ["Nikolay Kim "] workspace = "../" +edition = "2018" [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-rt = "0.1" +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" } +actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -futures = "0.1" +futures = "0.1.25" env_logger = "0.5" bytes = "0.4" diff --git a/basics/src/main.rs b/basics/src/main.rs index b4fbe9e9..fded1c3a 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -1,43 +1,34 @@ -#![allow(unused_variables)] -#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] - -extern crate actix; -extern crate actix_web; -extern crate bytes; -extern crate env_logger; -extern crate futures; - -use bytes::Bytes; -use futures::sync::mpsc; -use futures::Stream; - -use actix_web::http::{header, Method, StatusCode}; -use actix_web::middleware::session::{self, RequestSession}; -use actix_web::{ - error, fs, middleware, pred, server, App, Error, HttpRequest, HttpResponse, Path, - Result, -}; -use futures::future::{result, FutureResult}; use std::{env, io}; +use actix_session::{CookieSession, Session}; +use actix_staticfiles as fs; +use actix_web::extract::Path; +use actix_web::http::{header, Method, StatusCode}; +use actix_web::{ + error, guard, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, +}; +use bytes::Bytes; +use futures::unsync::mpsc; +use futures::{future::ok, Future, Stream}; + /// favicon handler -fn favicon(req: &HttpRequest) -> Result { +fn favicon() -> Result { Ok(fs::NamedFile::open("static/favicon.ico")?) } /// simple index handler -fn welcome(req: &HttpRequest) -> Result { +fn welcome(session: Session, req: HttpRequest) -> Result { println!("{:?}", req); // session let mut counter = 1; - if let Some(count) = req.session().get::("counter")? { + if let Some(count) = session.get::("counter")? { println!("SESSION value: {}", count); counter = count + 1; } // set counter to session - req.session().set("counter", counter)?; + session.set("counter", counter)?; // response Ok(HttpResponse::build(StatusCode::OK) @@ -46,17 +37,17 @@ fn welcome(req: &HttpRequest) -> Result { } /// 404 handler -fn p404(req: &HttpRequest) -> Result { +fn p404() -> Result { Ok(fs::NamedFile::open("static/404.html")?.set_status_code(StatusCode::NOT_FOUND)) } /// async handler -fn index_async(req: &HttpRequest) -> FutureResult { +fn index_async(req: HttpRequest) -> impl Future { println!("{:?}", req); - result(Ok(HttpResponse::Ok().content_type("text/html").body( - format!("Hello {}!", req.match_info().get("name").unwrap()), - ))) + ok(HttpResponse::Ok() + .content_type("text/html") + .body(format!("Hello {}!", req.match_info().get("name").unwrap()))) } /// async body @@ -67,76 +58,86 @@ fn index_async_body(path: Path) -> HttpResponse { let _ = tx.unbounded_send(Bytes::from(text.as_bytes())); HttpResponse::Ok() - .streaming(rx_body.map_err(|e| error::ErrorBadRequest("bad request"))) + .streaming(rx_body.map_err(|_| error::ErrorBadRequest("bad request"))) } /// handler with path parameters like `/user/{name}/` -fn with_param(req: &HttpRequest) -> HttpResponse { +fn with_param(req: HttpRequest, path: Path<(String,)>) -> HttpResponse { println!("{:?}", req); HttpResponse::Ok() .content_type("text/plain") - .body(format!("Hello {}!", req.match_info().get("name").unwrap())) + .body(format!("Hello {}!", path.0)) } -fn main() { +fn main() -> io::Result<()> { env::set_var("RUST_LOG", "actix_web=debug"); env::set_var("RUST_BACKTRACE", "1"); env_logger::init(); - let sys = actix::System::new("basic-example"); + let sys = actix_rt::System::new("basic-example"); - let addr = server::new( - || App::new() + HttpServer::new(|| { + App::new() // enable logger - .middleware(middleware::Logger::default()) + // .middleware(middleware::Logger::default()) // cookie session middleware - .middleware(session::SessionStorage::new( - session::CookieSessionBackend::signed(&[0; 32]).secure(false) - )) + .middleware(CookieSession::signed(&[0; 32]).secure(false)) // register favicon - .resource("/favicon", |r| r.f(favicon)) + .resource("/favicon", |r| r.to(favicon)) // register simple route, handle all methods - .resource("/welcome", |r| r.f(welcome)) + .resource("/welcome", |r| r.to(welcome)) // with path parameters - .resource("/user/{name}", |r| r.method(Method::GET).f(with_param)) + .resource("/user/{name}", |r| r.route(web::get().to(with_param))) // async handler - .resource("/async/{name}", |r| r.method(Method::GET).a(index_async)) + .resource("/async/{name}", |r| { + r.route(web::get().to_async(index_async)) + }) // async handler - .resource("/async-body/{name}", |r| r.method(Method::GET).with(index_async_body)) - .resource("/test", |r| r.f(|req| { - match *req.method() { + .resource("/async-body/{name}", |r| { + r.route(web::get().to(index_async_body)) + }) + .resource("/test", |r| { + r.to(|req: HttpRequest| match *req.method() { Method::GET => HttpResponse::Ok(), Method::POST => HttpResponse::MethodNotAllowed(), _ => HttpResponse::NotFound(), - } - })) - .resource("/error", |r| r.f(|req| { - error::InternalError::new( - io::Error::new(io::ErrorKind::Other, "test"), StatusCode::INTERNAL_SERVER_ERROR) - })) + }) + }) + .resource("/error", |r| { + r.to(|| { + error::InternalError::new( + io::Error::new(io::ErrorKind::Other, "test"), + StatusCode::INTERNAL_SERVER_ERROR, + ) + }) + }) // static files - .handler("/static", fs::StaticFiles::new("static").unwrap()) + .service(fs::StaticFiles::new("/static", "static").unwrap()) // redirect - .resource("/", |r| r.method(Method::GET).f(|req| { - println!("{:?}", req); - HttpResponse::Found() - .header(header::LOCATION, "static/welcome.html") - .finish() - })) + .resource("/", |r| { + r.route(web::get().to(|req: HttpRequest| { + println!("{:?}", req); + HttpResponse::Found() + .header(header::LOCATION, "static/welcome.html") + .finish() + })) + }) // default .default_resource(|r| { // 404 for GET request - r.method(Method::GET).f(p404); - - // all requests that are not `GET` - r.route().filter(pred::Not(pred::Get())).f( - |req| HttpResponse::MethodNotAllowed()); - })) - - .bind("127.0.0.1:8080").expect("Can not bind to 127.0.0.1:8080") - .shutdown_timeout(0) // <- Set shutdown timeout to 0 seconds (default 60s) - .start(); + r.route(web::get().to(p404)) + // all requests that are not `GET` + .route( + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ) + }) + }) + .bind("127.0.0.1:8080")? + .start(); println!("Starting http server: 127.0.0.1:8080"); let _ = sys.run(); + Ok(()) } From 40b5498902aced8ba3babd55ec2dc5979fd4a64e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 09:27:56 -0800 Subject: [PATCH 002/111] enable files listing --- basics/Cargo.toml | 5 +++++ basics/src/main.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/basics/Cargo.toml b/basics/Cargo.toml index b13337c7..ddb7736e 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,10 +7,15 @@ edition = "2018" [dependencies] actix-rt = "0.1" + 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" } actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +#actix-web = { path="../../actix-web/" } +#actix-session = { path="../../actix-web/actix-session/" } +#actix-staticfiles = { path="../../actix-web/actix-staticfiles/" } + futures = "0.1.25" env_logger = "0.5" bytes = "0.4" diff --git a/basics/src/main.rs b/basics/src/main.rs index fded1c3a..0700d9d2 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -112,7 +112,7 @@ fn main() -> io::Result<()> { }) }) // static files - .service(fs::StaticFiles::new("/static", "static").unwrap()) + .service(fs::StaticFiles::new("/static", "static").show_files_listing()) // redirect .resource("/", |r| { r.route(web::get().to(|req: HttpRequest| { From 10731e43c6ffe5e9138009af27f35feb25922084 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 10:04:41 -0800 Subject: [PATCH 003/111] convert r2d2 example --- basics/Cargo.toml | 1 - r2d2/Cargo.toml | 19 +++++----- r2d2/src/db.rs | 44 ----------------------- r2d2/src/main.rs | 90 +++++++++++++++++++++-------------------------- 4 files changed, 48 insertions(+), 106 deletions(-) delete mode 100644 r2d2/src/db.rs diff --git a/basics/Cargo.toml b/basics/Cargo.toml index ddb7736e..4e288328 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] actix-rt = "0.1" - 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" } actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index 884d84c4..b9f8de7c 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -2,20 +2,17 @@ name = "r2d2-example" version = "0.1.0" authors = ["Nikolay Kim "] +edition = "2018" workspace = "../" [dependencies] -env_logger = "0.5" - -actix = "0.7" -actix-web = "0.7" +actix-rt = "0.1" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } futures = "0.1" -uuid = { version = "0.5", features = ["serde", "v4"] } -serde = "1.0" -serde_json = "1.0" -serde_derive = "1.0" +env_logger = "0.6" +uuid = { version = "0.7", features = ["v4"] } -r2d2 = "*" -r2d2_sqlite = "*" -rusqlite = "*" +r2d2 = "0.8" +r2d2_sqlite = "0.8" +rusqlite = "0.16" diff --git a/r2d2/src/db.rs b/r2d2/src/db.rs deleted file mode 100644 index 5df9b3ff..00000000 --- a/r2d2/src/db.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Db executor actor -use actix::prelude::*; -use actix_web::*; -use r2d2::Pool; -use r2d2_sqlite::SqliteConnectionManager; -use std::io; -use uuid; - -/// This is db executor actor. We are going to run 3 of them in parallel. -pub struct DbExecutor(pub Pool); - -/// This is only message that this actor can handle, but it is easy to extend -/// number of messages. -pub struct CreateUser { - pub name: String, -} - -impl Message for CreateUser { - type Result = Result; -} - -impl Actor for DbExecutor { - type Context = SyncContext; -} - -impl Handler for DbExecutor { - type Result = Result; - - fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result { - let conn = self.0.get().unwrap(); - - let uuid = format!("{}", uuid::Uuid::new_v4()); - conn.execute( - "INSERT INTO users (id, name) VALUES ($1, $2)", - &[&uuid, &msg.name], - ).unwrap(); - - Ok(conn - .query_row("SELECT name FROM users WHERE id=$1", &[&uuid], |row| { - row.get(0) - }) - .map_err(|_| io::Error::new(io::ErrorKind::Other, "db error"))?) - } -} diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index e3cdb421..c594253f 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -1,68 +1,58 @@ //! Actix web r2d2 example -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; -extern crate r2d2; -extern crate r2d2_sqlite; -extern crate rusqlite; -extern crate serde; -extern crate serde_json; -extern crate uuid; +use std::io; -use actix::prelude::*; use actix_web::{ - http, middleware, server, App, AsyncResponder, Error, HttpRequest, HttpResponse, + blocking, extract::Path, web, App, Error, HttpResponse, HttpServer, State, }; -use futures::future::Future; +use futures::Future; +use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; +use uuid; -mod db; -use db::{CreateUser, DbExecutor}; +/// Async request handler. Ddb pool is stored in application state. +fn index( + path: Path, + db: State>, +) -> impl Future { + // execute sync code in threadpool + blocking::run(move || { + let conn = db.get().unwrap(); -/// State with DbExecutor address -struct State { - db: Addr, + let uuid = format!("{}", uuid::Uuid::new_v4()); + conn.execute( + "INSERT INTO users (id, name) VALUES ($1, $2)", + &[&uuid, &path.into_inner()], + ) + .unwrap(); + + conn.query_row("SELECT name FROM users WHERE id=$1", &[&uuid], |row| { + row.get::<_, String>(0) + }) + }) + .then(|res| match res { + Ok(user) => Ok(HttpResponse::Ok().json(user)), + Err(_) => Ok(HttpResponse::InternalServerError().into()), + }) } -/// Async request handler -fn index(req: &HttpRequest) -> Box> { - let name = &req.match_info()["name"]; - - req.state() - .db - .send(CreateUser { - name: name.to_owned(), - }) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok().json(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }) - .responder() -} - -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=debug"); +fn main() -> io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=debug"); env_logger::init(); - let sys = actix::System::new("r2d2-example"); + let sys = actix_rt::System::new("r2d2-example"); // r2d2 pool let manager = SqliteConnectionManager::file("test.db"); let pool = r2d2::Pool::new(manager).unwrap(); - // Start db executor actors - let addr = SyncArbiter::start(3, move || DbExecutor(pool.clone())); - - // Start http server - server::new(move || { - App::with_state(State{db: addr.clone()}) - // enable logger - .middleware(middleware::Logger::default()) - .resource("/{name}", |r| r.method(http::Method::GET).a(index)) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); + // start http server + HttpServer::new(move || { + App::new() + .state(pool.clone()) // <- store db pool in app state + .resource("/{name}", |r| r.route(web::get().to_async(index))) + }) + .bind("127.0.0.1:8080")? + .start(); let _ = sys.run(); + Ok(()) } From 80615b8579aa95f3237ae112e40ae4b84bb9207b Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 10:29:01 -0800 Subject: [PATCH 004/111] use new actix-rt --- basics/Cargo.toml | 2 +- basics/src/main.rs | 3 +-- r2d2/Cargo.toml | 2 +- r2d2/src/main.rs | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 4e288328..95c7608b 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../" edition = "2018" [dependencies] -actix-rt = "0.1" +actix-rt = "0.2" 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" } actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } diff --git a/basics/src/main.rs b/basics/src/main.rs index 0700d9d2..344ff49c 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -138,6 +138,5 @@ fn main() -> io::Result<()> { .start(); println!("Starting http server: 127.0.0.1:8080"); - let _ = sys.run(); - Ok(()) + sys.run() } diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index b9f8de7c..7046f298 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = "../" [dependencies] -actix-rt = "0.1" +actix-rt = "0.2" actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } futures = "0.1" diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index c594253f..05d07849 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -53,6 +53,5 @@ fn main() -> io::Result<()> { .bind("127.0.0.1:8080")? .start(); - let _ = sys.run(); - Ok(()) + sys.run() } From 1edbb348d9f327dbbb2a208c89f50468372c07d5 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 11:51:05 -0800 Subject: [PATCH 005/111] port async_db to actix-web 1.0 --- async_db/Cargo.toml | 6 ++- async_db/src/db.rs | 50 ++++++++----------- async_db/src/main.rs | 115 +++++++++++++++---------------------------- 3 files changed, 66 insertions(+), 105 deletions(-) diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 56e97c2f..9dee0d2f 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -2,10 +2,12 @@ name = "async_db" version = "0.1.0" authors = ["Darin Gordon "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-rt = "0.2" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } dotenv = "0.10" env_logger = "0.5" diff --git a/async_db/src/db.rs b/async_db/src/db.rs index a7903d71..9b700237 100644 --- a/async_db/src/db.rs +++ b/async_db/src/db.rs @@ -1,17 +1,14 @@ -use actix::prelude::*; +use actix_web::{blocking, Error as AWError}; use failure::Error; +use futures::Future; use r2d2; use r2d2_sqlite; +use serde_derive::{Deserialize, Serialize}; use std::{thread::sleep, time::Duration}; pub type Pool = r2d2::Pool; pub type Connection = r2d2::PooledConnection; -pub struct DbExecutor(pub Pool); -impl Actor for DbExecutor { - type Context = SyncContext; -} - #[derive(Debug, Serialize, Deserialize)] pub enum WeatherAgg { AnnualAgg { year: i32, total: f64 }, @@ -25,29 +22,24 @@ pub enum Queries { GetTopTenColdestMonths, } -//pub struct GetTopTenHottestYears; -impl Message for Queries { - type Result = Result, Error>; -} -impl Handler for DbExecutor { - type Result = Result, Error>; - - fn handle(&mut self, msg: Queries, _: &mut Self::Context) -> Self::Result { - let conn: Connection = self.0.get()?; - - match msg { - Queries::GetTopTenHottestYears => get_hottest_years(conn), - Queries::GetTopTenColdestYears => get_coldest_years(conn), - Queries::GetTopTenHottestMonths => get_hottest_months(conn), - Queries::GetTopTenColdestMonths => get_coldest_months(conn), - } - } +pub fn execute( + pool: &Pool, + query: Queries, +) -> impl Future, Error = AWError> { + let pool = pool.clone(); + blocking::run(move || match query { + Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?), + Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?), + Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?), + Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?), + }) + .from_err() } fn get_hottest_years(conn: Connection) -> Result, Error> { let stmt = " SELECT cast(strftime('%Y', date) as int) as theyear, - sum(tmax) as total + sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear @@ -73,7 +65,7 @@ fn get_hottest_years(conn: Connection) -> Result, Error> { fn get_coldest_years(conn: Connection) -> Result, Error> { let stmt = " SELECT cast(strftime('%Y', date) as int) as theyear, - sum(tmax) as total + sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear @@ -98,8 +90,8 @@ fn get_coldest_years(conn: Connection) -> Result, Error> { fn get_hottest_months(conn: Connection) -> Result, Error> { let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear, - cast(strftime('%m', date) as int) as themonth, - sum(tmax) as total + cast(strftime('%m', date) as int) as themonth, + sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear, themonth @@ -124,8 +116,8 @@ fn get_hottest_months(conn: Connection) -> Result, Error> { fn get_coldest_months(conn: Connection) -> Result, Error> { let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear, - cast(strftime('%m', date) as int) as themonth, - sum(tmax) as total + cast(strftime('%m', date) as int) as themonth, + sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear, themonth diff --git a/async_db/src/main.rs b/async_db/src/main.rs index 42dcb1bd..cd66d3f0 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -8,122 +8,89 @@ This project illustrates two examples: 2. An asynchronous handler that executes 4 queries in *parallel*, collecting the results and returning them as a single serialized json object -*/ + */ +use std::io; -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate failure; -extern crate futures; -extern crate num_cpus; -extern crate r2d2; -extern crate r2d2_sqlite; -extern crate serde; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; - -use actix::prelude::*; -use actix_web::{ - http, middleware, server, App, AsyncResponder, Error as AWError, FutureResponse, - HttpResponse, State, -}; +use actix_web::{web, App, Error as AWError, HttpResponse, HttpServer, State}; use futures::future::{join_all, ok as fut_ok, Future}; +use r2d2_sqlite; use r2d2_sqlite::SqliteConnectionManager; mod db; -use db::{DbExecutor, Pool, Queries, WeatherAgg}; - -/// State with DbExecutor address -struct AppState { - db: Addr, -} +use db::{Pool, Queries, WeatherAgg}; /// Version 1: Calls 4 queries in sequential order, as an asynchronous handler -fn asyncio_weather(state: State) -> FutureResponse { +fn asyncio_weather( + db: State, +) -> impl Future { let mut result: Vec> = vec![]; - state - .db - .send(Queries::GetTopTenHottestYears) + db::execute(&db, Queries::GetTopTenHottestYears) .from_err() .and_then(move |res| { - result.push(res.unwrap()); - state - .db - .send(Queries::GetTopTenColdestYears) + result.push(res); + db::execute(&db, Queries::GetTopTenColdestYears) .from_err() .and_then(move |res| { - result.push(res.unwrap()); - state - .db - .send(Queries::GetTopTenHottestMonths) + result.push(res); + db::execute(&db, Queries::GetTopTenHottestMonths) .from_err() .and_then(move |res| { - result.push(res.unwrap()); - state - .db - .send(Queries::GetTopTenColdestMonths) + result.push(res); + db::execute(&db, Queries::GetTopTenColdestMonths) .from_err() .and_then(move |res| { - result.push(res.unwrap()); + result.push(res); fut_ok(result) }) }) }) }) .and_then(|res| Ok(HttpResponse::Ok().json(res))) - .responder() } /// Version 2: Calls 4 queries in parallel, as an asynchronous handler /// Returning Error types turn into None values in the response -fn parallel_weather(state: State) -> FutureResponse { +fn parallel_weather( + db: State, +) -> impl Future { let fut_result = vec![ - Box::new(state.db.send(Queries::GetTopTenHottestYears)), - Box::new(state.db.send(Queries::GetTopTenColdestYears)), - Box::new(state.db.send(Queries::GetTopTenHottestMonths)), - Box::new(state.db.send(Queries::GetTopTenColdestMonths)), + Box::new(db::execute(&db, Queries::GetTopTenHottestYears)), + Box::new(db::execute(&db, Queries::GetTopTenColdestYears)), + Box::new(db::execute(&db, Queries::GetTopTenHottestMonths)), + Box::new(db::execute(&db, Queries::GetTopTenColdestMonths)), ]; join_all(fut_result) .map_err(AWError::from) - .and_then(|result| { - let res: Vec>> = - result.into_iter().map(|x| x.ok()).collect(); - - Ok(HttpResponse::Ok().json(res)) - }) - .responder() + .map(|result| HttpResponse::Ok().json(result)) } -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("parallel_db_example"); + let sys = actix_rt::System::new("parallel_db_example"); // Start N db executor actors (N = number of cores avail) - let manager = SqliteConnectionManager::file("weather.db"); let pool = Pool::new(manager).unwrap(); - let addr = SyncArbiter::start(num_cpus::get(), move || DbExecutor(pool.clone())); - // Start http server - server::new(move || { - App::with_state(AppState{db: addr.clone()}) + HttpServer::new(move || { + App::new() + .state(pool.clone()) // enable logger - .middleware(middleware::Logger::default()) - .resource("/asyncio_weather", |r| - r.method(http::Method::GET) - .with(asyncio_weather)) - .resource("/parallel_weather", |r| - r.method(http::Method::GET) - .with(parallel_weather)) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); + // .middleware(middleware::Logger::default()) + .resource("/asyncio_weather", |r| { + r.route(web::get().to_async(asyncio_weather)) + }) + .resource("/parallel_weather", |r| { + r.route(web::get().to_async(parallel_weather)) + }) + }) + .bind("127.0.0.1:8080")? + .start(); println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + sys.run() } From 51860a4f2ad2403d102d2bbbc8a2b185f0f73e3e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 15:51:56 -0800 Subject: [PATCH 006/111] update web api --- async_db/src/main.rs | 14 ++++++----- basics/src/main.rs | 55 +++++++++++++++++++++----------------------- r2d2/src/main.rs | 2 +- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/async_db/src/main.rs b/async_db/src/main.rs index cd66d3f0..fc3d910d 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -81,12 +81,14 @@ fn main() -> io::Result<()> { .state(pool.clone()) // enable logger // .middleware(middleware::Logger::default()) - .resource("/asyncio_weather", |r| { - r.route(web::get().to_async(asyncio_weather)) - }) - .resource("/parallel_weather", |r| { - r.route(web::get().to_async(parallel_weather)) - }) + .service( + web::resource("/asyncio_weather") + .route(web::get().to_async(asyncio_weather)), + ) + .service( + web::resource("/parallel_weather") + .route(web::get().to_async(parallel_weather)), + ) }) .bind("127.0.0.1:8080")? .start(); diff --git a/basics/src/main.rs b/basics/src/main.rs index 344ff49c..ccd73b05 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -83,45 +83,42 @@ fn main() -> io::Result<()> { // cookie session middleware .middleware(CookieSession::signed(&[0; 32]).secure(false)) // register favicon - .resource("/favicon", |r| r.to(favicon)) + .service(web::resource("/favicon").to(favicon)) // register simple route, handle all methods - .resource("/welcome", |r| r.to(welcome)) + .service(web::resource("/welcome").to(welcome)) // with path parameters - .resource("/user/{name}", |r| r.route(web::get().to(with_param))) + .service(web::resource("/user/{name}").route(web::get().to(with_param))) // async handler - .resource("/async/{name}", |r| { - r.route(web::get().to_async(index_async)) - }) + .service( + web::resource("/async/{name}").route(web::get().to_async(index_async)), + ) // async handler - .resource("/async-body/{name}", |r| { - r.route(web::get().to(index_async_body)) - }) - .resource("/test", |r| { - r.to(|req: HttpRequest| match *req.method() { + .service( + web::resource("/async-body/{name}") + .route(web::get().to(index_async_body)), + ) + .service( + web::resource("/test").to(|req: HttpRequest| match *req.method() { Method::GET => HttpResponse::Ok(), Method::POST => HttpResponse::MethodNotAllowed(), _ => HttpResponse::NotFound(), - }) - }) - .resource("/error", |r| { - r.to(|| { - error::InternalError::new( - io::Error::new(io::ErrorKind::Other, "test"), - StatusCode::INTERNAL_SERVER_ERROR, - ) - }) - }) + }), + ) + .service(web::resource("/error").to(|| { + error::InternalError::new( + io::Error::new(io::ErrorKind::Other, "test"), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })) // static files .service(fs::StaticFiles::new("/static", "static").show_files_listing()) // redirect - .resource("/", |r| { - r.route(web::get().to(|req: HttpRequest| { - println!("{:?}", req); - HttpResponse::Found() - .header(header::LOCATION, "static/welcome.html") - .finish() - })) - }) + .service(web::resource("/").route(web::get().to(|req: HttpRequest| { + println!("{:?}", req); + HttpResponse::Found() + .header(header::LOCATION, "static/welcome.html") + .finish() + }))) // default .default_resource(|r| { // 404 for GET request diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index 05d07849..abe564d1 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -48,7 +48,7 @@ fn main() -> io::Result<()> { HttpServer::new(move || { App::new() .state(pool.clone()) // <- store db pool in app state - .resource("/{name}", |r| r.route(web::get().to_async(index))) + .route("/{name}", web::get().to_async(index)) }) .bind("127.0.0.1:8080")? .start(); From c4df3356c7ea54211a817dbb2f195bc675435cd2 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 19:45:45 -0800 Subject: [PATCH 007/111] enable logger --- async_db/src/main.rs | 7 ++++--- basics/Cargo.toml | 4 ---- basics/src/main.rs | 5 +++-- r2d2/src/main.rs | 4 +++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/async_db/src/main.rs b/async_db/src/main.rs index fc3d910d..11027032 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -11,7 +11,9 @@ This project illustrates two examples: */ use std::io; -use actix_web::{web, App, Error as AWError, HttpResponse, HttpServer, State}; +use actix_web::{ + middleware, web, App, Error as AWError, HttpResponse, HttpServer, State, +}; use futures::future::{join_all, ok as fut_ok, Future}; use r2d2_sqlite; use r2d2_sqlite::SqliteConnectionManager; @@ -79,8 +81,7 @@ fn main() -> io::Result<()> { HttpServer::new(move || { App::new() .state(pool.clone()) - // enable logger - // .middleware(middleware::Logger::default()) + .middleware(middleware::Logger::default()) .service( web::resource("/asyncio_weather") .route(web::get().to_async(asyncio_weather)), diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 95c7608b..518a4637 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -11,10 +11,6 @@ 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" } actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -#actix-web = { path="../../actix-web/" } -#actix-session = { path="../../actix-web/actix-session/" } -#actix-staticfiles = { path="../../actix-web/actix-staticfiles/" } - futures = "0.1.25" env_logger = "0.5" bytes = "0.4" diff --git a/basics/src/main.rs b/basics/src/main.rs index ccd73b05..d4f6eae0 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -5,7 +5,8 @@ use actix_staticfiles as fs; use actix_web::extract::Path; use actix_web::http::{header, Method, StatusCode}; use actix_web::{ - error, guard, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, + error, guard, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, + Result, }; use bytes::Bytes; use futures::unsync::mpsc; @@ -79,7 +80,7 @@ fn main() -> io::Result<()> { HttpServer::new(|| { App::new() // enable logger - // .middleware(middleware::Logger::default()) + .middleware(middleware::Logger::default()) // cookie session middleware .middleware(CookieSession::signed(&[0; 32]).secure(false)) // register favicon diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index abe564d1..da83a8a6 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -2,7 +2,8 @@ use std::io; use actix_web::{ - blocking, extract::Path, web, App, Error, HttpResponse, HttpServer, State, + blocking, extract::Path, middleware, web, App, Error, HttpResponse, HttpServer, + State, }; use futures::Future; use r2d2::Pool; @@ -48,6 +49,7 @@ fn main() -> io::Result<()> { HttpServer::new(move || { App::new() .state(pool.clone()) // <- store db pool in app state + .middleware(middleware::Logger::default()) .route("/{name}", web::get().to_async(index)) }) .bind("127.0.0.1:8080")? From ab2fdbd6391cbbae55bee5ee384a1b84dc646427 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 23:16:56 -0800 Subject: [PATCH 008/111] migrate tls example --- tls/Cargo.toml | 10 ++++--- tls/cert.pem | 43 +++++++++------------------ tls/key.pem | 79 ++++++++++++++++++------------------------------- tls/src/main.rs | 35 ++++++++++------------ 4 files changed, 63 insertions(+), 104 deletions(-) diff --git a/tls/Cargo.toml b/tls/Cargo.toml index dcae3d35..b18ff5a7 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "tls-example" -version = "0.1.0" +version = "0.2.0" authors = ["Nikolay Kim "] -workspace = "../" +edition = "2018" +workspace = ".." [[bin]] name = "tls-server" @@ -11,5 +12,6 @@ path = "src/main.rs" [dependencies] env_logger = "0.5" openssl = { version="0.10" } -actix = "0.7" -actix-web = { version = "0.7", features=["ssl"] } + +actix-rt = "0.2" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0", features=["ssl"] } diff --git a/tls/cert.pem b/tls/cert.pem index 159aacea..9a744d16 100644 --- a/tls/cert.pem +++ b/tls/cert.pem @@ -1,31 +1,16 @@ -----BEGIN CERTIFICATE----- -MIIFPjCCAyYCCQDvLYiYD+jqeTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV -UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww -CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xODAxMjUx -NzQ2MDFaFw0xOTAxMjUxNzQ2MDFaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD -QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY -MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEPn8k1 -sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+MIK5U -NLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM54jXy -voLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZWLWr -odGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAkoqND -xdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNliJDmA -CRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6/stI -yFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuDYX2U -UuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nPwPTO -vRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA69un -CEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEAATAN -BgkqhkiG9w0BAQsFAAOCAgEApavsgsn7SpPHfhDSN5iZs1ILZQRewJg0Bty0xPfk -3tynSW6bNH3nSaKbpsdmxxomthNSQgD2heOq1By9YzeOoNR+7Pk3s4FkASnf3ToI -JNTUasBFFfaCG96s4Yvs8KiWS/k84yaWuU8c3Wb1jXs5Rv1qE1Uvuwat1DSGXSoD -JNluuIkCsC4kWkyq5pWCGQrabWPRTWsHwC3PTcwSRBaFgYLJaR72SloHB1ot02zL -d2age9dmFRFLLCBzP+D7RojBvL37qS/HR+rQ4SoQwiVc/JzaeqSe7ZbvEH9sZYEu -ALowJzgbwro7oZflwTWunSeSGDSltkqKjvWvZI61pwfHKDahUTmZ5h2y67FuGEaC -CIOUI8dSVSPKITxaq3JL4ze2e9/0Lt7hj19YK2uUmtMAW5Tirz4Yx5lyGH9U8Wur -y/X8VPxTc4A9TMlJgkyz0hqvhbPOT/zSWB10zXh0glKAsSBryAOEDxV1UygmSir7 -YV8Qaq+oyKUTMc1MFq5vZ07M51EPaietn85t8V2Y+k/8XYltRp32NxsypxAJuyxh -g/ko6RVTrWa1sMvz/F9LFqAdKiK5eM96lh9IU4xiLg4ob8aS/GRAA8oIFkZFhLrt -tOwjIUPmEPyHWFi8dLpNuQKYalLYhuwZftG/9xV+wqhKGZO9iPrpHSYBRTap8w2y -1QU= +MIICljCCAX4CCQDztMNlxk6oeTANBgkqhkiG9w0BAQsFADANMQswCQYDVQQIDAJj +YTAeFw0xOTAzMDcwNzEyNThaFw0yMDAzMDYwNzEyNThaMA0xCzAJBgNVBAgMAmNh +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0GMP3YzDVFWgNhRiHnfe +d192131Zi23p8WiutneD9I5WO42c79fOXsxLWn+2HSqPvCPHIBLoMX8o9lgCxt2P +/JUCAWbrE2EuvhkMrWk6/q7xB211XZYfnkqdt7mA0jMUC5o32AX3ew456TAq5P8Y +dq9H/qXdRtAvKD0QdkFfq8ePCiqOhcqacZ/NWva7R4HdgTnbL1DRQjGBXszI07P9 +1yw8GOym46uxNHRujQp3lYEhc1V3JTF9kETpSBHyEAkQ8WHxGf8UBHDhh7hcc+KI +JHMlVYy5wDv4ZJeYsY1rD6/n4tyd3r0yzBM57UGf6qrVZEYmLB7Jad+8Df5vIoGh +WwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB1DEu9NiShCfQuA17MG5O0Jr2/PS1z +/+HW7oW15WXpqDKOEJalid31/Bzwvwq0bE12xKE4ZLdbqJHmJTdSUoGfOfBZKka6 +R2thOjqH7hFvxjfgS7kBy5BrRZewM9xKIJ6zU6+6mxR64x9vmkOmppV0fx5clZjH +c7qn5kSNWTMsFbjPnb5BeJJwZdqpMLs99jgoMvGtCUmkyVYODGhh65g6tR9kIPvM +zu/Cw122/y7tFfkuknMSYwGEYF3XcZpXt54a6Lu5hk6PuOTsK+7lC+HX7CSF1dpv +u1szL5fDgiCBFCnyKeOqF61mxTCUht3U++37VDFvhzN1t6HIVTYm2JJ7 -----END CERTIFICATE----- diff --git a/tls/key.pem b/tls/key.pem index aac387c6..4416facc 100644 --- a/tls/key.pem +++ b/tls/key.pem @@ -1,51 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEP -n8k1sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+M -IK5UNLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM5 -4jXyvoLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZ -WLWrodGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAk -oqNDxdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNli -JDmACRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6 -/stIyFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuD -YX2UUuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nP -wPTOvRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA -69unCEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEA -AQKCAgAME3aoeXNCPxMrSri7u4Xnnk71YXl0Tm9vwvjRQlMusXZggP8VKN/KjP0/ -9AE/GhmoxqPLrLCZ9ZE1EIjgmZ9Xgde9+C8rTtfCG2RFUL7/5J2p6NonlocmxoJm -YkxYwjP6ce86RTjQWL3RF3s09u0inz9/efJk5O7M6bOWMQ9VZXDlBiRY5BYvbqUR -6FeSzD4MnMbdyMRoVBeXE88gTvZk8xhB6DJnLzYgc0tKiRoeKT0iYv5JZw25VyRM -ycLzfTrFmXCPfB1ylb483d9Ly4fBlM8nkx37PzEnAuukIawDxsPOb9yZC+hfvNJI -7NFiMN+3maEqG2iC00w4Lep4skHY7eHUEUMl+Wjr+koAy2YGLWAwHZQTm7iXn9Ab -L6adL53zyCKelRuEQOzbeosJAqS+5fpMK0ekXyoFIuskj7bWuIoCX7K/kg6q5IW+ -vC2FrlsrbQ79GztWLVmHFO1I4J9M5r666YS0qdh8c+2yyRl4FmSiHfGxb3eOKpxQ -b6uI97iZlkxPF9LYUCSc7wq0V2gGz+6LnGvTHlHrOfVXqw/5pLAKhXqxvnroDTwz -0Ay/xFF6ei/NSxBY5t8ztGCBm45wCU3l8pW0X6dXqwUipw5b4MRy1VFRu6rqlmbL -OPSCuLxqyqsigiEYsBgS/icvXz9DWmCQMPd2XM9YhsHvUq+R4QKCAQEA98EuMMXI -6UKIt1kK2t/3OeJRyDd4iv/fCMUAnuPjLBvFE4cXD/SbqCxcQYqb+pue3PYkiTIC -71rN8OQAc5yKhzmmnCE5N26br/0pG4pwEjIr6mt8kZHmemOCNEzvhhT83nfKmV0g -9lNtuGEQMiwmZrpUOF51JOMC39bzcVjYX2Cmvb7cFbIq3lR0zwM+aZpQ4P8LHCIu -bgHmwbdlkLyIULJcQmHIbo6nPFB3ZZE4mqmjwY+rA6Fh9rgBa8OFCfTtrgeYXrNb -IgZQ5U8GoYRPNC2ot0vpTinraboa/cgm6oG4M7FW1POCJTl+/ktHEnKuO5oroSga -/BSg7hCNFVaOhwKCAQEA4Kkys0HtwEbV5mY/NnvUD5KwfXX7BxoXc9lZ6seVoLEc -KjgPYxqYRVrC7dB2YDwwp3qcRTi/uBAgFNm3iYlDzI4xS5SeaudUWjglj7BSgXE2 -iOEa7EwcvVPluLaTgiWjlzUKeUCNNHWSeQOt+paBOT+IgwRVemGVpAgkqQzNh/nP -tl3p9aNtgzEm1qVlPclY/XUCtf3bcOR+z1f1b4jBdn0leu5OhnxkC+Htik+2fTXD -jt6JGrMkanN25YzsjnD3Sn+v6SO26H99wnYx5oMSdmb8SlWRrKtfJHnihphjG/YY -l1cyorV6M/asSgXNQfGJm4OuJi0I4/FL2wLUHnU+JwKCAQEAzh4WipcRthYXXcoj -gMKRkMOb3GFh1OpYqJgVExtudNTJmZxq8GhFU51MR27Eo7LycMwKy2UjEfTOnplh -Us2qZiPtW7k8O8S2m6yXlYUQBeNdq9IuuYDTaYD94vsazscJNSAeGodjE+uGvb1q -1wLqE87yoE7dUInYa1cOA3+xy2/CaNuviBFJHtzOrSb6tqqenQEyQf6h9/12+DTW -t5pSIiixHrzxHiFqOoCLRKGToQB+71rSINwTf0nITNpGBWmSj5VcC3VV3TG5/XxI -fPlxV2yhD5WFDPVNGBGvwPDSh4jSMZdZMSNBZCy4XWFNSKjGEWoK4DFYed3DoSt9 -5IG1YwKCAQA63ntHl64KJUWlkwNbboU583FF3uWBjee5VqoGKHhf3CkKMxhtGqnt -+oN7t5VdUEhbinhqdx1dyPPvIsHCS3K1pkjqii4cyzNCVNYa2dQ00Qq+QWZBpwwc -3GAkz8rFXsGIPMDa1vxpU6mnBjzPniKMcsZ9tmQDppCEpBGfLpio2eAA5IkK8eEf -cIDB3CM0Vo94EvI76CJZabaE9IJ+0HIJb2+jz9BJ00yQBIqvJIYoNy9gP5Xjpi+T -qV/tdMkD5jwWjHD3AYHLWKUGkNwwkAYFeqT/gX6jpWBP+ZRPOp011X3KInJFSpKU -DT5GQ1Dux7EMTCwVGtXqjO8Ym5wjwwsfAoIBAEcxlhIW1G6BiNfnWbNPWBdh3v/K -5Ln98Rcrz8UIbWyl7qNPjYb13C1KmifVG1Rym9vWMO3KuG5atK3Mz2yLVRtmWAVc -fxzR57zz9MZFDun66xo+Z1wN3fVxQB4CYpOEI4Lb9ioX4v85hm3D6RpFukNtRQEc -Gfr4scTjJX4jFWDp0h6ffMb8mY+quvZoJ0TJqV9L9Yj6Ksdvqez/bdSraev97bHQ -4gbQxaTZ6WjaD4HjpPQefMdWp97Metg0ZQSS8b8EzmNFgyJ3XcjirzwliKTAQtn6 -I2sd0NCIooelrKRD8EJoDUwxoOctY7R97wpZ7/wEHU45cBCbRV3H4JILS5c= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQYw/djMNUVaA2 +FGIed953X3bXfVmLbenxaK62d4P0jlY7jZzv185ezEtaf7YdKo+8I8cgEugxfyj2 +WALG3Y/8lQIBZusTYS6+GQytaTr+rvEHbXVdlh+eSp23uYDSMxQLmjfYBfd7Djnp +MCrk/xh2r0f+pd1G0C8oPRB2QV+rx48KKo6Fyppxn81a9rtHgd2BOdsvUNFCMYFe +zMjTs/3XLDwY7Kbjq7E0dG6NCneVgSFzVXclMX2QROlIEfIQCRDxYfEZ/xQEcOGH +uFxz4ogkcyVVjLnAO/hkl5ixjWsPr+fi3J3evTLMEzntQZ/qqtVkRiYsHslp37wN +/m8igaFbAgMBAAECggEAJI278rkGany6pcHdlEqik34DcrliQ7r8FoSuYQOF+hgd +uESXCttoL+jWLwHICEW3AOGlxFKMuGH95Xh6xDeJUl0xBN3wzm11rZLnTmPvHU3C +qfLha5Ex6qpcECZSGo0rLv3WXeZuCv/r2KPCYnj86ZTFpD2kGw/Ztc1AXf4Jsi/1 +478Mf23QmAvCAPimGCyjLQx2c9/vg/6K7WnDevY4tDuDKLeSJxKZBSHUn3cM1Bwj +2QzaHfSFA5XljOF5PLeR3cY5ncrrVLWChT9XuGt9YMdLAcSQxgE6kWV1RSCq+lbj +e6OOe879IrrqwBvMQfKQqnm1kl8OrfPMT5CNWKvEgQKBgQD8q5E4x9taDS9RmhRO +07ptsr/I795tX8CaJd/jc4xGuCGBqpNw/hVebyNNYQvpiYzDNBSEhtd59957VyET +hcrGyxD0ByKm8F/lPgFw5y6wi3RUnucCV/jxkMHmxVzYMbFUEGCQ0pIU9/GFS7RZ +9VjqRDeE86U3yHO+WCFoHtd8aQKBgQDTIhi0uq0oY87bUGnWbrrkR0UVRNPDG1BT +cuXACYlv/DV/XpxPC8iPK1UwG4XaOVxodtIRjdBqvb8fUM6HSY6qll64N/4/1jre +Ho+d4clE4tK6a9WU96CKxwHn2BrWUZJPtoldaCZJFJ7SfiHuLlqW7TtYFrOfPIjN +ADiqK+bHIwKBgQCpfIiAVwebo0Z/bWR77+iZFxMwvT4tjdJLVGaXUvXgpjjLmtkm +LTm2S8SZbiSodfz3H+M3dp/pj8wsXiiwyMlZifOITZT/+DPLOUmMK3cVM6ZH8QMy +fkJd/+UhYHhECSlTI10zKByXdi4LZNnIkhwfoLzBMRI9lfeV0dYu2qlfKQKBgEVI +kRbtk1kHt5/ceX62g3nZsV/TYDJMSkW4FJC6EHHBL8UGRQDjewMQUzogLgJ4hEx7 +gV/lS5lbftZF7CAVEU4FXjvRlAtav6KYIMTMjQGf9UrbjBEAWZxwxb1Q+y2NQxgJ +bHZMcRPWQnAMmBHTAEM6whicCoGcmb+77Nxa37ZFAoGBALBuUNeD3fKvQR8v6GoA +spv+RYL9TB4wz2Oe9EYSp9z5EiWlTmuvFz3zk8pHDSpntxYH5O5HJ/3OzwhHz9ym ++DNE9AP9LW9hAzMuu7Gob1h8ShGwJVYwrQN3q/83ooUL7WSAuVOLpzJ7BFFlcCjp +MhFvd9iOt/R0N30/3AbQXkOp +-----END PRIVATE KEY----- diff --git a/tls/src/main.rs b/tls/src/main.rs index 329e15db..f8c8961c 100644 --- a/tls/src/main.rs +++ b/tls/src/main.rs @@ -1,26 +1,21 @@ -#![allow(unused_variables)] -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate openssl; +use std::io; -use actix_web::{http, middleware, server, App, Error, HttpRequest, HttpResponse}; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; /// simple handle -fn index(req: &HttpRequest) -> Result { +fn index(req: HttpRequest) -> Result { println!("{:?}", req); Ok(HttpResponse::Ok() .content_type("text/plain") .body("Welcome!")) } -fn main() { - if ::std::env::var("RUST_LOG").is_err() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); - } +fn main() -> io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=debug"); env_logger::init(); - let sys = actix::System::new("ws-example"); + + let sys = actix_rt::System::new("tls-example"); // load ssl keys let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); @@ -29,22 +24,22 @@ fn main() { .unwrap(); builder.set_certificate_chain_file("cert.pem").unwrap(); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger .middleware(middleware::Logger::default()) // register simple handler, handle all methods - .resource("/index.html", |r| r.f(index)) + .service(web::resource("/index.html").to(index)) // with path parameters - .resource("/", |r| r.method(http::Method::GET).f(|req| { + .service(web::resource("/").route(web::get().to(|| { HttpResponse::Found() .header("LOCATION", "/index.html") .finish() - })) - }).bind_ssl("127.0.0.1:8443", builder) - .unwrap() - .start(); + }))) + }) + .bind_ssl("127.0.0.1:8443", builder)? + .start(); println!("Started http server: 127.0.0.1:8443"); - let _ = sys.run(); + sys.run() } From 60a9df8abdffd5f4aa16b22c5ea9893c0634fa91 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 6 Mar 2019 23:44:46 -0800 Subject: [PATCH 009/111] rename to Files --- basics/Cargo.toml | 2 +- basics/src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 518a4637..71a98837 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" [dependencies] actix-rt = "0.2" actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-staticfiles = { git="https://github.com/actix/actix-web.git", branch = "1.0" } futures = "0.1.25" env_logger = "0.5" diff --git a/basics/src/main.rs b/basics/src/main.rs index d4f6eae0..8768718c 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -1,7 +1,7 @@ use std::{env, io}; +use actix_files as fs; use actix_session::{CookieSession, Session}; -use actix_staticfiles as fs; use actix_web::extract::Path; use actix_web::http::{header, Method, StatusCode}; use actix_web::{ @@ -112,7 +112,7 @@ fn main() -> io::Result<()> { ) })) // static files - .service(fs::StaticFiles::new("/static", "static").show_files_listing()) + .service(fs::Files::new("/static", "static").show_files_listing()) // redirect .service(web::resource("/").route(web::get().to(|req: HttpRequest| { println!("{:?}", req); From f39a53ea3a3bdd8c7e783a9789c043f8aa4d4d71 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 7 Mar 2019 14:50:29 -0800 Subject: [PATCH 010/111] upgrade diesel, r2d2, state examples --- async_db/src/main.rs | 8 +-- basics/src/main.rs | 14 ++-- diesel/Cargo.toml | 11 ++- diesel/src/db.rs | 55 -------------- diesel/src/main.rs | 166 ++++++++++++++++++++----------------------- json/Cargo.toml | 8 +-- json/src/main.rs | 135 +++++++++++++++-------------------- r2d2/src/main.rs | 11 ++- state/Cargo.toml | 10 +-- state/src/main.rs | 49 +++++-------- 10 files changed, 185 insertions(+), 282 deletions(-) delete mode 100644 diesel/src/db.rs diff --git a/async_db/src/main.rs b/async_db/src/main.rs index 11027032..e9583999 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -11,9 +11,7 @@ This project illustrates two examples: */ use std::io; -use actix_web::{ - middleware, web, App, Error as AWError, HttpResponse, HttpServer, State, -}; +use actix_web::{middleware, web, App, Error as AWError, HttpResponse, HttpServer}; use futures::future::{join_all, ok as fut_ok, Future}; use r2d2_sqlite; use r2d2_sqlite::SqliteConnectionManager; @@ -23,7 +21,7 @@ use db::{Pool, Queries, WeatherAgg}; /// Version 1: Calls 4 queries in sequential order, as an asynchronous handler fn asyncio_weather( - db: State, + db: web::State, ) -> impl Future { let mut result: Vec> = vec![]; @@ -54,7 +52,7 @@ fn asyncio_weather( /// Version 2: Calls 4 queries in parallel, as an asynchronous handler /// Returning Error types turn into None values in the response fn parallel_weather( - db: State, + db: web::State, ) -> impl Future { let fut_result = vec![ Box::new(db::execute(&db, Queries::GetTopTenHottestYears)), diff --git a/basics/src/main.rs b/basics/src/main.rs index 8768718c..55f25bb0 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -1,8 +1,10 @@ +#[macro_use] +extern crate actix_web; + use std::{env, io}; use actix_files as fs; use actix_session::{CookieSession, Session}; -use actix_web::extract::Path; use actix_web::http::{header, Method, StatusCode}; use actix_web::{ error, guard, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, @@ -13,11 +15,13 @@ use futures::unsync::mpsc; use futures::{future::ok, Future, Stream}; /// favicon handler +#[get("/favicon")] fn favicon() -> Result { Ok(fs::NamedFile::open("static/favicon.ico")?) } /// simple index handler +#[get("/welcome")] fn welcome(session: Session, req: HttpRequest) -> Result { println!("{:?}", req); @@ -52,7 +56,7 @@ fn index_async(req: HttpRequest) -> impl Future) -> HttpResponse { +fn index_async_body(path: web::Path) -> HttpResponse { let text = format!("Hello {}!", *path); let (tx, rx_body) = mpsc::unbounded(); @@ -63,7 +67,7 @@ fn index_async_body(path: Path) -> HttpResponse { } /// handler with path parameters like `/user/{name}/` -fn with_param(req: HttpRequest, path: Path<(String,)>) -> HttpResponse { +fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse { println!("{:?}", req); HttpResponse::Ok() @@ -84,9 +88,9 @@ fn main() -> io::Result<()> { // cookie session middleware .middleware(CookieSession::signed(&[0; 32]).secure(false)) // register favicon - .service(web::resource("/favicon").to(favicon)) + .service(favicon) // register simple route, handle all methods - .service(web::resource("/welcome").to(welcome)) + .service(welcome) // with path parameters .service(web::resource("/user/{name}").route(web::get().to(with_param))) // async handler diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index a2f309b8..af94c957 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -2,15 +2,14 @@ name = "diesel-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } + bytes = "0.4" -env_logger = "0.5" - -actix = "0.7" -actix-web = "0.7" - +env_logger = "0.6" futures = "0.1" uuid = { version = "0.5", features = ["serde", "v4"] } serde = "1.0" diff --git a/diesel/src/db.rs b/diesel/src/db.rs deleted file mode 100644 index de3dd179..00000000 --- a/diesel/src/db.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Db executor actor -use actix::prelude::*; -use actix_web::*; -use diesel; -use diesel::prelude::*; -use diesel::r2d2::{ConnectionManager, Pool}; -use uuid; - -use models; -use schema; - -/// This is db executor actor. We are going to run 3 of them in parallel. -pub struct DbExecutor(pub Pool>); - -/// This is only message that this actor can handle, but it is easy to extend -/// number of messages. -pub struct CreateUser { - pub name: String, -} - -impl Message for CreateUser { - type Result = Result; -} - -impl Actor for DbExecutor { - type Context = SyncContext; -} - -impl Handler for DbExecutor { - type Result = Result; - - fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result { - use self::schema::users::dsl::*; - - let uuid = format!("{}", uuid::Uuid::new_v4()); - let new_user = models::NewUser { - id: &uuid, - name: &msg.name, - }; - - let conn: &SqliteConnection = &self.0.get().unwrap(); - - diesel::insert_into(users) - .values(&new_user) - .execute(conn) - .map_err(|_| error::ErrorInternalServerError("Error inserting person"))?; - - let mut items = users - .filter(id.eq(&uuid)) - .load::(conn) - .map_err(|_| error::ErrorInternalServerError("Error loading person"))?; - - Ok(items.pop().unwrap()) - } -} diff --git a/diesel/src/main.rs b/diesel/src/main.rs index d30519d6..8ff8ce68 100644 --- a/diesel/src/main.rs +++ b/diesel/src/main.rs @@ -4,77 +4,74 @@ //! Actix supports sync actors by default, so we going to create sync actor //! that use diesel. Technically sync actors are worker style actors, multiple //! of them can run in parallel and process messages from same queue. -extern crate serde; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; #[macro_use] extern crate diesel; -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; -extern crate r2d2; -extern crate uuid; -extern crate bytes; -// extern crate json; - - -use bytes::BytesMut; -use actix::prelude::*; -use actix_web::{ - http, middleware, server, App, AsyncResponder, FutureResponse, HttpResponse, Path, Error, HttpRequest, - State, HttpMessage, error, Json -}; +#[macro_use] +extern crate serde_derive; +use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; +use bytes::{Bytes, BytesMut}; use diesel::prelude::*; -use diesel::r2d2::ConnectionManager; -use futures::{future, Future, Stream}; +use diesel::r2d2::{self, ConnectionManager}; +use futures::future::{err, Either}; +use futures::{Future, Stream}; -mod db; mod models; mod schema; -use db::{CreateUser, DbExecutor}; +type Pool = r2d2::Pool>; -/// State with DbExecutor address -struct AppState { - db: Addr, +/// Diesel query +fn query( + nm: String, + pool: web::State, +) -> Result { + use self::schema::users::dsl::*; + + let uuid = format!("{}", uuid::Uuid::new_v4()); + let new_user = models::NewUser { + id: &uuid, + name: nm.as_str(), + }; + let conn: &SqliteConnection = &pool.get().unwrap(); + + diesel::insert_into(users).values(&new_user).execute(conn)?; + + let mut items = users.filter(id.eq(&uuid)).load::(conn)?; + Ok(items.pop().unwrap()) } /// Async request handler fn add( - (name, state): (Path, State), -) -> FutureResponse { - // send async `CreateUser` message to a `DbExecutor` - state - .db - .send(CreateUser { - name: name.into_inner(), - }) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok().json(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }) - .responder() + name: web::Path, + pool: web::State, +) -> impl Future { + // run diesel blocking code + web::block(move || query(name.into_inner(), pool)).then(|res| match res { + Ok(user) => Ok(HttpResponse::Ok().json(user)), + Err(_) => Ok(HttpResponse::InternalServerError().into()), + }) } #[derive(Debug, Serialize, Deserialize)] struct MyUser { - name: String + name: String, } const MAX_SIZE: usize = 262_144; // max payload size is 256k /// This handler manually load request payload and parse json object -fn index_add((req, state): (HttpRequest, State)) -> impl Future { - // HttpRequest::payload() is stream of Bytes objects - req.payload() +fn index_add

( + pl: web::Payload

, + pool: web::State, +) -> impl Future +where + P: Stream, +{ + pl // `Future::from_err` acts like `?` in that it coerces the error type from // the future into the final error type .from_err() - // `fold` will asynchronously read each chunk of the request body and // call supplied closure, then it resolves to result of closure .fold(BytesMut::new(), move |mut body, chunk| { @@ -92,45 +89,39 @@ fn index_add((req, state): (HttpRequest, State)) -> impl Fut // Douman NOTE: // The return value in this closure helps, to clarify result for compiler // as otheriwse it cannot understand it - .and_then(move |body| -> Box> { + .and_then(move |body| { // body is loaded, now we can deserialize serde-json let r_obj = serde_json::from_slice::(&body); // Send to the db for create match r_obj { Ok(obj) => { - let res = state.db.send(CreateUser { name: obj.name, }) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok().json(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }); - - Box::new(res) + Either::A(web::block(move || query(obj.name, pool)).then(|res| { + match res { + Ok(user) => Ok(HttpResponse::Ok().json(user)), + Err(_) => Ok(HttpResponse::InternalServerError().into()), + } + })) } - Err(_) => Box::new(future::err(error::ErrorBadRequest("Json Decode Failed"))) + Err(_) => Either::B(err(error::ErrorBadRequest("Json Decode Failed"))), } }) } -fn add2((item, state): (Json, State)) -> impl Future { - state.db - .send(CreateUser { - // into_inner to move into the reference, then accessing name to - // move the name out. - name: item.into_inner().name, - }) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok().json(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }) +fn add2( + item: web::Json, + pool: web::State, +) -> impl Future { + // run diesel blocking code + web::block(move || query(item.into_inner().name, pool)).then(|res| match res { + Ok(user) => Ok(HttpResponse::Ok().json(user)), + Err(_) => Ok(HttpResponse::InternalServerError().into()), + }) } -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("diesel-example"); // Start 3 db executor actors let manager = ConnectionManager::::new("test.db"); @@ -138,32 +129,29 @@ fn main() { .build(manager) .expect("Failed to create pool."); - let addr = SyncArbiter::start(3, move || DbExecutor(pool.clone())); - // Start http server - server::new(move || { - App::with_state(AppState{db: addr.clone()}) + HttpServer::new(move || { + App::new() + .state(pool.clone()) // enable logger .middleware(middleware::Logger::default()) // This can be called with: // curl -S --header "Content-Type: application/json" --request POST --data '{"name":"xyz"}' http://127.0.0.1:8080/add // Use of the extractors makes some post conditions simpler such // as size limit protections and built in json validation. - .resource("/add2", |r| { - r.method(http::Method::POST) - .with_async_config(add2, |(json_cfg, )| { - json_cfg.0.limit(4096); // <- limit size of the payload - }) - }) + .service( + web::resource("/add2").route( + web::post() + .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .to_async(add2), + ), + ) // Manual parsing would allow custom error construction, use of // other parsers *beside* json (for example CBOR, protobuf, xml), and allows // an application to standardise on a single parser implementation. - .resource("/add", |r| r.method(http::Method::POST).with_async(index_add)) - .resource("/add/{name}", |r| r.method(http::Method::GET).with(add)) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .service(web::resource("/add").route(web::post().to_async(index_add))) + .service(web::resource("/add/{name}").route(web::get().to_async(add))) + }) + .bind("127.0.0.1:8080")? + .run() } diff --git a/json/Cargo.toml b/json/Cargo.toml index c358f4ae..ff724d24 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -2,9 +2,12 @@ name = "json-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } + bytes = "0.4" futures = "0.1" env_logger = "*" @@ -13,6 +16,3 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" json = "*" - -actix = "0.7" -actix-web = "^0.7" diff --git a/json/src/main.rs b/json/src/main.rs index a93f761e..6c9d7a5c 100644 --- a/json/src/main.rs +++ b/json/src/main.rs @@ -1,22 +1,13 @@ -extern crate actix; -extern crate actix_web; -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; #[macro_use] extern crate json; use actix_web::{ - error, http, middleware, server, App, AsyncResponder, Error, HttpMessage, - HttpRequest, HttpResponse, Json, + error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, }; - -use bytes::BytesMut; +use bytes::{Bytes, BytesMut}; use futures::{Future, Stream}; use json::JsonValue; +use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct MyObj { @@ -24,39 +15,34 @@ struct MyObj { number: i32, } -/// This handler uses `HttpRequest::json()` for loading json object. -fn index(req: &HttpRequest) -> Box> { - req.json() - .from_err() // convert all errors into `Error` - .and_then(|val: MyObj| { - println!("model: {:?}", val); - Ok(HttpResponse::Ok().json(val)) // <- send response - }) - .responder() -} - /// This handler uses json extractor -fn extract_item(item: Json) -> HttpResponse { +fn index(item: web::Json) -> HttpResponse { println!("model: {:?}", &item); HttpResponse::Ok().json(item.0) // <- send response } /// This handler uses json extractor with limit -fn extract_item_limit((item, _req): (Json, HttpRequest)) -> HttpResponse { - println!("model: {:?}", &item); - HttpResponse::Ok().json(item.0) // <- send response +fn extract_item(item: web::Json, req: HttpRequest) -> HttpResponse { + println!("request: {:?}", req); + println!("model: {:?}", item); + + HttpResponse::Ok().json(item.0) // <- send json response } const MAX_SIZE: usize = 262_144; // max payload size is 256k /// This handler manually load request payload and parse json object -fn index_manual(req: &HttpRequest) -> Box> { - // HttpRequest::payload() is stream of Bytes objects - req.payload() +fn index_manual

( + payload: web::Payload

, +) -> impl Future +where + P: Stream, +{ + // payload is a stream of Bytes objects + payload // `Future::from_err` acts like `?` in that it coerces the error type from // the future into the final error type .from_err() - // `fold` will asynchronously read each chunk of the request body and // call supplied closure, then it resolves to result of closure .fold(BytesMut::new(), move |mut body, chunk| { @@ -75,59 +61,56 @@ fn index_manual(req: &HttpRequest) -> Box(&body)?; Ok(HttpResponse::Ok().json(obj)) // <- send response }) - .responder() } /// This handler manually load request payload and parse json-rust -fn index_mjsonrust( - req: &HttpRequest, -) -> Box> { - req.payload() - .concat2() - .from_err() - .and_then(|body| { - // body is loaded, now we can deserialize json-rust - let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result - let injson: JsonValue = match result { - Ok(v) => v, - Err(e) => object!{"err" => e.to_string() }, - }; - Ok(HttpResponse::Ok() - .content_type("application/json") - .body(injson.dump())) - }) - .responder() +fn index_mjsonrust

( + pl: web::Payload

, +) -> impl Future +where + P: Stream, +{ + pl.concat2().from_err().and_then(|body| { + // body is loaded, now we can deserialize json-rust + let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result + let injson: JsonValue = match result { + Ok(v) => v, + Err(e) => json::object! {"err" => e.to_string() }, + }; + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(injson.dump())) + }) } -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("json-example"); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger .middleware(middleware::Logger::default()) - .resource("/extractor", |r| { - r.method(http::Method::POST) - .with_config(extract_item, |(cfg,)| { - cfg.limit(4096); // <- limit size of the payload - }) - }) - .resource("/extractor2", |r| { - r.method(http::Method::POST) - .with_config(extract_item_limit, |((cfg, _),)| { - cfg.limit(4096); // <- limit size of the payload - }) - }) - .resource("/manual", |r| r.method(http::Method::POST).f(index_manual)) - .resource("/mjsonrust", |r| r.method(http::Method::POST).f(index_mjsonrust)) - .resource("/", |r| r.method(http::Method::POST).f(index)) - }).bind("127.0.0.1:8080") - .unwrap() - .shutdown_timeout(1) - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .service( + web::resource("/extractor").route( + web::post() + .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .to(index), + ), + ) + .service( + web::resource("/extractor2").route( + web::post() + .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .to_async(extract_item), + ), + ) + .service(web::resource("/manual").route(web::post().to_async(index_manual))) + .service( + web::resource("/mjsonrust").route(web::post().to_async(index_mjsonrust)), + ) + .service(web::resource("/").route(web::post().to(index))) + }) + .bind("127.0.0.1:8080")? + .run() } diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index da83a8a6..9b1060d2 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -1,10 +1,7 @@ //! Actix web r2d2 example use std::io; -use actix_web::{ - blocking, extract::Path, middleware, web, App, Error, HttpResponse, HttpServer, - State, -}; +use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use futures::Future; use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; @@ -12,11 +9,11 @@ use uuid; /// Async request handler. Ddb pool is stored in application state. fn index( - path: Path, - db: State>, + path: web::Path, + db: web::State>, ) -> impl Future { // execute sync code in threadpool - blocking::run(move || { + web::block(move || { let conn = db.get().unwrap(); let uuid = format!("{}", uuid::Uuid::new_v4()); diff --git a/state/Cargo.toml b/state/Cargo.toml index edf0e382..7d8e0a02 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -2,11 +2,11 @@ name = "state" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -futures = "0.1" -env_logger = "0.5" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix = "0.7" -actix-web = "0.7" +futures = "0.1" +env_logger = "0.6" diff --git a/state/src/main.rs b/state/src/main.rs index be1bd465..f67e9290 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] -//! There are two level of statefulness in actix-web. Application has state -//! that is shared across all handlers within same Application. -//! And individual handler can have state. +//! Application may have multiple states that are shared across +//! all handlers within same Application. State could be added +//! with `App::state()` method, multiple different states could be added. //! //! > **Note**: http server accepts an application factory rather than an //! application > instance. Http server constructs an application instance for @@ -11,45 +11,34 @@ //! //! Check [user guide](https://actix.rs/book/actix-web/sec-2-application.html) for more info. -extern crate actix; -extern crate actix_web; -extern crate env_logger; +use std::io; +use std::sync::{Arc, Mutex}; -use std::sync::Arc; -use std::sync::Mutex; - -use actix_web::{middleware, server, App, HttpRequest, HttpResponse}; - -/// Application state -struct AppState { - counter: Arc>, -} +use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer}; /// simple handle -fn index(req: &HttpRequest) -> HttpResponse { +fn index(state: web::State>>, req: HttpRequest) -> HttpResponse { println!("{:?}", req); - *(req.state().counter.lock().unwrap()) += 1; + *(state.lock().unwrap()) += 1; - HttpResponse::Ok().body(format!("Num of requests: {}", req.state().counter.lock().unwrap())) + HttpResponse::Ok().body(format!("Num of requests: {}", state.lock().unwrap())) } -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("ws-example"); let counter = Arc::new(Mutex::new(0)); + //move is necessary to give closure below ownership of counter - server::new(move || { - App::with_state(AppState{counter: counter.clone()}) // <- create app with shared state + HttpServer::new(move || { + App::new() + .state(counter.clone()) // <- create app with shared state // enable logger .middleware(middleware::Logger::default()) // register simple handler, handle all methods - .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(); + .service(web::resource("/").to(index)) + }) + .bind("127.0.0.1:8080")? + .run() } From e2945b9b3949532d0002660cd6d25fdf0bcb4362 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 9 Mar 2019 18:03:09 -0800 Subject: [PATCH 011/111] update more examples and rustfmt --- Cargo.toml | 1 - actix_redis/src/main.rs | 81 +++--- actix_todo/src/api.rs | 6 +- actix_todo/src/model.rs | 3 +- async_ex1/Cargo.toml | 7 +- async_ex1/src/main.rs | 117 ++++---- cookie-auth-full/Cargo.toml | 14 - cookie-auth-full/src/auth.rs | 274 ------------------- cookie-auth-full/src/main.rs | 49 ---- cookie-auth/Cargo.toml | 3 +- cookie-auth/src/main.rs | 9 +- cookie-session/Cargo.toml | 9 +- cookie-session/src/main.rs | 42 +-- error_handling/Cargo.toml | 10 +- error_handling/src/main.rs | 145 ++++------ form/src/main.rs | 34 +-- hello-world/src/main.rs | 7 +- http-full-proxy/src/main.rs | 18 +- http-proxy/src/main.rs | 42 +-- http-proxy/src/server.rs | 11 +- juniper/src/main.rs | 19 +- middleware/src/main.rs | 11 +- multipart/src/main.rs | 18 +- protobuf/src/main.rs | 13 +- redis-session/src/main.rs | 14 +- rustls/src/main.rs | 17 +- simple-auth-server/src/app.rs | 6 +- simple-auth-server/src/auth_handler.rs | 22 +- simple-auth-server/src/auth_routes.rs | 12 +- simple-auth-server/src/email_service.rs | 21 +- simple-auth-server/src/errors.rs | 19 +- simple-auth-server/src/invitation_handler.rs | 2 - simple-auth-server/src/invitation_routes.rs | 7 +- simple-auth-server/src/main.rs | 24 +- simple-auth-server/src/models.rs | 10 +- simple-auth-server/src/register_handler.rs | 17 +- simple-auth-server/src/register_routes.rs | 17 +- simple-auth-server/src/schema.rs | 5 +- static_index/src/main.rs | 17 +- template_askama/src/main.rs | 12 +- template_tera/src/main.rs | 9 +- unix-socket/src/main.rs | 3 +- web-cors/backend/src/main.rs | 9 +- websocket-chat-broker/src/main.rs | 9 +- websocket-chat/src/main.rs | 33 +-- websocket-tcp-chat/src/codec.rs | 8 +- websocket-tcp-chat/src/main.rs | 27 +- websocket/src/main.rs | 23 +- 48 files changed, 485 insertions(+), 801 deletions(-) delete mode 100644 cookie-auth-full/Cargo.toml delete mode 100644 cookie-auth-full/src/auth.rs delete mode 100644 cookie-auth-full/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index ae0b605e..5c287311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ members = [ "async_ex1", "basics", "cookie-auth", - "cookie-auth-full", "cookie-session", "diesel", "error_handling", diff --git a/actix_redis/src/main.rs b/actix_redis/src/main.rs index d9ccfa8e..e8072a21 100644 --- a/actix_redis/src/main.rs +++ b/actix_redis/src/main.rs @@ -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, HttpRequest)) - -> impl Future { +fn cache_stuff( + (info, req): (Json, HttpRequest), +) -> impl Future { let info = info.into_inner(); let redis = req.state().redis_addr.clone(); @@ -59,25 +61,33 @@ fn cache_stuff((info, req): (Json, HttpRequest)) .responder() } -fn del_stuff(req: HttpRequest) - -> impl Future { +fn del_stuff( + req: HttpRequest, +) -> impl Future { let redis = req.state().redis_addr.clone(); - redis.send(Command(resp_array!["DEL", "mydomain:one", "mydomain:two", "mydomain:three"])) - .map_err(AWError::from) - .and_then(|res: Result| - match &res { - Ok(RespValue::Integer(x)) if x==&3 => - Ok(HttpResponse::Ok().body("successfully deleted values")), - _ =>{println!("---->{:?}", res); - Ok(HttpResponse::InternalServerError().finish())} - }) + redis + .send(Command(resp_array![ + "DEL", + "mydomain:one", + "mydomain:two", + "mydomain:three" + ])) + .map_err(AWError::from) + .and_then(|res: Result| 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> + pub redis_addr: Arc>, } fn main() { @@ -87,20 +97,19 @@ fn main() { server::new(|| { let redis_addr = Arc::new(RedisActor::start("127.0.0.1:6379")); - let app_state = AppState{redis_addr}; + let app_state = AppState { redis_addr }; 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") - .unwrap() - .workers(1) - .start(); + 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(); let _ = sys.run(); } diff --git a/actix_todo/src/api.rs b/actix_todo/src/api.rs index fcb67a0c..73c58e30 100644 --- a/actix_todo/src/api.rs +++ b/actix_todo/src/api.rs @@ -32,7 +32,8 @@ pub fn index(req: HttpRequest) -> FutureResponse { 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 diff --git a/actix_todo/src/model.rs b/actix_todo/src/model.rs index 3f1afb13..60eb551c 100644 --- a/actix_todo/src/model.rs +++ b/actix_todo/src/model.rs @@ -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)] diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 1c30e0f9..69985d71 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -2,10 +2,13 @@ name = "awc_examples" version = "0.1.0" authors = ["dowwie "] +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" diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index a3d5a028..4e8c94dd 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -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,38 +54,39 @@ struct HttpBinResponse { /// post json to httpbin, get it back in the response body, return deserialized fn step_x_v1(data: SomeData) -> Box> { + 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)) - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then( - |resp| resp.body() // <- this is MessageBody type, resolves to complete body - .from_err() // <- convert PayloadError to an Error + .json(data) + .unwrap() + .send(&mut connector) + .map_err(Error::from) // <- convert SendRequestError to an Error + .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, + some_data: web::Json, ) -> Box> { - 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() - .content_type("application/json") - .body(serde_json::to_string(&d).unwrap()) - .into()) - }) + 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() + .content_type("application/json") + .body(serde_json::to_string(&d).unwrap()) + .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 { + let mut connector = client::Connector::default().service(); + client::ClientRequest::post("https://httpbin.org/post") - .json(data).unwrap() - .send() - .conn_timeout(Duration::from_secs(10)) - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then( - |resp| resp.body() // <- this is MessageBody type, resolves to complete body - .from_err() // <- convert PayloadError to an Error + .json(data) + .unwrap() + .send(&mut connector) + .map_err(Error::from) // <- convert SendRequestError to an Error + .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, + some_data: web::Json, ) -> impl Future { 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) - }) - .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(); + .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)), + ) + }) + .bind("127.0.0.1:8088")? + .run() } diff --git a/cookie-auth-full/Cargo.toml b/cookie-auth-full/Cargo.toml deleted file mode 100644 index 87e6df95..00000000 --- a/cookie-auth-full/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "cookie-auth-full" -version = "0.1.0" -authors = ["Nikolay Kim "] -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" diff --git a/cookie-auth-full/src/auth.rs b/cookie-auth-full/src/auth.rs deleted file mode 100644 index 56ec54e4..00000000 --- a/cookie-auth-full/src/auth.rs +++ /dev/null @@ -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; - - /// Remember identity. - fn remember(&self, identity: String); - - /// This method is used to 'forget' the current identity on subsequent - /// requests. - fn forget(&self); -} - -impl RequestIdentity for HttpRequest { - fn identity(&self) -> Option { - if let Some(id) = self.extensions().get::() { - return id.0.identity().map(|s| s.to_owned()); - } - None - } - - fn remember(&self, identity: String) { - if let Some(id) = self.extensions_mut().get_mut::() { - return id.0.as_mut().remember(identity); - } - } - - fn forget(&self) { - if let Some(id) = self.extensions_mut().get_mut::() { - 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; -} - -/// Identity policy definition. -pub trait IdentityPolicy: Sized + 'static { - type Identity: Identity; - type Future: Future; - - /// Parse the session from request and load data from a service identity. - fn from_request(&self, request: &mut HttpRequest) -> Self::Future; -} - -/// Middleware that implements identity service -pub struct IdentityService { - backend: T, -} - -impl IdentityService { - /// Create new identity service with specified backend. - pub fn new(backend: T) -> Self { - IdentityService { backend } - } -} - -struct IdentityBox(Box); - -#[doc(hidden)] -unsafe impl Send for IdentityBox {} -#[doc(hidden)] -unsafe impl Sync for IdentityBox {} - -impl> Middleware for IdentityService { - fn start(&self, req: &HttpRequest) -> Result { - 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, resp: HttpResponse) -> Result { - if let Some(mut id) = req.extensions_mut().remove::() { - id.0.write(resp) - } else { - Ok(Response::Done(resp)) - } - } -} - -/// Identity that uses private cookies as identity storage -pub struct CookieIdentity { - changed: bool, - identity: Option, - inner: Rc, -} - -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 { - 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, - secure: bool, - max_age: Option, -} - -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) -> 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(&self, req: &mut HttpRequest) -> Option { - 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); - -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>(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>(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>(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 IdentityPolicy for CookieIdentityPolicy { - type Identity = CookieIdentity; - type Future = FutureResult; - - fn from_request(&self, req: &mut HttpRequest) -> Self::Future { - let identity = self.0.load(req); - FutOk(CookieIdentity { - identity, - changed: false, - inner: Rc::clone(&self.0), - }) - } -} diff --git a/cookie-auth-full/src/main.rs b/cookie-auth-full/src/main.rs deleted file mode 100644 index f7a0c09c..00000000 --- a/cookie-auth-full/src/main.rs +++ /dev/null @@ -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(); -} diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index ceda654d..2e7858d3 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -5,6 +5,5 @@ authors = ["Nikolay Kim "] workspace = "../" [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-web = { git="https://github.com/actix/actix-web.git" } env_logger = "0.5" diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index a7444793..82db1da3 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -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,9 +36,10 @@ 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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 399a6172..2947b950 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -2,12 +2,13 @@ name = "cookie-session" version = "0.1.0" authors = ["Nikolay Kim "] -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" diff --git a/cookie-session/src/main.rs b/cookie-session/src/main.rs index 94f736f9..6e0df123 100644 --- a/cookie-session/src/main.rs +++ b/cookie-session/src/main.rs @@ -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::("counter")? { + if let Some(count) = session.get::("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() } diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index fe27b1c3..f1df6a48 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -2,11 +2,13 @@ name = "error_handling" version = "0.1.0" authors = ["dowwie "] +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" diff --git a/error_handling/src/main.rs b/error_handling/src/main.rs index 6a1788f0..676a8ce8 100644 --- a/error_handling/src/main.rs +++ b/error_handling/src/main.rs @@ -1,10 +1,10 @@ /* -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 -http errors will be chosen, each with an equal chance of being selected: +http errors will be chosen, each with an equal chance of being selected: 1. 403 Forbidden 2. 401 Unauthorized 3. 500 InternalServerError @@ -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 for Standard { fn sample(&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, -// Error = ActixWebError> { fn do_something_random() -> impl Future { 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(()) + if rng.gen_bool(2.0 / 10.0) { + ok(()) + } else { + err(rand::random::()) } - - let err: CustomError = rand::random(); - return fut_err(err) } - -fn do_something(_req: HttpRequest) - -> impl Future { - - 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 { + 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() } diff --git a/form/src/main.rs b/form/src/main.rs index 615fff2e..01f416fb 100644 --- a/form/src/main.rs +++ b/form/src/main.rs @@ -18,22 +18,24 @@ fn main() { let _addr = server::new(|| { App::with_state(AppState { foo: "bar".to_string(), - }).middleware(middleware::Logger::default()) - .resource("/", |r| { - r.method(http::Method::GET).with(index); - }) - .resource("/post1", |r| { - r.method(http::Method::POST).with(handle_post_1) - }) - .resource("/post2", |r| { - r.method(http::Method::POST).with(handle_post_2) - }) - .resource("/post3", |r| { - r.method(http::Method::POST).with(handle_post_3) - }) - }).bind("127.0.0.1:8080") - .expect("Can not bind to 127.0.0.1:8080") - .start(); + }) + .middleware(middleware::Logger::default()) + .resource("/", |r| { + r.method(http::Method::GET).with(index); + }) + .resource("/post1", |r| { + r.method(http::Method::POST).with(handle_post_1) + }) + .resource("/post2", |r| { + r.method(http::Method::POST).with(handle_post_2) + }) + .resource("/post3", |r| { + r.method(http::Method::POST).with(handle_post_3) + }) + }) + .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(); diff --git a/hello-world/src/main.rs b/hello-world/src/main.rs index 90d93b7d..2d787836 100644 --- a/hello-world/src/main.rs +++ b/hello-world/src/main.rs @@ -19,9 +19,10 @@ 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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 4d691870..05bfb394 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -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() diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index 3785ae6c..9d51aceb 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -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> { 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 - .from_err() // <- convert PayloadError to an Error - .and_then(|body| { // <- we got complete body, now send as server response + .map_err(Error::from) // <- convert SendRequestError to an Error + .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 Ok(HttpResponse::Ok().body(body)) - })) + }) + }) .responder() } @@ -28,14 +31,16 @@ fn index(_req: &HttpRequest) -> Box> fn streaming(_req: &HttpRequest) -> Box> { // send client request client::ClientRequest::get("https://www.rust-lang.org/en-US/") - .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 + .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 Ok(HttpResponse::Ok() - // read one chunk from client response and send this chunk to a server response - // .from_err() converts PayloadError to an Error - .body(Body::Streaming(Box::new(resp.payload().from_err())))) + // read one chunk from client response and send this chunk to a server response + // .from_err() converts PayloadError to an Error + .body(Body::Streaming(Box::new(resp.payload().from_err())))) }) .responder() } @@ -50,10 +55,11 @@ fn main() { .middleware(middleware::Logger::default()) .resource("/streaming", |r| r.f(streaming)) .resource("/", |r| r.f(index)) - }).workers(1) - .bind("127.0.0.1:8080") - .unwrap() - .start(); + }) + .workers(1) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/http-proxy/src/server.rs b/http-proxy/src/server.rs index ca1dfb26..11584def 100644 --- a/http-proxy/src/server.rs +++ b/http-proxy/src/server.rs @@ -20,14 +20,15 @@ fn main() { server::new(|| { App::new() - // enable logger + // enable logger .middleware(middleware::Logger::default()) .resource("/index.html", |r| r.f(|_| "Hello world!")) .resource("/", |r| r.f(index)) - }).workers(1) - .bind("127.0.0.1:8081") - .unwrap() - .start(); + }) + .workers(1) + .bind("127.0.0.1:8081") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8081"); let _ = sys.run(); diff --git a/juniper/src/main.rs b/juniper/src/main.rs index d06cc5e7..468c093a 100644 --- a/juniper/src/main.rs +++ b/juniper/src/main.rs @@ -93,14 +93,17 @@ fn main() { // Start http server server::new(move || { - 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") - .unwrap() - .start(); + 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") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 539a3076..91ae9d0c 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -16,14 +16,17 @@ 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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); let _ = sys.run(); } diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 6cea2536..37c17bf6 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -101,14 +101,16 @@ fn main() { server::new(|| { App::with_state(AppState { counter: Cell::new(0), - }).middleware(middleware::Logger::default()) - .resource("/", |r| { - r.method(http::Method::GET).with(index); - r.method(http::Method::POST).with(upload); - }) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); + }) + .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") + .unwrap() + .start(); println!("Starting http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/protobuf/src/main.rs b/protobuf/src/main.rs index aaae1f18..83220301 100644 --- a/protobuf/src/main.rs +++ b/protobuf/src/main.rs @@ -28,10 +28,10 @@ pub struct MyObj { /// This handler uses `ProtoBufMessage` for loading protobuf object. fn index(req: &HttpRequest) -> Box> { protobuf::ProtoBufMessage::new(req) - .from_err() // convert all errors into `Error` + .from_err() // convert all errors into `Error` .and_then(|val: MyObj| { println!("model: {:?}", val); - Ok(HttpResponse::Ok().protobuf(val)?) // <- send response + Ok(HttpResponse::Ok().protobuf(val)?) // <- send response }) .responder() } @@ -45,10 +45,11 @@ fn main() { App::new() .middleware(middleware::Logger::default()) .resource("/", |r| r.method(http::Method::POST).f(index)) - }).bind("127.0.0.1:8080") - .unwrap() - .shutdown_timeout(1) - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .shutdown_timeout(1) + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 3b68ab56..18a68e15 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -35,14 +35,16 @@ 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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); let _ = sys.run(); } diff --git a/rustls/src/main.rs b/rustls/src/main.rs index 58220215..33bcb538 100644 --- a/rustls/src/main.rs +++ b/rustls/src/main.rs @@ -49,16 +49,19 @@ 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(|_| { - HttpResponse::Found() - .header("LOCATION", "/index.html") - .finish() - })) + .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(); println!("Started http server: 127.0.0.1:8443"); let _ = sys.run(); -} \ No newline at end of file +} diff --git a/simple-auth-server/src/app.rs b/simple-auth-server/src/app.rs index f56be1a2..05fdf2f7 100644 --- a/simple-auth-server/src/app.rs +++ b/simple-auth-server/src/app.rs @@ -14,8 +14,10 @@ pub struct AppState { /// creates and returns the app after mounting all routes/resources pub fn create_app(db: Addr) -> App { // 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()) diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index cedfa90e..161a951f 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -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 for DbExecutor { type Result = 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 mut items = users - .filter(email.eq(&msg.email)) - .load::(conn)?; + let mut items = users.filter(email.eq(&msg.email)).load::(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(), + )) } } diff --git a/simple-auth-server/src/auth_routes.rs b/simple-auth-server/src/auth_routes.rs index 48ee15c0..90cafec4 100644 --- a/simple-auth-server/src/auth_routes.rs +++ b/simple-auth-server/src/auth_routes.rs @@ -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, HttpRequest)) - -> FutureResponse { +pub fn login( + (auth_data, req): (Json, HttpRequest), +) -> FutureResponse { req.state() .db .send(auth_data.into_inner()) @@ -19,7 +22,8 @@ pub fn login((auth_data, req): (Json, HttpRequest)) Ok(HttpResponse::Ok().into()) } Err(err) => Ok(err.error_response()), - }).responder() + }) + .responder() } pub fn logout(req: HttpRequest) -> HttpResponse { diff --git a/simple-auth-server/src/email_service.rs b/simple-auth-server/src/email_service.rs index f1db1172..d9854f49 100644 --- a/simple-auth-server/src/email_service.rs +++ b/simple-auth-server/src/email_service.rs @@ -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 { - TransmissionResponse::ApiResponse(api_res) => { - println!("API Response: \n {:#?}", api_res); - } - TransmissionResponse::ApiError(errors) => { - println!("Response Errors: \n {:#?}", &errors); - } + 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); } diff --git a/simple-auth-server/src/errors.rs b/simple-auth-server/src/errors.rs index b65aa4f7..0be63125 100644 --- a/simple-auth-server/src/errors.rs +++ b/simple-auth-server/src/errors.rs @@ -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 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, } } } diff --git a/simple-auth-server/src/invitation_handler.rs b/simple-auth-server/src/invitation_handler.rs index 425e4c0a..ac117f79 100644 --- a/simple-auth-server/src/invitation_handler.rs +++ b/simple-auth-server/src/invitation_handler.rs @@ -35,5 +35,3 @@ impl Handler for DbExecutor { Ok(inserted_invitation) } } - - diff --git a/simple-auth-server/src/invitation_routes.rs b/simple-auth-server/src/invitation_routes.rs index 9232c6d0..bd6a46c6 100644 --- a/simple-auth-server/src/invitation_routes.rs +++ b/simple-auth-server/src/invitation_routes.rs @@ -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() } diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index f5d096b2..5c1b3c27 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -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 = SyncArbiter::start(4, move || DbExecutor(pool.clone())); + let address: Addr = + SyncArbiter::start(4, move || DbExecutor(pool.clone())); server::new(move || app::create_app(address.clone())) .bind("127.0.0.1:3000") diff --git a/simple-auth-server/src/models.rs b/simple-auth-server/src/models.rs index fcafb9c5..651ad9f3 100644 --- a/simple-auth-server/src/models.rs +++ b/simple-auth-server/src/models.rs @@ -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>); @@ -51,8 +51,6 @@ pub struct SlimUser { impl From for SlimUser { fn from(user: User) -> Self { - SlimUser { - email: user.email - } + SlimUser { email: user.email } } } diff --git a/simple-auth-server/src/register_handler.rs b/simple-auth-server/src/register_handler.rs index 7cf98fd3..961061b0 100644 --- a/simple-auth-server/src/register_handler.rs +++ b/simple-auth-server/src/register_handler.rs @@ -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; } - impl Handler for DbExecutor { type Result = 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; let conn: &PgConnection = &self.0.get().unwrap(); @@ -35,7 +34,8 @@ impl Handler 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::(conn) .map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into())) .and_then(|mut result| { @@ -45,9 +45,8 @@ impl Handler 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 for DbExecutor { }) } } - - diff --git a/simple-auth-server/src/register_routes.rs b/simple-auth-server/src/register_routes.rs index 5924ba50..79b9f9a2 100644 --- a/simple-auth-server/src/register_routes.rs +++ b/simple-auth-server/src/register_routes.rs @@ -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, Json, State)) - -> FutureResponse { +pub fn register_user( + (invitation_id, user_data, state): (Path, Json, State), +) -> FutureResponse { 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() } diff --git a/simple-auth-server/src/schema.rs b/simple-auth-server/src/schema.rs index 646632db..95c37038 100644 --- a/simple-auth-server/src/schema.rs +++ b/simple-auth-server/src/schema.rs @@ -14,7 +14,4 @@ table! { } } -allow_tables_to_appear_in_same_query!( - invitations, - users, -); +allow_tables_to_appear_in_same_query!(invitations, users,); diff --git a/static_index/src/main.rs b/static_index/src/main.rs index 25c77c03..df6233dc 100644 --- a/static_index/src/main.rs +++ b/static_index/src/main.rs @@ -13,15 +13,18 @@ fn main() { server::new(|| { App::new() - // enable logger - .middleware(middleware::Logger::default()) - .handler( + // enable logger + .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") - .expect("Can not start server on given IP/Port") - .start(); + }) + .bind("127.0.0.1:8080") + .expect("Can not start server on given IP/Port") + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index 4a34abf1..27dc7617 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -24,8 +24,9 @@ fn index(query: Query>) -> Result { UserTemplate { name: name, text: "Welcome!", - }.render() - .unwrap() + } + .render() + .unwrap() } else { Index.render().unwrap() }; @@ -38,9 +39,10 @@ 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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/template_tera/src/main.rs b/template_tera/src/main.rs index e7e2c780..7cbd5579 100644 --- a/template_tera/src/main.rs +++ b/template_tera/src/main.rs @@ -44,13 +44,14 @@ fn main() { let tera = compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")); - App::with_state(AppState{template: tera}) + App::with_state(AppState { template: tera }) // enable logger .middleware(middleware::Logger::default()) .resource("/", |r| r.method(http::Method::GET).with(index)) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/unix-socket/src/main.rs b/unix-socket/src/main.rs index d999f8e9..6a3e3ed3 100644 --- a/unix-socket/src/main.rs +++ b/unix-socket/src/main.rs @@ -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(); diff --git a/web-cors/backend/src/main.rs b/web-cors/backend/src/main.rs index 8191ceeb..2fcec25b 100644 --- a/web-cors/backend/src/main.rs +++ b/web-cors/backend/src/main.rs @@ -39,10 +39,11 @@ fn main() { }) .register() }) - }).bind("127.0.0.1:8000") - .unwrap() - .shutdown_timeout(2) - .start(); + }) + .bind("127.0.0.1:8000") + .unwrap() + .shutdown_timeout(2) + .start(); let _ = sys.run(); } diff --git a/websocket-chat-broker/src/main.rs b/websocket-chat-broker/src/main.rs index 24ae4929..4ddc3bc7 100644 --- a/websocket-chat-broker/src/main.rs +++ b/websocket-chat-broker/src/main.rs @@ -52,7 +52,8 @@ impl WsChatSession { } fut::ok(()) - }).spawn(ctx); + }) + .spawn(ctx); } fn list_rooms(&mut self, ctx: &mut ws::WebsocketContext) { @@ -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(); diff --git a/websocket-chat/src/main.rs b/websocket-chat/src/main.rs index 477b8e40..8849aba7 100644 --- a/websocket-chat/src/main.rs +++ b/websocket-chat/src/main.rs @@ -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 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(); @@ -233,19 +231,22 @@ fn main() { }; App::with_state(state) - // redirect to websocket.html - .resource("/", |r| r.method(http::Method::GET).f(|_| { - HttpResponse::Found() - .header("LOCATION", "/static/websocket.html") - .finish() - })) - // websocket + // redirect to websocket.html + .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 + // static resources .handler("/static/", fs::StaticFiles::new("static/").unwrap()) - }).bind("127.0.0.1:8080") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/websocket-tcp-chat/src/codec.rs b/websocket-tcp-chat/src/codec.rs index 55cf0db3..8d362630 100644 --- a/websocket-tcp-chat/src/codec.rs +++ b/websocket-tcp-chat/src/codec.rs @@ -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(); diff --git a/websocket-tcp-chat/src/main.rs b/websocket-tcp-chat/src/main.rs index 099ba8d4..dff734c8 100644 --- a/websocket-tcp-chat/src/main.rs +++ b/websocket-tcp-chat/src/main.rs @@ -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 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,18 +245,21 @@ fn main() { App::with_state(state) // redirect to websocket.html - .resource("/", |r| r.method(http::Method::GET).f(|_| { - HttpResponse::Found() - .header("LOCATION", "/static/websocket.html") - .finish() - })) + .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") - .unwrap() - .start(); + }) + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); diff --git a/websocket/src/main.rs b/websocket/src/main.rs index 84aa4646..0b9a5716 100644 --- a/websocket/src/main.rs +++ b/websocket/src/main.rs @@ -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,19 +96,24 @@ 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/") - .unwrap() - .index_file("index.html"))) - // start http server on 127.0.0.1:8080 - .bind("127.0.0.1:8080").unwrap() - .start(); + .handler( + "/", + fs::StaticFiles::new("static/") + .unwrap() + .index_file("index.html"), + ) + }) + // start http server on 127.0.0.1:8080 + .bind("127.0.0.1:8080") + .unwrap() + .start(); println!("Started http server: 127.0.0.1:8080"); let _ = sys.run(); From 4d26988edfc15b79ccd2edabb955cbcc975e361e Mon Sep 17 00:00:00 2001 From: Allen <31905380+fairingrey@users.noreply.github.com> Date: Sat, 9 Mar 2019 20:10:39 -0800 Subject: [PATCH 012/111] Perform unused validation in async_ex1 example (#83) --- async_ex1/src/main.rs | 64 ++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index a3d5a028..917443b1 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -29,9 +29,9 @@ extern crate validator; use actix_web::{ client, http::Method, server, App, AsyncResponder, Error, HttpMessage, HttpResponse, - Json, + Json, error::ErrorBadRequest, }; -use futures::{future::ok as fut_ok, Future}; +use futures::{future::ok as fut_ok, future::result as fut_result, Future}; use std::collections::HashMap; use std::time::Duration; use validator::Validate; @@ -63,19 +63,23 @@ struct HttpBinResponse { /// post json to httpbin, get it back in the response body, return deserialized fn step_x_v1(data: SomeData) -> Box> { Box::new( - client::ClientRequest::post("https://httpbin.org/post") - .json(data).unwrap() - .send() - .conn_timeout(Duration::from_secs(10)) - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then( - |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) - }) - ), + fut_result(data.validate()) // <- call .validate() on data to validate the parameters + .map_err(ErrorBadRequest) // - convert ValidationErrors to an Error + .and_then(|_| { + client::ClientRequest::post("https://httpbin.org/post") + .json(data).unwrap() + .send() + .conn_timeout(Duration::from_secs(10)) + .map_err(Error::from) // <- convert SendRequestError to an Error + .and_then( + |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) + }) + ) + }) ) } @@ -102,19 +106,23 @@ 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 { - client::ClientRequest::post("https://httpbin.org/post") - .json(data).unwrap() - .send() - .conn_timeout(Duration::from_secs(10)) - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then( - |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) - }) - ) + fut_result(data.validate()) // <- call .validate() on data to validate the parameters + .map_err(ErrorBadRequest) // - convert ValidationErrors to an Error + .and_then(|_| { + client::ClientRequest::post("https://httpbin.org/post") + .json(data).unwrap() + .send() + .conn_timeout(Duration::from_secs(10)) + .map_err(Error::from) // <- convert SendRequestError to an Error + .and_then( + |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) + }) + ) + }) } fn create_something_v2( From b6929b47b125df85ec77b121d00c48bb38c92e54 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 9 Mar 2019 21:08:08 -0800 Subject: [PATCH 013/111] post cookie-auth and form examples --- cookie-auth/Cargo.toml | 7 ++-- cookie-auth/src/main.rs | 41 +++++++++------------- form/Cargo.toml | 5 +-- form/src/main.rs | 76 ++++++++++++++++------------------------- 4 files changed, 52 insertions(+), 77 deletions(-) diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index 2e7858d3..81fd8eb9 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -2,8 +2,9 @@ name = "cookie-auth" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +edition = "2018" +workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } -env_logger = "0.5" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +env_logger = "0.6" diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 82db1da3..01ddde23 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -1,31 +1,26 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; - -use actix_web::middleware::identity::RequestIdentity; +use actix_web::middleware::identity::Identity; use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService}; -use actix_web::{middleware, server, App, HttpRequest, HttpResponse}; +use actix_web::{middleware, web, App, HttpResponse, HttpServer}; -fn index(req: &HttpRequest) -> String { - format!("Hello {}", req.identity().unwrap_or("Anonymous".to_owned())) +fn index(id: Identity) -> String { + format!("Hello {}", id.identity().unwrap_or("Anonymous".to_owned())) } -fn login(req: &HttpRequest) -> HttpResponse { - req.remember("user1".to_owned()); +fn login(id: Identity) -> HttpResponse { + id.remember("user1".to_owned()); HttpResponse::Found().header("location", "/").finish() } -fn logout(req: &HttpRequest) -> HttpResponse { - req.forget(); +fn logout(id: Identity) -> HttpResponse { + id.forget(); HttpResponse::Found().header("location", "/").finish() } -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("cookie-auth"); - server::new(|| { + HttpServer::new(|| { App::new() .middleware(middleware::Logger::default()) .middleware(IdentityService::new( @@ -33,14 +28,10 @@ fn main() { .name("auth-example") .secure(false), )) - .resource("/login", |r| r.f(login)) - .resource("/logout", |r| r.f(logout)) - .resource("/", |r| r.f(index)) + .service(web::resource("/login").route(web::post().to(login))) + .service(web::resource("/logout").to(logout)) + .service(web::resource("/").route(web::get().to(index))) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/form/Cargo.toml b/form/Cargo.toml index 42c314ff..1fd56d4e 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -2,10 +2,11 @@ name = "form-example" version = "0.1.0" authors = ["Gorm Casper "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } serde = "1.0" serde_derive = "1.0" diff --git a/form/src/main.rs b/form/src/main.rs index 01f416fb..c0c38690 100644 --- a/form/src/main.rs +++ b/form/src/main.rs @@ -1,48 +1,32 @@ -extern crate actix; -extern crate actix_web; - #[macro_use] extern crate serde_derive; use actix_web::{ - http, middleware, server, App, Form, HttpRequest, HttpResponse, Result, State, + middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder, Result, }; struct AppState { foo: String, } -fn main() { - let sys = actix::System::new("form-example"); - - let _addr = server::new(|| { - App::with_state(AppState { - foo: "bar".to_string(), - }) - .middleware(middleware::Logger::default()) - .resource("/", |r| { - r.method(http::Method::GET).with(index); - }) - .resource("/post1", |r| { - r.method(http::Method::POST).with(handle_post_1) - }) - .resource("/post2", |r| { - r.method(http::Method::POST).with(handle_post_2) - }) - .resource("/post3", |r| { - r.method(http::Method::POST).with(handle_post_3) - }) +fn main() -> std::io::Result<()> { + HttpServer::new(|| { + App::new() + .state(AppState { + foo: "bar".to_string(), + }) + .middleware(middleware::Logger::default()) + .service(web::resource("/").route(web::get().to(index))) + .service(web::resource("/post1").route(web::post().to(handle_post_1))) + .service(web::resource("/post2").route(web::post().to(handle_post_2))) + .service(web::resource("/post3").route(web::post().to(handle_post_3))) }) - .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(); + .bind("127.0.0.1:8080")? + .run() } -fn index(_req: HttpRequest) -> Result { - Ok(HttpResponse::build(http::StatusCode::OK) +fn index() -> Result { + Ok(HttpResponse::Ok() .content_type("text/html; charset=utf-8") .body(include_str!("../static/form.html"))) } @@ -53,30 +37,28 @@ pub struct MyParams { } /// Simple handle POST request -fn handle_post_1(params: Form) -> Result { - Ok(HttpResponse::build(http::StatusCode::OK) +fn handle_post_1(params: web::Form) -> Result { + Ok(HttpResponse::Ok() .content_type("text/plain") .body(format!("Your name is {}", params.name))) } /// State and POST Params fn handle_post_2( - (state, params): (State, Form), -) -> Result { - Ok(HttpResponse::build(http::StatusCode::OK) - .content_type("text/plain") - .body(format!( - "Your name is {}, and in AppState I have foo: {}", - params.name, state.foo - ))) + state: web::State, + params: web::Form, +) -> HttpResponse { + HttpResponse::Ok().content_type("text/plain").body(format!( + "Your name is {}, and in AppState I have foo: {}", + params.name, state.foo + )) } /// Request and POST Params -fn handle_post_3( - (req, params): (HttpRequest, Form), -) -> Result { +fn handle_post_3(req: HttpRequest, params: web::Form) -> impl Responder { println!("Handling POST request: {:?}", req); - Ok(HttpResponse::build(http::StatusCode::OK) + + HttpResponse::Ok() .content_type("text/plain") - .body(format!("Your name is {}", params.name))) + .body(format!("Your name is {}", params.name)) } From 52c12f264a24c905ab9699590c225347f3e2a57d Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 9 Mar 2019 22:38:15 -0800 Subject: [PATCH 014/111] port more examples --- hello-world/Cargo.toml | 9 +++---- hello-world/src/main.rs | 28 +++++++------------- rustfmt.toml | 3 --- static_index/Cargo.toml | 7 ++--- static_index/src/main.rs | 32 +++++++---------------- template_askama/Cargo.toml | 9 +++---- template_askama/src/main.rs | 22 +++++----------- template_tera/Cargo.toml | 8 +++--- template_tera/src/main.rs | 52 +++++++++++++------------------------ 9 files changed, 61 insertions(+), 109 deletions(-) diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 7126813c..cb47b1e0 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -2,10 +2,9 @@ name = "hello-world" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" - -actix = "0.7" -actix-web = "^0.7" +env_logger = "0.6" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } diff --git a/hello-world/src/main.rs b/hello-world/src/main.rs index 2d787836..3bb9064a 100644 --- a/hello-world/src/main.rs +++ b/hello-world/src/main.rs @@ -1,29 +1,21 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; +use actix_web::{middleware, web, App, HttpRequest, HttpServer}; -use actix_web::{middleware, server, App, HttpRequest}; - -fn index(_req: &HttpRequest) -> &'static str { +fn index(req: HttpRequest) -> &'static str { + println!("REQ: {:?}", req); "Hello world!" } -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("hello-world"); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger .middleware(middleware::Logger::default()) - .resource("/index.html", |r| r.f(|_| "Hello world!")) - .resource("/", |r| r.f(index)) + .service(web::resource("/index.html").to(|| "Hello world!")) + .service(web::resource("/").to(index)) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/rustfmt.toml b/rustfmt.toml index 4fff285e..94bd11d5 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,2 @@ max_width = 89 reorder_imports = true -#wrap_comments = true -fn_args_density = "Compressed" -#use_small_heuristics = false diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index 6f427322..ee3d5377 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -2,11 +2,12 @@ name = "static_index" version = "0.1.0" authors = ["Jose Marinez "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] futures = "0.1" env_logger = "0.5" -actix = "0.7" -actix-web = "0.7" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } diff --git a/static_index/src/main.rs b/static_index/src/main.rs index df6233dc..e4c4fa83 100644 --- a/static_index/src/main.rs +++ b/static_index/src/main.rs @@ -1,31 +1,19 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; +use actix_files as fs; +use actix_web::{middleware, App, HttpServer}; -use actix_web::{fs, middleware, server, App}; - -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); - ::std::env::set_var("RUST_BACKTRACE", "1"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let sys = actix::System::new("static_index"); - - server::new(|| { + HttpServer::new(|| { App::new() // enable logger .middleware(middleware::Logger::default()) - .handler( - "/", - fs::StaticFiles::new("./static/") - .unwrap() - .index_file("index.html"), + .service( + // static files + fs::Files::new("/", "./static/").index_file("index.html"), ) }) - .bind("127.0.0.1:8080") - .expect("Can not start server on given IP/Port") - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 5eba342c..d3297425 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -2,14 +2,13 @@ name = "template-askama" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" +env_logger = "0.6" askama = "0.6" - -actix = "0.7" -actix-web = "0.7" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } [build-dependencies] askama = "0.6" diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index 27dc7617..b27e94af 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -1,11 +1,9 @@ -extern crate actix; -extern crate actix_web; #[macro_use] extern crate askama; use std::collections::HashMap; -use actix_web::{http, server, App, HttpResponse, Query, Result}; +use actix_web::{web, App, HttpResponse, HttpServer, Result}; use askama::Template; #[derive(Template)] @@ -19,7 +17,7 @@ struct UserTemplate<'a> { #[template(path = "index.html")] struct Index; -fn index(query: Query>) -> Result { +fn index(query: web::Query>) -> Result { let s = if let Some(name) = query.get("name") { UserTemplate { name: name, @@ -33,17 +31,11 @@ fn index(query: Query>) -> Result { Ok(HttpResponse::Ok().content_type("text/html").body(s)) } -fn main() { - let sys = actix::System::new("template-askama"); - +fn main() -> std::io::Result<()> { // start http server - server::new(move || { - App::new().resource("/", |r| r.method(http::Method::GET).with(index)) + HttpServer::new(move || { + App::new().service(web::resource("/").route(web::get()).to(index)) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index 9e55bf4a..2c01582d 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -2,10 +2,10 @@ name = "template-tera" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" +env_logger = "0.6" tera = "*" -actix = "0.7" -actix-web = "0.7" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } diff --git a/template_tera/src/main.rs b/template_tera/src/main.rs index 7cbd5579..b442e82a 100644 --- a/template_tera/src/main.rs +++ b/template_tera/src/main.rs @@ -1,58 +1,42 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; #[macro_use] extern crate tera; use std::collections::HashMap; -use actix_web::{ - error, http, middleware, server, App, Error, HttpResponse, Query, State, -}; - -struct AppState { - template: tera::Tera, // <- store tera template in application state -} +use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; +// store tera template in application state fn index( - (state, query): (State, Query>), + tmpl: web::State, + query: web::Query>, ) -> Result { let s = if let Some(name) = query.get("name") { - // <- submitted form + // submitted form let mut ctx = tera::Context::new(); - ctx.add("name", &name.to_owned()); - ctx.add("text", &"Welcome!".to_owned()); - state - .template - .render("user.html", &ctx) + ctx.insert("name", &name.to_owned()); + ctx.insert("text", &"Welcome!".to_owned()); + tmpl.render("user.html", &ctx) .map_err(|_| error::ErrorInternalServerError("Template error"))? } else { - state - .template - .render("index.html", &tera::Context::new()) + tmpl.render("index.html", &tera::Context::new()) .map_err(|_| error::ErrorInternalServerError("Template error"))? }; Ok(HttpResponse::Ok().content_type("text/html").body(s)) } -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("tera-example"); - server::new(|| { + HttpServer::new(|| { let tera = compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")); - App::with_state(AppState { template: tera }) - // enable logger - .middleware(middleware::Logger::default()) - .resource("/", |r| r.method(http::Method::GET).with(index)) + App::new() + .state(tera) + .middleware(middleware::Logger::default()) // enable logger + .service(web::resource("/").route(web::get().to(index))) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } From 17744bbfe4dd3f9df42fcbd6fdbc38ed8e99b757 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 10 Mar 2019 18:23:44 -0700 Subject: [PATCH 015/111] upgrade actix_todo --- actix_todo/Cargo.toml | 7 +- actix_todo/src/api.rs | 184 ++++++++++++++++++-------------------- actix_todo/src/db.rs | 97 ++++---------------- actix_todo/src/main.rs | 56 ++++-------- actix_todo/src/model.rs | 2 +- actix_todo/src/session.rs | 15 ++-- 6 files changed, 137 insertions(+), 224 deletions(-) diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index eb17097e..09b9a010 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -2,10 +2,13 @@ authors = ["Dan Munckton "] name = "actix-todo" version = "0.1.0" +workspace = ".." +edition = "2018" [dependencies] -actix = "0.7.3" -actix-web = "0.7.4" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" } dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/actix_todo/src/api.rs b/actix_todo/src/api.rs index 73c58e30..069e5db8 100644 --- a/actix_todo/src/api.rs +++ b/actix_todo/src/api.rs @@ -1,42 +1,34 @@ -use actix::prelude::Addr; -use actix_web::middleware::Response; -use actix_web::{ - error, fs::NamedFile, http, AsyncResponder, Form, FutureResponse, HttpRequest, - HttpResponse, Path, Responder, Result, -}; -use futures::{future, Future}; +use actix_files::NamedFile; +use actix_session::Session; +use actix_web::middleware::ErrorHandlerResponse; +use actix_web::{dev, error, http, web, Error, HttpResponse, Responder, Result}; +use futures::future::{err, Either, Future, IntoFuture}; use tera::{Context, Tera}; -use db::{AllTasks, CreateTask, DbExecutor, DeleteTask, ToggleTask}; -use session::{self, FlashMessage}; +use crate::db; +use crate::session::{self, FlashMessage}; -pub struct AppState { - pub template: Tera, - pub db: Addr, -} - -pub fn index(req: HttpRequest) -> FutureResponse { - req.state() - .db - .send(AllTasks) +pub fn index( + pool: web::State, + tmpl: web::State, + session: Session, +) -> impl Future { + web::block(move || db::get_all_tasks(&pool)) .from_err() - .and_then(move |res| match res { + .then(move |res| match res { Ok(tasks) => { let mut context = Context::new(); - context.add("tasks", &tasks); + context.insert("tasks", &tasks); //Session is set during operations on other endpoints //that can redirect to index - if let Some(flash) = session::get_flash(&req)? { - context.add("msg", &(flash.kind, flash.message)); - session::clear_flash(&req); + if let Some(flash) = session::get_flash(&session)? { + context.insert("msg", &(flash.kind, flash.message)); + session::clear_flash(&session); } - let rendered = req - .state() - .template - .render("index.html.tera", &context) - .map_err(|e| { + let rendered = + tmpl.render("index.html.tera", &context).map_err(|e| { error::ErrorInternalServerError(e.description().to_owned()) })?; @@ -44,7 +36,6 @@ pub fn index(req: HttpRequest) -> FutureResponse { } Err(e) => Err(e), }) - .responder() } #[derive(Deserialize)] @@ -53,35 +44,34 @@ pub struct CreateForm { } pub fn create( - (req, params): (HttpRequest, Form), -) -> FutureResponse { + params: web::Form, + pool: web::State, + session: Session, +) -> impl Future { if params.description.is_empty() { - future::lazy(move || { + Either::A( session::set_flash( - &req, + &session, FlashMessage::error("Description cannot be empty"), - )?; - Ok(redirect_to("/")) - }) - .responder() + ) + .map(|_| redirect_to("/")) + .into_future(), + ) } else { - req.state() - .db - .send(CreateTask { - description: params.description.clone(), - }) - .from_err() - .and_then(move |res| match res { - Ok(_) => { - session::set_flash( - &req, - FlashMessage::success("Task successfully added"), - )?; - Ok(redirect_to("/")) - } - Err(e) => Err(e), - }) - .responder() + Either::B( + web::block(move || db::create_task(params.into_inner().description, &pool)) + .from_err() + .then(move |res| match res { + Ok(_) => { + session::set_flash( + &session, + FlashMessage::success("Task successfully added"), + )?; + Ok(redirect_to("/")) + } + Err(e) => Err(e), + }), + ) } } @@ -96,49 +86,50 @@ pub struct UpdateForm { } pub fn update( - (req, params, form): (HttpRequest, Path, Form), -) -> FutureResponse { + db: web::State, + params: web::Path, + form: web::Form, + session: Session, +) -> impl Future { match form._method.as_ref() { - "put" => toggle(req, params), - "delete" => delete(req, params), + "put" => Either::A(Either::A(toggle(db, params))), + "delete" => Either::A(Either::B(delete(db, params, session))), unsupported_method => { let msg = format!("Unsupported HTTP method: {}", unsupported_method); - future::err(error::ErrorBadRequest(msg)).responder() + Either::B(err(error::ErrorBadRequest(msg))) } } } fn toggle( - req: HttpRequest, - params: Path, -) -> FutureResponse { - req.state() - .db - .send(ToggleTask { id: params.id }) + pool: web::State, + params: web::Path, +) -> impl Future { + web::block(move || db::toggle_task(params.id, &pool)) .from_err() - .and_then(move |res| match res { + .then(move |res| match res { Ok(_) => Ok(redirect_to("/")), Err(e) => Err(e), }) - .responder() } fn delete( - req: HttpRequest, - params: Path, -) -> FutureResponse { - req.state() - .db - .send(DeleteTask { id: params.id }) + pool: web::State, + params: web::Path, + session: Session, +) -> impl Future { + web::block(move || db::delete_task(params.id, &pool)) .from_err() - .and_then(move |res| match res { + .then(move |res| match res { Ok(_) => { - session::set_flash(&req, FlashMessage::success("Task was deleted."))?; + session::set_flash( + &session, + FlashMessage::success("Task was deleted."), + )?; Ok(redirect_to("/")) } Err(e) => Err(e), }) - .responder() } fn redirect_to(location: &str) -> HttpResponse { @@ -147,32 +138,31 @@ fn redirect_to(location: &str) -> HttpResponse { .finish() } -pub fn bad_request( - req: &HttpRequest, - resp: HttpResponse, -) -> Result { +pub fn bad_request(res: dev::ServiceResponse) -> Result> { let new_resp = NamedFile::open("static/errors/400.html")? - .set_status_code(resp.status()) - .respond_to(req)?; - Ok(Response::Done(new_resp)) + .set_status_code(res.status()) + .respond_to(res.request())?; + Ok(ErrorHandlerResponse::Response( + res.into_response(new_resp.into_body()), + )) } -pub fn not_found( - req: &HttpRequest, - resp: HttpResponse, -) -> Result { +pub fn not_found(res: dev::ServiceResponse) -> Result> { let new_resp = NamedFile::open("static/errors/404.html")? - .set_status_code(resp.status()) - .respond_to(req)?; - Ok(Response::Done(new_resp)) + .set_status_code(res.status()) + .respond_to(res.request())?; + Ok(ErrorHandlerResponse::Response( + res.into_response(new_resp.into_body()), + )) } -pub fn internal_server_error( - req: &HttpRequest, - resp: HttpResponse, -) -> Result { +pub fn internal_server_error( + res: dev::ServiceResponse, +) -> Result> { let new_resp = NamedFile::open("static/errors/500.html")? - .set_status_code(resp.status()) - .respond_to(req)?; - Ok(Response::Done(new_resp)) + .set_status_code(res.status()) + .respond_to(res.request())?; + Ok(ErrorHandlerResponse::Response( + res.into_response(new_resp.into_body()), + )) } diff --git a/actix_todo/src/db.rs b/actix_todo/src/db.rs index 534ae648..579b0b5d 100644 --- a/actix_todo/src/db.rs +++ b/actix_todo/src/db.rs @@ -1,13 +1,11 @@ use std::ops::Deref; -use actix::prelude::{Actor, Handler, Message, SyncContext}; -use actix_web::{error, Error}; use diesel::pg::PgConnection; use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection}; -use model::{NewTask, Task}; +use crate::model::{NewTask, Task}; -type PgPool = Pool>; +pub type PgPool = Pool>; type PgPooledConnection = PooledConnection>; pub fn init_pool(database_url: &str) -> Result { @@ -15,86 +13,29 @@ pub fn init_pool(database_url: &str) -> Result { Pool::builder().build(manager) } -pub struct DbExecutor(pub PgPool); - -impl DbExecutor { - pub fn get_conn(&self) -> Result { - self.0.get().map_err(|e| error::ErrorInternalServerError(e)) - } +fn get_conn(pool: &PgPool) -> Result { + pool.get().map_err(|_| "can get connection") } -impl Actor for DbExecutor { - type Context = SyncContext; +pub fn get_all_tasks(pool: &PgPool) -> Result, &'static str> { + Task::all(get_conn(pool)?.deref()).map_err(|_| "Error inserting task") } -pub struct AllTasks; - -impl Message for AllTasks { - type Result = Result, Error>; +pub fn create_task(todo: String, pool: &PgPool) -> Result<(), &'static str> { + let new_task = NewTask { description: todo }; + Task::insert(new_task, get_conn(pool)?.deref()) + .map(|_| ()) + .map_err(|_| "Error inserting task") } -impl Handler for DbExecutor { - type Result = Result, Error>; - - fn handle(&mut self, _: AllTasks, _: &mut Self::Context) -> Self::Result { - Task::all(self.get_conn()?.deref()) - .map_err(|_| error::ErrorInternalServerError("Error inserting task")) - } +pub fn toggle_task(id: i32, pool: &PgPool) -> Result<(), &'static str> { + Task::toggle_with_id(id, get_conn(pool)?.deref()) + .map(|_| ()) + .map_err(|_| "Error inserting task") } -pub struct CreateTask { - pub description: String, -} - -impl Message for CreateTask { - type Result = Result<(), Error>; -} - -impl Handler for DbExecutor { - type Result = Result<(), Error>; - - fn handle(&mut self, todo: CreateTask, _: &mut Self::Context) -> Self::Result { - let new_task = NewTask { - description: todo.description, - }; - Task::insert(new_task, self.get_conn()?.deref()) - .map(|_| ()) - .map_err(|_| error::ErrorInternalServerError("Error inserting task")) - } -} - -pub struct ToggleTask { - pub id: i32, -} - -impl Message for ToggleTask { - type Result = Result<(), Error>; -} - -impl Handler for DbExecutor { - type Result = Result<(), Error>; - - fn handle(&mut self, task: ToggleTask, _: &mut Self::Context) -> Self::Result { - Task::toggle_with_id(task.id, self.get_conn()?.deref()) - .map(|_| ()) - .map_err(|_| error::ErrorInternalServerError("Error inserting task")) - } -} - -pub struct DeleteTask { - pub id: i32, -} - -impl Message for DeleteTask { - type Result = Result<(), Error>; -} - -impl Handler for DbExecutor { - type Result = Result<(), Error>; - - fn handle(&mut self, task: DeleteTask, _: &mut Self::Context) -> Self::Result { - Task::delete_with_id(task.id, self.get_conn()?.deref()) - .map(|_| ()) - .map_err(|_| error::ErrorInternalServerError("Error inserting task")) - } +pub fn delete_task(id: i32, pool: &PgPool) -> Result<(), &'static str> { + Task::delete_with_id(id, get_conn(pool)?.deref()) + .map(|_| ()) + .map_err(|_| "Error inserting task") } diff --git a/actix_todo/src/main.rs b/actix_todo/src/main.rs index f2de26af..9c9664aa 100644 --- a/actix_todo/src/main.rs +++ b/actix_todo/src/main.rs @@ -1,8 +1,3 @@ -extern crate actix; -extern crate actix_web; -extern crate dotenv; -extern crate env_logger; -extern crate futures; #[macro_use] extern crate diesel; #[macro_use] @@ -12,12 +7,13 @@ extern crate serde_derive; #[macro_use] extern crate tera; -use actix::prelude::SyncArbiter; -use actix_web::middleware::session::{CookieSessionBackend, SessionStorage}; +use std::{env, io}; + +use actix_files as fs; +use actix_session::CookieSession; use actix_web::middleware::{ErrorHandlers, Logger}; -use actix_web::{dev::Resource, fs, http, server, App}; +use actix_web::{http, web, App, HttpServer}; use dotenv::dotenv; -use std::env; use tera::Tera; mod api; @@ -27,29 +23,22 @@ mod schema; mod session; static SESSION_SIGNING_KEY: &[u8] = &[0; 32]; -const NUM_DB_THREADS: usize = 3; -fn main() { +fn main() -> io::Result<()> { dotenv().ok(); - std::env::set_var("RUST_LOG", "actix_todo=debug,actix_web=info"); + env::set_var("RUST_LOG", "actix_todo=debug,actix_web=info"); env_logger::init(); - // Start the Actix system - let system = actix::System::new("todo-app"); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); let pool = db::init_pool(&database_url).expect("Failed to create pool"); - let addr = SyncArbiter::start(NUM_DB_THREADS, move || db::DbExecutor(pool.clone())); let app = move || { debug!("Constructing the App"); let templates: Tera = compile_templates!("templates/**/*"); - let session_store = SessionStorage::new( - CookieSessionBackend::signed(SESSION_SIGNING_KEY).secure(false), - ); + let session_store = CookieSession::signed(SESSION_SIGNING_KEY).secure(false); let error_handlers = ErrorHandlers::new() .handler( @@ -59,29 +48,20 @@ fn main() { .handler(http::StatusCode::BAD_REQUEST, api::bad_request) .handler(http::StatusCode::NOT_FOUND, api::not_found); - let static_files = fs::StaticFiles::new("static/") - .expect("failed constructing static files handler"); - - let state = api::AppState { - template: templates, - db: addr.clone(), - }; - - App::with_state(state) + App::new() + .state(templates) + .state(pool.clone()) .middleware(Logger::default()) .middleware(session_store) .middleware(error_handlers) - .route("/", http::Method::GET, api::index) - .route("/todo", http::Method::POST, api::create) - .resource("/todo/{id}", |r: &mut Resource<_>| { - r.post().with(api::update) - }) - .handler("/static", static_files) + .service(web::resource("/").route(web::get().to_async(api::index))) + .service(web::resource("/todo").route(web::post().to_async(api::create))) + .service( + web::resource("/todo/{id}").route(web::post().to_async(api::update)), + ) + .service(fs::Files::new("/static", "static/")) }; debug!("Starting server"); - server::new(app).bind("localhost:8088").unwrap().start(); - - // Run actix system, this method actually starts all async processes - let _ = system.run(); + HttpServer::new(app).bind("localhost:8088")?.run() } diff --git a/actix_todo/src/model.rs b/actix_todo/src/model.rs index 60eb551c..4b80f4a8 100644 --- a/actix_todo/src/model.rs +++ b/actix_todo/src/model.rs @@ -2,7 +2,7 @@ use diesel; use diesel::pg::PgConnection; use diesel::prelude::*; -use schema::{ +use crate::schema::{ tasks, tasks::dsl::{completed as task_completed, tasks as all_tasks}, }; diff --git a/actix_todo/src/session.rs b/actix_todo/src/session.rs index c4c6aadb..d1cfc7a4 100644 --- a/actix_todo/src/session.rs +++ b/actix_todo/src/session.rs @@ -1,19 +1,18 @@ +use actix_session::Session; use actix_web::error::Result; -use actix_web::middleware::session::RequestSession; -use actix_web::HttpRequest; const FLASH_KEY: &str = "flash"; -pub fn set_flash(request: &HttpRequest, flash: FlashMessage) -> Result<()> { - request.session().set(FLASH_KEY, flash) +pub fn set_flash(session: &Session, flash: FlashMessage) -> Result<()> { + session.set(FLASH_KEY, flash) } -pub fn get_flash(req: &HttpRequest) -> Result> { - req.session().get::(FLASH_KEY) +pub fn get_flash(session: &Session) -> Result> { + session.get::(FLASH_KEY) } -pub fn clear_flash(req: &HttpRequest) { - req.session().remove(FLASH_KEY); +pub fn clear_flash(session: &Session) { + session.remove(FLASH_KEY); } #[derive(Deserialize, Serialize)] From 0b46125f5d21b0467300348fed7bc82d0e4dc577 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 10 Mar 2019 18:39:54 -0700 Subject: [PATCH 016/111] use new location for blocking --- async_db/src/db.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/async_db/src/db.rs b/async_db/src/db.rs index 9b700237..e23adba2 100644 --- a/async_db/src/db.rs +++ b/async_db/src/db.rs @@ -1,4 +1,4 @@ -use actix_web::{blocking, Error as AWError}; +use actix_web::{web, Error as AWError}; use failure::Error; use futures::Future; use r2d2; @@ -27,7 +27,7 @@ pub fn execute( query: Queries, ) -> impl Future, Error = AWError> { let pool = pool.clone(); - blocking::run(move || match query { + web::block(move || match query { Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?), Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?), Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?), From 14eed91fcd73aa65247e145ed394d86989a93ee3 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 10 Mar 2019 19:19:50 -0700 Subject: [PATCH 017/111] update juniper and middleware examples --- basics/src/main.rs | 1 - juniper/Cargo.toml | 11 ++-- juniper/src/main.rs | 115 +++++++++++-------------------------- middleware/Cargo.toml | 8 ++- middleware/src/main.rs | 37 ++++++------ middleware/src/redirect.rs | 74 ++++++++++++++++++------ middleware/src/simple.rs | 76 ++++++++++++++++++------ 7 files changed, 170 insertions(+), 152 deletions(-) diff --git a/basics/src/main.rs b/basics/src/main.rs index 55f25bb0..58eae45c 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -77,7 +77,6 @@ fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse { fn main() -> io::Result<()> { env::set_var("RUST_LOG", "actix_web=debug"); - env::set_var("RUST_BACKTRACE", "1"); env_logger::init(); let sys = actix_rt::System::new("basic-example"); diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index d19b3527..e1295d2f 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -2,17 +2,14 @@ name = "juniper-example" version = "0.1.0" authors = ["pyros2097 "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" - -actix = "0.7" -actix-web = "0.7" - +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +env_logger = "0.6" futures = "0.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" - juniper = "0.9.2" diff --git a/juniper/src/main.rs b/juniper/src/main.rs index 468c093a..34967eb1 100644 --- a/juniper/src/main.rs +++ b/juniper/src/main.rs @@ -1,110 +1,59 @@ //! Actix web juniper example //! //! A simple example integrating juniper in actix-web -extern crate serde; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; +use std::io; +use std::sync::Arc; + #[macro_use] extern crate juniper; -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; -use actix::prelude::*; -use actix_web::{ - http, middleware, server, App, AsyncResponder, Error, FutureResponse, HttpRequest, - HttpResponse, Json, State, -}; +use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use futures::future::Future; use juniper::http::graphiql::graphiql_source; use juniper::http::GraphQLRequest; mod schema; -use schema::create_schema; -use schema::Schema; +use crate::schema::{create_schema, Schema}; -struct AppState { - executor: Addr, -} - -#[derive(Serialize, Deserialize)] -pub struct GraphQLData(GraphQLRequest); - -impl Message for GraphQLData { - type Result = Result; -} - -pub struct GraphQLExecutor { - schema: std::sync::Arc, -} - -impl GraphQLExecutor { - fn new(schema: std::sync::Arc) -> GraphQLExecutor { - GraphQLExecutor { schema: schema } - } -} - -impl Actor for GraphQLExecutor { - type Context = SyncContext; -} - -impl Handler for GraphQLExecutor { - type Result = Result; - - fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result { - let res = msg.0.execute(&self.schema, &()); - let res_text = serde_json::to_string(&res)?; - Ok(res_text) - } -} - -fn graphiql(_req: &HttpRequest) -> Result { +fn graphiql() -> HttpResponse { let html = graphiql_source("http://127.0.0.1:8080/graphql"); - Ok(HttpResponse::Ok() + HttpResponse::Ok() .content_type("text/html; charset=utf-8") - .body(html)) + .body(html) } fn graphql( - (st, data): (State, Json), -) -> FutureResponse { - st.executor - .send(data.0) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok() - .content_type("application/json") - .body(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }) - .responder() + st: web::State>, + data: web::Json, +) -> impl Future { + web::block(move || { + let res = data.execute(&st, &()); + Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?) + }) + .map_err(Error::from) + .and_then(|user| { + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(user)) + }) } -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("juniper-example"); + // Create Juniper schema let schema = std::sync::Arc::new(create_schema()); - let addr = SyncArbiter::start(3, move || GraphQLExecutor::new(schema.clone())); // Start http server - server::new(move || { - 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)) + HttpServer::new(move || { + App::new() + .state(schema.clone()) + .middleware(middleware::Logger::default()) + .service(web::resource("/graphql").route(web::post().to_async(graphql))) + .service(web::resource("/graphiql").route(web::get().to(graphiql))) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index b14354f4..2d533c8e 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -2,7 +2,11 @@ name = "middleware-example" version = "0.1.0" authors = ["Gorm Casper "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-service = "0.3.3" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +futures = "0.1.25" +env_logger = "0.6" \ No newline at end of file diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 91ae9d0c..6e1ec82e 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -1,32 +1,27 @@ -extern crate actix; -extern crate actix_web; - -use actix_web::{server, App}; +use actix_web::{web, App, HttpServer}; #[allow(dead_code)] mod redirect; #[allow(dead_code)] mod simple; -fn main() { - let sys = actix::System::new("middleware-example"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=debug"); + env_logger::init(); - let _addr = server::new(|| { + HttpServer::new(|| { App::new() + .middleware(redirect::CheckLogin) .middleware(simple::SayHi) - // .middleware(redirect::CheckLogin) - .resource("/login", |r| { - 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.") - }) + .service(web::resource("/login").to(|| { + "You are on /login. Go to src/redirect.rs to change this behavior." + })) + .service( + web::resource("/").to(|| { + "Hello, middleware! Check the console where the server is run." + }), + ) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/middleware/src/redirect.rs b/middleware/src/redirect.rs index a0d5de6c..3ffd3a87 100644 --- a/middleware/src/redirect.rs +++ b/middleware/src/redirect.rs @@ -1,28 +1,64 @@ -extern crate actix_web; - -use actix_web::middleware::{Middleware, Started}; -use actix_web::{http, HttpRequest, HttpResponse, Result}; +use actix_service::{Service, Transform}; +use actix_web::dev::{ServiceRequest, ServiceResponse}; +use actix_web::{http, HttpResponse}; +use futures::future::{ok, Either, FutureResult}; +use futures::Poll; pub struct CheckLogin; -impl Middleware for CheckLogin { - // We only need to hook into the `start` for this middleware. - fn start(&self, req: &HttpRequest) -> Result { +impl Transform for CheckLogin +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type InitError = (); + type Transform = CheckLoginMiddleware; + type Future = FutureResult; + + fn new_transform(&self, service: S) -> Self::Future { + ok(CheckLoginMiddleware { service }) + } +} +pub struct CheckLoginMiddleware { + service: S, +} + +impl Service for CheckLoginMiddleware +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type Future = Either>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, req: ServiceRequest

) -> Self::Future { + // We only need to hook into the `start` for this middleware. + let is_logged_in = false; // Change this to see the change in outcome in the browser if is_logged_in { - return Ok(Started::Done); + Either::A(self.service.call(req)) + } else { + // Don't forward to /login if we are already on /login + if req.path() == "/login" { + Either::A(self.service.call(req)) + } else { + Either::B(ok(req.into_response( + HttpResponse::Found() + .header(http::header::LOCATION, "/login") + .finish() + .into_body(), + ))) + } } - - // Don't forward to /login if we are already on /login - if req.path() == "/login" { - return Ok(Started::Done); - } - - Ok(Started::Response( - HttpResponse::Found() - .header(http::header::LOCATION, "/login") - .finish(), - )) } } diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index 254f263d..68f6e143 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -1,25 +1,63 @@ -extern crate actix_web; +use actix_service::{Service, Transform}; +use actix_web::dev::{ServiceRequest, ServiceResponse}; +use futures::future::{ok, FutureResult}; +use futures::{Future, Poll}; -use actix_web::middleware::{Finished, Middleware, Response, Started}; -use actix_web::{HttpRequest, HttpResponse, Result}; - -// Middleware can get called at three stages during the request/response handling. Below is a -// struct that implements all three of them. +// There are two step in middleware processing. +// 1. Middleware initialization, middleware factory get called with +// next service in chain as parameter. +// 2. Middleware's call method get called with normal request. pub struct SayHi; -impl Middleware for SayHi { - fn start(&self, req: &HttpRequest) -> Result { - println!("Hi from start. You requested: {}", req.path()); - Ok(Started::Done) - } +// Middleware factory is `Transform` trait from actix-service crate +// `S` - type of the next service +// `P` - type of request's payload +// `B` - type of response's body +impl Transform for SayHi +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, + S::Error: 'static, + B: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type InitError = (); + type Transform = SayHiMiddleware; + type Future = FutureResult; - fn response(&self, _req: &HttpRequest, resp: HttpResponse) -> Result { - println!("Hi from response"); - Ok(Response::Done(resp)) - } - - fn finish(&self, _req: &HttpRequest, _resp: &HttpResponse) -> Finished { - println!("Hi from finish"); - Finished::Done + fn new_transform(&self, service: S) -> Self::Future { + ok(SayHiMiddleware { service }) + } +} + +pub struct SayHiMiddleware { + service: S, +} + +impl Service for SayHiMiddleware +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, + S::Error: 'static, + B: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type Future = Box>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, req: ServiceRequest

) -> Self::Future { + println!("Hi from start. You requested: {}", req.path()); + + Box::new(self.service.call(req).and_then(|res| { + println!("Hi from response"); + Ok(res) + })) } } From 7ed8d19b66a348e680d1e274602dd3f21b086029 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Tue, 12 Mar 2019 21:15:53 +0100 Subject: [PATCH 018/111] Add template yarte --- .travis.yml | 1 + Cargo.toml | 1 + template_yarte/Cargo.toml | 17 ++++++++++++++ template_yarte/README.md | 11 ++++++++++ template_yarte/build.rs | 5 +++++ template_yarte/src/lib.rs | 21 ++++++++++++++++++ template_yarte/src/main.rs | 19 ++++++++++++++++ .../templates/deep/more/deep/welcome.hbs | 1 + template_yarte/templates/index.hbs | 22 +++++++++++++++++++ template_yarte/yarte.toml | 14 ++++++++++++ 10 files changed, 112 insertions(+) create mode 100644 template_yarte/Cargo.toml create mode 100644 template_yarte/README.md create mode 100644 template_yarte/build.rs create mode 100644 template_yarte/src/lib.rs create mode 100644 template_yarte/src/main.rs create mode 100644 template_yarte/templates/deep/more/deep/welcome.hbs create mode 100644 template_yarte/templates/index.hbs create mode 100644 template_yarte/yarte.toml diff --git a/.travis.yml b/.travis.yml index 66f91d8b..4c82f956 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,6 +60,7 @@ script: cd static_index && cargo check && cd .. cd template_askama && cargo check && cd .. cd template_tera && cargo check && cd .. + cd template_yarte && cargo check && cd .. cd tls && cargo check && cd .. cd rustls && cargo check && cd .. cd unix-socket && cargo check && cd .. diff --git a/Cargo.toml b/Cargo.toml index 5c287311..7422c22d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ members = [ "static_index", "template_askama", "template_tera", + "template_yarte", "tls", "rustls", "unix-socket", diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml new file mode 100644 index 00000000..4a7f8cbb --- /dev/null +++ b/template_yarte/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "example" +version = "0.0.1" +authors = ["Rust-iendo Barcelona "] +publish = false +edition = "2018" + +workspace = ".." + +[dependencies] +env_logger = "0.6" + +yarte = "0.1" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } + +[build-dependencies] +yarte = "0.1" diff --git a/template_yarte/README.md b/template_yarte/README.md new file mode 100644 index 00000000..df534a7c --- /dev/null +++ b/template_yarte/README.md @@ -0,0 +1,11 @@ +# yarte + +Example of composition with partials and `with-actix-web` feature + +See the generated code on stdout when run at debug +```bash +cargo run +``` +> open `localhost:8080` + +More at [mdbook](https://yarte.netlify.com/) and [repository](https://gitlab.com/r-iendo/yarte) diff --git a/template_yarte/build.rs b/template_yarte/build.rs new file mode 100644 index 00000000..da256d18 --- /dev/null +++ b/template_yarte/build.rs @@ -0,0 +1,5 @@ +use yarte::recompile; + +fn main() { + recompile::when_changed(); +} diff --git a/template_yarte/src/lib.rs b/template_yarte/src/lib.rs new file mode 100644 index 00000000..83f1f848 --- /dev/null +++ b/template_yarte/src/lib.rs @@ -0,0 +1,21 @@ +use actix_web::{error::ErrorInternalServerError, web::Query, HttpResponse, Result}; +use yarte::Template; + +use std::collections::HashMap; + +#[derive(Template)] +#[template(path = "index.hbs")] +struct IndexTemplate { + query: Query>, +} + +pub fn index(query: Query>) -> Result { + IndexTemplate { query } + .call() + .map(|s| { + HttpResponse::Ok() + .content_type(IndexTemplate::mime()) + .body(s) + }) + .map_err(|_| ErrorInternalServerError("Template parsing error")) +} diff --git a/template_yarte/src/main.rs b/template_yarte/src/main.rs new file mode 100644 index 00000000..6a4a896e --- /dev/null +++ b/template_yarte/src/main.rs @@ -0,0 +1,19 @@ +use actix_web::{middleware, web, App, HttpServer}; + +#[path = "lib.rs"] +mod template; + +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info"); + env_logger::init(); + + // start http server + HttpServer::new(|| { + App::new() + // enable logger + .middleware(middleware::Logger::default()) + .service(web::resource("/").to(template::index)) + }) + .bind("127.0.0.1:8080")? + .run() +} diff --git a/template_yarte/templates/deep/more/deep/welcome.hbs b/template_yarte/templates/deep/more/deep/welcome.hbs new file mode 100644 index 00000000..5cb2a971 --- /dev/null +++ b/template_yarte/templates/deep/more/deep/welcome.hbs @@ -0,0 +1 @@ +<{{ tag }}>Welcome! diff --git a/template_yarte/templates/index.hbs b/template_yarte/templates/index.hbs new file mode 100644 index 00000000..503bb845 --- /dev/null +++ b/template_yarte/templates/index.hbs @@ -0,0 +1,22 @@ + + + + + Actix web + + +{{~#if let Some(name) = query.get("name") ~}} +

Hi, {{ name }}!

+ {{~> alias/welcome tag='p' ~}} +{{~ else ~}} + {{~> alias/welcome tag="h1" ~}} +

+

What is your name?

+
+
+

+
+

+{{~/if~}} + + diff --git a/template_yarte/yarte.toml b/template_yarte/yarte.toml new file mode 100644 index 00000000..19a63673 --- /dev/null +++ b/template_yarte/yarte.toml @@ -0,0 +1,14 @@ +# root dir of templates +[main] +dir = "templates" +debug = "code" + +# Alias for partials. In call, change the start of partial path with one of this, if exist. +[partials] +alias = "./deep/more/deep" + +[debug] +# prettyprint themes, put anything for options +theme = "zenburn" +number_line = true +grid = true From e8f83c558590329520fe0129f000b9a69e5fbd86 Mon Sep 17 00:00:00 2001 From: "D.Loh" Date: Wed, 13 Mar 2019 09:39:13 -0700 Subject: [PATCH 019/111] add example from community --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a79557f5..82bf29da 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ A curated list of examples related to actix. ## from community +* [RutHub](https://www.ruthub.com/): A service for sharing read list powered by actix-web + diesel, [repo](https://github.com/danloh/rut-server-rust). * [Rust-webapp-starter ](https://github.com/rustlang-cn/Rust-webapp-starter) : Rust single page webapp written in actix-web with vuejs. * [Rust中文社区](http://47.104.146.58/) : A CN online community forum written in Actix-web with vuejs [source](https://github.com/rustlang-cn/ruster). From b31c8e3308a29cc76f124b42e3d0d7123a2a6b35 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 16 Mar 2019 20:23:09 -0700 Subject: [PATCH 020/111] rename web::State to web::Data --- actix_todo/src/api.rs | 12 ++++++------ async_db/src/main.rs | 4 ++-- diesel/src/main.rs | 8 ++++---- form/src/main.rs | 2 +- juniper/src/main.rs | 2 +- r2d2/src/main.rs | 2 +- state/src/main.rs | 14 +++++++------- template_tera/src/main.rs | 2 +- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/actix_todo/src/api.rs b/actix_todo/src/api.rs index 069e5db8..833e2b2d 100644 --- a/actix_todo/src/api.rs +++ b/actix_todo/src/api.rs @@ -9,8 +9,8 @@ use crate::db; use crate::session::{self, FlashMessage}; pub fn index( - pool: web::State, - tmpl: web::State, + pool: web::Data, + tmpl: web::Data, session: Session, ) -> impl Future { web::block(move || db::get_all_tasks(&pool)) @@ -45,7 +45,7 @@ pub struct CreateForm { pub fn create( params: web::Form, - pool: web::State, + pool: web::Data, session: Session, ) -> impl Future { if params.description.is_empty() { @@ -86,7 +86,7 @@ pub struct UpdateForm { } pub fn update( - db: web::State, + db: web::Data, params: web::Path, form: web::Form, session: Session, @@ -102,7 +102,7 @@ pub fn update( } fn toggle( - pool: web::State, + pool: web::Data, params: web::Path, ) -> impl Future { web::block(move || db::toggle_task(params.id, &pool)) @@ -114,7 +114,7 @@ fn toggle( } fn delete( - pool: web::State, + pool: web::Data, params: web::Path, session: Session, ) -> impl Future { diff --git a/async_db/src/main.rs b/async_db/src/main.rs index e9583999..e5648b23 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -21,7 +21,7 @@ use db::{Pool, Queries, WeatherAgg}; /// Version 1: Calls 4 queries in sequential order, as an asynchronous handler fn asyncio_weather( - db: web::State, + db: web::Data, ) -> impl Future { let mut result: Vec> = vec![]; @@ -52,7 +52,7 @@ fn asyncio_weather( /// Version 2: Calls 4 queries in parallel, as an asynchronous handler /// Returning Error types turn into None values in the response fn parallel_weather( - db: web::State, + db: web::Data, ) -> impl Future { let fut_result = vec![ Box::new(db::execute(&db, Queries::GetTopTenHottestYears)), diff --git a/diesel/src/main.rs b/diesel/src/main.rs index 8ff8ce68..044db371 100644 --- a/diesel/src/main.rs +++ b/diesel/src/main.rs @@ -24,7 +24,7 @@ type Pool = r2d2::Pool>; /// Diesel query fn query( nm: String, - pool: web::State, + pool: web::Data, ) -> Result { use self::schema::users::dsl::*; @@ -44,7 +44,7 @@ fn query( /// Async request handler fn add( name: web::Path, - pool: web::State, + pool: web::Data, ) -> impl Future { // run diesel blocking code web::block(move || query(name.into_inner(), pool)).then(|res| match res { @@ -63,7 +63,7 @@ const MAX_SIZE: usize = 262_144; // max payload size is 256k /// This handler manually load request payload and parse json object fn index_add

( pl: web::Payload

, - pool: web::State, + pool: web::Data, ) -> impl Future where P: Stream, @@ -110,7 +110,7 @@ where fn add2( item: web::Json, - pool: web::State, + pool: web::Data, ) -> impl Future { // run diesel blocking code web::block(move || query(item.into_inner().name, pool)).then(|res| match res { diff --git a/form/src/main.rs b/form/src/main.rs index c0c38690..3219ccba 100644 --- a/form/src/main.rs +++ b/form/src/main.rs @@ -45,7 +45,7 @@ fn handle_post_1(params: web::Form) -> Result { /// State and POST Params fn handle_post_2( - state: web::State, + state: web::Data, params: web::Form, ) -> HttpResponse { HttpResponse::Ok().content_type("text/plain").body(format!( diff --git a/juniper/src/main.rs b/juniper/src/main.rs index 34967eb1..433688e0 100644 --- a/juniper/src/main.rs +++ b/juniper/src/main.rs @@ -24,7 +24,7 @@ fn graphiql() -> HttpResponse { } fn graphql( - st: web::State>, + st: web::Data>, data: web::Json, ) -> impl Future { web::block(move || { diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index 9b1060d2..7b7f91b3 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -10,7 +10,7 @@ use uuid; /// Async request handler. Ddb pool is stored in application state. fn index( path: web::Path, - db: web::State>, + db: web::Data>, ) -> impl Future { // execute sync code in threadpool web::block(move || { diff --git a/state/src/main.rs b/state/src/main.rs index f67e9290..642d34ef 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -1,12 +1,12 @@ #![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] -//! Application may have multiple states that are shared across -//! all handlers within same Application. State could be added -//! with `App::state()` method, multiple different states could be added. +//! Application may have multiple data objects that are shared across +//! all handlers within same Application. Data could be added +//! with `App::data()` method, multiple different data objects could be added. //! //! > **Note**: http server accepts an application factory rather than an //! application > instance. Http server constructs an application instance for -//! each thread, > thus application state -//! > must be constructed multiple times. If you want to share state between +//! each thread, > thus application data +//! > must be constructed multiple times. If you want to share data between //! different > threads, a shared object should be used, e.g. `Arc`. //! //! Check [user guide](https://actix.rs/book/actix-web/sec-2-application.html) for more info. @@ -17,7 +17,7 @@ use std::sync::{Arc, Mutex}; use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer}; /// simple handle -fn index(state: web::State>>, req: HttpRequest) -> HttpResponse { +fn index(state: web::Data>>, req: HttpRequest) -> HttpResponse { println!("{:?}", req); *(state.lock().unwrap()) += 1; @@ -33,7 +33,7 @@ fn main() -> io::Result<()> { //move is necessary to give closure below ownership of counter HttpServer::new(move || { App::new() - .state(counter.clone()) // <- create app with shared state + .data(counter.clone()) // <- create app with shared state // enable logger .middleware(middleware::Logger::default()) // register simple handler, handle all methods diff --git a/template_tera/src/main.rs b/template_tera/src/main.rs index b442e82a..37c9d93b 100644 --- a/template_tera/src/main.rs +++ b/template_tera/src/main.rs @@ -7,7 +7,7 @@ use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; // store tera template in application state fn index( - tmpl: web::State, + tmpl: web::Data, query: web::Query>, ) -> Result { let s = if let Some(name) = query.get("name") { From d003fa9fb4a81b81871f49386095c83000050b39 Mon Sep 17 00:00:00 2001 From: Hans Ole Hatzel Date: Sun, 17 Mar 2019 05:35:10 +0100 Subject: [PATCH 021/111] Update example to most recent askama release (#93) --- template_askama/Cargo.toml | 4 ++-- template_askama/src/main.rs | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 5eba342c..03b2a3fe 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,10 +6,10 @@ workspace = "../" [dependencies] env_logger = "0.5" -askama = "0.6" +askama = { version = "0.8", features = ["with-actix-web"] } actix = "0.7" actix-web = "0.7" [build-dependencies] -askama = "0.6" +askama = "0.8" diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index 4a34abf1..50829e82 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; use actix_web::{http, server, App, HttpResponse, Query, Result}; use askama::Template; +use askama::actix_web::TemplateIntoResponse; #[derive(Template)] #[template(path = "user.html")] @@ -20,16 +21,14 @@ struct UserTemplate<'a> { struct Index; fn index(query: Query>) -> Result { - let s = if let Some(name) = query.get("name") { + if let Some(name) = query.get("name") { UserTemplate { name: name, text: "Welcome!", - }.render() - .unwrap() + }.into_response() } else { - Index.render().unwrap() - }; - Ok(HttpResponse::Ok().content_type("text/html").body(s)) + Index.into_response() + } } fn main() { From 1779f963d9c77b46a09dd2b6ae720b89760ff09b Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 18 Mar 2019 05:31:32 -0700 Subject: [PATCH 022/111] migrate websocket example --- websocket/Cargo.toml | 19 ++++++++++-------- websocket/src/main.rs | 45 +++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index 4ed656ec..a3f662c0 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -2,19 +2,22 @@ name = "websocket" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +edition = "2018" +workspace = ".." [[bin]] name = "websocket-server" path = "src/main.rs" -[[bin]] -name = "websocket-client" -path = "src/client.rs" +#[[bin]] +#name = "websocket-client" +#path = "src/client.rs" [dependencies] -env_logger = "*" +actix = { git="https://github.com/actix/actix.git" } +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web-actors = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +env_logger = "0.6" futures = "0.1" - -actix = "0.7" -actix-web = "0.7" +bytes = "0.4" \ No newline at end of file diff --git a/websocket/src/main.rs b/websocket/src/main.rs index 0b9a5716..25aac6ab 100644 --- a/websocket/src/main.rs +++ b/websocket/src/main.rs @@ -3,17 +3,16 @@ //! or [python console client](https://github.com/actix/examples/blob/master/websocket/websocket-client.py) //! could be used for testing. -#![allow(unused_variables)] -extern crate actix; -extern crate actix_web; -extern crate env_logger; - use std::time::{Duration, Instant}; use actix::prelude::*; +use actix_files as fs; use actix_web::{ - fs, http, middleware, server, ws, App, Error, HttpRequest, HttpResponse, + error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, }; +use actix_web_actors::ws; +use bytes::Bytes; +use futures::Stream; /// How often heartbeat pings are sent const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); @@ -21,8 +20,14 @@ const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); const CLIENT_TIMEOUT: Duration = Duration::from_secs(10); /// do websocket handshake and start `MyWebSocket` actor -fn ws_index(r: &HttpRequest) -> Result { - ws::start(r, MyWebSocket::new()) +fn ws_index(r: HttpRequest, stream: web::Payload) -> Result +where + S: Stream + 'static, +{ + println!("{:?}", r); + let res = ws::start(MyWebSocket::new(), &r, stream); + println!("{:?}", res.as_ref().unwrap()); + res } /// websocket connection is long running connection, it easier @@ -91,30 +96,20 @@ impl MyWebSocket { } } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); env_logger::init(); - let sys = actix::System::new("ws-example"); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger .middleware(middleware::Logger::default()) // websocket route - .resource("/ws/", |r| r.method(http::Method::GET).f(ws_index)) + .service(web::resource("/ws/").route(web::get().to(ws_index))) // static files - .handler( - "/", - fs::StaticFiles::new("static/") - .unwrap() - .index_file("index.html"), - ) + .service(fs::Files::new("/", "static/").index_file("index.html")) }) // start http server on 127.0.0.1:8080 - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } From 53fc2221efc0c4c2b4fd3d480e01d8ff1cac5174 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Date: Tue, 26 Mar 2019 04:29:00 +0100 Subject: [PATCH 023/111] Update to master (#90) --- .travis.yml | 2 -- actix_todo/Cargo.toml | 6 +++--- actix_todo/src/api.rs | 2 +- actix_todo/src/main.rs | 12 ++++++------ async_db/Cargo.toml | 2 +- async_db/src/main.rs | 4 ++-- async_ex1/Cargo.toml | 2 +- async_ex1/src/main.rs | 38 +++++++++++++++++++++++--------------- basics/Cargo.toml | 6 +++--- basics/src/main.rs | 4 ++-- cookie-auth/Cargo.toml | 2 +- cookie-auth/src/main.rs | 4 ++-- cookie-session/Cargo.toml | 4 ++-- cookie-session/src/main.rs | 4 ++-- diesel/Cargo.toml | 2 +- diesel/src/main.rs | 28 ++++++++++++++++++---------- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- form/src/main.rs | 4 ++-- hello-world/Cargo.toml | 2 +- hello-world/src/main.rs | 2 +- json/Cargo.toml | 2 +- json/src/main.rs | 24 ++++++++---------------- juniper/Cargo.toml | 2 +- juniper/src/main.rs | 4 ++-- middleware/Cargo.toml | 2 +- middleware/src/main.rs | 4 ++-- r2d2/Cargo.toml | 2 +- r2d2/src/main.rs | 4 ++-- state/Cargo.toml | 2 +- state/src/main.rs | 2 +- static_index/Cargo.toml | 4 ++-- static_index/src/main.rs | 2 +- template_askama/Cargo.toml | 2 +- template_tera/Cargo.toml | 2 +- template_tera/src/main.rs | 4 ++-- template_yarte/Cargo.toml | 2 +- template_yarte/src/lib.rs | 20 -------------------- template_yarte/src/main.rs | 34 +++++++++++++++++++++++++++++----- template_yarte/yarte.toml | 7 ------- tls/Cargo.toml | 2 +- tls/src/main.rs | 2 +- websocket/Cargo.toml | 6 +++--- websocket/src/main.rs | 13 +++---------- 44 files changed, 139 insertions(+), 143 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c82f956..8050c10d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,6 @@ script: cd actix_todo && cargo check && cd .. cd basics && cargo check && cd .. cd cookie-auth && cargo check && cd .. - cd cookie-auth-full && cargo check && cd .. cd cookie-session && cargo check && cd .. cd diesel && cargo check && cd .. cd error_handling && cargo check && cd .. @@ -55,7 +54,6 @@ script: cd protobuf && cargo check && cd .. cd r2d2 && cargo check && cd .. cd redis-session && cargo check && cd .. - cd simple-auth-sarver && cargo check && cd .. cd state && cargo check && cd .. cd static_index && cargo check && cd .. cd template_askama && cargo check && cd .. diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 09b9a010..736178d1 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } +actix-files = { git="https://github.com/actix/actix-web.git" } +actix-session = { git="https://github.com/actix/actix-web.git" } dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/actix_todo/src/api.rs b/actix_todo/src/api.rs index 833e2b2d..cb3e15ae 100644 --- a/actix_todo/src/api.rs +++ b/actix_todo/src/api.rs @@ -1,6 +1,6 @@ use actix_files::NamedFile; use actix_session::Session; -use actix_web::middleware::ErrorHandlerResponse; +use actix_web::middleware::errhandlers::ErrorHandlerResponse; use actix_web::{dev, error, http, web, Error, HttpResponse, Responder, Result}; use futures::future::{err, Either, Future, IntoFuture}; use tera::{Context, Tera}; diff --git a/actix_todo/src/main.rs b/actix_todo/src/main.rs index 9c9664aa..aca105ec 100644 --- a/actix_todo/src/main.rs +++ b/actix_todo/src/main.rs @@ -11,7 +11,7 @@ use std::{env, io}; use actix_files as fs; use actix_session::CookieSession; -use actix_web::middleware::{ErrorHandlers, Logger}; +use actix_web::middleware::{errhandlers::ErrorHandlers, Logger}; use actix_web::{http, web, App, HttpServer}; use dotenv::dotenv; use tera::Tera; @@ -49,11 +49,11 @@ fn main() -> io::Result<()> { .handler(http::StatusCode::NOT_FOUND, api::not_found); App::new() - .state(templates) - .state(pool.clone()) - .middleware(Logger::default()) - .middleware(session_store) - .middleware(error_handlers) + .data(templates) + .data(pool.clone()) + .wrap(Logger::default()) + .wrap(session_store) + .wrap(error_handlers) .service(web::resource("/").route(web::get().to_async(api::index))) .service(web::resource("/todo").route(web::post().to_async(api::create))) .service( diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 9dee0d2f..3161c19d 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } dotenv = "0.10" env_logger = "0.5" diff --git a/async_db/src/main.rs b/async_db/src/main.rs index e5648b23..b2293fed 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -78,8 +78,8 @@ fn main() -> io::Result<()> { // Start http server HttpServer::new(move || { App::new() - .state(pool.clone()) - .middleware(middleware::Logger::default()) + .data(pool.clone()) + .wrap(middleware::Logger::default()) .service( web::resource("/asyncio_weather") .route(web::get().to_async(asyncio_weather)), diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 69985d71..01a79760 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -8,7 +8,7 @@ workspace = ".." [dependencies] 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"] } +actix-web = { git="https://github.com/actix/actix-web.git", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index 4e8c94dd..8781ce9c 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -24,8 +24,9 @@ use std::collections::HashMap; use std::io; use actix_http::client; -use actix_web::{web, App, Error, HttpMessage, HttpResponse, HttpServer}; -use futures::future::{ok, Future}; +use actix_web::web::BytesMut; +use actix_web::{web, App, Error, HttpResponse, HttpServer}; +use futures::{Future, Stream}; use validator::Validate; #[derive(Debug, Validate, Deserialize, Serialize)] @@ -54,7 +55,7 @@ struct HttpBinResponse { /// post json to httpbin, get it back in the response body, return deserialized fn step_x_v1(data: SomeData) -> Box> { - let mut connector = client::Connector::default().service(); + let mut connector = client::Connector::new().service(); Box::new( client::ClientRequest::post("https://httpbin.org/post") @@ -62,13 +63,17 @@ fn step_x_v1(data: SomeData) -> Box> { .unwrap() .send(&mut connector) .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then(|mut resp| { - resp.body() // <- this is MessageBody type, resolves to complete body + .and_then(|resp| { + resp // <- this is MessageBody type, resolves to complete body .from_err() // <- convert PayloadError to an Error - .and_then(|body| { - let resp: HttpBinResponse = + .fold(BytesMut::new(), |mut acc, chunk| { + acc.extend_from_slice(&chunk); + Ok::<_, Error>(acc) + }) + .map(|body| { + let body: HttpBinResponse = serde_json::from_slice(&body).unwrap(); - ok(resp.json) + body.json }) }), ) @@ -95,19 +100,22 @@ 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 { - let mut connector = client::Connector::default().service(); + let mut connector = client::Connector::new().service(); client::ClientRequest::post("https://httpbin.org/post") .json(data) .unwrap() .send(&mut connector) .map_err(Error::from) // <- convert SendRequestError to an Error - .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(); - ok(resp.json) + .and_then(|resp| { + resp.from_err() + .fold(BytesMut::new(), |mut acc, chunk| { + acc.extend_from_slice(&chunk); + Ok::<_, Error>(acc) + }) + .map(|body| { + let body: HttpBinResponse = serde_json::from_slice(&body).unwrap(); + body.json }) }) } diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 71a98837..0147e333 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-session = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } +actix-files = { git="https://github.com/actix/actix-web.git" } +actix-session = { git="https://github.com/actix/actix-web.git" } futures = "0.1.25" env_logger = "0.5" diff --git a/basics/src/main.rs b/basics/src/main.rs index 58eae45c..7ab8a725 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -83,9 +83,9 @@ fn main() -> io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // cookie session middleware - .middleware(CookieSession::signed(&[0; 32]).secure(false)) + .wrap(CookieSession::signed(&[0; 32]).secure(false)) // register favicon .service(favicon) // register simple route, handle all methods diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index 81fd8eb9..efeb709c 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } env_logger = "0.6" diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 01ddde23..9d1f8577 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -22,8 +22,8 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - .middleware(middleware::Logger::default()) - .middleware(IdentityService::new( + .wrap(middleware::Logger::default()) + .wrap(IdentityService::new( CookieIdentityPolicy::new(&[0; 32]) .name("auth-example") .secure(false), diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 2947b950..d7bee4dd 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -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" } +actix-web = { git="https://github.com/actix/actix-web.git" } +actix-session = { git="https://github.com/actix/actix-web.git" } futures = "0.1" time = "0.1" diff --git a/cookie-session/src/main.rs b/cookie-session/src/main.rs index 6e0df123..497f01da 100644 --- a/cookie-session/src/main.rs +++ b/cookie-session/src/main.rs @@ -32,9 +32,9 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(Logger::default()) + .wrap(Logger::default()) // cookie session middleware - .middleware(CookieSession::signed(&[0; 32]).secure(false)) + .wrap(CookieSession::signed(&[0; 32]).secure(false)) .service(web::resource("/").to(index)) }) .bind("127.0.0.1:8080")? diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index af94c957..4089a877 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } bytes = "0.4" env_logger = "0.6" diff --git a/diesel/src/main.rs b/diesel/src/main.rs index 044db371..fdf3cbc4 100644 --- a/diesel/src/main.rs +++ b/diesel/src/main.rs @@ -10,7 +10,7 @@ extern crate diesel; extern crate serde_derive; use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; -use bytes::{Bytes, BytesMut}; +use bytes::BytesMut; use diesel::prelude::*; use diesel::r2d2::{self, ConnectionManager}; use futures::future::{err, Either}; @@ -61,13 +61,10 @@ struct MyUser { const MAX_SIZE: usize = 262_144; // max payload size is 256k /// This handler manually load request payload and parse json object -fn index_add

( - pl: web::Payload

, +fn index_add( + pl: web::Payload, pool: web::Data, -) -> impl Future -where - P: Stream, -{ +) -> impl Future { pl // `Future::from_err` acts like `?` in that it coerces the error type from // the future into the final error type @@ -132,9 +129,9 @@ fn main() -> std::io::Result<()> { // Start http server HttpServer::new(move || { App::new() - .state(pool.clone()) + .data(pool.clone()) // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // This can be called with: // curl -S --header "Content-Type: application/json" --request POST --data '{"name":"xyz"}' http://127.0.0.1:8080/add // Use of the extractors makes some post conditions simpler such @@ -142,7 +139,18 @@ fn main() -> std::io::Result<()> { .service( web::resource("/add2").route( web::post() - .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .data( + web::JsonConfig::default() + .limit(4096) // <- limit size of the payload + .error_handler(|err, _| { + // <- create custom error response + error::InternalError::from_response( + err, + HttpResponse::Conflict().finish(), + ) + .into() + }), + ) .to_async(add2), ), ) diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index f1df6a48..c4cb0973 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index 1fd56d4e..a849fed4 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } serde = "1.0" serde_derive = "1.0" diff --git a/form/src/main.rs b/form/src/main.rs index 3219ccba..ebdddf0a 100644 --- a/form/src/main.rs +++ b/form/src/main.rs @@ -12,10 +12,10 @@ struct AppState { fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - .state(AppState { + .data(AppState { foo: "bar".to_string(), }) - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) .service(web::resource("/").route(web::get().to(index))) .service(web::resource("/post1").route(web::post().to(handle_post_1))) .service(web::resource("/post2").route(web::post().to(handle_post_2))) diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index cb47b1e0..d3d38429 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" [dependencies] env_logger = "0.6" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } diff --git a/hello-world/src/main.rs b/hello-world/src/main.rs index 3bb9064a..ac294063 100644 --- a/hello-world/src/main.rs +++ b/hello-world/src/main.rs @@ -12,7 +12,7 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) .service(web::resource("/index.html").to(|| "Hello world!")) .service(web::resource("/").to(index)) }) diff --git a/json/Cargo.toml b/json/Cargo.toml index ff724d24..c5d09827 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } bytes = "0.4" futures = "0.1" diff --git a/json/src/main.rs b/json/src/main.rs index 6c9d7a5c..9b0d9a57 100644 --- a/json/src/main.rs +++ b/json/src/main.rs @@ -4,7 +4,7 @@ extern crate json; use actix_web::{ error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, }; -use bytes::{Bytes, BytesMut}; +use bytes::BytesMut; use futures::{Future, Stream}; use json::JsonValue; use serde_derive::{Deserialize, Serialize}; @@ -32,12 +32,9 @@ fn extract_item(item: web::Json, req: HttpRequest) -> HttpResponse { const MAX_SIZE: usize = 262_144; // max payload size is 256k /// This handler manually load request payload and parse json object -fn index_manual

( - payload: web::Payload

, -) -> impl Future -where - P: Stream, -{ +fn index_manual( + payload: web::Payload, +) -> impl Future { // payload is a stream of Bytes objects payload // `Future::from_err` acts like `?` in that it coerces the error type from @@ -64,12 +61,7 @@ where } /// This handler manually load request payload and parse json-rust -fn index_mjsonrust

( - pl: web::Payload

, -) -> impl Future -where - P: Stream, -{ +fn index_mjsonrust(pl: web::Payload) -> impl Future { pl.concat2().from_err().and_then(|body| { // body is loaded, now we can deserialize json-rust let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result @@ -90,18 +82,18 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) .service( web::resource("/extractor").route( web::post() - .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload .to(index), ), ) .service( web::resource("/extractor2").route( web::post() - .config(web::JsonConfig::default().limit(4096)) // <- limit size of the payload + .data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload .to_async(extract_item), ), ) diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index e1295d2f..07ac6365 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/juniper/src/main.rs b/juniper/src/main.rs index 433688e0..2615d34e 100644 --- a/juniper/src/main.rs +++ b/juniper/src/main.rs @@ -49,8 +49,8 @@ fn main() -> io::Result<()> { // Start http server HttpServer::new(move || { App::new() - .state(schema.clone()) - .middleware(middleware::Logger::default()) + .data(schema.clone()) + .wrap(middleware::Logger::default()) .service(web::resource("/graphql").route(web::post().to_async(graphql))) .service(web::resource("/graphiql").route(web::get().to(graphiql))) }) diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index 2d533c8e..7905b56c 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -7,6 +7,6 @@ workspace = ".." [dependencies] actix-service = "0.3.3" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 6e1ec82e..0496db27 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -11,8 +11,8 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - .middleware(redirect::CheckLogin) - .middleware(simple::SayHi) + .wrap(redirect::CheckLogin) + .wrap(simple::SayHi) .service(web::resource("/login").to(|| { "You are on /login. Go to src/redirect.rs to change this behavior." })) diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index 7046f298..a0b5e037 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = "../" [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } futures = "0.1" env_logger = "0.6" diff --git a/r2d2/src/main.rs b/r2d2/src/main.rs index 7b7f91b3..c323784c 100644 --- a/r2d2/src/main.rs +++ b/r2d2/src/main.rs @@ -45,8 +45,8 @@ fn main() -> io::Result<()> { // start http server HttpServer::new(move || { App::new() - .state(pool.clone()) // <- store db pool in app state - .middleware(middleware::Logger::default()) + .data(pool.clone()) // <- store db pool in app state + .wrap(middleware::Logger::default()) .route("/{name}", web::get().to_async(index)) }) .bind("127.0.0.1:8080")? diff --git a/state/Cargo.toml b/state/Cargo.toml index 7d8e0a02..39bf08a7 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } futures = "0.1" env_logger = "0.6" diff --git a/state/src/main.rs b/state/src/main.rs index 642d34ef..3ebb38a9 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -35,7 +35,7 @@ fn main() -> io::Result<()> { App::new() .data(counter.clone()) // <- create app with shared state // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // register simple handler, handle all methods .service(web::resource("/").to(index)) }) diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index ee3d5377..2dcdba30 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } +actix-files = { git="https://github.com/actix/actix-web.git" } diff --git a/static_index/src/main.rs b/static_index/src/main.rs index e4c4fa83..ced7b689 100644 --- a/static_index/src/main.rs +++ b/static_index/src/main.rs @@ -8,7 +8,7 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) .service( // static files fs::Files::new("/", "./static/").index_file("index.html"), diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index d3297425..242087ac 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] env_logger = "0.6" askama = "0.6" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } [build-dependencies] askama = "0.6" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index 2c01582d..ff35ad15 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "*" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } diff --git a/template_tera/src/main.rs b/template_tera/src/main.rs index 37c9d93b..a5942140 100644 --- a/template_tera/src/main.rs +++ b/template_tera/src/main.rs @@ -33,8 +33,8 @@ fn main() -> std::io::Result<()> { compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")); App::new() - .state(tera) - .middleware(middleware::Logger::default()) // enable logger + .data(tera) + .wrap(middleware::Logger::default()) // enable logger .service(web::resource("/").route(web::get().to(index))) }) .bind("127.0.0.1:8080")? diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 4a7f8cbb..47a03b22 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -11,7 +11,7 @@ workspace = ".." env_logger = "0.6" yarte = "0.1" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } [build-dependencies] yarte = "0.1" diff --git a/template_yarte/src/lib.rs b/template_yarte/src/lib.rs index 83f1f848..8b137891 100644 --- a/template_yarte/src/lib.rs +++ b/template_yarte/src/lib.rs @@ -1,21 +1 @@ -use actix_web::{error::ErrorInternalServerError, web::Query, HttpResponse, Result}; -use yarte::Template; -use std::collections::HashMap; - -#[derive(Template)] -#[template(path = "index.hbs")] -struct IndexTemplate { - query: Query>, -} - -pub fn index(query: Query>) -> Result { - IndexTemplate { query } - .call() - .map(|s| { - HttpResponse::Ok() - .content_type(IndexTemplate::mime()) - .body(s) - }) - .map_err(|_| ErrorInternalServerError("Template parsing error")) -} diff --git a/template_yarte/src/main.rs b/template_yarte/src/main.rs index 6a4a896e..cd4434b7 100644 --- a/template_yarte/src/main.rs +++ b/template_yarte/src/main.rs @@ -1,7 +1,31 @@ -use actix_web::{middleware, web, App, HttpServer}; +#[macro_use] +extern crate actix_web; -#[path = "lib.rs"] -mod template; +use std::collections::HashMap; + +use actix_web::{ + error::ErrorInternalServerError, middleware, web::Query, App, HttpResponse, + HttpServer, Result, +}; +use yarte::Template; + +#[derive(Template)] +#[template(path = "index.hbs")] +struct IndexTemplate { + query: Query>, +} + +#[get("/")] +pub fn index(query: Query>) -> Result { + IndexTemplate { query } + .call() + .map(|s| { + HttpResponse::Ok() + .content_type(IndexTemplate::mime()) + .body(s) + }) + .map_err(|_| ErrorInternalServerError("Template parsing error")) +} fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); @@ -11,8 +35,8 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) - .service(web::resource("/").to(template::index)) + .wrap(middleware::Logger::default()) + .service(index) }) .bind("127.0.0.1:8080")? .run() diff --git a/template_yarte/yarte.toml b/template_yarte/yarte.toml index 19a63673..bcf89202 100644 --- a/template_yarte/yarte.toml +++ b/template_yarte/yarte.toml @@ -1,14 +1,7 @@ # root dir of templates [main] dir = "templates" -debug = "code" # Alias for partials. In call, change the start of partial path with one of this, if exist. [partials] alias = "./deep/more/deep" - -[debug] -# prettyprint themes, put anything for options -theme = "zenburn" -number_line = true -grid = true diff --git a/tls/Cargo.toml b/tls/Cargo.toml index b18ff5a7..0442f206 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -14,4 +14,4 @@ env_logger = "0.5" openssl = { version="0.10" } actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0", features=["ssl"] } +actix-web = { git="https://github.com/actix/actix-web.git", features=["ssl"] } diff --git a/tls/src/main.rs b/tls/src/main.rs index f8c8961c..7e95309a 100644 --- a/tls/src/main.rs +++ b/tls/src/main.rs @@ -27,7 +27,7 @@ fn main() -> io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // register simple handler, handle all methods .service(web::resource("/index.html").to(index)) // with path parameters diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index a3f662c0..a68b058f 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -15,9 +15,9 @@ path = "src/main.rs" [dependencies] actix = { git="https://github.com/actix/actix.git" } -actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-web-actors = { git="https://github.com/actix/actix-web.git", branch = "1.0" } -actix-files = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web-actors = { git="https://github.com/actix/actix-web.git" } +actix-files = { git="https://github.com/actix/actix-web.git" } env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file diff --git a/websocket/src/main.rs b/websocket/src/main.rs index 25aac6ab..67d57918 100644 --- a/websocket/src/main.rs +++ b/websocket/src/main.rs @@ -7,12 +7,8 @@ use std::time::{Duration, Instant}; use actix::prelude::*; use actix_files as fs; -use actix_web::{ - error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, -}; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use actix_web_actors::ws; -use bytes::Bytes; -use futures::Stream; /// How often heartbeat pings are sent const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); @@ -20,10 +16,7 @@ const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); const CLIENT_TIMEOUT: Duration = Duration::from_secs(10); /// do websocket handshake and start `MyWebSocket` actor -fn ws_index(r: HttpRequest, stream: web::Payload) -> Result -where - S: Stream + 'static, -{ +fn ws_index(r: HttpRequest, stream: web::Payload) -> Result { println!("{:?}", r); let res = ws::start(MyWebSocket::new(), &r, stream); println!("{:?}", res.as_ref().unwrap()); @@ -103,7 +96,7 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // websocket route .service(web::resource("/ws/").route(web::get().to(ws_index))) // static files From 48b8e7c335df9f0f195a5c7b0d7393e7f3c6b6fa Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 26 Mar 2019 23:33:13 -0700 Subject: [PATCH 024/111] migrate http proxy examples --- async_db/Cargo.toml | 3 +- async_db/src/db.rs | 9 +-- async_ex1/Cargo.toml | 1 - async_ex1/src/main.rs | 59 ++++++++++-------- http-full-proxy/Cargo.toml | 7 ++- http-full-proxy/src/main.rs | 119 +++++++++++++----------------------- http-proxy/Cargo.toml | 9 +-- http-proxy/src/main.rs | 56 +++++++---------- http-proxy/src/server.rs | 39 ++++-------- 9 files changed, 125 insertions(+), 177 deletions(-) diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 3161c19d..7848d1b7 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -15,7 +15,8 @@ failure = "0.1.1" futures = "0.1" num_cpus = "1.10.0" r2d2 = "0.8.2" -r2d2_sqlite = "0.5.0" +r2d2_sqlite = "0.8.0" +rusqlite = "0.16" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" diff --git a/async_db/src/db.rs b/async_db/src/db.rs index e23adba2..4ca80daf 100644 --- a/async_db/src/db.rs +++ b/async_db/src/db.rs @@ -3,6 +3,7 @@ use failure::Error; use futures::Future; use r2d2; use r2d2_sqlite; +use rusqlite::NO_PARAMS; use serde_derive::{Deserialize, Serialize}; use std::{thread::sleep, time::Duration}; @@ -47,7 +48,7 @@ fn get_hottest_years(conn: Connection) -> Result, Error> { let mut prep_stmt = conn.prepare(stmt)?; let annuals = prep_stmt - .query_map(&[], |row| WeatherAgg::AnnualAgg { + .query_map(NO_PARAMS, |row| WeatherAgg::AnnualAgg { year: row.get(0), total: row.get(1), }) @@ -73,7 +74,7 @@ fn get_coldest_years(conn: Connection) -> Result, Error> { let mut prep_stmt = conn.prepare(stmt)?; let annuals = prep_stmt - .query_map(&[], |row| WeatherAgg::AnnualAgg { + .query_map(NO_PARAMS, |row| WeatherAgg::AnnualAgg { year: row.get(0), total: row.get(1), }) @@ -99,7 +100,7 @@ fn get_hottest_months(conn: Connection) -> Result, Error> { let mut prep_stmt = conn.prepare(stmt)?; let annuals = prep_stmt - .query_map(&[], |row| WeatherAgg::MonthAgg { + .query_map(NO_PARAMS, |row| WeatherAgg::MonthAgg { year: row.get(0), month: row.get(1), total: row.get(2), @@ -125,7 +126,7 @@ fn get_coldest_months(conn: Connection) -> Result, Error> { let mut prep_stmt = conn.prepare(stmt)?; let annuals = prep_stmt - .query_map(&[], |row| WeatherAgg::MonthAgg { + .query_map(NO_PARAMS, |row| WeatherAgg::MonthAgg { year: row.get(0), month: row.get(1), total: row.get(2), diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 01a79760..f89f97b5 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -7,7 +7,6 @@ workspace = ".." [dependencies] 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", features=["ssl"] } futures = "0.1" diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index 8781ce9c..a9eb054b 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -23,7 +23,7 @@ extern crate serde_derive; use std::collections::HashMap; use std::io; -use actix_http::client; +use actix_web::client::Client; use actix_web::web::BytesMut; use actix_web::{web, App, Error, HttpResponse, HttpServer}; use futures::{Future, Stream}; @@ -54,14 +54,14 @@ struct HttpBinResponse { // ----------------------------------------------------------------------- /// post json to httpbin, get it back in the response body, return deserialized -fn step_x_v1(data: SomeData) -> Box> { - let mut connector = client::Connector::new().service(); - +fn step_x_v1( + data: SomeData, + client: &Client, +) -> Box> { Box::new( - client::ClientRequest::post("https://httpbin.org/post") - .json(data) - .unwrap() - .send(&mut connector) + client + .post("https://httpbin.org/post") + .send_json(data) .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { resp // <- this is MessageBody type, resolves to complete body @@ -81,17 +81,20 @@ fn step_x_v1(data: SomeData) -> Box> { fn create_something_v1( some_data: web::Json, + client: web::Data, ) -> Box> { - 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() - .content_type("application/json") - .body(serde_json::to_string(&d).unwrap()) - .into()) + Box::new( + step_x_v1(some_data.into_inner(), &client).and_then(move |some_data_2| { + step_x_v1(some_data_2, &client).and_then(move |some_data_3| { + step_x_v1(some_data_3, &client).and_then(|d| { + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(serde_json::to_string(&d).unwrap()) + .into()) + }) }) - }) - })) + }), + ) } // --------------------------------------------------------------- @@ -99,13 +102,13 @@ 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 { - let mut connector = client::Connector::new().service(); - - client::ClientRequest::post("https://httpbin.org/post") - .json(data) - .unwrap() - .send(&mut connector) +fn step_x_v2( + data: SomeData, + client: &Client, +) -> impl Future { + client + .post("https://httpbin.org/post") + .send_json(data) .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { resp.from_err() @@ -122,10 +125,11 @@ fn step_x_v2(data: SomeData) -> impl Future { fn create_something_v2( some_data: web::Json, + client: web::Data, ) -> impl Future { - 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_3).and_then(|d| { + step_x_v2(some_data.into_inner(), &client).and_then(move |some_data_2| { + step_x_v2(some_data_2, &client).and_then(move |some_data_3| { + step_x_v2(some_data_3, &client).and_then(|d| { Ok(HttpResponse::Ok() .content_type("application/json") .body(serde_json::to_string(&d).unwrap()) @@ -141,6 +145,7 @@ fn main() -> io::Result<()> { HttpServer::new(|| { App::new() + .data(Client::default()) .service( web::resource("/something_v1") .route(web::post().to(create_something_v1)), diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index f9363344..b7686cfe 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -2,10 +2,13 @@ name = "http-full-proxy" version = "0.1.0" authors = ["Rotem Yaari"] +workspace = ".." +edition = "2018" [dependencies] -actix = "0.7.5" -actix-web = "0.7.13" +actix-rt = "0.2" +actix-web = { git="https://github.com/actix/actix-web.git" } + clap = "2.32.0" futures = "0.1.25" failure = "0.1.3" diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 05bfb394..f350769e 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -1,85 +1,53 @@ -#![deny(warnings)] -extern crate actix; -extern crate actix_web; -extern crate clap; -extern crate failure; -extern crate futures; -extern crate url; - -use actix_web::{ - client, http, server, App, AsyncResponder, Error, HttpMessage, HttpRequest, - HttpResponse, -}; +use actix_web::client::Client; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use clap::{value_t, Arg}; -use futures::{future, Future}; +use futures::Future; use std::net::ToSocketAddrs; use url::Url; -struct AppState { - forward_url: Url, -} - -impl AppState { - pub fn init(forward_url: Url) -> AppState { - AppState { forward_url } - } -} - fn forward( - req: &HttpRequest, -) -> Box> { - let mut new_url = req.state().forward_url.clone(); + req: HttpRequest, + payload: web::Payload, + url: web::Data, + client: web::Data, +) -> impl Future { + let mut new_url = url.get_ref().clone(); new_url.set_path(req.uri().path()); new_url.set_query(req.uri().query()); - let mut forwarded_req = client::ClientRequest::build_from(req) - .no_default_headers() - .uri(new_url) - .streaming(req.payload()) - .unwrap(); + let forwarded_req = client + .request_from(new_url.as_str(), &req) + .no_default_headers(); - if let Some(addr) = req.peer_addr() { - match forwarded_req.headers_mut().entry("x-forwarded-for") { - Ok(http::header::Entry::Vacant(entry)) => { - let addr = format!("{}", addr.ip()); - entry.insert(addr.parse().unwrap()); - } - Ok(http::header::Entry::Occupied(mut entry)) => { - let addr = format!("{}, {}", entry.get().to_str().unwrap(), addr.ip()); - entry.insert(addr.parse().unwrap()); - } - _ => unreachable!(), - } - } + // if let Some(addr) = req.peer_addr() { + // match forwarded_req.headers_mut().entry("x-forwarded-for") { + // Ok(http::header::Entry::Vacant(entry)) => { + // let addr = format!("{}", addr.ip()); + // entry.insert(addr.parse().unwrap()); + // } + // Ok(http::header::Entry::Occupied(mut entry)) => { + // let addr = format!("{}, {}", entry.get().to_str().unwrap(), addr.ip()); + // entry.insert(addr.parse().unwrap()); + // } + // _ => unreachable!(), + // } + // } forwarded_req - .send() + .send_stream(payload) .map_err(Error::from) - .and_then(construct_response) - .responder() + .map(|res| { + let mut client_resp = HttpResponse::build(res.status()); + for (header_name, header_value) in + res.headers().iter().filter(|(h, _)| *h != "connection") + { + client_resp.header(header_name.clone(), header_value.clone()); + } + client_resp.streaming(res) + }) } -fn construct_response( - resp: client::ClientResponse, -) -> Box> { - let mut client_resp = HttpResponse::build(resp.status()); - for (header_name, header_value) in - resp.headers().iter().filter(|(h, _)| *h != "connection") - { - client_resp.header(header_name.clone(), header_value.clone()); - } - if resp.chunked().unwrap_or(false) { - Box::new(future::ok(client_resp.streaming(resp.payload()))) - } else { - Box::new( - resp.body() - .from_err() - .and_then(move |body| Ok(client_resp.body(body))), - ) - } -} - -fn main() { +fn main() -> std::io::Result<()> { let matches = clap::App::new("HTTP Proxy") .arg( Arg::with_name("listen_addr") @@ -128,14 +96,13 @@ fn main() { )) .unwrap(); - server::new(move || { - App::with_state(AppState::init(forward_url.clone())).default_resource(|r| { - r.f(forward); - }) + HttpServer::new(move || { + App::new() + .data(forward_url.clone()) + .wrap(middleware::Logger::default()) + .default_resource(|r| r.to_async(forward)) }) - .workers(32) - .bind((listen_addr, listen_port)) - .expect("Cannot bind listening port") + .bind((listen_addr, listen_port))? .system_exit() - .run(); + .run() } diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index b06a5946..ca1176d4 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -2,7 +2,8 @@ name = "http-proxy" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +edition = "2018" +workspace = ".." [[bin]] name = "proxy" @@ -13,8 +14,8 @@ name = "proxy-example-server" path = "src/server.rs" [dependencies] +actix-rt = "0.2" +actix-web = { git="https://github.com/actix/actix-web.git" } + env_logger = "0.5" futures = "0.1" - -actix = "0.7" -actix-web = "^0.7" diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index 9d51aceb..080c848d 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -1,19 +1,11 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; - -use actix_web::{ - client, middleware, server, App, AsyncResponder, Body, Error, HttpMessage, - HttpRequest, HttpResponse, -}; -use futures::{Future, Stream}; +use actix_web::client::Client; +use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; +use futures::Future; /// Stream client request response and then send body to a server response -fn index(_req: &HttpRequest) -> Box> { - client::ClientRequest::get("http://127.0.0.1:8081/") - .finish() - .unwrap() +fn index(client: web::Data) -> impl Future { + client + .get("http://127.0.0.1:8081/") .send() .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { @@ -24,15 +16,15 @@ fn index(_req: &HttpRequest) -> Box> Ok(HttpResponse::Ok().body(body)) }) }) - .responder() } /// streaming client request to a streaming server response -fn streaming(_req: &HttpRequest) -> Box> { +fn streaming( + client: web::Data, +) -> impl Future> { // send client request - client::ClientRequest::get("https://www.rust-lang.org/en-US/") - .finish() - .unwrap() + client + .get("https://www.rust-lang.org/en-US/") .send() // <- connect to host and send request .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { @@ -40,27 +32,21 @@ fn streaming(_req: &HttpRequest) -> Box std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); env_logger::init(); - let sys = actix::System::new("http-proxy"); - server::new(|| { + HttpServer::new(|| { App::new() - .middleware(middleware::Logger::default()) - .resource("/streaming", |r| r.f(streaming)) - .resource("/", |r| r.f(index)) + .data(Client::new()) + .wrap(middleware::Logger::default()) + .service(web::resource("/streaming").to_async(streaming)) + .service(web::resource("/").to_async(index)) }) - .workers(1) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/http-proxy/src/server.rs b/http-proxy/src/server.rs index 11584def..a8e7559e 100644 --- a/http-proxy/src/server.rs +++ b/http-proxy/src/server.rs @@ -1,35 +1,20 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; +use actix_web::{middleware, web, App, HttpResponse, HttpServer, Responder}; -use actix_web::*; -use futures::Future; - -fn index(req: &HttpRequest) -> FutureResponse { - req.body() - .from_err() - .map(|bytes| HttpResponse::Ok().body(bytes)) - .responder() +fn index(body: web::Bytes) -> impl Responder { + HttpResponse::Ok().body(body) } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=error"); - let _ = env_logger::init(); - let sys = actix::System::new("ws-example"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); + env_logger::init(); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) - .resource("/index.html", |r| r.f(|_| "Hello world!")) - .resource("/", |r| r.f(index)) + .wrap(middleware::Logger::default()) + .service(web::resource("/index.html").to(|| "Hello world!")) + .service(web::resource("/").to(index)) }) - .workers(1) - .bind("127.0.0.1:8081") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8081"); - let _ = sys.run(); + .bind("127.0.0.1:8081")? + .run() } From e4f71e8fd521c726c3c1d25f0fdbcce305ddc340 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 29 Mar 2019 13:43:03 -0700 Subject: [PATCH 025/111] update deps --- actix_redis/Cargo.toml | 10 +- actix_redis/src/main.rs | 82 ++++++--------- actix_todo/Cargo.toml | 6 +- async_db/Cargo.toml | 2 +- async_ex1/Cargo.toml | 2 +- basics/Cargo.toml | 6 +- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 +- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 2 +- multipart/Cargo.toml | 11 +- multipart/src/main.rs | 103 ++++++++----------- r2d2/Cargo.toml | 4 +- redis-session/Cargo.toml | 12 ++- redis-session/src/main.rs | 42 +++----- simple-auth-server/Cargo.toml | 12 ++- simple-auth-server/src/app.rs | 56 ---------- simple-auth-server/src/auth_handler.rs | 25 +++-- simple-auth-server/src/auth_routes.rs | 34 +++--- simple-auth-server/src/email_service.rs | 2 +- simple-auth-server/src/errors.rs | 9 +- simple-auth-server/src/invitation_handler.rs | 7 +- simple-auth-server/src/invitation_routes.rs | 21 ++-- simple-auth-server/src/main.rs | 97 +++++++++++------ simple-auth-server/src/models.rs | 2 +- simple-auth-server/src/register_handler.rs | 11 +- simple-auth-server/src/register_routes.rs | 22 ++-- simple-auth-server/src/utils.rs | 13 ++- state/Cargo.toml | 5 +- static_index/Cargo.toml | 4 +- template_askama/Cargo.toml | 2 +- template_askama/src/main.rs | 3 - template_tera/Cargo.toml | 4 +- template_yarte/Cargo.toml | 4 +- tls/Cargo.toml | 7 +- web-cors/backend/Cargo.toml | 9 +- web-cors/backend/src/main.rs | 44 +++----- web-cors/backend/src/user.rs | 8 +- websocket/Cargo.toml | 8 +- websocket/src/client.rs | 9 +- 47 files changed, 307 insertions(+), 415 deletions(-) delete mode 100644 simple-auth-server/src/app.rs diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index a716e624..b8014247 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -2,13 +2,15 @@ name = "actix_redis" version = "0.1.0" authors = ["dowwie "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7.3" -actix-web = "0.7.3" -actix-redis = "0.5.1" +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.1" +actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" serde = "1.0.71" serde_derive = "1.0.71" -env_logger = "0.5.12" +env_logger = "0.6" diff --git a/actix_redis/src/main.rs b/actix_redis/src/main.rs index e8072a21..a9ed3c4c 100644 --- a/actix_redis/src/main.rs +++ b/actix_redis/src/main.rs @@ -1,23 +1,13 @@ -extern crate actix; -extern crate actix_redis; -extern crate actix_web; -extern crate env_logger; -extern crate futures; #[macro_use] extern crate redis_async; -extern crate serde; #[macro_use] extern crate serde_derive; use actix::prelude::*; use actix_redis::{Command, Error as ARError, RedisActor}; -use actix_web::{ - http::Method, middleware, server, App, AsyncResponder, Error as AWError, - HttpRequest, HttpResponse, Json, -}; +use actix_web::{middleware, web, App, Error as AWError, HttpResponse, HttpServer}; use futures::future::{join_all, Future}; use redis_async::resp::RespValue; -use std::sync::Arc; #[derive(Deserialize)] pub struct CacheInfo { @@ -27,10 +17,10 @@ pub struct CacheInfo { } fn cache_stuff( - (info, req): (Json, HttpRequest), + info: web::Json, + redis: web::Data>, ) -> impl Future { let info = info.into_inner(); - let redis = req.state().redis_addr.clone(); let one = redis.send(Command(resp_array!["SET", "mydomain:one", info.one])); let two = redis.send(Command(resp_array!["SET", "mydomain:two", info.two])); @@ -46,26 +36,23 @@ fn cache_stuff( let info_set = join_all(vec![one, two, three].into_iter()); info_set - .map_err(AWError::from) - .and_then(|res: Vec>| - // successful operations return "OK", so confirm that all returned as so - if !res.iter().all(|res| match res { - Ok(RespValue::SimpleString(x)) if x=="OK" => true, - _ => false - }) { - Ok(HttpResponse::InternalServerError().finish()) - } else { - Ok(HttpResponse::Ok().body("successfully cached values")) - } - ) - .responder() + .map_err(AWError::from) + .and_then(|res: Vec>| + // successful operations return "OK", so confirm that all returned as so + if !res.iter().all(|res| match res { + Ok(RespValue::SimpleString(x)) if x=="OK" => true, + _ => false + }) { + Ok(HttpResponse::InternalServerError().finish()) + } else { + Ok(HttpResponse::Ok().body("successfully cached values")) + } + ) } fn del_stuff( - req: HttpRequest, + redis: web::Data>, ) -> impl Future { - let redis = req.state().redis_addr.clone(); - redis .send(Command(resp_array![ "DEL", @@ -83,33 +70,24 @@ fn del_stuff( Ok(HttpResponse::InternalServerError().finish()) } }) - .responder() } -pub struct AppState { - pub redis_addr: Arc>, -} - -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info"); env_logger::init(); - let sys = actix::System::new("actix_redis_ex"); - server::new(|| { - let redis_addr = Arc::new(RedisActor::start("127.0.0.1:6379")); - let app_state = AppState { redis_addr }; + HttpServer::new(|| { + let redis_addr = RedisActor::start("127.0.0.1:6379"); - 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) - }) + App::new() + .data(redis_addr) + .wrap(middleware::Logger::default()) + .service( + web::resource("/stuff") + .route(web::post().to_async(cache_stuff)) + .route(web::delete().to_async(del_stuff)), + ) }) - .bind("0.0.0.0:8080") - .unwrap() - .workers(1) - .start(); - - let _ = sys.run(); + .bind("0.0.0.0:8080")? + .run() } diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 736178d1..17a35307 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } -actix-files = { git="https://github.com/actix/actix-web.git" } -actix-session = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" +actix-session = "0.1.0-alpha.1" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 7848d1b7..2d322de3 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index f89f97b5..1be43ae9 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", features=["ssl"] } +actix-web = { version="1.0.0-alpha.1", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 0147e333..4eb17bcc 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git" } -actix-files = { git="https://github.com/actix/actix-web.git" } -actix-session = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" +actix-session = "0.1.0-alpha.1" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index efeb709c..d728e3ed 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index d7bee4dd..ce876957 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } -actix-session = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" +actix-session = "0.1.0-alpha.1" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 4089a877..d8dfb918 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index c4cb0973..7e05407c 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index a849fed4..150b9417 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index d3d38429..502b1410 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] +actix-web = "1.0.0-alpha.1" env_logger = "0.6" -actix-web = { git="https://github.com/actix/actix-web.git" } diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index b7686cfe..f906fdd2 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" clap = "2.32.0" futures = "0.1.25" diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index ca1176d4..487d4580 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index c5d09827..82b525c8 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" bytes = "0.4" futures = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 07ac6365..ff47263a 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index 7905b56c..c5657087 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -7,6 +7,6 @@ workspace = ".." [dependencies] actix-service = "0.3.3" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 771e28f7..994c80fc 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -2,15 +2,16 @@ name = "multipart-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [[bin]] name = "multipart" path = "src/main.rs" [dependencies] -env_logger = "*" -futures = "0.1" +#actix-web = "1.0.0-alpha.1" +actix-web = { git="https://github.com/actix/actix-web.git" } -actix = "0.7" -actix-web = "0.7" +env_logger = "0.6" +futures = "0.1.25" diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 37c17bf6..40f22d38 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -1,44 +1,30 @@ -#![allow(unused_variables)] -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; - use std::cell::Cell; use std::fs; use std::io::Write; -use actix_web::{ - dev, error, http, middleware, multipart, server, App, Error, FutureResponse, - HttpMessage, HttpRequest, HttpResponse, -}; - -use futures::future; +use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; +use futures::future::{err, Either}; use futures::{Future, Stream}; pub struct AppState { pub counter: Cell, } -pub fn save_file( - field: multipart::Field, -) -> Box> { +pub fn save_file(field: web::MultipartField) -> impl Future { let file_path_string = "upload.png"; let mut file = match fs::File::create(file_path_string) { Ok(file) => file, - Err(e) => return Box::new(future::err(error::ErrorInternalServerError(e))), + Err(e) => return Either::A(err(error::ErrorInternalServerError(e))), }; - Box::new( + Either::B( field .fold(0i64, move |acc, bytes| { - let rt = file - .write_all(bytes.as_ref()) + file.write_all(bytes.as_ref()) .map(|_| acc + bytes.len() as i64) .map_err(|e| { println!("file.write_all failed: {:?}", e); error::MultipartError::Payload(error::PayloadError::Io(e)) - }); - future::result(rt) + }) }) .map_err(|e| { println!("save_file failed, {:?}", e); @@ -48,13 +34,11 @@ pub fn save_file( } pub fn handle_multipart_item( - item: multipart::MultipartItem, + item: web::MultipartItem, ) -> Box> { match item { - multipart::MultipartItem::Field(field) => { - Box::new(save_file(field).into_stream()) - } - multipart::MultipartItem::Nested(mp) => Box::new( + web::MultipartItem::Field(field) => Box::new(save_file(field).into_stream()), + web::MultipartItem::Nested(mp) => Box::new( mp.map_err(error::ErrorInternalServerError) .map(handle_multipart_item) .flatten(), @@ -62,24 +46,26 @@ pub fn handle_multipart_item( } } -pub fn upload(req: HttpRequest) -> FutureResponse { - req.state().counter.set(req.state().counter.get() + 1); - println!("{:?}", req.state().counter.get()); - Box::new( - req.multipart() - .map_err(error::ErrorInternalServerError) - .map(handle_multipart_item) - .flatten() - .collect() - .map(|sizes| HttpResponse::Ok().json(sizes)) - .map_err(|e| { - println!("failed: {}", e); - e - }), - ) +pub fn upload( + multipart: web::Multipart, + counter: web::Data>, +) -> impl Future { + counter.set(counter.get() + 1); + println!("{:?}", counter.get()); + + multipart + .map_err(error::ErrorInternalServerError) + .map(handle_multipart_item) + .flatten() + .collect() + .map(|sizes| HttpResponse::Ok().json(sizes)) + .map_err(|e| { + println!("failed: {}", e); + e + }) } -fn index(_req: HttpRequest) -> Result { +fn index() -> HttpResponse { let html = r#" Upload Test @@ -90,28 +76,23 @@ fn index(_req: HttpRequest) -> Result { "#; - Ok(HttpResponse::Ok().body(html)) + HttpResponse::Ok().body(html) } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); env_logger::init(); - let sys = actix::System::new("multipart-example"); - server::new(|| { - App::with_state(AppState { - counter: Cell::new(0), - }) - .middleware(middleware::Logger::default()) - .resource("/", |r| { - r.method(http::Method::GET).with(index); - r.method(http::Method::POST).with(upload); - }) + HttpServer::new(|| { + App::new() + .data(Cell::new(0usize)) + .wrap(middleware::Logger::default()) + .service( + web::resource("/") + .route(web::get().to(index)) + .route(web::post().to_async(upload)), + ) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Starting http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index a0b5e037..0f6d7b57 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -3,11 +3,11 @@ name = "r2d2-example" version = "0.1.0" authors = ["Nikolay Kim "] edition = "2018" -workspace = "../" +workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 8b6152a6..5198d902 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -2,10 +2,12 @@ name = "redis-session" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" -actix = "0.7" -actix-web = "0.7.3" -actix-redis = { version = "0.5.1", features = ["web"] } +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.1" +actix-session = "0.1.0-alpha.1" +actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } +env_logger = "0.6" diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 18a68e15..0c49c6bf 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -1,50 +1,38 @@ //! Example of redis based session //! //! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions) -extern crate actix; -extern crate actix_redis; -extern crate actix_web; -extern crate env_logger; - -use actix_redis::RedisSessionBackend; -use actix_web::middleware::session::{RequestSession, SessionStorage}; -use actix_web::{middleware, server, App, HttpRequest, HttpResponse, Result}; +use actix_redis::RedisSession; +use actix_session::Session; +use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Result}; /// simple handler -fn index(req: &HttpRequest) -> Result { +fn index(req: HttpRequest, session: Session) -> Result { println!("{:?}", req); // session - if let Some(count) = req.session().get::("counter")? { + if let Some(count) = session.get::("counter")? { println!("SESSION value: {}", count); - req.session().set("counter", count + 1)?; + session.set("counter", count + 1)?; } else { - req.session().set("counter", 1)?; + session.set("counter", 1)?; } Ok("Welcome!".into()) } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info"); env_logger::init(); - let sys = actix::System::new("basic-example"); - server::new(|| { + HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // redis session middleware - .middleware(SessionStorage::new(RedisSessionBackend::new( - "127.0.0.1:6379", - &[0; 32], - ))) + .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) // register simple route, handle all methods - .resource("/", |r| r.f(index)) + .service(web::resource("/").to(index)) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 25ba9407..0c6a42be 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -2,18 +2,22 @@ name = "simple-auth-server" version = "0.1.0" authors = ["mygnu "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7.7" -actix-web = "0.7.14" +actix = { version = "0.8.0-alpha.2", features = ["http"] } +actix-web = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" + bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } diesel = { version = "1.3.3", features = ["postgres", "uuid", "r2d2", "chrono"] } dotenv = "0.13.0" +derive_more = "0.14" env_logger = "0.6.0" -failure = "0.1.3" jsonwebtoken = "5.0" -futures = "0.1" +futures = "0.1.25" r2d2 = "0.8.3" serde_derive="1.0.80" serde_json="1.0" diff --git a/simple-auth-server/src/app.rs b/simple-auth-server/src/app.rs deleted file mode 100644 index 05fdf2f7..00000000 --- a/simple-auth-server/src/app.rs +++ /dev/null @@ -1,56 +0,0 @@ -use actix::prelude::*; -use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService}; -use actix_web::{fs, http::Method, middleware::Logger, App}; -use auth_routes::{get_me, login, logout}; -use chrono::Duration; -use invitation_routes::register_email; -use models::DbExecutor; -use register_routes::register_user; - -pub struct AppState { - pub db: Addr, -} - -/// creates and returns the app after mounting all routes/resources -pub fn create_app(db: Addr) -> App { - // 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()); - - App::with_state(AppState { db }) - .middleware(Logger::default()) - .middleware(IdentityService::new( - CookieIdentityPolicy::new(secret.as_bytes()) - .name("auth") - .path("/") - .domain(domain.as_str()) - .max_age(Duration::days(1)) - .secure(false), // this can only be true if you have https - )) - // everything under '/api/' route - .scope("/api", |api| { - // routes for authentication - api.resource("/auth", |r| { - r.method(Method::POST).with(login); - r.method(Method::DELETE).with(logout); - r.method(Method::GET).with(get_me); - }) - // routes to invitation - .resource("/invitation", |r| { - r.method(Method::POST).with(register_email); - }) - // routes to register as a user after the - .resource("/register/{invitation_id}", |r| { - r.method(Method::POST).with(register_user); - }) - }) - // serve static files - .handler( - "/", - fs::StaticFiles::new("./static/") - .unwrap() - .index_file("index.html"), - ) -} diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 161a951f..13eb1476 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,10 +1,12 @@ use actix::{Handler, Message}; -use actix_web::{middleware::identity::RequestIdentity, FromRequest, HttpRequest}; +use actix_web::{dev::ServiceFromRequest, Error}; +use actix_web::{middleware::identity::Identity, FromRequest, HttpRequest}; use bcrypt::verify; use diesel::prelude::*; -use errors::ServiceError; -use models::{DbExecutor, SlimUser, User}; -use utils::decode_token; + +use crate::errors::ServiceError; +use crate::models::{DbExecutor, SlimUser, User}; +use crate::utils::decode_token; #[derive(Debug, Deserialize)] pub struct AuthData { @@ -19,7 +21,7 @@ impl Message for AuthData { impl Handler for DbExecutor { type Result = Result; fn handle(&mut self, msg: AuthData, _: &mut Self::Context) -> Self::Result { - use schema::users::dsl::{email, users}; + use crate::schema::users::dsl::{email, users}; let conn: &PgConnection = &self.0.get().unwrap(); let mut items = users.filter(email.eq(&msg.email)).load::(conn)?; @@ -44,14 +46,15 @@ impl Handler for DbExecutor { // simple aliasing makes the intentions clear and its more readable pub type LoggedUser = SlimUser; -impl FromRequest for LoggedUser { - type Config = (); - type Result = Result; - fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result { - if let Some(identity) = req.identity() { +impl

FromRequest

for LoggedUser { + type Error = Error; + type Future = Result; + + fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { + if let Some(identity) = Identity::from_request(req)?.identity() { let user: SlimUser = decode_token(&identity)?; return Ok(user as LoggedUser); } - Err(ServiceError::Unauthorized) + Err(ServiceError::Unauthorized.into()) } } diff --git a/simple-auth-server/src/auth_routes.rs b/simple-auth-server/src/auth_routes.rs index 90cafec4..269c3a67 100644 --- a/simple-auth-server/src/auth_routes.rs +++ b/simple-auth-server/src/auth_routes.rs @@ -1,34 +1,32 @@ -use actix_web::middleware::identity::RequestIdentity; -use actix_web::{ - AsyncResponder, FutureResponse, HttpRequest, HttpResponse, Json, ResponseError, -}; -use futures::future::Future; -use utils::create_token; +use actix::Addr; +use actix_web::middleware::identity::Identity; +use actix_web::{web, Error, HttpRequest, HttpResponse, Responder, ResponseError}; +use futures::Future; -use app::AppState; -use auth_handler::{AuthData, LoggedUser}; +use crate::auth_handler::{AuthData, LoggedUser}; +use crate::models::DbExecutor; +use crate::utils::create_token; pub fn login( - (auth_data, req): (Json, HttpRequest), -) -> FutureResponse { - req.state() - .db - .send(auth_data.into_inner()) + auth_data: web::Json, + id: Identity, + db: web::Data>, +) -> impl Future { + db.send(auth_data.into_inner()) .from_err() .and_then(move |res| match res { Ok(user) => { let token = create_token(&user)?; - req.remember(token); + id.remember(token); Ok(HttpResponse::Ok().into()) } Err(err) => Ok(err.error_response()), }) - .responder() } -pub fn logout(req: HttpRequest) -> HttpResponse { - req.forget(); - HttpResponse::Ok().into() +pub fn logout(id: Identity) -> impl Responder { + id.forget(); + HttpResponse::Ok() } pub fn get_me(logged_user: LoggedUser) -> HttpResponse { diff --git a/simple-auth-server/src/email_service.rs b/simple-auth-server/src/email_service.rs index d9854f49..290d37ab 100644 --- a/simple-auth-server/src/email_service.rs +++ b/simple-auth-server/src/email_service.rs @@ -1,4 +1,4 @@ -use models::Invitation; +use crate::models::Invitation; use sparkpost::transmission::{ EmailAddress, Message, Options, Recipient, Transmission, TransmissionResponse, }; diff --git a/simple-auth-server/src/errors.rs b/simple-auth-server/src/errors.rs index 0be63125..bac56094 100644 --- a/simple-auth-server/src/errors.rs +++ b/simple-auth-server/src/errors.rs @@ -1,17 +1,18 @@ use actix_web::{error::ResponseError, HttpResponse}; +use derive_more::Display; use diesel::result::{DatabaseErrorKind, Error}; use std::convert::From; use uuid::ParseError; -#[derive(Fail, Debug)] +#[derive(Debug, Display)] pub enum ServiceError { - #[fail(display = "Internal Server Error")] + #[display(fmt = "Internal Server Error")] InternalServerError, - #[fail(display = "BadRequest: {}", _0)] + #[display(fmt = "BadRequest: {}", _0)] BadRequest(String), - #[fail(display = "Unauthorized")] + #[display(fmt = "Unauthorized")] Unauthorized, } diff --git a/simple-auth-server/src/invitation_handler.rs b/simple-auth-server/src/invitation_handler.rs index ac117f79..b0a8ceb7 100644 --- a/simple-auth-server/src/invitation_handler.rs +++ b/simple-auth-server/src/invitation_handler.rs @@ -1,10 +1,11 @@ use actix::{Handler, Message}; use chrono::{Duration, Local}; use diesel::{self, prelude::*}; -use errors::ServiceError; -use models::{DbExecutor, Invitation}; use uuid::Uuid; +use crate::errors::ServiceError; +use crate::models::{DbExecutor, Invitation}; + #[derive(Deserialize)] pub struct CreateInvitation { pub email: String, @@ -18,7 +19,7 @@ impl Handler for DbExecutor { type Result = Result; fn handle(&mut self, msg: CreateInvitation, _: &mut Self::Context) -> Self::Result { - use schema::invitations::dsl::*; + use crate::schema::invitations::dsl::*; let conn: &PgConnection = &self.0.get().unwrap(); // creating a new Invitation object with expired at time that is 24 hours from now diff --git a/simple-auth-server/src/invitation_routes.rs b/simple-auth-server/src/invitation_routes.rs index bd6a46c6..ea76bca2 100644 --- a/simple-auth-server/src/invitation_routes.rs +++ b/simple-auth-server/src/invitation_routes.rs @@ -1,18 +1,16 @@ -use actix_web::{ - AsyncResponder, FutureResponse, HttpResponse, Json, ResponseError, State, -}; +use actix::Addr; +use actix_web::{web, Error, HttpResponse, ResponseError}; use futures::future::Future; -use app::AppState; -use email_service::send_invitation; -use invitation_handler::CreateInvitation; +use crate::email_service::send_invitation; +use crate::invitation_handler::CreateInvitation; +use crate::models::DbExecutor; pub fn register_email( - (signup_invitation, state): (Json, State), -) -> FutureResponse { - state - .db - .send(signup_invitation.into_inner()) + signup_invitation: web::Json, + db: web::Data>, +) -> impl Future { + db.send(signup_invitation.into_inner()) .from_err() .and_then(|db_response| match db_response { Ok(invitation) => { @@ -21,5 +19,4 @@ pub fn register_email( } Err(err) => Ok(err.error_response()), }) - .responder() } diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index 5c1b3c27..90024095 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -1,26 +1,21 @@ -// to avoid the warning from diesel macros -#![allow(proc_macro_derive_resolution_fallback)] +#![allow(unused_imports)] -extern crate actix; -extern crate actix_web; -extern crate bcrypt; -extern crate chrono; -extern crate dotenv; -extern crate env_logger; -extern crate futures; -extern crate jsonwebtoken as jwt; -extern crate r2d2; -extern crate serde; -extern crate sparkpost; -extern crate uuid; #[macro_use] extern crate diesel; #[macro_use] extern crate serde_derive; -#[macro_use] -extern crate failure; -mod app; +use actix::prelude::*; +use actix_files as fs; +use actix_web::middleware::{ + identity::{CookieIdentityPolicy, IdentityService}, + Logger, +}; +use actix_web::{web, App, HttpServer}; +use chrono::Duration; +use diesel::{r2d2::ConnectionManager, PgConnection}; +use dotenv::dotenv; + mod auth_handler; mod auth_routes; mod email_service; @@ -33,20 +28,17 @@ mod register_routes; mod schema; mod utils; -use actix::prelude::*; -use actix_web::server; -use diesel::{r2d2::ConnectionManager, PgConnection}; -use dotenv::dotenv; -use models::DbExecutor; -use std::env; +use crate::models::DbExecutor; -fn main() { +fn main() -> std::io::Result<()> { dotenv().ok(); - std::env::set_var("RUST_LOG", "simple-auth-server=debug,actix_web=info"); - std::env::set_var("RUST_BACKTRACE", "1"); + std::env::set_var( + "RUST_LOG", + "simple-auth-server=debug,actix_web=info,actix_server=info", + ); env_logger::init(); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - let sys = actix::System::new("Actix_Tutorial"); + + let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); // create db connection pool let manager = ConnectionManager::::new(database_url); @@ -57,10 +49,49 @@ fn main() { let address: Addr = SyncArbiter::start(4, move || DbExecutor(pool.clone())); - server::new(move || app::create_app(address.clone())) - .bind("127.0.0.1:3000") - .expect("Can not bind to '127.0.0.1:3000'") - .start(); + HttpServer::new(move || { + // 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()); - sys.run(); + App::new() + .data(address.clone()) + .wrap(Logger::default()) + .wrap(IdentityService::new( + CookieIdentityPolicy::new(secret.as_bytes()) + .name("auth") + .path("/") + .domain(domain.as_str()) + .max_age(Duration::days(1)) + .secure(false), // this can only be true if you have https + )) + // everything under '/api/' route + .service( + web::scope("/api") + // routes for authentication + .service( + web::resource("/auth") + .route(web::post().to_async(auth_routes::login)) + .route(web::delete().to(auth_routes::logout)) + .route(web::get().to_async(auth_routes::get_me)), + ) + // routes to invitation + .service( + web::resource("/invitation").route( + web::post().to_async(invitation_routes::register_email), + ), + ) + // routes to register as a user after the + .service( + web::resource("/register/{invitation_id}") + .route(web::post().to_async(register_routes::register_user)), + ), + ) + // serve static files + .service(fs::Files::new("/", "./static/").index_file("index.html")) + }) + .bind("127.0.0.1:3000")? + .run() } diff --git a/simple-auth-server/src/models.rs b/simple-auth-server/src/models.rs index 651ad9f3..76dcfac7 100644 --- a/simple-auth-server/src/models.rs +++ b/simple-auth-server/src/models.rs @@ -5,7 +5,7 @@ use diesel::r2d2::{ConnectionManager, Pool}; use std::convert::From; use uuid::Uuid; -use schema::{invitations, users}; +use crate::schema::{invitations, users}; /// This is db executor actor. can be run in parallel pub struct DbExecutor(pub Pool>); diff --git a/simple-auth-server/src/register_handler.rs b/simple-auth-server/src/register_handler.rs index 961061b0..04fe164e 100644 --- a/simple-auth-server/src/register_handler.rs +++ b/simple-auth-server/src/register_handler.rs @@ -1,11 +1,12 @@ use actix::{Handler, Message}; use chrono::Local; use diesel::prelude::*; -use errors::ServiceError; -use models::{DbExecutor, Invitation, SlimUser, User}; -use utils::hash_password; use uuid::Uuid; +use crate::errors::ServiceError; +use crate::models::{DbExecutor, Invitation, SlimUser, User}; +use crate::utils::hash_password; + // UserData is used to extract data from a post request by the client #[derive(Debug, Deserialize)] pub struct UserData { @@ -26,8 +27,8 @@ impl Message for RegisterUser { impl Handler for DbExecutor { type Result = Result; fn handle(&mut self, msg: RegisterUser, _: &mut Self::Context) -> Self::Result { - use schema::invitations::dsl::{id, invitations}; - use schema::users::dsl::users; + use crate::schema::invitations::dsl::{id, invitations}; + use crate::schema::users::dsl::users; let conn: &PgConnection = &self.0.get().unwrap(); // try parsing the string provided by the user as url parameter diff --git a/simple-auth-server/src/register_routes.rs b/simple-auth-server/src/register_routes.rs index 79b9f9a2..19b3866f 100644 --- a/simple-auth-server/src/register_routes.rs +++ b/simple-auth-server/src/register_routes.rs @@ -1,27 +1,25 @@ -use actix_web::{ - AsyncResponder, FutureResponse, HttpResponse, Json, Path, ResponseError, State, -}; -use futures::future::Future; +use actix::Addr; +use actix_web::{web, Error, HttpResponse, ResponseError}; +use futures::Future; -use app::AppState; -use register_handler::{RegisterUser, UserData}; +use crate::models::DbExecutor; +use crate::register_handler::{RegisterUser, UserData}; pub fn register_user( - (invitation_id, user_data, state): (Path, Json, State), -) -> FutureResponse { + invitation_id: web::Path, + user_data: web::Json, + db: web::Data>, +) -> impl Future { 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) + 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() } diff --git a/simple-auth-server/src/utils.rs b/simple-auth-server/src/utils.rs index 1f65d3e8..37035277 100644 --- a/simple-auth-server/src/utils.rs +++ b/simple-auth-server/src/utils.rs @@ -1,14 +1,13 @@ use bcrypt::{hash, DEFAULT_COST}; use chrono::{Duration, Local}; -use errors::ServiceError; -use jwt::{decode, encode, Header, Validation}; -use models::SlimUser; -use std::convert::From; -use std::env; +use jsonwebtoken::{decode, encode, Header, Validation}; + +use crate::errors::ServiceError; +use crate::models::SlimUser; pub fn hash_password(plain: &str) -> Result { // get the hashing cost from the env variable or use default - let hashing_cost: u32 = match env::var("HASH_ROUNDS") { + let hashing_cost: u32 = match std::env::var("HASH_ROUNDS") { Ok(cost) => cost.parse().unwrap_or(DEFAULT_COST), _ => DEFAULT_COST, }; @@ -64,5 +63,5 @@ pub fn decode_token(token: &str) -> Result { } fn get_secret() -> String { - env::var("JWT_SECRET").unwrap_or_else(|_| "my secret".into()) + std::env::var("JWT_SECRET").unwrap_or_else(|_| "my secret".into()) } diff --git a/state/Cargo.toml b/state/Cargo.toml index 39bf08a7..962b35d8 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,7 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = { git="https://github.com/actix/actix-web.git" } - -futures = "0.1" +actix-web = "1.0.0-alpha.1" +futures = "0.1.25" env_logger = "0.6" diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index 2dcdba30..6ae309a8 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = { git="https://github.com/actix/actix-web.git" } -actix-files = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 242087ac..68ca3a9f 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] +actix-web = "1.0.0-alpha.1" env_logger = "0.6" askama = "0.6" -actix-web = { git="https://github.com/actix/actix-web.git" } [build-dependencies] askama = "0.6" diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index b27e94af..b07879ab 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate askama; - use std::collections::HashMap; use actix_web::{web, App, HttpResponse, HttpServer, Result}; diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index ff35ad15..81ecb160 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -7,5 +7,5 @@ edition = "2018" [dependencies] env_logger = "0.6" -tera = "*" -actix-web = { git="https://github.com/actix/actix-web.git" } +tera = "0.11" +actix-web = "1.0.0-alpha.1" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 47a03b22..328052ee 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -4,14 +4,12 @@ version = "0.0.1" authors = ["Rust-iendo Barcelona "] publish = false edition = "2018" - workspace = ".." [dependencies] +actix-web = "1.0.0-alpha.1" env_logger = "0.6" - yarte = "0.1" -actix-web = { git="https://github.com/actix/actix-web.git" } [build-dependencies] yarte = "0.1" diff --git a/tls/Cargo.toml b/tls/Cargo.toml index 0442f206..6e9be047 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -10,8 +10,7 @@ name = "tls-server" path = "src/main.rs" [dependencies] -env_logger = "0.5" -openssl = { version="0.10" } - actix-rt = "0.2" -actix-web = { git="https://github.com/actix/actix-web.git", features=["ssl"] } +actix-web = { version="1.0.0-alpha.1", features=["ssl"] } +env_logger = "0.6" +openssl = { version="0.10" } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index f78d7adc..c50eb197 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -3,16 +3,13 @@ name = "actix-web-cors" version = "0.1.0" authors = ["krircc "] workspace = "../../" +edition = "2018" [dependencies] +actix-web = "1.0.0-alpha.1" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -http = "0.1" - -actix = "0.7" -actix-web = "0.7" - dotenv = "0.10" -env_logger = "0.5" +env_logger = "0.6" futures = "0.1" diff --git a/web-cors/backend/src/main.rs b/web-cors/backend/src/main.rs index 2fcec25b..5d951e03 100644 --- a/web-cors/backend/src/main.rs +++ b/web-cors/backend/src/main.rs @@ -1,49 +1,29 @@ #[macro_use] extern crate serde_derive; -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; -extern crate serde; -extern crate serde_json; use actix_web::{ - http::{header, Method}, - middleware, - middleware::cors::Cors, - server, App, + http::header, middleware::cors::Cors, middleware::Logger, web, App, HttpServer, }; -use std::env; mod user; -use user::info; -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("Actix-web-CORS"); - - server::new(move || { + HttpServer::new(move || { App::new() - .middleware(middleware::Logger::default()) - .configure(|app| { - Cors::for_app(app) + .wrap( + Cors::new() .allowed_origin("http://localhost:1234") .allowed_methods(vec!["GET", "POST"]) .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT]) .allowed_header(header::CONTENT_TYPE) - .max_age(3600) - .resource("/user/info", |r| { - r.method(Method::POST).with(info); - }) - .register() - }) + .max_age(3600), + ) + .wrap(Logger::default()) + .service(web::resource("/user/info").route(web::post().to(user::info))) }) - .bind("127.0.0.1:8000") - .unwrap() - .shutdown_timeout(2) - .start(); - - let _ = sys.run(); + .bind("127.0.0.1:8000")? + .run() } diff --git a/web-cors/backend/src/user.rs b/web-cors/backend/src/user.rs index aca44cbf..ed795589 100644 --- a/web-cors/backend/src/user.rs +++ b/web-cors/backend/src/user.rs @@ -1,4 +1,4 @@ -use actix_web::{Json, Result}; +use actix_web::web; #[derive(Deserialize, Serialize, Debug)] pub struct Info { @@ -8,12 +8,12 @@ pub struct Info { confirm_password: String, } -pub fn info(info: Json) -> Result> { +pub fn info(info: web::Json) -> web::Json { println!("=========={:?}=========", info); - Ok(Json(Info { + web::Json(Info { username: info.username.clone(), email: info.email.clone(), password: info.password.clone(), confirm_password: info.confirm_password.clone(), - })) + }) } diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index a68b058f..2ceab26e 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -14,10 +14,10 @@ path = "src/main.rs" #path = "src/client.rs" [dependencies] -actix = { git="https://github.com/actix/actix.git" } -actix-web = { git="https://github.com/actix/actix-web.git" } -actix-web-actors = { git="https://github.com/actix/actix-web.git" } -actix-files = { git="https://github.com/actix/actix-web.git" } +actix = "0.8.0-alpha.1" +actix-web = "1.0.0-alpha.1" +actix-web-actors = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file diff --git a/websocket/src/client.rs b/websocket/src/client.rs index 7cb5fa3b..11f827bb 100644 --- a/websocket/src/client.rs +++ b/websocket/src/client.rs @@ -1,16 +1,9 @@ //! Simple websocket client. - -#![allow(unused_variables)] -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; - use std::time::Duration; use std::{io, thread}; use actix::*; -use actix_web::ws::{Client, ClientWriter, Message, ProtocolError}; +use actix_web::client::{Client, ClientWriter, Message, ProtocolError}; use futures::Future; fn main() { From 769cc5b84e86bcf2665762e63c702a76696b3605 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 29 Mar 2019 15:08:35 -0700 Subject: [PATCH 026/111] upgrade ws examples --- basics/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 19 +++--- websocket-chat/src/main.rs | 99 +++++++++++---------------- websocket-tcp-chat/Cargo.toml | 16 +++-- websocket-tcp-chat/src/main.rs | 109 ++++++++++++------------------ websocket-tcp-chat/src/server.rs | 2 +- websocket-tcp-chat/src/session.rs | 12 ++-- 7 files changed, 111 insertions(+), 148 deletions(-) diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 4eb17bcc..64c08aa1 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -2,7 +2,7 @@ name = "basics" version = "1.0.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." edition = "2018" [dependencies] diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index b6d281ff..64c7876e 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -2,23 +2,24 @@ name = "websocket-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [[bin]] name = "websocket-chat-server" path = "src/main.rs" [dependencies] -rand = "*" +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.1" +actix-web-actors = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" + +rand = "0.6" bytes = "0.4" byteorder = "1.1" -futures = "0.1" +futures = "0.1.25" tokio-io = "0.1" -tokio-core = "0.1" -env_logger = "*" - +env_logger = "0.6" serde = "1.0" serde_json = "1.0" - -actix = "0.7" -actix-web = "0.7" diff --git a/websocket-chat/src/main.rs b/websocket-chat/src/main.rs index 8849aba7..45085f7c 100644 --- a/websocket-chat/src/main.rs +++ b/websocket-chat/src/main.rs @@ -1,22 +1,9 @@ -#![allow(unused_variables)] -extern crate byteorder; -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate rand; -extern crate serde; -extern crate serde_json; -extern crate tokio_core; -extern crate tokio_io; - -extern crate actix; -extern crate actix_web; - use std::time::{Duration, Instant}; use actix::*; -use actix_web::server::HttpServer; -use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse}; +use actix_files as fs; +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web_actors::ws; mod server; @@ -25,22 +12,22 @@ const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); /// How long before lack of client response causes a timeout const CLIENT_TIMEOUT: Duration = Duration::from_secs(10); -/// This is our websocket route state, this state is shared with all route -/// instances via `HttpContext::state()` -struct WsChatSessionState { - addr: Addr, -} - /// Entry point for our route -fn chat_route(req: &HttpRequest) -> Result { +fn chat_route( + req: HttpRequest, + stream: web::Payload, + srv: web::Data>, +) -> Result { ws::start( - req, WsChatSession { id: 0, hb: Instant::now(), room: "Main".to_owned(), name: None, + addr: srv.get_ref().clone(), }, + &req, + stream, ) } @@ -54,10 +41,12 @@ struct WsChatSession { room: String, /// peer name name: Option, + /// Chat server + addr: Addr, } impl Actor for WsChatSession { - type Context = ws::WebsocketContext; + type Context = ws::WebsocketContext; /// Method is called on actor start. /// We register ws session with ChatServer @@ -71,8 +60,7 @@ impl Actor for WsChatSession { // HttpContext::state() is instance of WsChatSessionState, state is shared // across all routes within application let addr = ctx.address(); - ctx.state() - .addr + self.addr .send(server::Connect { addr: addr.recipient(), }) @@ -88,9 +76,9 @@ impl Actor for WsChatSession { .wait(ctx); } - fn stopping(&mut self, ctx: &mut Self::Context) -> Running { + fn stopping(&mut self, _: &mut Self::Context) -> Running { // notify chat server - ctx.state().addr.do_send(server::Disconnect { id: self.id }); + self.addr.do_send(server::Disconnect { id: self.id }); Running::Stop } } @@ -126,8 +114,7 @@ impl StreamHandler for WsChatSession { // Send ListRooms message to chat server and wait for // response println!("List rooms"); - ctx.state() - .addr + self.addr .send(server::ListRooms) .into_actor(self) .then(|res, _, ctx| { @@ -149,7 +136,7 @@ impl StreamHandler for WsChatSession { "/join" => { if v.len() == 2 { self.room = v[1].to_owned(); - ctx.state().addr.do_send(server::Join { + self.addr.do_send(server::Join { id: self.id, name: self.room.clone(), }); @@ -175,14 +162,14 @@ impl StreamHandler for WsChatSession { m.to_owned() }; // send message to chat server - ctx.state().addr.do_send(server::ClientMessage { + self.addr.do_send(server::ClientMessage { id: self.id, msg: msg, room: self.room.clone(), }) } } - ws::Message::Binary(bin) => println!("Unexpected binary"), + ws::Message::Binary(_) => println!("Unexpected binary"), ws::Message::Close(_) => { ctx.stop(); } @@ -194,7 +181,7 @@ impl WsChatSession { /// helper method that sends ping to client every second. /// /// also this method checks heartbeats from client - fn hb(&self, ctx: &mut ws::WebsocketContext) { + fn hb(&self, ctx: &mut ws::WebsocketContext) { ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| { // check client heartbeats if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT { @@ -202,7 +189,7 @@ impl WsChatSession { println!("Websocket Client heartbeat failed, disconnecting!"); // notify chat server - ctx.state().addr.do_send(server::Disconnect { id: act.id }); + act.addr.do_send(server::Disconnect { id: act.id }); // stop actor ctx.stop(); @@ -216,38 +203,30 @@ impl WsChatSession { } } -fn main() { - let _ = env_logger::init(); - let sys = actix::System::new("websocket-example"); +fn main() -> std::io::Result<()> { + env_logger::init(); + let sys = System::new("ws-example"); - // Start chat server actor in separate thread - let server = Arbiter::start(|_| server::ChatServer::default()); + // Start chat server actor + let server = server::ChatServer::default().start(); // Create Http server with websocket support HttpServer::new(move || { - // Websocket sessions state - let state = WsChatSessionState { - addr: server.clone(), - }; - - App::with_state(state) + App::new() + .data(server.clone()) // redirect to websocket.html - .resource("/", |r| { - r.method(http::Method::GET).f(|_| { - HttpResponse::Found() - .header("LOCATION", "/static/websocket.html") - .finish() - }) - }) + .service(web::resource("/").route(web::get().to(|| { + HttpResponse::Found() + .header("LOCATION", "/static/websocket.html") + .finish() + }))) // websocket - .resource("/ws/", |r| r.route().f(chat_route)) + .service(web::resource("/ws/").to(chat_route)) // static resources - .handler("/static/", fs::StaticFiles::new("static/").unwrap()) + .service(fs::Files::new("/static/", "static/")) }) - .bind("127.0.0.1:8080") - .unwrap() + .bind("127.0.0.1:8080")? .start(); - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + sys.run() } diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index c73d5678..b4a06eb7 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -2,7 +2,8 @@ name = "websocket-tcp-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [[bin]] name = "websocket-tcp-server" @@ -13,18 +14,19 @@ name = "websocket-tcp-client" path = "src/client.rs" [dependencies] -rand = "*" +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.1" +actix-web-actors = "1.0.0-alpha.1" +actix-files = "0.1.0-alpha.1" + +rand = "0.6" bytes = "0.4" byteorder = "1.1" futures = "0.1" tokio-io = "0.1" tokio-tcp = "0.1" tokio-codec = "0.1" -env_logger = "*" - +env_logger = "0.6" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" - -actix = "0.7" -actix-web = "0.7" diff --git a/websocket-tcp-chat/src/main.rs b/websocket-tcp-chat/src/main.rs index dff734c8..cd96c40b 100644 --- a/websocket-tcp-chat/src/main.rs +++ b/websocket-tcp-chat/src/main.rs @@ -1,25 +1,14 @@ -#![allow(unused_variables)] -extern crate byteorder; -extern crate bytes; -extern crate env_logger; -extern crate futures; -extern crate rand; -extern crate serde; -extern crate serde_json; -extern crate tokio_codec; -extern crate tokio_io; -extern crate tokio_tcp; #[macro_use] extern crate serde_derive; - #[macro_use] extern crate actix; -extern crate actix_web; + +use std::time::{Duration, Instant}; use actix::*; -use actix_web::server::HttpServer; -use actix_web::{fs, http, ws, App, Error, HttpRequest, HttpResponse}; -use std::time::{Duration, Instant}; +use actix_files as fs; +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web_actors::ws; mod codec; mod server; @@ -30,22 +19,22 @@ const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); /// How long before lack of client response causes a timeout const CLIENT_TIMEOUT: Duration = Duration::from_secs(10); -/// This is our websocket route state, this state is shared with all route -/// instances via `HttpContext::state()` -struct WsChatSessionState { - addr: Addr, -} - /// Entry point for our route -fn chat_route(req: &HttpRequest) -> Result { +fn chat_route( + req: HttpRequest, + stream: web::Payload, + srv: web::Data>, +) -> Result { ws::start( - req, WsChatSession { id: 0, hb: Instant::now(), room: "Main".to_owned(), name: None, + addr: srv.get_ref().clone(), }, + &req, + stream, ) } @@ -59,26 +48,26 @@ struct WsChatSession { room: String, /// peer name name: Option, + /// Chat server + addr: Addr, } impl Actor for WsChatSession { - type Context = ws::WebsocketContext; + type Context = ws::WebsocketContext; /// Method is called on actor start. /// We register ws session with ChatServer fn started(&mut self, ctx: &mut Self::Context) { + // we'll start heartbeat process on session start. + self.hb(ctx); + // register self in chat server. `AsyncContext::wait` register // future within context, but context waits until this future resolves // before processing any other events. // HttpContext::state() is instance of WsChatSessionState, state is shared // across all routes within application - - // we'll start heartbeat process on session start. - self.hb(ctx); - let addr = ctx.address(); - ctx.state() - .addr + self.addr .send(server::Connect { addr: addr.recipient(), }) @@ -94,9 +83,9 @@ impl Actor for WsChatSession { .wait(ctx); } - fn stopping(&mut self, ctx: &mut Self::Context) -> Running { + fn stopping(&mut self, _: &mut Self::Context) -> Running { // notify chat server - ctx.state().addr.do_send(server::Disconnect { id: self.id }); + self.addr.do_send(server::Disconnect { id: self.id }); Running::Stop } } @@ -132,8 +121,7 @@ impl StreamHandler for WsChatSession { // Send ListRooms message to chat server and wait for // response println!("List rooms"); - ctx.state() - .addr + self.addr .send(server::ListRooms) .into_actor(self) .then(|res, _, ctx| { @@ -155,7 +143,7 @@ impl StreamHandler for WsChatSession { "/join" => { if v.len() == 2 { self.room = v[1].to_owned(); - ctx.state().addr.do_send(server::Join { + self.addr.do_send(server::Join { id: self.id, name: self.room.clone(), }); @@ -181,14 +169,14 @@ impl StreamHandler for WsChatSession { m.to_owned() }; // send message to chat server - ctx.state().addr.do_send(server::Message { + self.addr.do_send(server::Message { id: self.id, msg: msg, room: self.room.clone(), }) } } - ws::Message::Binary(bin) => println!("Unexpected binary"), + ws::Message::Binary(_) => println!("Unexpected binary"), ws::Message::Close(_) => { ctx.stop(); } @@ -200,7 +188,7 @@ impl WsChatSession { /// helper method that sends ping to client every second. /// /// also this method checks heartbeats from client - fn hb(&self, ctx: &mut ws::WebsocketContext) { + fn hb(&self, ctx: &mut ws::WebsocketContext) { ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| { // check client heartbeats if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT { @@ -208,7 +196,7 @@ impl WsChatSession { println!("Websocket Client heartbeat failed, disconnecting!"); // notify chat server - ctx.state().addr.do_send(server::Disconnect { id: act.id }); + act.addr.do_send(server::Disconnect { id: act.id }); // stop actor ctx.stop(); @@ -222,45 +210,38 @@ impl WsChatSession { } } -fn main() { +fn main() -> std::io::Result<()> { let _ = env_logger::init(); let sys = actix::System::new("websocket-example"); - // Start chat server actor in separate thread - let server = Arbiter::start(|_| server::ChatServer::default()); + // Start chat server actor + let server = server::ChatServer::default().start(); // Start tcp server in separate thread let srv = server.clone(); - Arbiter::new("tcp-server").do_send::(msgs::Execute::new(move || { + Arbiter::new().exec(move || { session::TcpServer::new("127.0.0.1:12345", srv); - Ok(()) - })); + Ok::<_, ()>(()) + }); // Create Http server with websocket support HttpServer::new(move || { - // Websocket sessions state - let state = WsChatSessionState { - addr: server.clone(), - }; - - App::with_state(state) + App::new() + .data(server.clone()) // redirect to websocket.html - .resource("/", |r| { - r.method(http::Method::GET).f(|_| { - HttpResponse::Found() - .header("LOCATION", "/static/websocket.html") - .finish() - }) - }) + .service(web::resource("/").route(web::get().to(|| { + HttpResponse::Found() + .header("LOCATION", "/static/websocket.html") + .finish() + }))) // websocket - .resource("/ws/", |r| r.route().f(chat_route)) + .service(web::resource("/ws/").to(chat_route)) // static resources - .handler("/static/", fs::StaticFiles::new("static/").unwrap()) + .service(fs::Files::new("/static/", "static/")) }) - .bind("127.0.0.1:8080") - .unwrap() + .bind("127.0.0.1:8080")? .start(); println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + sys.run() } diff --git a/websocket-tcp-chat/src/server.rs b/websocket-tcp-chat/src/server.rs index efc946a8..c30b928b 100644 --- a/websocket-tcp-chat/src/server.rs +++ b/websocket-tcp-chat/src/server.rs @@ -6,7 +6,7 @@ use actix::prelude::*; use rand::{self, rngs::ThreadRng, Rng}; use std::collections::{HashMap, HashSet}; -use session; +use crate::session; /// Message for chat server communications diff --git a/websocket-tcp-chat/src/session.rs b/websocket-tcp-chat/src/session.rs index 37bd33a9..27478794 100644 --- a/websocket-tcp-chat/src/session.rs +++ b/websocket-tcp-chat/src/session.rs @@ -11,8 +11,8 @@ use tokio_tcp::{TcpListener, TcpStream}; use actix::prelude::*; -use codec::{ChatCodec, ChatRequest, ChatResponse}; -use server::{self, ChatServer}; +use crate::codec::{ChatCodec, ChatRequest, ChatResponse}; +use crate::server::{self, ChatServer}; /// Chat server sends this messages to session #[derive(Message)] @@ -62,7 +62,7 @@ impl Actor for ChatSession { .wait(ctx); } - fn stopping(&mut self, ctx: &mut Self::Context) -> Running { + fn stopping(&mut self, _: &mut Self::Context) -> Running { // notify chat server self.addr.do_send(server::Disconnect { id: self.id }); Running::Stop @@ -82,7 +82,7 @@ impl StreamHandler for ChatSession { self.addr .send(server::ListRooms) .into_actor(self) - .then(|res, act, ctx| { + .then(|res, act, _| { match res { Ok(rooms) => { act.framed.write(ChatResponse::Rooms(rooms)); @@ -124,7 +124,7 @@ impl StreamHandler for ChatSession { impl Handler for ChatSession { type Result = (); - fn handle(&mut self, msg: Message, ctx: &mut Context) { + fn handle(&mut self, msg: Message, _: &mut Context) { // send message to peer self.framed.write(ChatResponse::Message(msg.0)); } @@ -175,7 +175,7 @@ pub struct TcpServer { } impl TcpServer { - pub fn new(s: &str, chat: Addr) { + pub fn new(_s: &str, chat: Addr) { // Create server listener let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap(); let listener = TcpListener::bind(&addr).unwrap(); From a45aaec41260ca1f92e4ff1b1eff49e2437879b0 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:43:07 +0800 Subject: [PATCH 027/111] Update main.rs --- web-cors/backend/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-cors/backend/src/main.rs b/web-cors/backend/src/main.rs index 5d951e03..c009db8e 100644 --- a/web-cors/backend/src/main.rs +++ b/web-cors/backend/src/main.rs @@ -15,7 +15,7 @@ fn main() -> std::io::Result<()> { App::new() .wrap( Cors::new() - .allowed_origin("http://localhost:1234") + .allowed_origin("http://localhost:8080") .allowed_methods(vec!["GET", "POST"]) .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT]) .allowed_header(header::CONTENT_TYPE) From 40cbb4e2f97591d7ca6b24353c612bde3ba154f1 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:43:29 +0800 Subject: [PATCH 028/111] Delete package-lock.json --- web-cors/frontend/package-lock.json | 7407 --------------------------- 1 file changed, 7407 deletions(-) delete mode 100644 web-cors/frontend/package-lock.json diff --git a/web-cors/frontend/package-lock.json b/web-cors/frontend/package-lock.json deleted file mode 100644 index d89f0754..00000000 --- a/web-cors/frontend/package-lock.json +++ /dev/null @@ -1,7407 +0,0 @@ -{ - "name": "actix-web-cors", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "dev": true, - "requires": { - "util": "0.10.3" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "dev": true - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true - }, - "atob": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.0.tgz", - "integrity": "sha512-SuiKH8vbsOyCALjA/+EINmt/Kdl+TQPrtFgW7XZZcwtryFu9e5kQoX3bjCW6mIvGH1fbeAZZuvwGR5IlBRznGw==", - "dev": true - }, - "autoprefixer": { - "version": "6.7.7", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", - "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", - "dev": true, - "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000828", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "browserslist": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", - "dev": true, - "requires": { - "caniuse-db": "1.0.30000828", - "electron-to-chromium": "1.3.42" - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "axios": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", - "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", - "requires": { - "follow-redirects": "1.4.1", - "is-buffer": "1.1.6" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.1", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.5.1", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.5", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "dev": true, - "requires": { - "babel-helper-explode-assignable-expression": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-builder-react-jsx": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", - "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "esutils": "2.0.2" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.5" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "dev": true, - "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.5" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "dev": true, - "requires": { - "babel-helper-optimise-call-expression": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", - "dev": true - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", - "dev": true - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", - "dev": true - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", - "dev": true - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "6.24.1", - "babel-plugin-syntax-async-functions": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.5" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "6.26.0", - "babel-helper-function-name": "6.24.1", - "babel-helper-optimise-call-expression": "6.24.1", - "babel-helper-replace-supers": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", - "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "dev": true, - "requires": { - "babel-helper-replace-supers": "6.24.1", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, - "requires": { - "babel-helper-call-delegate": "6.24.1", - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "dev": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "regexpu-core": "2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", - "babel-plugin-syntax-exponentiation-operator": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-react-jsx": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", - "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", - "dev": true, - "requires": { - "babel-helper-builder-react-jsx": "6.26.0", - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "dev": true, - "requires": { - "regenerator-transform": "0.10.1" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-preset-env": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", - "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", - "dev": true, - "requires": { - "babel-plugin-check-es2015-constants": "6.22.0", - "babel-plugin-syntax-trailing-function-commas": "6.22.0", - "babel-plugin-transform-async-to-generator": "6.24.1", - "babel-plugin-transform-es2015-arrow-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoping": "6.26.0", - "babel-plugin-transform-es2015-classes": "6.24.1", - "babel-plugin-transform-es2015-computed-properties": "6.24.1", - "babel-plugin-transform-es2015-destructuring": "6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", - "babel-plugin-transform-es2015-for-of": "6.23.0", - "babel-plugin-transform-es2015-function-name": "6.24.1", - "babel-plugin-transform-es2015-literals": "6.22.0", - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", - "babel-plugin-transform-es2015-modules-umd": "6.24.1", - "babel-plugin-transform-es2015-object-super": "6.24.1", - "babel-plugin-transform-es2015-parameters": "6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", - "babel-plugin-transform-es2015-spread": "6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "6.24.1", - "babel-plugin-transform-es2015-template-literals": "6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "6.24.1", - "babel-plugin-transform-exponentiation-operator": "6.24.1", - "babel-plugin-transform-regenerator": "6.26.0", - "browserslist": "2.11.3", - "invariant": "2.2.4", - "semver": "5.5.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "6.26.0", - "babel-runtime": "6.26.0", - "core-js": "2.5.5", - "home-or-tmp": "2.0.0", - "lodash": "4.17.5", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "2.5.5", - "regenerator-runtime": "0.11.1" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "babylon-walk": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/babylon-walk/-/babylon-walk-1.0.2.tgz", - "integrity": "sha1-OxWl3btIKni0zpwByLoYFwLZ1s4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash.clone": "4.5.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", - "dev": true - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true - }, - "bindings": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", - "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", - "dev": true - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "brfs": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", - "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", - "dev": true, - "requires": { - "quote-stream": "1.0.2", - "resolve": "1.7.1", - "static-module": "2.2.4", - "through2": "2.0.3" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.1", - "evp_bytestokey": "1.0.3" - } - }, - "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.4.0", - "inherits": "2.0.3", - "parse-asn1": "5.1.1" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "1.0.6" - }, - "dependencies": { - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true - } - } - }, - "browserslist": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", - "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", - "dev": true, - "requires": { - "caniuse-lite": "1.0.30000828", - "electron-to-chromium": "1.3.42" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "1.2.3", - "ieee754": "1.1.11", - "isarray": "1.0.0" - } - }, - "buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=", - "dev": true - }, - "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" - } - }, - "caniuse-api": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", - "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", - "dev": true, - "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000828", - "lodash.memoize": "4.1.2", - "lodash.uniq": "4.5.0" - }, - "dependencies": { - "browserslist": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", - "dev": true, - "requires": { - "caniuse-db": "1.0.30000828", - "electron-to-chromium": "1.3.42" - } - } - } - }, - "caniuse-db": { - "version": "1.0.30000828", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000828.tgz", - "integrity": "sha1-7W1vA7WoH7KRw8DgiIKLEacJSL8=", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30000828", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000828.tgz", - "integrity": "sha512-v+ySC6Ih8N8CyGZYd4svPipuFIqskKsTOi18chFM0qtu1G8mGuSYajb+h49XDWgmzX8MRDOp1Agw6KQaPUdIhg==", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "chokidar": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", - "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", - "dev": true, - "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.1.3", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0", - "upath": "1.0.4" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "clap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", - "dev": true, - "requires": { - "chalk": "1.1.3" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clones": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/clones/-/clones-1.1.0.tgz", - "integrity": "sha1-h+kEEy1hQMXAtyAGwIwNBb17Y7M=", - "dev": true - }, - "coa": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", - "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", - "dev": true, - "requires": { - "q": "1.5.1" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" - } - }, - "color": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", - "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", - "dev": true, - "requires": { - "clone": "1.0.4", - "color-convert": "1.9.1", - "color-string": "0.3.0" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-string": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", - "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "colormin": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", - "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", - "dev": true, - "requires": { - "color": "0.11.4", - "css-color-names": "0.0.4", - "has": "1.0.1" - } - }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - }, - "command-exists": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.4.tgz", - "integrity": "sha512-9NoZJMIzkBfe26RwXIGr0thU/bZw68pw3dHjPav+m+AIns73SDe2ggMLTGXkzed4R67D8eTUnRZ2fraxAffQqw==", - "dev": true - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "1.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "config-chain": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", - "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", - "dev": true, - "requires": { - "ini": "1.3.5", - "proto-list": "1.2.4" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "0.1.4" - } - }, - "consolidate": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", - "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", - "dev": true, - "requires": { - "bluebird": "3.5.1" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz", - "integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", - "dev": true, - "requires": { - "is-directory": "0.3.1", - "js-yaml": "3.11.0", - "minimist": "1.2.0", - "object-assign": "4.1.1", - "os-homedir": "1.0.2", - "parse-json": "2.2.0", - "require-from-string": "1.2.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "create-ecdh": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.1.tgz", - "integrity": "sha512-iZvCCg8XqHQZ1ioNBTzXS/cQSkqkqcPs8xSX4upNB+DAk9Ht3uzQf2J32uAHNCne8LDmKr29AgZrEs4oIrwLuQ==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "md5.js": "1.3.4", - "ripemd160": "2.0.1", - "sha.js": "2.4.11" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.11" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "1.0.4", - "path-key": "2.0.1", - "semver": "5.5.0", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.3", - "pbkdf2": "3.0.14", - "public-encrypt": "4.0.2", - "randombytes": "2.0.6", - "randomfill": "1.0.4" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-select": { - "version": "1.3.0-rc0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.3.0-rc0.tgz", - "integrity": "sha1-b5MZaqrnN2ZuoQNqjLFKj8t6kjE=", - "dev": true, - "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.0", - "domutils": "1.5.1", - "nth-check": "1.0.1" - }, - "dependencies": { - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" - } - } - } - }, - "css-select-base-adapter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz", - "integrity": "sha1-AQKz0UYw34bD65+p9UVicBBs+ZA=", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha25", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha25.tgz", - "integrity": "sha512-XC6xLW/JqIGirnZuUWHXCHRaAjje2b3OIB0Vj5RIJo6mIi/AdJo30quQl5LxUl0gkXDIrTrFGbMlcZjyFplz1A==", - "dev": true, - "requires": { - "mdn-data": "1.1.1", - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", - "dev": true - }, - "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", - "dev": true - }, - "cssnano": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", - "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", - "dev": true, - "requires": { - "autoprefixer": "6.7.7", - "decamelize": "1.2.0", - "defined": "1.0.0", - "has": "1.0.1", - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-calc": "5.3.1", - "postcss-colormin": "2.2.2", - "postcss-convert-values": "2.6.1", - "postcss-discard-comments": "2.0.4", - "postcss-discard-duplicates": "2.1.0", - "postcss-discard-empty": "2.1.0", - "postcss-discard-overridden": "0.1.1", - "postcss-discard-unused": "2.2.3", - "postcss-filter-plugins": "2.0.2", - "postcss-merge-idents": "2.1.7", - "postcss-merge-longhand": "2.0.2", - "postcss-merge-rules": "2.1.2", - "postcss-minify-font-values": "1.0.5", - "postcss-minify-gradients": "1.0.5", - "postcss-minify-params": "1.2.2", - "postcss-minify-selectors": "2.1.1", - "postcss-normalize-charset": "1.1.1", - "postcss-normalize-url": "3.0.8", - "postcss-ordered-values": "2.2.3", - "postcss-reduce-idents": "2.4.0", - "postcss-reduce-initial": "1.0.1", - "postcss-reduce-transforms": "1.0.4", - "postcss-svgo": "2.1.6", - "postcss-unique-selectors": "2.0.2", - "postcss-value-parser": "3.3.0", - "postcss-zindex": "2.2.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "csso": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", - "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", - "dev": true, - "requires": { - "clap": "1.2.3", - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "dev": true - }, - "deasync": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.12.tgz", - "integrity": "sha512-gpacYo8FBZh3INBp2KOtrQp9kCO5faHvOmEZx3/cZTr3Mm8/kAYs7/Ws3E3OAH0ApBNK6Y6N+7+Dka2Zn2Fldw==", - "dev": true, - "requires": { - "bindings": "1.2.1", - "nan": "2.10.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "dev": true, - "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - } - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" - } - }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", - "dev": true - }, - "domhandler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", - "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", - "dev": true, - "requires": { - "domelementtype": "1.3.0" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" - } - }, - "dotenv": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==", - "dev": true - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "2.3.6" - } - }, - "editorconfig": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", - "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", - "dev": true, - "requires": { - "bluebird": "3.5.1", - "commander": "2.15.1", - "lru-cache": "3.2.0", - "semver": "5.5.0", - "sigmund": "1.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.42", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.42.tgz", - "integrity": "sha1-lcM78B0MxAVVauyJn+Yf1NduoPk=", - "dev": true - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "1.0.1" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es-abstract": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", - "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", - "dev": true, - "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "dev": true, - "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", - "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", - "dev": true, - "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - } - } - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.1" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - } - } - }, - "falafel": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz", - "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=", - "dev": true, - "requires": { - "acorn": "5.5.3", - "foreach": "2.0.5", - "isarray": "0.0.1", - "object-keys": "1.0.11" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", - "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, - "follow-redirects": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", - "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", - "requires": { - "debug": "3.1.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.10.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "2.1.1" - } - } - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "grapheme-breaker": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/grapheme-breaker/-/grapheme-breaker-0.3.2.tgz", - "integrity": "sha1-W55reMODJFLSuiuxy4MPlidkEKw=", - "dev": true, - "requires": { - "brfs": "1.6.1", - "unicode-trie": "0.3.1" - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "html-comment-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", - "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", - "dev": true - }, - "htmlnano": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-0.1.7.tgz", - "integrity": "sha512-t8Gy+r/loFP2VXAJl6ClaNIomGI609oyQcT7O3IoJE6VcDCLR6PYWXaSh+hfd/dnoZ6KPbpgPek/Crm3havqig==", - "dev": true, - "requires": { - "cssnano": "3.10.0", - "object-assign": "4.1.1", - "posthtml": "0.11.3", - "posthtml-render": "1.1.3", - "svgo": "1.0.5", - "uglify-js": "3.3.21" - }, - "dependencies": { - "coa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.1.tgz", - "integrity": "sha512-5wfTTO8E2/ja4jFSxePXlG5nRu5bBtL/r1HCIpJW/lzT6yDtKl0u0Z4o/Vpz32IpKmBn7HerheEZQgA9N2DarQ==", - "dev": true, - "requires": { - "q": "1.5.1" - } - }, - "csso": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.0.tgz", - "integrity": "sha512-WtJjFP3ZsSdWhiZr4/k1B9uHPgYjFYnDxfbaJxk1hz5PDLIJ5BCRWkJqaztZ0DbP8d2ZIVwUPIJb2YmCwkPaMw==", - "dev": true, - "requires": { - "css-tree": "1.0.0-alpha.27" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.27", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.27.tgz", - "integrity": "sha512-BAYp9FyN4jLXjfvRpTDchBllDptqlK9I7OsagXCG9Am5C+5jc8eRZHgqb9x500W2OKS14MMlpQc/nmh/aA7TEQ==", - "dev": true, - "requires": { - "mdn-data": "1.1.1", - "source-map": "0.5.7" - } - } - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - }, - "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", - "dev": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "svgo": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.0.5.tgz", - "integrity": "sha512-nYrifviB77aNKDNKKyuay3M9aYiK6Hv5gJVDdjj2ZXTQmI8WZc8+UPLR5IpVlktJfSu3co/4XcWgrgI6seGBPg==", - "dev": true, - "requires": { - "coa": "2.0.1", - "colors": "1.1.2", - "css-select": "1.3.0-rc0", - "css-select-base-adapter": "0.1.0", - "css-tree": "1.0.0-alpha25", - "css-url-regex": "1.1.0", - "csso": "3.5.0", - "js-yaml": "3.10.0", - "mkdirp": "0.5.1", - "object.values": "1.0.4", - "sax": "1.2.4", - "stable": "0.1.6", - "unquote": "1.1.1", - "util.promisify": "1.0.0" - } - }, - "uglify-js": { - "version": "3.3.21", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.21.tgz", - "integrity": "sha512-uy82472lH8tshK3jS3c5IFb5MmNKd/5qyBd0ih8sM42L3jWvxnE339U9gZU1zufnLVs98Stib9twq8dLm2XYCA==", - "dev": true, - "requires": { - "commander": "2.15.1", - "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - } - } - }, - "htmlparser2": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", - "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", - "dev": true, - "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.4.1", - "domutils": "1.7.0", - "entities": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": "1.4.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", - "dev": true - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "1.3.1" - } - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "1.11.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "1.0.1" - } - }, - "is-svg": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", - "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", - "dev": true, - "requires": { - "html-comment-regex": "1.1.1" - } - }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true - }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", - "dev": true - }, - "js-beautify": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.7.5.tgz", - "integrity": "sha512-9OhfAqGOrD7hoQBLJMTA+BKuKmoEtTJXzZ7WDF/9gvjtey1koVLuZqIY6c51aPDjbNdNtIXAkiWKVhziawE9Og==", - "dev": true, - "requires": { - "config-chain": "1.1.11", - "editorconfig": "0.13.3", - "mkdirp": "0.5.1", - "nopt": "3.0.6" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", - "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", - "dev": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - } - } - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "3.0.2" - } - }, - "lru-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", - "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", - "dev": true, - "requires": { - "pseudomap": "1.0.2" - } - }, - "macaddress": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", - "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", - "dev": true - }, - "magic-string": { - "version": "0.22.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", - "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", - "dev": true, - "requires": { - "vlq": "0.2.3" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "1.0.1" - } - }, - "math-expression-evaluator": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", - "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", - "dev": true - }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, - "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" - } - }, - "mdn-data": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.1.tgz", - "integrity": "sha512-2J5JENcb4yD5AzBI4ilTakiq2P9gHSsi4LOygnMu/bkchgTiA63AjsHAhDc+3U36AJHRfcz30Qv6Tb7i/Qsiew==", - "dev": true - }, - "merge-source-map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", - "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", - "dev": true, - "requires": { - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.9", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" - } - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, - "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true - }, - "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-odd": "2.0.0", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, - "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", - "dev": true - }, - "node-forge": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", - "dev": true - }, - "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", - "dev": true, - "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.2.0", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", - "events": "1.1.1", - "https-browserify": "1.0.0", - "os-browserify": "0.3.0", - "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.6", - "stream-browserify": "2.0.1", - "stream-http": "2.8.1", - "string_decoder": "1.1.1", - "timers-browserify": "2.0.6", - "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "0.0.4" - } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1.1.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "dev": true, - "requires": { - "object-assign": "4.1.1", - "prepend-http": "1.0.4", - "query-string": "4.3.4", - "sort-keys": "1.1.2" - } - }, - "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "dev": true, - "requires": { - "boolbase": "1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "object-inspect": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", - "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==", - "dev": true - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0", - "function-bind": "1.1.1", - "has": "1.0.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "opn": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", - "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", - "dev": true, - "requires": { - "is-wsl": "1.1.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", - "dev": true - }, - "parcel-bundler": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/parcel-bundler/-/parcel-bundler-1.7.0.tgz", - "integrity": "sha512-U3AeOJWVZXhzTCceuCUfKpKX3hGDOAhYArdJLMrTZGFjKhg+hJboWqy6Tw6ye36WpqLWZrBLeGx7kBpLHJBr3A==", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-core": "6.26.0", - "babel-generator": "6.26.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-plugin-transform-react-jsx": "6.24.1", - "babel-preset-env": "1.6.1", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "babylon-walk": "1.0.2", - "browserslist": "2.11.3", - "chalk": "2.3.2", - "chokidar": "2.0.3", - "command-exists": "1.2.4", - "commander": "2.15.1", - "cross-spawn": "6.0.5", - "cssnano": "3.10.0", - "deasync": "0.1.12", - "dotenv": "5.0.1", - "filesize": "3.6.1", - "get-port": "3.2.0", - "glob": "7.1.2", - "grapheme-breaker": "0.3.2", - "htmlnano": "0.1.7", - "is-url": "1.2.4", - "js-yaml": "3.11.0", - "json5": "0.5.1", - "micromatch": "3.1.10", - "mkdirp": "0.5.1", - "node-forge": "0.7.5", - "node-libs-browser": "2.1.0", - "opn": "5.3.0", - "physical-cpu-count": "2.0.0", - "postcss": "6.0.21", - "postcss-value-parser": "3.3.0", - "posthtml": "0.11.3", - "posthtml-parser": "0.4.1", - "posthtml-render": "1.1.3", - "resolve": "1.7.1", - "semver": "5.5.0", - "serialize-to-js": "1.2.0", - "serve-static": "1.13.2", - "source-map": "0.6.1", - "strip-ansi": "4.0.0", - "toml": "2.3.3", - "tomlify-j0.4": "3.0.0", - "uglify-es": "3.3.9", - "v8-compile-cache": "1.1.2", - "worker-farm": "1.6.0", - "ws": "4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "parcel-plugin-vue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/parcel-plugin-vue/-/parcel-plugin-vue-1.5.0.tgz", - "integrity": "sha512-f6f/o1eiOvoeFoYC4puZrzDbygwlja6rl+6ejp4KycHTbdW3HjhqPXeaFBmAEPvp7D1llTeCaT8ck9SLp8F2RA==", - "dev": true, - "requires": { - "debug": "3.1.0", - "vue-hot-reload-api": "2.3.0", - "vueify": "9.4.1", - "vueify-bolt": "1.0.2" - } - }, - "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", - "dev": true, - "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.14" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", - "dev": true, - "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.11" - } - }, - "physical-cpu-count": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz", - "integrity": "sha1-GN4vl+S/epVRrXURlCtUlverpmA=", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz", - "integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==", - "dev": true, - "requires": { - "chalk": "2.3.2", - "source-map": "0.6.1", - "supports-color": "5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" - } - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "postcss-calc": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", - "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "postcss-message-helpers": "2.0.0", - "reduce-css-calc": "1.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-colormin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", - "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", - "dev": true, - "requires": { - "colormin": "1.1.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-convert-values": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", - "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-discard-comments": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", - "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-discard-duplicates": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", - "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-discard-empty": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", - "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-discard-overridden": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", - "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-discard-unused": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", - "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "uniqs": "2.0.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-filter-plugins": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", - "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "uniqid": "4.1.1" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-load-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", - "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", - "dev": true, - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1", - "postcss-load-options": "1.2.0", - "postcss-load-plugins": "2.3.0" - } - }, - "postcss-load-options": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", - "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", - "dev": true, - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" - } - }, - "postcss-load-plugins": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", - "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", - "dev": true, - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" - } - }, - "postcss-merge-idents": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", - "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", - "dev": true, - "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-merge-longhand": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", - "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-merge-rules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", - "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", - "dev": true, - "requires": { - "browserslist": "1.7.7", - "caniuse-api": "1.6.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3", - "vendors": "1.0.1" - }, - "dependencies": { - "browserslist": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", - "dev": true, - "requires": { - "caniuse-db": "1.0.30000828", - "electron-to-chromium": "1.3.42" - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-message-helpers": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", - "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", - "dev": true - }, - "postcss-minify-font-values": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", - "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", - "dev": true, - "requires": { - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-minify-gradients": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", - "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-minify-params": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", - "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", - "dev": true, - "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0", - "uniqs": "2.0.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-minify-selectors": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", - "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", - "dev": true, - "requires": { - "alphanum-sort": "1.0.2", - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-normalize-charset": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", - "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-normalize-url": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", - "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", - "dev": true, - "requires": { - "is-absolute-url": "2.1.0", - "normalize-url": "1.9.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-ordered-values": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", - "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-reduce-idents": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", - "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", - "dev": true, - "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-reduce-initial": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", - "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", - "dev": true, - "requires": { - "postcss": "5.2.18" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-reduce-transforms": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", - "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", - "dev": true, - "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-selector-parser": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", - "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", - "dev": true, - "requires": { - "flatten": "1.0.2", - "indexes-of": "1.0.1", - "uniq": "1.0.1" - } - }, - "postcss-svgo": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", - "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", - "dev": true, - "requires": { - "is-svg": "2.1.0", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0", - "svgo": "0.7.2" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-unique-selectors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", - "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", - "dev": true, - "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.18", - "uniqs": "2.0.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", - "dev": true - }, - "postcss-zindex": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", - "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", - "dev": true, - "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "uniqs": "2.0.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "posthtml": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.11.3.tgz", - "integrity": "sha512-quMHnDckt2DQ9lRi6bYLnuyBDnVzK+McHa8+ar4kTdYbWEo/92hREOu3h70ZirudOOp/my2b3r0m5YtxY52yrA==", - "dev": true, - "requires": { - "object-assign": "4.1.1", - "posthtml-parser": "0.3.3", - "posthtml-render": "1.1.3" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "posthtml-parser": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.3.3.tgz", - "integrity": "sha512-H/Z/yXGwl49A7hYQLV1iQ3h87NE0aZ/PMZhFwhw3lKeCAN+Ti4idrHvVvh4/GX10I7u77aQw+QB4vV5/Lzvv5A==", - "dev": true, - "requires": { - "htmlparser2": "3.9.2", - "isobject": "2.1.0", - "object-assign": "4.1.1" - } - } - } - }, - "posthtml-parser": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.4.1.tgz", - "integrity": "sha512-h7vXIQ21Ikz2w5wPClPakNP6mJeJCK6BT0GpqnQrNNABdR7/TchNlFyryL1Bz6Ww53YWCKkr6tdZuHlxY1AVdQ==", - "dev": true, - "requires": { - "htmlparser2": "3.9.2", - "object-assign": "4.1.1" - } - }, - "posthtml-render": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-1.1.3.tgz", - "integrity": "sha512-aYvEMUxvKAv7D+ob2qlosyEL5qzsxCvauN/gjkRxr7fsW3+R2CJ1L3YHxx9kAjBJehmSwbNkSKzREdVfz1NWew==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "prettier": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.0.tgz", - "integrity": "sha512-Wz0SMncgaglBzDcohH3ZIAi4nVpzOIEweFzCOmgVEoRSeO72b4dcKGfgxoRGVMaFlh1r7dlVaJ+f3CIHfeH6xg==", - "dev": true - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "parse-asn1": "5.1.1", - "randombytes": "2.0.6" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "4.1.1", - "strict-uri-encode": "1.1.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "quote-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", - "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", - "dev": true, - "requires": { - "buffer-equal": "0.0.1", - "minimist": "1.2.0", - "through2": "2.0.3" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.1" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.6", - "set-immediate-shim": "1.0.1" - } - }, - "reduce-css-calc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", - "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "math-expression-evaluator": "1.2.17", - "reduce-function-call": "1.0.2" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - } - } - }, - "reduce-function-call": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", - "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", - "dev": true, - "requires": { - "balanced-match": "0.4.2" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - } - } - }, - "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "private": "0.1.8" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "dev": true, - "requires": { - "regenerate": "1.3.3", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "dev": true, - "requires": { - "jsesc": "0.5.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "require-from-string": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", - "dev": true - }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", - "dev": true, - "requires": { - "hash-base": "2.0.2", - "inherits": "2.0.3" - }, - "dependencies": { - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - } - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "0.1.15" - } - }, - "safer-eval": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/safer-eval/-/safer-eval-1.2.3.tgz", - "integrity": "sha512-nDwXOhiheoaBT6op02n8wzsshjLXHhh4YAeqsDEoVmy1k2+lGv/ENLsGaWqkaKArUkUx48VO12/ZPa3sI/OEqQ==", - "dev": true, - "requires": { - "clones": "1.1.0" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "fresh": "0.5.2", - "http-errors": "1.6.3", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "serialize-to-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/serialize-to-js/-/serialize-to-js-1.2.0.tgz", - "integrity": "sha512-BjvRI+63PY/I3OVBe4rCI0ENW+odR2V0PIyPndz22PbesNZNc2axReOPA4NrO0C7gEljUUvg0E/yZOJ1Ifs+5g==", - "dev": true, - "requires": { - "js-beautify": "1.7.5", - "safer-eval": "1.2.3" - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "dev": true, - "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", - "send": "0.16.2" - } - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.1", - "use": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "requires": { - "is-plain-obj": "1.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "dev": true, - "requires": { - "atob": "2.1.0", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "3.0.2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stable": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz", - "integrity": "sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=", - "dev": true - }, - "static-eval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.0.tgz", - "integrity": "sha512-6flshd3F1Gwm+Ksxq463LtFd1liC77N/PX1FVVc3OzL3hAmo2fwHFbuArkcfi7s9rTNsLEhcRmXGFZhlgy40uw==", - "dev": true, - "requires": { - "escodegen": "1.9.1" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - } - } - }, - "static-module": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.4.tgz", - "integrity": "sha512-qlzhn8tYcfLsXK2RTWtkx1v/cqiPtS9eFy+UmQ9UnpEDYcwtgbceOybnKp5JncsOnLI/pyGeyzI9Bej9tv0xiA==", - "dev": true, - "requires": { - "concat-stream": "1.6.2", - "convert-source-map": "1.5.1", - "duplexer2": "0.1.4", - "escodegen": "1.9.1", - "falafel": "2.1.0", - "has": "1.0.1", - "magic-string": "0.22.5", - "merge-source-map": "1.0.4", - "object-inspect": "1.4.1", - "quote-stream": "1.0.2", - "readable-stream": "2.3.6", - "shallow-copy": "0.0.1", - "static-eval": "2.0.0", - "through2": "2.0.3" - } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" - } - }, - "stream-http": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", - "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", - "dev": true, - "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" - } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "svgo": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", - "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", - "dev": true, - "requires": { - "coa": "1.0.4", - "colors": "1.1.2", - "csso": "2.3.2", - "js-yaml": "3.7.0", - "mkdirp": "0.5.1", - "sax": "1.2.4", - "whet.extend": "0.9.9" - }, - "dependencies": { - "js-yaml": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", - "dev": true, - "requires": { - "argparse": "1.0.10", - "esprima": "2.7.3" - } - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" - } - }, - "timers-browserify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", - "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", - "dev": true, - "requires": { - "setimmediate": "1.0.5" - } - }, - "tiny-inflate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.2.tgz", - "integrity": "sha1-k9nez/yIBb1X6uQxDwt0Xptvs6c=", - "dev": true - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" - } - }, - "toml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.3.tgz", - "integrity": "sha512-O7L5hhSQHxuufWUdcTRPfuTh3phKfAZ/dqfxZFoxPCj2RYmpaSGLEIs016FCXItQwNr08yefUB5TSjzRYnajTA==", - "dev": true - }, - "tomlify-j0.4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz", - "integrity": "sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==", - "dev": true - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "2.13.0", - "source-map": "0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - } - } - }, - "unicode-trie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", - "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", - "dev": true, - "requires": { - "pako": "0.2.9", - "tiny-inflate": "1.0.2" - } - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqid": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", - "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", - "dev": true, - "requires": { - "macaddress": "0.2.8" - } - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", - "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==", - "dev": true - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "object.getownpropertydescriptors": "2.0.3" - } - }, - "v8-compile-cache": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", - "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==", - "dev": true - }, - "vendors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", - "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", - "dev": true - }, - "vlq": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", - "dev": true - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, - "vue": { - "version": "2.5.16", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.16.tgz", - "integrity": "sha512-/ffmsiVuPC8PsWcFkZngdpas19ABm5mh2wA7iDqcltyCTwlgZjHGeJYOXkBMo422iPwIcviOtrTCUpSfXmToLQ==" - }, - "vue-hot-reload-api": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz", - "integrity": "sha512-2j/t+wIbyVMP5NvctQoSUvLkYKoWAAk2QlQiilrM2a6/ulzFgdcLUJfTvs4XQ/3eZhHiBmmEojbjmM4AzZj8JA==", - "dev": true - }, - "vue-loader": { - "version": "13.7.1", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.1.tgz", - "integrity": "sha512-v6PbKMGl/hWHGPxB2uGHsA66vusrXF66J/h1QiFXtU6z5zVSK8jq5xl95M1p3QNXmuEJKNP3nxoXfbgQNs7hJg==", - "dev": true, - "requires": { - "consolidate": "0.14.5", - "hash-sum": "1.0.2", - "loader-utils": "1.1.0", - "lru-cache": "4.1.2", - "postcss": "6.0.21", - "postcss-load-config": "1.2.0", - "postcss-selector-parser": "2.2.3", - "prettier": "1.12.0", - "resolve": "1.7.1", - "source-map": "0.6.1", - "vue-hot-reload-api": "2.3.0", - "vue-style-loader": "3.1.2", - "vue-template-es2015-compiler": "1.6.0" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - } - } - }, - "vue-router": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz", - "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w==" - }, - "vue-style-loader": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-3.1.2.tgz", - "integrity": "sha512-ICtVdK/p+qXWpdSs2alWtsXt9YnDoYjQe0w5616j9+/EhjoxZkbun34uWgsMFnC1MhrMMwaWiImz3K2jK1Yp2Q==", - "dev": true, - "requires": { - "hash-sum": "1.0.2", - "loader-utils": "1.1.0" - } - }, - "vue-template-compiler": { - "version": "2.5.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz", - "integrity": "sha512-ZbuhCcF/hTYmldoUOVcu2fcbeSAZnfzwDskGduOrnjBiIWHgELAd+R8nAtX80aZkceWDKGQ6N9/0/EUpt+l22A==", - "dev": true, - "requires": { - "de-indent": "1.0.2", - "he": "1.1.1" - } - }, - "vue-template-es2015-compiler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz", - "integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==", - "dev": true - }, - "vueify": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/vueify/-/vueify-9.4.1.tgz", - "integrity": "sha1-0pqXdaM8S4qGAeGGqF2iq4AMoNY=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "convert-source-map": "1.5.1", - "cssnano": "3.10.0", - "hash-sum": "1.0.2", - "json5": "0.5.1", - "lru-cache": "4.1.2", - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3", - "source-map": "0.5.7", - "through": "2.3.8", - "vue-hot-reload-api": "2.3.0", - "vue-template-compiler": "2.5.16", - "vue-template-es2015-compiler": "1.6.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "vueify-bolt": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/vueify-bolt/-/vueify-bolt-1.0.2.tgz", - "integrity": "sha1-t40ZZkG5q/aRRQ9J7xSQzyBvwhQ=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "convert-source-map": "1.5.1", - "cssnano": "3.10.0", - "hash-sum": "1.0.2", - "json5": "0.5.1", - "lru-cache": "4.1.2", - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3", - "source-map": "0.5.7", - "through": "2.3.8", - "vue-hot-reload-api": "2.3.0", - "vue-loader": "13.7.1", - "vue-template-es2015-compiler": "1.6.0" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.3", - "source-map": "0.5.7", - "supports-color": "3.2.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - } - } - }, - "whet.extend": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", - "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", - "dev": true - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", - "dev": true, - "requires": { - "errno": "0.1.7" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", - "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", - "dev": true, - "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.1" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } -} From 4a1a9e16789c45662669edf1c559a5c81aca812e Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:43:56 +0800 Subject: [PATCH 029/111] Update .gitignore --- web-cors/frontend/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/web-cors/frontend/.gitignore b/web-cors/frontend/.gitignore index 8875af86..765645ee 100644 --- a/web-cors/frontend/.gitignore +++ b/web-cors/frontend/.gitignore @@ -5,6 +5,7 @@ node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* +package-lock.json # Editor directories and files .idea From 77e218b8b823cbeace48ea3f13037da1a9b07218 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:44:08 +0800 Subject: [PATCH 030/111] Delete .babelrc --- web-cors/frontend/.babelrc | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 web-cors/frontend/.babelrc diff --git a/web-cors/frontend/.babelrc b/web-cors/frontend/.babelrc deleted file mode 100644 index 002b4aa0..00000000 --- a/web-cors/frontend/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["env"] -} From 1182ca3ad2f1dee69e35e4f3f723f29dd0cdbdd7 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:45:44 +0800 Subject: [PATCH 031/111] Update package.json --- web-cors/frontend/package.json | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/web-cors/frontend/package.json b/web-cors/frontend/package.json index 7ce2f641..6a5b84d5 100644 --- a/web-cors/frontend/package.json +++ b/web-cors/frontend/package.json @@ -1,22 +1,16 @@ { - "name": "actix-web-cors", + "name": "frontend-vue", "version": "0.1.0", "description": "webapp", - "main": "main.js", "scripts": { - "dev": "rm -rf dist/ && NODE_ENV=development parcel index.html", - "build": "NODE_ENV=production parcel build index.html", - "test": "echo \"Error: no test specified\" && exit 1" + "serve": "vue-cli-service serve", + "build": "vue-cli-service build" }, - "license": "ISC", "dependencies": { - "vue": "^2.5.13", - "vue-router": "^3.0.1", - "axios": "^0.17.1" + "vue": "2.6.10" }, "devDependencies": { - "babel-preset-env": "^1.6.1", - "parcel-bundler": "^1.4.1", - "parcel-plugin-vue": "^1.5.0" + "@vue/cli-service": "^3.0.0", + "vue-template-compiler": "^2.5.21" } } From ffec58f883faaad7b2b8aa7673615735bd317463 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:46:13 +0800 Subject: [PATCH 032/111] Update index.html --- web-cors/frontend/index.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web-cors/frontend/index.html b/web-cors/frontend/index.html index d71de81c..483dec27 100644 --- a/web-cors/frontend/index.html +++ b/web-cors/frontend/index.html @@ -6,8 +6,6 @@ webapp -

- +
- - \ No newline at end of file + From a3bef842e79006a0313ded4915e133d6e6bc86ff Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:46:41 +0800 Subject: [PATCH 033/111] Update main.js --- web-cors/frontend/src/main.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/web-cors/frontend/src/main.js b/web-cors/frontend/src/main.js index df1e4b7c..8b86123b 100644 --- a/web-cors/frontend/src/main.js +++ b/web-cors/frontend/src/main.js @@ -2,10 +2,5 @@ import Vue from 'vue' import App from './app' new Vue({ - el: '#app', render: h => h(App) -}) - -if (module.hot) { - module.hot.accept(); -} \ No newline at end of file +}).$mount('#app') From 1d3b392ac48809a5067f6bbf952d386b72ce30dd Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:47:04 +0800 Subject: [PATCH 034/111] Update app.vue --- web-cors/frontend/src/app.vue | 78 ++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/web-cors/frontend/src/app.vue b/web-cors/frontend/src/app.vue index 0c054c20..fa89f3f4 100644 --- a/web-cors/frontend/src/app.vue +++ b/web-cors/frontend/src/app.vue @@ -22,45 +22,50 @@ @@ -95,7 +100,6 @@ input[type="password"] { border-radius: 2px; font-family: 'Roboto', sans-serif; font-weight: bold; - text-transform: uppercase; transition: 0.1s ease; cursor: pointer; } @@ -142,4 +146,4 @@ cursor: pointer; padding-top: 100px; } } - \ No newline at end of file + From 6bb06a430cd6cb22e7bbb14b4370c6f69f40c1a1 Mon Sep 17 00:00:00 2001 From: krircc Date: Sat, 30 Mar 2019 09:48:55 +0800 Subject: [PATCH 035/111] Update README.md --- web-cors/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-cors/README.md b/web-cors/README.md index 6dd3d77f..cff3c1d0 100644 --- a/web-cors/README.md +++ b/web-cors/README.md @@ -10,6 +10,6 @@ $ cargo run ```bash $ cd web-cors/frontend $ npm install -$ npm run dev +$ npm run serve ``` -then open browser 'http://localhost:1234/' +then open browser 'http://localhost:8080' From 9a80911b9280f693ac9f7751ad8e834510d54c02 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 30 Mar 2019 09:12:42 -0700 Subject: [PATCH 036/111] update to alpha2 --- Cargo.toml | 8 ++--- actix_redis/Cargo.toml | 2 +- actix_todo/Cargo.toml | 4 +-- async_db/Cargo.toml | 2 +- async_ex1/Cargo.toml | 2 +- basics/Cargo.toml | 4 +-- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 +-- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 2 +- multipart/Cargo.toml | 3 +- protobuf/Cargo.toml | 11 ++++--- protobuf/src/main.rs | 38 +++++++----------------- protobuf/src/protobuf.rs | 47 ++++++++++++----------------- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 4 +-- rustls/Cargo.toml | 9 +++--- rustls/src/main.rs | 54 +++++++++++----------------------- simple-auth-server/Cargo.toml | 3 +- simple-auth-server/src/main.rs | 5 +++- state/Cargo.toml | 2 +- static_index/Cargo.toml | 2 +- template_askama/Cargo.toml | 2 +- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 2 +- tls/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 4 +-- websocket-chat/src/main.rs | 1 + websocket-tcp-chat/Cargo.toml | 4 +-- websocket-tcp-chat/src/main.rs | 1 + websocket/Cargo.toml | 6 ++-- websocket/src/main.rs | 1 + 40 files changed, 106 insertions(+), 147 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7422c22d..2e79a031 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,18 +21,18 @@ members = [ "protobuf", "r2d2", "redis-session", - "simple-auth-server", + "rustls", + #"simple-auth-server", "state", "static_index", "template_askama", "template_tera", "template_yarte", "tls", - "rustls", - "unix-socket", + #"unix-socket", "web-cors/backend", "websocket", "websocket-chat", - "websocket-chat-broker", + #"websocket-chat-broker", "websocket-tcp-chat", ] diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index b8014247..7c762a61 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 17a35307..52551f0f 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" -actix-session = "0.1.0-alpha.1" +actix-session = "0.1.0-alpha.2" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 2d322de3..3ccfbc26 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 1be43ae9..62154f4b 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.1", features=["ssl"] } +actix-web = { version="1.0.0-alpha.2", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 64c08aa1..4c2dc1e6 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" -actix-session = "0.1.0-alpha.1" +actix-session = "0.1.0-alpha.2" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index d728e3ed..f7cded59 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index ce876957..1655322f 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" -actix-session = "0.1.0-alpha.1" +actix-web = "1.0.0-alpha.2" +actix-session = "0.1.0-alpha.2" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index d8dfb918..5da09f40 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index 7e05407c..46f2f3e9 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index 150b9417..7e9eef60 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 502b1410..b3f23f99 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index f906fdd2..dfa5c50d 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" clap = "2.32.0" futures = "0.1.25" diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 487d4580..4bdeb424 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index 82b525c8..a742d2ab 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" bytes = "0.4" futures = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index ff47263a..14219124 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index c5657087..659dc317 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -7,6 +7,6 @@ workspace = ".." [dependencies] actix-service = "0.3.3" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 994c80fc..758bfc29 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,8 +10,7 @@ name = "multipart" path = "src/main.rs" [dependencies] -#actix-web = "1.0.0-alpha.1" -actix-web = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-alpha.2" env_logger = "0.6" futures = "0.1.25" diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index 130581e8..39e889f7 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -2,16 +2,15 @@ name = "protobuf-example" version = "0.1.0" authors = ["kingxsp "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] bytes = "0.4" futures = "0.1" -failure = "0.1" -env_logger = "*" - +env_logger = "0.6" +derive_more = "0.14" prost = "0.2.0" prost-derive = "0.2.0" -actix = "0.7" -actix-web = "0.7" +actix-web = "1.0.0-alpha.2" diff --git a/protobuf/src/main.rs b/protobuf/src/main.rs index 83220301..043fb59d 100644 --- a/protobuf/src/main.rs +++ b/protobuf/src/main.rs @@ -1,19 +1,8 @@ -extern crate actix; -extern crate actix_web; -extern crate bytes; -extern crate futures; -#[macro_use] -extern crate failure; -extern crate env_logger; -extern crate prost; #[macro_use] extern crate prost_derive; -use actix_web::{ - http, middleware, server, App, AsyncResponder, Error, HttpRequest, HttpResponse, -}; +use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use futures::Future; - mod protobuf; use protobuf::ProtoBufResponseBuilder; @@ -26,31 +15,24 @@ pub struct MyObj { } /// This handler uses `ProtoBufMessage` for loading protobuf object. -fn index(req: &HttpRequest) -> Box> { - protobuf::ProtoBufMessage::new(req) +fn index(pl: web::Payload) -> impl Future { + protobuf::ProtoBufMessage::new(pl) .from_err() // convert all errors into `Error` .and_then(|val: MyObj| { println!("model: {:?}", val); Ok(HttpResponse::Ok().protobuf(val)?) // <- send response }) - .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,actix_server=info"); env_logger::init(); - let sys = actix::System::new("protobuf-example"); - server::new(|| { + HttpServer::new(|| { App::new() - .middleware(middleware::Logger::default()) - .resource("/", |r| r.method(http::Method::POST).f(index)) + .wrap(middleware::Logger::default()) + .service(web::resource("/").route(web::post().to_async(index))) }) - .bind("127.0.0.1:8080") - .unwrap() - .shutdown_timeout(1) - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/protobuf/src/protobuf.rs b/protobuf/src/protobuf.rs index a9c22651..edde6250 100644 --- a/protobuf/src/protobuf.rs +++ b/protobuf/src/protobuf.rs @@ -1,7 +1,8 @@ use bytes::BytesMut; use futures::{Future, Poll, Stream}; -use bytes::IntoBuf; +use bytes::{Bytes, IntoBuf}; +use derive_more::{Display, From}; use prost::DecodeError as ProtoBufDecodeError; use prost::EncodeError as ProtoBufEncodeError; use prost::Message; @@ -9,25 +10,25 @@ use prost::Message; use actix_web::dev::HttpResponseBuilder; use actix_web::error::{Error, PayloadError, ResponseError}; use actix_web::http::header::CONTENT_TYPE; -use actix_web::{HttpMessage, HttpRequest, HttpResponse, Responder}; +use actix_web::{HttpRequest, HttpResponse, Responder}; -#[derive(Fail, Debug)] +#[derive(Debug, Display, From)] pub enum ProtoBufPayloadError { /// Payload size is bigger than 256k - #[fail(display = "Payload size is bigger than 256k")] + #[display(fmt = "Payload size is bigger than 256k")] Overflow, /// Content type error - #[fail(display = "Content type error")] + #[display(fmt = "Content type error")] ContentType, /// Serialize error - #[fail(display = "ProtoBud serialize error: {}", _0)] - Serialize(#[cause] ProtoBufEncodeError), + #[display(fmt = "ProtoBud serialize error: {}", _0)] + Serialize(ProtoBufEncodeError), /// Deserialize error - #[fail(display = "ProtoBud deserialize error: {}", _0)] - Deserialize(#[cause] ProtoBufDecodeError), + #[display(fmt = "ProtoBud deserialize error: {}", _0)] + Deserialize(ProtoBufDecodeError), /// Payload error - #[fail(display = "Error that occur during reading payload: {}", _0)] - Payload(#[cause] PayloadError), + #[display(fmt = "Error that occur during reading payload: {}", _0)] + Payload(PayloadError), } impl ResponseError for ProtoBufPayloadError { @@ -39,26 +40,14 @@ impl ResponseError for ProtoBufPayloadError { } } -impl From for ProtoBufPayloadError { - fn from(err: PayloadError) -> ProtoBufPayloadError { - ProtoBufPayloadError::Payload(err) - } -} - -impl From for ProtoBufPayloadError { - fn from(err: ProtoBufDecodeError) -> ProtoBufPayloadError { - ProtoBufPayloadError::Deserialize(err) - } -} - #[derive(Debug)] pub struct ProtoBuf(pub T); impl Responder for ProtoBuf { - type Item = HttpResponse; type Error = Error; + type Future = Result; - fn respond_to(self, _: &HttpRequest) -> Result { + fn respond_to(self, _: &HttpRequest) -> Result { let mut buf = Vec::new(); self.0 .encode(&mut buf) @@ -78,9 +67,11 @@ pub struct ProtoBufMessage { impl ProtoBufMessage { /// Create `ProtoBufMessage` for request. - pub fn new(req: &HttpRequest) -> Self { - let fut = req - .payload() + pub fn new(pl: S) -> Self + where + S: Stream + 'static, + { + let fut = pl .map_err(|e| ProtoBufPayloadError::Payload(e)) .fold(BytesMut::new(), move |mut body, chunk| { body.extend_from_slice(&chunk); diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index 0f6d7b57..1fbebaf6 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 5198d902..33c4e09a 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.1" -actix-session = "0.1.0-alpha.1" +actix-web = "1.0.0-alpha.2" +actix-session = "0.1.0-alpha.2" actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } env_logger = "0.6" diff --git a/rustls/Cargo.toml b/rustls/Cargo.toml index 477cb3d2..665ba2c4 100644 --- a/rustls/Cargo.toml +++ b/rustls/Cargo.toml @@ -2,7 +2,8 @@ name = "rustls-example" version = "0.1.0" authors = ["Nikolay Kim "] -workspace = "../" +workspace = ".." +edition = "2018" [[bin]] name = "rustls-server" @@ -10,6 +11,6 @@ path = "src/main.rs" [dependencies] env_logger = "0.5" -rustls = "0.14" -actix = "0.7" -actix-web = { version = "0.7", features=["rust-tls"] } +rustls = "0.15" +actix-web = { version = "1.0.0-alpha.2", features=["rust-tls"] } +actix-files = "0.1.0-alpha.1" diff --git a/rustls/src/main.rs b/rustls/src/main.rs index 33bcb538..8ef45663 100644 --- a/rustls/src/main.rs +++ b/rustls/src/main.rs @@ -1,32 +1,24 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate rustls; - use std::fs::File; use std::io::BufReader; -use actix_web::{http, middleware, server, App, Error, HttpRequest, HttpResponse}; +use actix_files::Files; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use rustls::internal::pemfile::{certs, rsa_private_keys}; use rustls::{NoClientAuth, ServerConfig}; -use server::ServerFlags; - -use actix_web::fs::StaticFiles; /// simple handle -fn index(req: &HttpRequest) -> Result { +fn index(req: HttpRequest) -> Result { println!("{:?}", req); Ok(HttpResponse::Ok() .content_type("text/plain") .body("Welcome!")) } -fn main() { - if ::std::env::var("RUST_LOG").is_err() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); +fn main() -> std::io::Result<()> { + if std::env::var("RUST_LOG").is_err() { + std::env::set_var("RUST_LOG", "actix_web=info"); } env_logger::init(); - let sys = actix::System::new("ws-example"); // load ssl keys let mut config = ServerConfig::new(NoClientAuth::new()); @@ -36,32 +28,20 @@ fn main() { let mut keys = rsa_private_keys(key_file).unwrap(); config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); - // actix acceptor - let acceptor = server::RustlsAcceptor::with_flags( - config, - ServerFlags::HTTP1 | ServerFlags::HTTP2, - ); - - server::new(|| { + HttpServer::new(|| { App::new() // enable logger - .middleware(middleware::Logger::default()) + .wrap(middleware::Logger::default()) // register simple handler, handle all methods - .resource("/index.html", |r| r.f(index)) + .service(web::resource("/index.html").to(index)) // with path parameters - .resource("/", |r| { - r.method(http::Method::GET).f(|_| { - HttpResponse::Found() - .header("LOCATION", "/index.html") - .finish() - }) - }) - .handler("/static", StaticFiles::new("static").unwrap()) + .service(web::resource("/").route(web::get().to(|| { + HttpResponse::Found() + .header("LOCATION", "/index.html") + .finish() + }))) + .service(Files::new("/static", "static")) }) - .bind_with("127.0.0.1:8443", move || acceptor.clone()) - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8443"); - let _ = sys.run(); + .bind_rustls("127.0.0.1:8443", config)? + .run() } diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 0c6a42be..176cdad6 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -7,7 +7,8 @@ workspace = ".." [dependencies] actix = { version = "0.8.0-alpha.2", features = ["http"] } -actix-web = "1.0.0-alpha.1" +actix-rt = "0.2.2" +actix-web = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" bcrypt = "0.2.1" diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index 90024095..cebfcd04 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -37,6 +37,7 @@ fn main() -> std::io::Result<()> { "simple-auth-server=debug,actix_web=info,actix_server=info", ); env_logger::init(); + let sys = actix_rt::System::new("example"); let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); @@ -93,5 +94,7 @@ fn main() -> std::io::Result<()> { .service(fs::Files::new("/", "./static/").index_file("index.html")) }) .bind("127.0.0.1:3000")? - .run() + .start(); + + sys.run() } diff --git a/state/Cargo.toml b/state/Cargo.toml index 962b35d8..468fa9e7 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" futures = "0.1.25" env_logger = "0.6" diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index 6ae309a8..7ead93ac 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index d88fed35..d0667be5 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] #askama = { version = "0.8", features = ["with-actix-web"] } -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.6" askama = "0.8" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index 81ecb160..560a9a74 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "0.11" -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 328052ee..bcc59083 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" env_logger = "0.6" yarte = "0.1" diff --git a/tls/Cargo.toml b/tls/Cargo.toml index 6e9be047..35dc8e68 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -11,6 +11,6 @@ path = "src/main.rs" [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.1", features=["ssl"] } +actix-web = { version="1.0.0-alpha.2", features=["ssl"] } env_logger = "0.6" openssl = { version="0.10" } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index c50eb197..59f7235f 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../../" edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index 64c7876e..a3601cf6 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -11,8 +11,8 @@ path = "src/main.rs" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.1" -actix-web-actors = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" +actix-web-actors = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" rand = "0.6" diff --git a/websocket-chat/src/main.rs b/websocket-chat/src/main.rs index 45085f7c..ec7da927 100644 --- a/websocket-chat/src/main.rs +++ b/websocket-chat/src/main.rs @@ -173,6 +173,7 @@ impl StreamHandler for WsChatSession { ws::Message::Close(_) => { ctx.stop(); } + ws::Message::Nop => (), } } } diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index b4a06eb7..ab1fff6c 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -15,8 +15,8 @@ path = "src/client.rs" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.1" -actix-web-actors = "1.0.0-alpha.1" +actix-web = "1.0.0-alpha.2" +actix-web-actors = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" rand = "0.6" diff --git a/websocket-tcp-chat/src/main.rs b/websocket-tcp-chat/src/main.rs index cd96c40b..fe73dc8e 100644 --- a/websocket-tcp-chat/src/main.rs +++ b/websocket-tcp-chat/src/main.rs @@ -180,6 +180,7 @@ impl StreamHandler for WsChatSession { ws::Message::Close(_) => { ctx.stop(); } + ws::Message::Nop => (), } } } diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index 2ceab26e..523eb74a 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -14,9 +14,9 @@ path = "src/main.rs" #path = "src/client.rs" [dependencies] -actix = "0.8.0-alpha.1" -actix-web = "1.0.0-alpha.1" -actix-web-actors = "1.0.0-alpha.1" +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.2" +actix-web-actors = "1.0.0-alpha.2" actix-files = "0.1.0-alpha.1" env_logger = "0.6" futures = "0.1" diff --git a/websocket/src/main.rs b/websocket/src/main.rs index 67d57918..b16e3fa3 100644 --- a/websocket/src/main.rs +++ b/websocket/src/main.rs @@ -58,6 +58,7 @@ impl StreamHandler for MyWebSocket { ws::Message::Close(_) => { ctx.stop(); } + ws::Message::Nop => (), } } } From 273068c362068423a787d9b12aa1f6a1d756ccee Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 30 Mar 2019 09:33:18 -0700 Subject: [PATCH 037/111] use jsonwebtoken repo as temp solution to ring dep --- .travis.yml | 35 +---------------------------------- Cargo.toml | 2 +- simple-auth-server/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8050c10d..25f7f0ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,37 +33,4 @@ before_script: - export PATH=$PATH:~/.cargo/bin script: - - | - cd async_db && cargo check && cd .. - cd async_ex1 && cargo check && cd .. - cd actix_redis && cargo check && cd .. - cd actix_todo && cargo check && cd .. - cd basics && cargo check && cd .. - cd cookie-auth && cargo check && cd .. - cd cookie-session && cargo check && cd .. - cd diesel && cargo check && cd .. - cd error_handling && cargo check && cd .. - cd form && cargo check && cd .. - cd hello-world && cargo check && cd .. - cd http-proxy && cargo check && cd .. - cd http-full-proxy && cargo check && cd .. - cd json && cargo check && cd .. - cd juniper && cargo check && cd .. - cd middleware && cargo check && cd .. - cd multipart && cargo check && cd .. - cd protobuf && cargo check && cd .. - cd r2d2 && cargo check && cd .. - cd redis-session && cargo check && cd .. - cd state && cargo check && cd .. - cd static_index && cargo check && cd .. - cd template_askama && cargo check && cd .. - cd template_tera && cargo check && cd .. - cd template_yarte && cargo check && cd .. - cd tls && cargo check && cd .. - cd rustls && cargo check && cd .. - cd unix-socket && cargo check && cd .. - cd web-cors/backend && cargo check && cd ../.. - cd websocket && cargo check && cd .. - cd websocket-chat && cargo check && cd .. - cd websocket-chat-broker && cargo check && cd .. - cd websocket-tcp-chat && cargo check && cd .. + - cargo check --all diff --git a/Cargo.toml b/Cargo.toml index 2e79a031..9ff86387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ "r2d2", "redis-session", "rustls", - #"simple-auth-server", + "simple-auth-server", "state", "static_index", "template_askama", diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 176cdad6..07a3c8d7 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -17,7 +17,7 @@ diesel = { version = "1.3.3", features = ["postgres", "uuid", "r2d2", "chrono"] dotenv = "0.13.0" derive_more = "0.14" env_logger = "0.6.0" -jsonwebtoken = "5.0" +jsonwebtoken = { git = "https://github.com/Keats/jsonwebtoken.git", branch = "next" } futures = "0.1.25" r2d2 = "0.8.3" serde_derive="1.0.80" From 8646a89249420a828eaee5a47858cbb44e8d72d1 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Mon, 1 Apr 2019 01:23:31 +0200 Subject: [PATCH 038/111] Update yarte to 0.2 --- template_yarte/Cargo.toml | 16 ++- template_yarte/README.md | 4 +- template_yarte/src/lib.rs | 1 - template_yarte/src/main.rs | 124 +++++++++++++++--- .../templates/deep/more/card/form.hbs | 20 +++ .../templates/deep/more/card/hi.hbs | 8 ++ .../templates/deep/more/deep/welcome.hbs | 9 +- .../templates/deep/more/doc/head.hbs | 1 + template_yarte/templates/deep/more/doc/t.hbs | 1 + template_yarte/templates/index.hbs | 30 ++--- template_yarte/yarte.toml | 2 + 11 files changed, 167 insertions(+), 49 deletions(-) delete mode 100644 template_yarte/src/lib.rs create mode 100644 template_yarte/templates/deep/more/card/form.hbs create mode 100644 template_yarte/templates/deep/more/card/hi.hbs create mode 100644 template_yarte/templates/deep/more/doc/head.hbs create mode 100644 template_yarte/templates/deep/more/doc/t.hbs diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index bcc59083..a734a375 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -1,15 +1,23 @@ [package] -name = "example" +name = "template_yarte" version = "0.0.1" authors = ["Rust-iendo Barcelona "] publish = false edition = "2018" + workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.2" env_logger = "0.6" -yarte = "0.1" + +yarte = { version = "0.2", features=["with-actix-web"] } + +actix-web = "1.0.0-alpha" [build-dependencies] -yarte = "0.1" +yarte = { version = "0.2", features=["with-actix-web"] } + +[dev-dependencies] +bytes = "0.4" +actix-http-test = "0.1.0-alpha" +actix-http = "0.1.0-alpha" diff --git a/template_yarte/README.md b/template_yarte/README.md index df534a7c..0f3d2756 100644 --- a/template_yarte/README.md +++ b/template_yarte/README.md @@ -2,10 +2,10 @@ Example of composition with partials and `with-actix-web` feature -See the generated code on stdout when run at debug ```bash +cargo test + cargo run ``` > open `localhost:8080` -More at [mdbook](https://yarte.netlify.com/) and [repository](https://gitlab.com/r-iendo/yarte) diff --git a/template_yarte/src/lib.rs b/template_yarte/src/lib.rs deleted file mode 100644 index 8b137891..00000000 --- a/template_yarte/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/template_yarte/src/main.rs b/template_yarte/src/main.rs index cd4434b7..4089a1bc 100644 --- a/template_yarte/src/main.rs +++ b/template_yarte/src/main.rs @@ -3,28 +3,18 @@ extern crate actix_web; use std::collections::HashMap; -use actix_web::{ - error::ErrorInternalServerError, middleware, web::Query, App, HttpResponse, - HttpServer, Result, -}; +use actix_web::{middleware::Logger, web, App, HttpServer, Responder}; use yarte::Template; #[derive(Template)] #[template(path = "index.hbs")] struct IndexTemplate { - query: Query>, + query: web::Query>, } #[get("/")] -pub fn index(query: Query>) -> Result { +pub fn index(query: web::Query>) -> impl Responder { IndexTemplate { query } - .call() - .map(|s| { - HttpResponse::Ok() - .content_type(IndexTemplate::mime()) - .body(s) - }) - .map_err(|_| ErrorInternalServerError("Template parsing error")) } fn main() -> std::io::Result<()> { @@ -32,12 +22,104 @@ fn main() -> std::io::Result<()> { env_logger::init(); // start http server - HttpServer::new(|| { - App::new() - // enable logger - .wrap(middleware::Logger::default()) - .service(index) - }) - .bind("127.0.0.1:8080")? - .run() + HttpServer::new(move || App::new().wrap(Logger::default()).service(index)) + .bind("127.0.0.1:8080")? + .run() +} + +#[cfg(test)] +mod test { + use super::*; + use actix_http::HttpService; + use actix_http_test::TestServer; + use actix_web::{http, App}; + use bytes::Bytes; + + #[test] + fn test() { + let mut srv = TestServer::new(|| HttpService::new(App::new().service(index))); + + let req = srv.get(); + let response = srv.block_on(req.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!( + response.headers().get(http::header::CONTENT_TYPE).unwrap(), + "text/html" + ); + + let bytes = srv.block_on(response.body()).unwrap(); + assert_eq!( + bytes, + Bytes::from_static( + "\ + \ + Actix web\ +

Welcome!

\ +

What is your name?

\ +
\ + Name: \ +
Last name: \ +

\ +
\ + " + .as_ref() + ) + ); + + let req = srv.get().uri(srv.url("/?name=foo&lastname=bar")); + let response = srv.block_on(req.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!( + response.headers().get(http::header::CONTENT_TYPE).unwrap(), + "text/html" + ); + + let bytes = srv.block_on(response.body()).unwrap(); + assert_eq!( + bytes, + Bytes::from_static( + "\ + \ + Actix web\ + \ +

Hi, foo bar!

Welcome

\ + " + .as_ref() + ) + ); + + let req = srv.get().uri(srv.url("/?name=foo")); + let response = srv.block_on(req.send()).unwrap(); + assert!(response.status().is_server_error()); + + let req = srv.get().uri(srv.url("/?lastname=bar")); + let response = srv.block_on(req.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!( + response.headers().get(http::header::CONTENT_TYPE).unwrap(), + "text/html" + ); + + let bytes = srv.block_on(response.body()).unwrap(); + assert_eq!( + bytes, + Bytes::from_static( + "\ + \ + Actix web\ +

Welcome!

\ +

What is your name?

\ +
\ + Name: \ +
Last name: \ +

\ +
\ + " + .as_ref() + ) + ); + } } diff --git a/template_yarte/templates/deep/more/card/form.hbs b/template_yarte/templates/deep/more/card/form.hbs new file mode 100644 index 00000000..a5b75a60 --- /dev/null +++ b/template_yarte/templates/deep/more/card/form.hbs @@ -0,0 +1,20 @@ +{{! + Form: What is your name? +!}} +{{> ../deep/welcome id = "welcome", tag = "h1", tail = '!' ~}} +
+ {{! Title !}} +

What is your name?

+ + {{! Form !}} +
+ {{! Input name !}} + Name: + {{! Input last name !}} +
Last name: + + {{! Submit !}} +

+ + {{! Order and remove whitespace with comments !}} +
diff --git a/template_yarte/templates/deep/more/card/hi.hbs b/template_yarte/templates/deep/more/card/hi.hbs new file mode 100644 index 00000000..7bd929f1 --- /dev/null +++ b/template_yarte/templates/deep/more/card/hi.hbs @@ -0,0 +1,8 @@ +{{! + Hi message: + args: + - lastname + - name +!}} +

Hi, {{ name }} {{ lastname }}!

+{{~> alias/welcome id = "hi", tag = 'p', tail = "" }} diff --git a/template_yarte/templates/deep/more/deep/welcome.hbs b/template_yarte/templates/deep/more/deep/welcome.hbs index 5cb2a971..e0fe08b1 100644 --- a/template_yarte/templates/deep/more/deep/welcome.hbs +++ b/template_yarte/templates/deep/more/deep/welcome.hbs @@ -1 +1,8 @@ -<{{ tag }}>Welcome! +{{! + Welcome card: + args: + - tag + - id + - tail +!}} +<{{ tag }} id="{{ id }}" class="welcome">Welcome{{ tail }} diff --git a/template_yarte/templates/deep/more/doc/head.hbs b/template_yarte/templates/deep/more/doc/head.hbs new file mode 100644 index 00000000..309846d0 --- /dev/null +++ b/template_yarte/templates/deep/more/doc/head.hbs @@ -0,0 +1 @@ +{{ title }} diff --git a/template_yarte/templates/deep/more/doc/t.hbs b/template_yarte/templates/deep/more/doc/t.hbs new file mode 100644 index 00000000..0e76edd6 --- /dev/null +++ b/template_yarte/templates/deep/more/doc/t.hbs @@ -0,0 +1 @@ + diff --git a/template_yarte/templates/index.hbs b/template_yarte/templates/index.hbs index 503bb845..b3afdf48 100644 --- a/template_yarte/templates/index.hbs +++ b/template_yarte/templates/index.hbs @@ -1,22 +1,12 @@ - +{{! Simple example !}} +{{> doc/t ~}} - - - Actix web - +{{~> doc/head title = "Actix web" ~}} -{{~#if let Some(name) = query.get("name") ~}} -

Hi, {{ name }}!

- {{~> alias/welcome tag='p' ~}} -{{~ else ~}} - {{~> alias/welcome tag="h1" ~}} -

-

What is your name?

-
-
-

-
-

-{{~/if~}} - - + {{~#if let Some(name) = query.get("name") }} + {{ let lastname = query.get("lastname").ok_or(yarte::Error)? }} + {{> card/hi ~}} + {{ else ~}} + {{> card/form ~}} + {{/if ~}} + diff --git a/template_yarte/yarte.toml b/template_yarte/yarte.toml index bcf89202..b3c60a67 100644 --- a/template_yarte/yarte.toml +++ b/template_yarte/yarte.toml @@ -5,3 +5,5 @@ dir = "templates" # Alias for partials. In call, change the start of partial path with one of this, if exist. [partials] alias = "./deep/more/deep" +doc = "./deep/more/doc" +card = "./deep/more/card" From b806d2254dff2e0db8a22141957a848ecbef77c3 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 1 Apr 2019 10:47:15 +0200 Subject: [PATCH 039/111] Update main.rs Switch the position of a rogue parenthesis. --- template_askama/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index b07879ab..f1060f8c 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -31,7 +31,7 @@ fn index(query: web::Query>) -> Result { fn main() -> std::io::Result<()> { // start http server HttpServer::new(move || { - App::new().service(web::resource("/").route(web::get()).to(index)) + App::new().service(web::resource("/").route(web::get().to(index))) }) .bind("127.0.0.1:8080")? .run() From 4f4acbd72784097806bfd932cda18d66ec4c3698 Mon Sep 17 00:00:00 2001 From: henrylee2cn Date: Thu, 4 Apr 2019 14:38:07 +0800 Subject: [PATCH 040/111] fix: send_json(data) -> send_json(&data) --- async_ex1/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index a9eb054b..30af79ed 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -61,7 +61,7 @@ fn step_x_v1( Box::new( client .post("https://httpbin.org/post") - .send_json(data) + .send_json(&data) .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { resp // <- this is MessageBody type, resolves to complete body @@ -108,7 +108,7 @@ fn step_x_v2( ) -> impl Future { client .post("https://httpbin.org/post") - .send_json(data) + .send_json(&data) .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { resp.from_err() From 86e0f3e02c4d5f724dbfeec2ee3fe50ca3ac2f10 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 4 Apr 2019 11:37:14 -0700 Subject: [PATCH 041/111] upgrade to alpha3 --- actix_redis/Cargo.toml | 2 +- actix_todo/Cargo.toml | 6 +++--- async_db/Cargo.toml | 2 +- async_ex1/Cargo.toml | 2 +- basics/Cargo.toml | 6 +++--- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 ++-- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-full-proxy/src/main.rs | 2 +- http-proxy/Cargo.toml | 2 +- http-proxy/src/main.rs | 2 +- json/Cargo.toml | 2 +- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 2 +- multipart/Cargo.toml | 2 +- multipart/src/main.rs | 1 + protobuf/Cargo.toml | 2 +- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 4 ++-- rustls/Cargo.toml | 4 ++-- simple-auth-server/Cargo.toml | 4 ++-- state/Cargo.toml | 2 +- static_index/Cargo.toml | 4 ++-- template_askama/Cargo.toml | 2 +- template_askama/build.rs | 5 ----- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 6 +++--- tls/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 6 +++--- websocket-tcp-chat/Cargo.toml | 6 +++--- websocket/Cargo.toml | 6 +++--- 36 files changed, 52 insertions(+), 56 deletions(-) delete mode 100644 template_askama/build.rs diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index 7c762a61..38a2daa8 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 52551f0f..e1e09251 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.2" -actix-files = "0.1.0-alpha.1" -actix-session = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.3" +actix-files = "0.1.0-alpha.2" +actix-session = "0.1.0-alpha.3" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 3ccfbc26..70e29622 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 62154f4b..69bcdc0d 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.2", features=["ssl"] } +actix-web = { version="1.0.0-alpha.3", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 4c2dc1e6..93ad3606 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.2" -actix-files = "0.1.0-alpha.1" -actix-session = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.3" +actix-files = "0.1.0-alpha.2" +actix-session = "0.1.0-alpha.3" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index f7cded59..ef75a84d 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 1655322f..466e2c67 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.2" -actix-session = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.3" +actix-session = "0.1.0-alpha.3" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 5da09f40..20643838 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index 46f2f3e9..71e013a0 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index 7e9eef60..f8386ad0 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index b3f23f99..879693a1 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index dfa5c50d..0030fad9 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" clap = "2.32.0" futures = "0.1.25" diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index f350769e..d6d91e50 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -16,7 +16,7 @@ fn forward( new_url.set_query(req.uri().query()); let forwarded_req = client - .request_from(new_url.as_str(), &req) + .request_from(new_url.as_str(), req.head()) .no_default_headers(); // if let Some(addr) = req.peer_addr() { diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 4bdeb424..cbca064c 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.2" +actix-web = "1.0.0-alpha.3" env_logger = "0.5" futures = "0.1" diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index 080c848d..e500bbee 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -8,7 +8,7 @@ fn index(client: web::Data) -> impl Future impl Future Date: Fri, 5 Apr 2019 18:43:47 +0200 Subject: [PATCH 042/111] Update template_yarte to actix_web-1.0.0-alpha.3 --- template_yarte/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/template_yarte/src/main.rs b/template_yarte/src/main.rs index 4089a1bc..d65a091d 100644 --- a/template_yarte/src/main.rs +++ b/template_yarte/src/main.rs @@ -39,8 +39,8 @@ mod test { fn test() { let mut srv = TestServer::new(|| HttpService::new(App::new().service(index))); - let req = srv.get(); - let response = srv.block_on(req.send()).unwrap(); + let req = srv.get("/"); + let mut response = srv.block_on(req.send()).unwrap(); assert!(response.status().is_success()); assert_eq!( @@ -67,8 +67,8 @@ mod test { ) ); - let req = srv.get().uri(srv.url("/?name=foo&lastname=bar")); - let response = srv.block_on(req.send()).unwrap(); + let req = srv.get("/?name=foo&lastname=bar"); + let mut response = srv.block_on(req.send()).unwrap(); assert!(response.status().is_success()); assert_eq!( @@ -90,12 +90,12 @@ mod test { ) ); - let req = srv.get().uri(srv.url("/?name=foo")); - let response = srv.block_on(req.send()).unwrap(); + let req = srv.get("/?name=foo"); + let mut response = srv.block_on(req.send()).unwrap(); assert!(response.status().is_server_error()); - let req = srv.get().uri(srv.url("/?lastname=bar")); - let response = srv.block_on(req.send()).unwrap(); + let req = srv.get("/?lastname=bar"); + let mut response = srv.block_on(req.send()).unwrap(); assert!(response.status().is_success()); assert_eq!( From 815e34f32ded77f73145fb0373a060b22636f689 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 7 Apr 2019 23:39:45 -0700 Subject: [PATCH 043/111] upgrade to alpha4 --- actix_redis/Cargo.toml | 2 +- actix_todo/Cargo.toml | 6 +-- async_db/Cargo.toml | 2 +- async_ex1/Cargo.toml | 2 +- basics/Cargo.toml | 6 +-- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 +- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 4 +- multipart/Cargo.toml | 3 +- multipart/src/main.rs | 65 ++++++++++++++++++-------- protobuf/Cargo.toml | 2 +- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 4 +- rustls/Cargo.toml | 4 +- simple-auth-server/Cargo.toml | 4 +- simple-auth-server/src/auth_handler.rs | 8 ++-- state/Cargo.toml | 2 +- static_index/Cargo.toml | 4 +- template_askama/Cargo.toml | 3 +- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 4 +- tls/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 6 +-- websocket-tcp-chat/Cargo.toml | 4 +- websocket/Cargo.toml | 4 +- 34 files changed, 97 insertions(+), 72 deletions(-) diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index 38a2daa8..7229262f 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index e1e09251..6e3acb91 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" -actix-session = "0.1.0-alpha.3" +actix-web = "1.0.0-alpha.4" +actix-files = "0.1.0-alpha.4" +actix-session = "0.1.0-alpha.4" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 70e29622..8063ead8 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index 69bcdc0d..a87eec91 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.3", features=["ssl"] } +actix-web = { version="1.0.0-alpha.4", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 93ad3606..e16db24a 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" -actix-session = "0.1.0-alpha.3" +actix-web = "1.0.0-alpha.4" +actix-files = "0.1.0-alpha.4" +actix-session = "0.1.0-alpha.4" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index ef75a84d..66d02b61 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 466e2c67..2a76fa63 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" -actix-session = "0.1.0-alpha.3" +actix-web = "1.0.0-alpha.4" +actix-session = "0.1.0-alpha.4" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 20643838..5c534ced 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index 71e013a0..9e0b003f 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index f8386ad0..1f983684 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 879693a1..733faa54 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index 0030fad9..593b1a5c 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" clap = "2.32.0" futures = "0.1.25" diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index cbca064c..9afc29ea 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index 3cd3d86a..eab6ddb7 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" bytes = "0.4" futures = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index e4161a03..71f410ca 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index 33fe3a3c..e6d9cc3a 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-service = "0.3.3" -actix-web = "1.0.0-alpha.3" +actix-service = "0.3.6" +actix-web = "1.0.0-alpha.4" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 1246fdd6..a6223938 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,7 +10,8 @@ name = "multipart" path = "src/main.rs" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" +actix-multipart = { git="https://github.com/actix/actix-web.git" } env_logger = "0.6" futures = "0.1.25" diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 5ff785cb..73d111f9 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -1,16 +1,18 @@ use std::cell::Cell; -use std::fs; +use std::fs::{self, File}; use std::io::Write; +use std::path::Path; +use actix_multipart::{Field, Item, Multipart, MultipartError}; use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; -use futures::future::{err, Either}; +use futures::future::{err, ok, Either}; use futures::{Future, Stream}; pub struct AppState { pub counter: Cell, } -pub fn save_file(field: web::MultipartField) -> impl Future { +pub fn save_file(field: Field) -> impl Future { let file_path_string = "upload.png"; let mut file = match fs::File::create(file_path_string) { Ok(file) => file, @@ -24,7 +26,7 @@ pub fn save_file(field: web::MultipartField) -> impl Future impl Future Box> { +pub fn handle_multipart_item(item: Item) -> Box> { match item { - web::MultipartItem::Field(field) => Box::new(save_file(field).into_stream()), - web::MultipartItem::Nested(mp) => Box::new( + Item::Field(field) => Box::new(save_file(field).into_stream()), + Item::Nested(mp) => Box::new( mp.map_err(error::ErrorInternalServerError) .map(handle_multipart_item) .flatten(), @@ -48,21 +48,46 @@ pub fn handle_multipart_item( } pub fn upload( - multipart: web::Multipart, + multipart: Multipart, counter: web::Data>, ) -> impl Future { - counter.set(counter.get() + 1); - println!("{:?}", counter.get()); - multipart - .map_err(error::ErrorInternalServerError) - .map(handle_multipart_item) - .flatten() + .from_err::() + .take(1) .collect() - .map(|sizes| HttpResponse::Ok().json(sizes)) - .map_err(|e| { - println!("failed: {}", e); - e + .map(|v| v.into_iter().next().expect("wat")) + .and_then(|item| match item { + Item::Field(field) => { + if let Some(disp) = field.content_disposition() { + if let Some(disp_fn) = disp.get_filename() { + if let Some(ext) = Path::new(&disp_fn).extension() { + let fname = format!("{}.{}", 10, ext.to_string_lossy()); + let pth = Path::new("./").join(&fname); + if let Ok(mut ff) = File::create(&pth) { + return Either::A( + field + .from_err::() + .map(move |c| ff.write_all(&c)) + .fold((), |_, _| Ok::<_, Error>(())) + //.finish() + .and_then(move |_| { + ok(HttpResponse::Created().body(format!( + "{{\"path\": \"{}\"}}", + fname + ))) + }) + .or_else(|_| { + ok(HttpResponse::InternalServerError() + .finish()) + }), + ); + } + } + } + } + Either::B(ok(HttpResponse::BadRequest().finish())) + } + Item::Nested(_) => Either::B(ok(HttpResponse::BadRequest().finish())), }) } diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index d71ec8ac..a20640b0 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -13,4 +13,4 @@ derive_more = "0.14" prost = "0.2.0" prost-derive = "0.2.0" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index a911f39f..86e70e3f 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 44b567c6..fc347f8f 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.3" -actix-session = "0.1.0-alpha.3" +actix-web = "1.0.0-alpha.4" +actix-session = "0.1.0-alpha.4" actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } env_logger = "0.6" diff --git a/rustls/Cargo.toml b/rustls/Cargo.toml index a1f30259..6abb0157 100644 --- a/rustls/Cargo.toml +++ b/rustls/Cargo.toml @@ -12,5 +12,5 @@ path = "src/main.rs" [dependencies] env_logger = "0.5" rustls = "0.15" -actix-web = { version = "1.0.0-alpha.3", features=["rust-tls"] } -actix-files = "0.1.0-alpha.2" +actix-web = { version = "1.0.0-alpha.4", features=["rust-tls"] } +actix-files = "0.1.0-alpha.4" diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 6bd3a666..fe59c1ff 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -8,8 +8,8 @@ workspace = ".." [dependencies] actix = { version = "0.8.0-alpha.2", features = ["http"] } actix-rt = "0.2.2" -actix-web = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.4" +actix-files = "0.1.0-alpha.4" bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 13eb1476..0a433e5a 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,6 +1,6 @@ use actix::{Handler, Message}; -use actix_web::{dev::ServiceFromRequest, Error}; -use actix_web::{middleware::identity::Identity, FromRequest, HttpRequest}; +use actix_web::{dev::Payload, Error, HttpRequest}; +use actix_web::{middleware::identity::Identity, FromRequest}; use bcrypt::verify; use diesel::prelude::*; @@ -50,8 +50,8 @@ impl

FromRequest

for LoggedUser { type Error = Error; type Future = Result; - fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { - if let Some(identity) = Identity::from_request(req)?.identity() { + fn from_request(req: &HttpRequest, pl: &mut Payload

) -> Self::Future { + if let Some(identity) = Identity::from_request(req, pl)?.identity() { let user: SlimUser = decode_token(&identity)?; return Ok(user as LoggedUser); } diff --git a/state/Cargo.toml b/state/Cargo.toml index f13f4f21..894d49d6 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" futures = "0.1.25" env_logger = "0.6" diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index a7e8847f..196e112d 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.4" +actix-files = "0.1.0-alpha.4" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 6f53dfa4..09fc9e81 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,8 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -#askama = { version = "0.8", features = ["with-actix-web"] } -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" env_logger = "0.6" askama = "0.8" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index bb4df6b6..700f4f8a 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "0.11" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 9ef98b58..f7645bc8 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -12,7 +12,7 @@ env_logger = "0.6" yarte = { version = "0.2", features=["with-actix-web"] } -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" [build-dependencies] yarte = { version = "0.2", features=["with-actix-web"] } @@ -20,4 +20,4 @@ yarte = { version = "0.2", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" actix-http-test = "0.1.0-alpha.3" -actix-http = "0.1.0-alpha.3" +actix-http = "0.1.0-alpha.4" diff --git a/tls/Cargo.toml b/tls/Cargo.toml index c1ef14a8..65302c68 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -11,6 +11,6 @@ path = "src/main.rs" [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.3", features=["ssl"] } +actix-web = { version="1.0.0-alpha.4", features=["ssl"] } env_logger = "0.6" openssl = { version="0.10" } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index f1794a52..19309063 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../../" edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index 34b389e6..e59f220a 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -11,9 +11,9 @@ path = "src/main.rs" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.3" -actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" +actix-web = "1.0.0-alpha.4" +actix-web-actors = "1.0.0-alpha.2" +actix-files = "0.1.0-alpha.4" rand = "0.6" bytes = "0.4" diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index 40f25f51..b812bfa0 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -15,9 +15,9 @@ path = "src/client.rs" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" +actix-files = "0.1.0-alpha.4" rand = "0.6" bytes = "0.4" diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index e3b9d153..1c67978f 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -15,9 +15,9 @@ path = "src/main.rs" [dependencies] actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.3" +actix-web = "1.0.0-alpha.4" actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.2" +actix-files = "0.1.0-alpha.4" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file From 6545bbfd3d72fcd9d86c7df8ed185adb55e47899 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 8 Apr 2019 16:33:35 +0200 Subject: [PATCH 044/111] Revert to alpha3 multipart example to avoid panic The alpha4 multipart example seems to cause a panic (as mentioned in #736). So this reverts to the alpha3 example, tweaked for the actix-multipart crate. https://github.com/actix/actix-web/issues/736 --- multipart/src/main.rs | 53 +++++++++++-------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 73d111f9..7c859b14 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -1,11 +1,10 @@ use std::cell::Cell; -use std::fs::{self, File}; +use std::fs::{self}; use std::io::Write; -use std::path::Path; use actix_multipart::{Field, Item, Multipart, MultipartError}; use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; -use futures::future::{err, ok, Either}; +use futures::future::{err, Either}; use futures::{Future, Stream}; pub struct AppState { @@ -16,12 +15,11 @@ pub fn save_file(field: Field) -> impl Future { let file_path_string = "upload.png"; let mut file = match fs::File::create(file_path_string) { Ok(file) => file, - Err(e) => return Either::A(err(error::ErrorInternalServerError(e))), + Err(e) => return Either::A(err(error::ErrorInternalServerError(e))) }; Either::B( field .fold(0i64, move |acc, bytes| { - println!("CHUNK: {:?}", bytes.len()); file.write_all(bytes.as_ref()) .map(|_| acc + bytes.len() as i64) .map_err(|e| { @@ -51,43 +49,18 @@ pub fn upload( multipart: Multipart, counter: web::Data>, ) -> impl Future { + counter.set(counter.get() + 1); + println!("{:?}", counter.get()); + multipart - .from_err::() - .take(1) + .map_err(error::ErrorInternalServerError) + .map(handle_multipart_item) + .flatten() .collect() - .map(|v| v.into_iter().next().expect("wat")) - .and_then(|item| match item { - Item::Field(field) => { - if let Some(disp) = field.content_disposition() { - if let Some(disp_fn) = disp.get_filename() { - if let Some(ext) = Path::new(&disp_fn).extension() { - let fname = format!("{}.{}", 10, ext.to_string_lossy()); - let pth = Path::new("./").join(&fname); - if let Ok(mut ff) = File::create(&pth) { - return Either::A( - field - .from_err::() - .map(move |c| ff.write_all(&c)) - .fold((), |_, _| Ok::<_, Error>(())) - //.finish() - .and_then(move |_| { - ok(HttpResponse::Created().body(format!( - "{{\"path\": \"{}\"}}", - fname - ))) - }) - .or_else(|_| { - ok(HttpResponse::InternalServerError() - .finish()) - }), - ); - } - } - } - } - Either::B(ok(HttpResponse::BadRequest().finish())) - } - Item::Nested(_) => Either::B(ok(HttpResponse::BadRequest().finish())), + .map(|sizes| HttpResponse::Ok().json(sizes)) + .map_err(|e| { + println!("failed: {}", e); + e }) } From 4b62438e05aab1af481ad969f9589495b782c485 Mon Sep 17 00:00:00 2001 From: dowwie Date: Tue, 9 Apr 2019 10:36:37 -0400 Subject: [PATCH 045/111] updated async_ex1, removing old Box example and fixing example --- async_ex1/README.md | 3 +- async_ex1/src/main.rs | 81 +++++++------------------------------------ 2 files changed, 14 insertions(+), 70 deletions(-) diff --git a/async_ex1/README.md b/async_ex1/README.md index 11bbbeed..1b446fc8 100644 --- a/async_ex1/README.md +++ b/async_ex1/README.md @@ -16,5 +16,4 @@ Actix-web features illustrated here include: Example query from the command line using httpie: - ```http post 127.0.0.1:8088/something id=1 name=JohnDoe``` - + ```echo '{"id":"1", "name": "JohnDoe"}' | http 127.0.0.1:8080/something``` diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index 30af79ed..7057e694 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -11,9 +11,7 @@ // 2. actix-web client features: // - POSTing json body // 3. chaining futures into a single response used by an asynch endpoint -// -// There are 2 versions in this example, one that uses Boxed Futures and the -// other that uses Impl Future, available since rustc v1.26. + #[macro_use] extern crate validator_derive; @@ -49,60 +47,10 @@ struct HttpBinResponse { url: String, } -// ----------------------------------------------------------------------- -// v1 uses Boxed Futures, which were the only option prior to rustc v1.26 -// ----------------------------------------------------------------------- + /// post json to httpbin, get it back in the response body, return deserialized -fn step_x_v1( - data: SomeData, - client: &Client, -) -> Box> { - Box::new( - client - .post("https://httpbin.org/post") - .send_json(&data) - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then(|resp| { - resp // <- this is MessageBody type, resolves to complete body - .from_err() // <- convert PayloadError to an Error - .fold(BytesMut::new(), |mut acc, chunk| { - acc.extend_from_slice(&chunk); - Ok::<_, Error>(acc) - }) - .map(|body| { - let body: HttpBinResponse = - serde_json::from_slice(&body).unwrap(); - body.json - }) - }), - ) -} - -fn create_something_v1( - some_data: web::Json, - client: web::Data, -) -> Box> { - Box::new( - step_x_v1(some_data.into_inner(), &client).and_then(move |some_data_2| { - step_x_v1(some_data_2, &client).and_then(move |some_data_3| { - step_x_v1(some_data_3, &client).and_then(|d| { - Ok(HttpResponse::Ok() - .content_type("application/json") - .body(serde_json::to_string(&d).unwrap()) - .into()) - }) - }) - }), - ) -} - -// --------------------------------------------------------------- -// v2 uses impl Future, available as of rustc v1.26 -// --------------------------------------------------------------- - -/// post json to httpbin, get it back in the response body, return deserialized -fn step_x_v2( +fn step_x( data: SomeData, client: &Client, ) -> impl Future { @@ -123,17 +71,16 @@ fn step_x_v2( }) } -fn create_something_v2( +fn create_something( some_data: web::Json, client: web::Data, ) -> impl Future { - step_x_v2(some_data.into_inner(), &client).and_then(move |some_data_2| { - step_x_v2(some_data_2, &client).and_then(move |some_data_3| { - step_x_v2(some_data_3, &client).and_then(|d| { + step_x(some_data.into_inner(), &client).and_then(move |some_data_2| { + step_x(some_data_2, &client).and_then(move |some_data_3| { + step_x(some_data_3, &client).and_then(|d| { Ok(HttpResponse::Ok() .content_type("application/json") - .body(serde_json::to_string(&d).unwrap()) - .into()) + .body(serde_json::to_string(&d).unwrap())) }) }) }) @@ -142,19 +89,17 @@ fn create_something_v2( fn main() -> io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); + let endpoint = "127.0.0.1:8080"; + println!("Starting server at: {:?}", endpoint); HttpServer::new(|| { App::new() .data(Client::default()) .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)), + web::resource("/something") + .route(web::post().to_async(create_something)), ) }) - .bind("127.0.0.1:8088")? + .bind(endpoint)? .run() } From d29f113ffc823046c2b9e0554d4e166c15413be4 Mon Sep 17 00:00:00 2001 From: dowwie Date: Tue, 9 Apr 2019 14:12:07 -0400 Subject: [PATCH 046/111] added async_ex2 --- .gitignore | 2 ++ Cargo.toml | 1 + async_ex2/Cargo.toml | 20 +++++++++++++ async_ex2/src/README.md | 3 ++ async_ex2/src/appconfig.rs | 47 ++++++++++++++++++++++++++++++ async_ex2/src/bin/main.rs | 19 ++++++++++++ async_ex2/src/common.rs | 17 +++++++++++ async_ex2/src/handlers/mod.rs | 3 ++ async_ex2/src/handlers/parts.rs | 26 +++++++++++++++++ async_ex2/src/handlers/products.rs | 26 +++++++++++++++++ async_ex2/src/lib.rs | 3 ++ 11 files changed, 167 insertions(+) create mode 100644 async_ex2/Cargo.toml create mode 100644 async_ex2/src/README.md create mode 100644 async_ex2/src/appconfig.rs create mode 100644 async_ex2/src/bin/main.rs create mode 100644 async_ex2/src/common.rs create mode 100644 async_ex2/src/handlers/mod.rs create mode 100644 async_ex2/src/handlers/parts.rs create mode 100644 async_ex2/src/handlers/products.rs create mode 100644 async_ex2/src/lib.rs diff --git a/.gitignore b/.gitignore index 4a903f99..532edaeb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ Cargo.lock # intellij files .idea/** + +.history/ diff --git a/Cargo.toml b/Cargo.toml index 9ff86387..d6285920 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "actix_todo", "async_db", "async_ex1", + "async_ex2", "basics", "cookie-auth", "cookie-session", diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml new file mode 100644 index 00000000..d8195f6c --- /dev/null +++ b/async_ex2/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "async_ex2" +version = "0.1.0" +authors = ["dowwie "] +edition = "2018" +workspace = ".." + +[dependencies] +actix-rt = "0.2.2" +actix-web = { version="1.0.0-alpha.4", features=["ssl"] } +actix-multipart = { git="https://github.com/actix/actix-web.git" } +bytes = "0.4.12" +env_logger = "0.6.1" +futures = "0.1" +serde = { version = "^1.0", features = ["derive"] } +serde_derive = "1.0.90" +serde_json = "1.0.39" +time = "0.1.42" +validator = "0.8.0" +validator_derive = "0.8.0" diff --git a/async_ex2/src/README.md b/async_ex2/src/README.md new file mode 100644 index 00000000..68374f9a --- /dev/null +++ b/async_ex2/src/README.md @@ -0,0 +1,3 @@ +This example illustrates how to use nested resource registration through application-level configuration. +The endpoints do nothing. + diff --git a/async_ex2/src/appconfig.rs b/async_ex2/src/appconfig.rs new file mode 100644 index 00000000..ae23b09c --- /dev/null +++ b/async_ex2/src/appconfig.rs @@ -0,0 +1,47 @@ +use actix_web::{error, web}; +use bytes::Bytes; +use futures::Stream; + +use crate::{ + handlers::{ + products, + parts + }, +}; + + +pub fn config_app

(cfg: &mut web::RouterConfig

) + where P: Stream + + 'static +{ + // domain includes: /products/{product_id}/parts/{part_id} + cfg.service( + web::scope("/products") + .service( + web::resource("") + .route(web::get().to_async(products::get_products)) + .route(web::post().to_async(products::add_product)) + ) + .service( + web::scope("/{product_id}") + .service( + web::resource("") + .route(web::get().to_async(products::get_product_detail)) + .route(web::delete().to_async(products::remove_product)) + ) + .service( + web::scope("/parts") + .service( + web::resource("") + .route(web::get().to_async(parts::get_parts)) + .route(web::post().to_async(parts::add_part)) + ) + .service( + web::resource("/{part_id}") + .route(web::get().to_async(parts::get_part_detail)) + .route(web::delete().to_async(parts::remove_part)) + ) + ) + ) + ); +} \ No newline at end of file diff --git a/async_ex2/src/bin/main.rs b/async_ex2/src/bin/main.rs new file mode 100644 index 00000000..44c9c7e7 --- /dev/null +++ b/async_ex2/src/bin/main.rs @@ -0,0 +1,19 @@ +use actix_web::{middleware, App, HttpServer}; + +use async_ex2::{ + appconfig::config_app, +}; + + +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); + env_logger::init(); + + HttpServer::new(|| + App::new() + .configure(config_app) + .wrap(middleware::Logger::default()) + ) + .bind("127.0.0.1:8080")? + .run() +} \ No newline at end of file diff --git a/async_ex2/src/common.rs b/async_ex2/src/common.rs new file mode 100644 index 00000000..4359c2ec --- /dev/null +++ b/async_ex2/src/common.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + + +#[derive(Deserialize, Serialize)] +pub struct Product { + id: Option, + product_type: Option, + name: Option, +} + + +#[derive(Deserialize, Serialize)] +pub struct Part { + id: Option, + part_type: Option, + name: Option, +} \ No newline at end of file diff --git a/async_ex2/src/handlers/mod.rs b/async_ex2/src/handlers/mod.rs new file mode 100644 index 00000000..17f9e2c2 --- /dev/null +++ b/async_ex2/src/handlers/mod.rs @@ -0,0 +1,3 @@ +pub mod products; +pub mod parts; + diff --git a/async_ex2/src/handlers/parts.rs b/async_ex2/src/handlers/parts.rs new file mode 100644 index 00000000..22bb017a --- /dev/null +++ b/async_ex2/src/handlers/parts.rs @@ -0,0 +1,26 @@ +use actix_multipart::{Field, Item, Multipart, MultipartError}; +use actix_web::{HttpResponse, web, error, Error}; +use futures::{future::{ok as fut_ok, err as fut_err, Either}, Future, Stream}; + +use crate::common::{Part, Product}; + + +pub fn get_parts(query: web::Query>) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn add_part(new_part: web::Json) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn get_part_detail(id: web::Path) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn remove_part(id: web::Path) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} \ No newline at end of file diff --git a/async_ex2/src/handlers/products.rs b/async_ex2/src/handlers/products.rs new file mode 100644 index 00000000..5d0cd2a9 --- /dev/null +++ b/async_ex2/src/handlers/products.rs @@ -0,0 +1,26 @@ +use actix_multipart::{Field, Item, Multipart, MultipartError}; +use actix_web::{HttpResponse, web, error, Error}; +use futures::{future::{ok as fut_ok, err as fut_err, Either}, Future, Stream}; + +use crate::common::{Part, Product}; + + +pub fn get_products(query: web::Query>) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn add_product(new_product: web::Json) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn get_product_detail(id: web::Path) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} + +pub fn remove_product(id: web::Path) + -> impl Future { + fut_ok(HttpResponse::Ok().finish()) +} \ No newline at end of file diff --git a/async_ex2/src/lib.rs b/async_ex2/src/lib.rs new file mode 100644 index 00000000..1e9c00b3 --- /dev/null +++ b/async_ex2/src/lib.rs @@ -0,0 +1,3 @@ +pub mod appconfig; +pub mod common; +pub mod handlers; From 3b548c20f4b54eb4b6b1241c3d418bc71c1d15d6 Mon Sep 17 00:00:00 2001 From: dowwie Date: Tue, 9 Apr 2019 14:34:55 -0400 Subject: [PATCH 047/111] moved readme for async_ex2 --- async_ex2/{src => }/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename async_ex2/{src => }/README.md (100%) diff --git a/async_ex2/src/README.md b/async_ex2/README.md similarity index 100% rename from async_ex2/src/README.md rename to async_ex2/README.md From 4be146424912cc86e087d6e1989807bbc09dbd98 Mon Sep 17 00:00:00 2001 From: dowwie Date: Wed, 10 Apr 2019 14:08:10 -0400 Subject: [PATCH 048/111] added unit test example to async_ex2 --- async_ex2/Cargo.toml | 1 + async_ex2/src/handlers/products.rs | 33 +++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml index d8195f6c..ace032b8 100644 --- a/async_ex2/Cargo.toml +++ b/async_ex2/Cargo.toml @@ -18,3 +18,4 @@ serde_json = "1.0.39" time = "0.1.42" validator = "0.8.0" validator_derive = "0.8.0" +actix-service = "0.3.6" diff --git a/async_ex2/src/handlers/products.rs b/async_ex2/src/handlers/products.rs index 5d0cd2a9..174b8286 100644 --- a/async_ex2/src/handlers/products.rs +++ b/async_ex2/src/handlers/products.rs @@ -23,4 +23,35 @@ pub fn get_product_detail(id: web::Path) pub fn remove_product(id: web::Path) -> impl Future { fut_ok(HttpResponse::Ok().finish()) -} \ No newline at end of file +} + + +#[cfg(test)] +mod tests { + use super::*; + use actix_service::Service; + use actix_web::{test, HttpResponse, HttpRequest, App, + http::{header, StatusCode}, web}; + use crate::appconfig::config_app; + + + #[test] + fn test_add_product() { + let mut app = test::init_service( + App::new() + .configure(config_app) + ); + + let payload = r#"{"id":12345,"product_type":"fancy","name":"test"}"#.as_bytes(); + + let req = test::TestRequest::post() + .uri("/products") + .header(header::CONTENT_TYPE, "application/json") + .set_payload(payload) + .to_request(); + + let resp = test::block_on(app.call(req)).unwrap(); + + assert_eq!(resp.status(), StatusCode::OK); + } +} From 8fb2bf686978af189f45a61eb5efa7a189e2c443 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 12 Apr 2019 13:39:14 -0700 Subject: [PATCH 049/111] update actix-web version --- http-full-proxy/Cargo.toml | 2 +- http-full-proxy/src/main.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index 593b1a5c..5e7f4f75 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-alpha.5" clap = "2.32.0" futures = "0.1.25" diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index d6d91e50..93eacbc8 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -15,9 +15,7 @@ fn forward( new_url.set_path(req.uri().path()); new_url.set_query(req.uri().query()); - let forwarded_req = client - .request_from(new_url.as_str(), req.head()) - .no_default_headers(); + let forwarded_req = client.request_from(new_url.as_str(), req.head()); // if let Some(addr) = req.peer_addr() { // match forwarded_req.headers_mut().entry("x-forwarded-for") { From 09b0188ff99e872898793bd815382a4105219b77 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 14 Apr 2019 10:34:41 -0700 Subject: [PATCH 050/111] upgrade to alpha.6 --- async_ex1/src/main.rs | 12 ++---- async_ex2/src/appconfig.rs | 31 +++++---------- async_ex2/src/bin/main.rs | 11 ++---- async_ex2/src/common.rs | 4 +- async_ex2/src/handlers/mod.rs | 3 +- async_ex2/src/handlers/parts.rs | 32 +++++++++------- async_ex2/src/handlers/products.rs | 53 ++++++++++++++------------ basics/src/main.rs | 9 +++-- http-full-proxy/src/main.rs | 2 +- middleware/src/redirect.rs | 14 +++---- middleware/src/simple.rs | 15 ++++---- multipart/src/main.rs | 19 ++------- simple-auth-server/src/auth_handler.rs | 5 ++- 13 files changed, 93 insertions(+), 117 deletions(-) diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index 7057e694..1bb4fd2d 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -12,7 +12,6 @@ // - POSTing json body // 3. chaining futures into a single response used by an asynch endpoint - #[macro_use] extern crate validator_derive; #[macro_use] @@ -47,8 +46,6 @@ struct HttpBinResponse { url: String, } - - /// post json to httpbin, get it back in the response body, return deserialized fn step_x( data: SomeData, @@ -93,12 +90,9 @@ fn main() -> io::Result<()> { println!("Starting server at: {:?}", endpoint); HttpServer::new(|| { - App::new() - .data(Client::default()) - .service( - web::resource("/something") - .route(web::post().to_async(create_something)), - ) + App::new().data(Client::default()).service( + web::resource("/something").route(web::post().to_async(create_something)), + ) }) .bind(endpoint)? .run() diff --git a/async_ex2/src/appconfig.rs b/async_ex2/src/appconfig.rs index ae23b09c..e38629a6 100644 --- a/async_ex2/src/appconfig.rs +++ b/async_ex2/src/appconfig.rs @@ -1,47 +1,36 @@ use actix_web::{error, web}; -use bytes::Bytes; -use futures::Stream; -use crate::{ - handlers::{ - products, - parts - }, -}; +use crate::handlers::{parts, products}; - -pub fn config_app

(cfg: &mut web::RouterConfig

) - where P: Stream - + 'static -{ +pub fn config_app(cfg: &mut web::RouterConfig) { // domain includes: /products/{product_id}/parts/{part_id} cfg.service( web::scope("/products") .service( web::resource("") .route(web::get().to_async(products::get_products)) - .route(web::post().to_async(products::add_product)) + .route(web::post().to_async(products::add_product)), ) .service( web::scope("/{product_id}") .service( web::resource("") .route(web::get().to_async(products::get_product_detail)) - .route(web::delete().to_async(products::remove_product)) + .route(web::delete().to_async(products::remove_product)), ) .service( web::scope("/parts") .service( web::resource("") .route(web::get().to_async(parts::get_parts)) - .route(web::post().to_async(parts::add_part)) + .route(web::post().to_async(parts::add_part)), ) .service( web::resource("/{part_id}") .route(web::get().to_async(parts::get_part_detail)) - .route(web::delete().to_async(parts::remove_part)) - ) - ) - ) + .route(web::delete().to_async(parts::remove_part)), + ), + ), + ), ); -} \ No newline at end of file +} diff --git a/async_ex2/src/bin/main.rs b/async_ex2/src/bin/main.rs index 44c9c7e7..f5ee4fb9 100644 --- a/async_ex2/src/bin/main.rs +++ b/async_ex2/src/bin/main.rs @@ -1,19 +1,16 @@ use actix_web::{middleware, App, HttpServer}; -use async_ex2::{ - appconfig::config_app, -}; - +use async_ex2::appconfig::config_app; fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); env_logger::init(); - HttpServer::new(|| + HttpServer::new(|| { App::new() .configure(config_app) .wrap(middleware::Logger::default()) - ) + }) .bind("127.0.0.1:8080")? .run() -} \ No newline at end of file +} diff --git a/async_ex2/src/common.rs b/async_ex2/src/common.rs index 4359c2ec..4c100617 100644 --- a/async_ex2/src/common.rs +++ b/async_ex2/src/common.rs @@ -1,6 +1,5 @@ use serde::{Deserialize, Serialize}; - #[derive(Deserialize, Serialize)] pub struct Product { id: Option, @@ -8,10 +7,9 @@ pub struct Product { name: Option, } - #[derive(Deserialize, Serialize)] pub struct Part { id: Option, part_type: Option, name: Option, -} \ No newline at end of file +} diff --git a/async_ex2/src/handlers/mod.rs b/async_ex2/src/handlers/mod.rs index 17f9e2c2..299c561b 100644 --- a/async_ex2/src/handlers/mod.rs +++ b/async_ex2/src/handlers/mod.rs @@ -1,3 +1,2 @@ -pub mod products; pub mod parts; - +pub mod products; diff --git a/async_ex2/src/handlers/parts.rs b/async_ex2/src/handlers/parts.rs index 22bb017a..0dba7b0f 100644 --- a/async_ex2/src/handlers/parts.rs +++ b/async_ex2/src/handlers/parts.rs @@ -1,26 +1,32 @@ -use actix_multipart::{Field, Item, Multipart, MultipartError}; -use actix_web::{HttpResponse, web, error, Error}; -use futures::{future::{ok as fut_ok, err as fut_err, Either}, Future, Stream}; +use actix_multipart::{Field, Multipart, MultipartError}; +use actix_web::{error, web, Error, HttpResponse}; +use futures::{ + future::{err as fut_err, ok as fut_ok, Either}, + Future, Stream, +}; use crate::common::{Part, Product}; - -pub fn get_parts(query: web::Query>) - -> impl Future { +pub fn get_parts( + query: web::Query>, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn add_part(new_part: web::Json) - -> impl Future { +pub fn add_part( + new_part: web::Json, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn get_part_detail(id: web::Path) - -> impl Future { +pub fn get_part_detail( + id: web::Path, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn remove_part(id: web::Path) - -> impl Future { +pub fn remove_part( + id: web::Path, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) -} \ No newline at end of file +} diff --git a/async_ex2/src/handlers/products.rs b/async_ex2/src/handlers/products.rs index 174b8286..1f3d68fd 100644 --- a/async_ex2/src/handlers/products.rs +++ b/async_ex2/src/handlers/products.rs @@ -1,54 +1,57 @@ -use actix_multipart::{Field, Item, Multipart, MultipartError}; -use actix_web::{HttpResponse, web, error, Error}; -use futures::{future::{ok as fut_ok, err as fut_err, Either}, Future, Stream}; +use actix_multipart::{Field, Multipart, MultipartError}; +use actix_web::{error, web, Error, HttpResponse}; +use futures::{ + future::{err as fut_err, ok as fut_ok, Either}, + Future, Stream, +}; use crate::common::{Part, Product}; - -pub fn get_products(query: web::Query>) - -> impl Future { +pub fn get_products( + query: web::Query>, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn add_product(new_product: web::Json) - -> impl Future { +pub fn add_product( + new_product: web::Json, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn get_product_detail(id: web::Path) - -> impl Future { +pub fn get_product_detail( + id: web::Path, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } -pub fn remove_product(id: web::Path) - -> impl Future { +pub fn remove_product( + id: web::Path, +) -> impl Future { fut_ok(HttpResponse::Ok().finish()) } - #[cfg(test)] mod tests { use super::*; - use actix_service::Service; - use actix_web::{test, HttpResponse, HttpRequest, App, - http::{header, StatusCode}, web}; use crate::appconfig::config_app; - + use actix_service::Service; + use actix_web::{ + http::{header, StatusCode}, + test, web, App, HttpRequest, HttpResponse, + }; #[test] fn test_add_product() { - let mut app = test::init_service( - App::new() - .configure(config_app) - ); + let mut app = test::init_service(App::new().configure(config_app)); let payload = r#"{"id":12345,"product_type":"fancy","name":"test"}"#.as_bytes(); let req = test::TestRequest::post() - .uri("/products") - .header(header::CONTENT_TYPE, "application/json") - .set_payload(payload) - .to_request(); + .uri("/products") + .header(header::CONTENT_TYPE, "application/json") + .set_payload(payload) + .to_request(); let resp = test::block_on(app.call(req)).unwrap(); diff --git a/basics/src/main.rs b/basics/src/main.rs index 7ab8a725..5d74e3d9 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -124,16 +124,17 @@ fn main() -> io::Result<()> { .finish() }))) // default - .default_resource(|r| { + .default_service( // 404 for GET request - r.route(web::get().to(p404)) + web::resource("") + .route(web::get().to(p404)) // all requests that are not `GET` .route( web::route() .guard(guard::Not(guard::Get())) .to(|| HttpResponse::MethodNotAllowed()), - ) - }) + ), + ) }) .bind("127.0.0.1:8080")? .start(); diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 93eacbc8..2d7a8426 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -98,7 +98,7 @@ fn main() -> std::io::Result<()> { App::new() .data(forward_url.clone()) .wrap(middleware::Logger::default()) - .default_resource(|r| r.to_async(forward)) + .default_service(web::route().to_async(forward)) }) .bind((listen_addr, listen_port))? .system_exit() diff --git a/middleware/src/redirect.rs b/middleware/src/redirect.rs index 3ffd3a87..670caa4a 100644 --- a/middleware/src/redirect.rs +++ b/middleware/src/redirect.rs @@ -6,12 +6,12 @@ use futures::Poll; pub struct CheckLogin; -impl Transform for CheckLogin +impl Transform for CheckLogin where - S: Service, Response = ServiceResponse>, + S: Service>, S::Future: 'static, { - type Request = ServiceRequest

; + type Request = ServiceRequest; type Response = ServiceResponse; type Error = S::Error; type InitError = (); @@ -26,12 +26,12 @@ pub struct CheckLoginMiddleware { service: S, } -impl Service for CheckLoginMiddleware +impl Service for CheckLoginMiddleware where - S: Service, Response = ServiceResponse>, + S: Service>, S::Future: 'static, { - type Request = ServiceRequest

; + type Request = ServiceRequest; type Response = ServiceResponse; type Error = S::Error; type Future = Either>; @@ -40,7 +40,7 @@ where self.service.poll_ready() } - fn call(&mut self, req: ServiceRequest

) -> Self::Future { + fn call(&mut self, req: ServiceRequest) -> Self::Future { // We only need to hook into the `start` for this middleware. let is_logged_in = false; // Change this to see the change in outcome in the browser diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index 68f6e143..277257e4 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -11,16 +11,15 @@ pub struct SayHi; // Middleware factory is `Transform` trait from actix-service crate // `S` - type of the next service -// `P` - type of request's payload // `B` - type of response's body -impl Transform for SayHi +impl Transform for SayHi where - S: Service, Response = ServiceResponse>, + S: Service>, S::Future: 'static, S::Error: 'static, B: 'static, { - type Request = ServiceRequest

; + type Request = ServiceRequest; type Response = ServiceResponse; type Error = S::Error; type InitError = (); @@ -36,14 +35,14 @@ pub struct SayHiMiddleware { service: S, } -impl Service for SayHiMiddleware +impl Service for SayHiMiddleware where - S: Service, Response = ServiceResponse>, + S: Service>, S::Future: 'static, S::Error: 'static, B: 'static, { - type Request = ServiceRequest

; + type Request = ServiceRequest; type Response = ServiceResponse; type Error = S::Error; type Future = Box>; @@ -52,7 +51,7 @@ where self.service.poll_ready() } - fn call(&mut self, req: ServiceRequest

) -> Self::Future { + fn call(&mut self, req: ServiceRequest) -> Self::Future { println!("Hi from start. You requested: {}", req.path()); Box::new(self.service.call(req).and_then(|res| { diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 7c859b14..5505af8e 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -1,8 +1,8 @@ use std::cell::Cell; -use std::fs::{self}; +use std::fs; use std::io::Write; -use actix_multipart::{Field, Item, Multipart, MultipartError}; +use actix_multipart::{Field, Multipart, MultipartError}; use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; use futures::future::{err, Either}; use futures::{Future, Stream}; @@ -15,7 +15,7 @@ pub fn save_file(field: Field) -> impl Future { let file_path_string = "upload.png"; let mut file = match fs::File::create(file_path_string) { Ok(file) => file, - Err(e) => return Either::A(err(error::ErrorInternalServerError(e))) + Err(e) => return Either::A(err(error::ErrorInternalServerError(e))), }; Either::B( field @@ -34,17 +34,6 @@ pub fn save_file(field: Field) -> impl Future { ) } -pub fn handle_multipart_item(item: Item) -> Box> { - match item { - Item::Field(field) => Box::new(save_file(field).into_stream()), - Item::Nested(mp) => Box::new( - mp.map_err(error::ErrorInternalServerError) - .map(handle_multipart_item) - .flatten(), - ), - } -} - pub fn upload( multipart: Multipart, counter: web::Data>, @@ -54,7 +43,7 @@ pub fn upload( multipart .map_err(error::ErrorInternalServerError) - .map(handle_multipart_item) + .map(|field| save_file(field).into_stream()) .flatten() .collect() .map(|sizes| HttpResponse::Ok().json(sizes)) diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 0a433e5a..444063a6 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -46,11 +46,12 @@ impl Handler for DbExecutor { // simple aliasing makes the intentions clear and its more readable pub type LoggedUser = SlimUser; -impl

FromRequest

for LoggedUser { +impl FromRequest for LoggedUser { + type Config = (); type Error = Error; type Future = Result; - fn from_request(req: &HttpRequest, pl: &mut Payload

) -> Self::Future { + fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future { if let Some(identity) = Identity::from_request(req, pl)?.identity() { let user: SlimUser = decode_token(&identity)?; return Ok(user as LoggedUser); From 8371d77f7c06fa59efe74e5ba3f250e02d8ad214 Mon Sep 17 00:00:00 2001 From: mohanson Date: Mon, 15 Apr 2019 10:05:22 +0800 Subject: [PATCH 051/111] Add jsonrpc example --- Cargo.toml | 1 + jsonrpc/Cargo.toml | 17 +++++ jsonrpc/README.md | 34 +++++++++ jsonrpc/src/convention.rs | 137 +++++++++++++++++++++++++++++++++ jsonrpc/src/main.rs | 143 +++++++++++++++++++++++++++++++++++ jsonrpc/tests/test_client.py | 38 ++++++++++ 6 files changed, 370 insertions(+) create mode 100644 jsonrpc/Cargo.toml create mode 100644 jsonrpc/README.md create mode 100644 jsonrpc/src/convention.rs create mode 100644 jsonrpc/src/main.rs create mode 100644 jsonrpc/tests/test_client.py diff --git a/Cargo.toml b/Cargo.toml index d6285920..14ad4224 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "http-proxy", "http-full-proxy", "json", + "jsonrpc", "juniper", "middleware", "multipart", diff --git a/jsonrpc/Cargo.toml b/jsonrpc/Cargo.toml new file mode 100644 index 00000000..65410619 --- /dev/null +++ b/jsonrpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "jsonrpc-example" +version = "0.1.0" +authors = ["mohanson "] +edition = "2018" +workspace = ".." + +[dependencies] +actix = "0.8.0-alpha.2" +actix-web = "1.0.0-alpha.4" +env_logger = "0.6" +futures = "0.1.23" +futures-timer = "0.1" +log = "0.4" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/jsonrpc/README.md b/jsonrpc/README.md new file mode 100644 index 00000000..35966663 --- /dev/null +++ b/jsonrpc/README.md @@ -0,0 +1,34 @@ +A simple demo for building a `JSONRPC over HTTP` server in [actix-web](https://github.com/actix/actix-web). + +# Server + +```sh +$ cargo run +# Starting server on 127.0.0.1:8080 +``` + +# Client + +**curl** + +```sh +$ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "ping", "params": [], "id": 1}' http://127.0.0.1:8080 +# {"jsonrpc":"2.0","result":"pong","error":null,"id":1} +``` + + +**python** + +```sh +$ python tests\test_client.py +# {'jsonrpc': '2.0', 'result': 'pong', 'error': None, 'id': 1} +``` + +# Methods + +- `ping`: Pong immeditely +- `pong`: Wait `n` seconds, and then pong +- `get`: Get global count +- `inc`: Increment global count + +See `tests\test_client.py` to get more information. diff --git a/jsonrpc/src/convention.rs b/jsonrpc/src/convention.rs new file mode 100644 index 00000000..300b826d --- /dev/null +++ b/jsonrpc/src/convention.rs @@ -0,0 +1,137 @@ +//! JSON-RPC 2.0 Specification +//! See: https://www.jsonrpc.org/specification +use std::error; +use std::fmt; + +use serde_derive::{Deserialize, Serialize}; +use serde_json::Value; + +pub static JSONRPC_VERSION: &str = "2.0"; + +/// When a rpc call encounters an error, the Response Object MUST contain the +/// error member with a value that is a Object with the following members: +#[derive(Debug, Serialize, Deserialize)] +pub struct ErrorData { + /// A Number that indicates the error type that occurred. This MUST be an integer. + pub code: i32, + + /// A String providing a short description of the error. The message SHOULD be + /// limited to a concise single sentence. + pub message: String, + + /// A Primitive or Structured value that contains additional information + /// about the error. This may be omitted. The value of this member is + /// defined by the Server (e.g. detailed error information, nested errors + /// etc.). + pub data: Value, +} + +impl ErrorData { + pub fn new(code: i32, message: &str) -> Self { + Self { + code, + message: String::from(message), + data: Value::Null, + } + } + + pub fn std(code: i32) -> Self { + match code { + // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. + -32700 => ErrorData::new(-32700, "Parse error"), + // The JSON sent is not a valid Request object. + -32600 => ErrorData::new(-32600, "Invalid Request"), + // The method does not exist / is not available. + -32601 => ErrorData::new(-32601, "Method not found"), + // Invalid method parameter(s). + -32602 => ErrorData::new(-32602, "Invalid params"), + // Internal JSON-RPC error. + -32603 => ErrorData::new(-32603, "Internal error"), + // The error codes from and including -32768 to -32000 are reserved for pre-defined errors. Any code within + // this range, but not defined explicitly below is reserved for future use. + _ => panic!("Undefined pre-defined error codes"), + } + } + + /// Prints out the value as JSON string. + pub fn dump(&self) -> String { + serde_json::to_string(self).expect("Should never failed") + } +} + +impl error::Error for ErrorData {} +impl fmt::Display for ErrorData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {})", self.code, self.message, self.data) + } +} + +/// A rpc call is represented by sending a Request object to a Server. +#[derive(Debug, Serialize, Deserialize)] +pub struct Request { + /// A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0". + pub jsonrpc: String, + + /// A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by + /// a period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be + /// used for anything else. + pub method: String, + + /// A Structured value that holds the parameter values to be used during the invocation of the method. This member + /// MAY be omitted. + pub params: Vec, + + /// An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is + /// not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD + /// NOT contain fractional parts. + pub id: Value, +} + +impl Request { + /// Prints out the value as JSON string. + pub fn dump(&self) -> String { + serde_json::to_string(self).expect("Should never failed") + } +} + +/// When a rpc call is made, the Server MUST reply with a Response, except for in the case of Notifications. The +/// Response is expressed as a single JSON Object, with the following members: +#[derive(Debug, Serialize, Deserialize)] +pub struct Response { + /// A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0". + pub jsonrpc: String, + + /// This member is REQUIRED on success. + /// This member MUST NOT exist if there was an error invoking the method. + /// The value of this member is determined by the method invoked on the Server. + pub result: Value, + + // This member is REQUIRED on error. + // This member MUST NOT exist if there was no error triggered during invocation. + // The value for this member MUST be an Object as defined in section 5.1. + pub error: Option, + + /// This member is REQUIRED. + /// It MUST be the same as the value of the id member in the Request Object. + /// If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), + /// it MUST be Null. + pub id: Value, +} + +impl Response { + /// Prints out the value as JSON string. + pub fn dump(&self) -> String { + serde_json::to_string(self).expect("Should never failed") + } +} + +impl Default for Response { + fn default() -> Self { + Self { + jsonrpc: JSONRPC_VERSION.into(), + result: Value::Null, + error: None, + id: Value::Null, + } + } +} diff --git a/jsonrpc/src/main.rs b/jsonrpc/src/main.rs new file mode 100644 index 00000000..08237762 --- /dev/null +++ b/jsonrpc/src/main.rs @@ -0,0 +1,143 @@ +use std::error; +use std::sync::Arc; +use std::sync::RwLock; +use std::time::Duration; + +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use futures::{future, Future, Stream}; +use futures_timer::Delay; +use serde_json; +use serde_json::Value; + +#[allow(dead_code)] +mod convention; + +/// The main handler for JSONRPC server. +fn rpc_handler( + req: HttpRequest, + payload: web::Payload, +) -> impl Future { + payload.concat2().from_err().and_then(move |body| { + let reqjson: convention::Request = match serde_json::from_slice(body.as_ref()) { + Ok(ok) => ok, + Err(_) => { + let r = convention::Response { + jsonrpc: String::from(convention::JSONRPC_VERSION), + result: Value::Null, + error: Some(convention::ErrorData::std(-32700)), + id: Value::Null, + }; + return Ok(HttpResponse::Ok() + .content_type("application/json") + .body(r.dump())); + } + }; + let app_state = req.app_data().unwrap(); + let mut result = convention::Response::default(); + result.id = reqjson.id.clone(); + + match rpc_select(&app_state, reqjson.method.as_str()) { + Ok(ok) => result.result = ok, + Err(e) => result.error = Some(e), + } + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(result.dump())) + }) +} + +fn rpc_select(app_state: &AppState, method: &str) -> Result { + match method { + "ping" => { + let r = app_state.network.read().unwrap().ping(); + Ok(Value::from(r)) + } + "wait" => match app_state.network.read().unwrap().wait(4).wait() { + Ok(ok) => Ok(Value::from(ok)), + Err(e) => Err(convention::ErrorData::new(500, &format!("{:?}", e)[..])), + }, + "get" => { + let r = app_state.network.read().unwrap().get(); + Ok(Value::from(r)) + } + "inc" => { + app_state.network.write().unwrap().inc(); + Ok(Value::Null) + } + _ => Err(convention::ErrorData::std(-32601)), + } +} + +pub trait ImplNetwork { + fn ping(&self) -> String; + fn wait(&self, d: u64) -> Box>>; + + fn get(&self) -> u32; + fn inc(&mut self); +} + +pub struct ObjNetwork { + c: u32, +} + +impl ObjNetwork { + fn new() -> Self { + Self { c: 0 } + } +} + +impl ImplNetwork for ObjNetwork { + fn ping(&self) -> String { + String::from("pong") + } + + fn wait(&self, d: u64) -> Box>> { + if let Err(e) = Delay::new(Duration::from_secs(d)).wait() { + let e: Box = Box::new(e); + return Box::new(future::err(e)); + }; + Box::new(future::ok(String::from("pong"))) + } + + fn get(&self) -> u32 { + self.c + } + + fn inc(&mut self) { + self.c += 1; + } +} + +#[derive(Clone)] +pub struct AppState { + network: Arc>, +} + +impl AppState { + pub fn new(network: Arc>) -> Self { + Self { network } + } +} + +fn main() { + std::env::set_var("RUST_LOG", "info"); + env_logger::init(); + + let network = Arc::new(RwLock::new(ObjNetwork::new())); + + let sys = actix::System::new("actix_jrpc"); + HttpServer::new(move || { + let app_state = AppState::new(network.clone()); + App::new() + .data(app_state) + .wrap(middleware::Logger::default()) + .service(web::resource("/").route(web::post().to_async(rpc_handler))) + }) + .bind("127.0.0.1:8080") + .unwrap() + .workers(1) + .start(); + + let _ = sys.run(); +} diff --git a/jsonrpc/tests/test_client.py b/jsonrpc/tests/test_client.py new file mode 100644 index 00000000..1df92bbd --- /dev/null +++ b/jsonrpc/tests/test_client.py @@ -0,0 +1,38 @@ +import requests + +print('ping: pong immediately') +r = requests.post('http://127.0.0.1:8080/', json={ + 'jsonrpc': '2.0', + 'method': 'ping', + 'params': [], + 'id': 1 +}) +print(r.json()) + + +print('ping: pong after 4 secs') +r = requests.post('http://127.0.0.1:8080/', json={ + 'jsonrpc': '2.0', + 'method': 'wait', + 'params': [4], + 'id': 1 +}) +print(r.json()) + +for i in range(10): + print(f'inc {i:>02}') + r = requests.post('http://127.0.0.1:8080/', json={ + 'jsonrpc': '2.0', + 'method': 'inc', + 'params': [], + 'id': 1 + }) + +print(f'get') +r = requests.post('http://127.0.0.1:8080/', json={ + 'jsonrpc': '2.0', + 'method': 'get', + 'params': [], + 'id': 1 +}) +print(r.json()) From 397b8e22fa8999e1a415530af040d2eac9aa6bc9 Mon Sep 17 00:00:00 2001 From: mohanson Date: Mon, 15 Apr 2019 10:27:25 +0800 Subject: [PATCH 052/111] Fix an error in method `wait` --- jsonrpc/src/main.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/jsonrpc/src/main.rs b/jsonrpc/src/main.rs index 08237762..18ba5545 100644 --- a/jsonrpc/src/main.rs +++ b/jsonrpc/src/main.rs @@ -36,7 +36,7 @@ fn rpc_handler( let mut result = convention::Response::default(); result.id = reqjson.id.clone(); - match rpc_select(&app_state, reqjson.method.as_str()) { + match rpc_select(&app_state, reqjson.method.as_str(), reqjson.params) { Ok(ok) => result.result = ok, Err(e) => result.error = Some(e), } @@ -47,16 +47,31 @@ fn rpc_handler( }) } -fn rpc_select(app_state: &AppState, method: &str) -> Result { +fn rpc_select( + app_state: &AppState, + method: &str, + params: Vec, +) -> Result { match method { "ping" => { let r = app_state.network.read().unwrap().ping(); Ok(Value::from(r)) } - "wait" => match app_state.network.read().unwrap().wait(4).wait() { - Ok(ok) => Ok(Value::from(ok)), - Err(e) => Err(convention::ErrorData::new(500, &format!("{:?}", e)[..])), - }, + "wait" => { + if params.len() != 1 || !params[0].is_u64() { + return Err(convention::ErrorData::std(-32602)); + } + match app_state + .network + .read() + .unwrap() + .wait(params[0].as_u64().unwrap()) + .wait() + { + Ok(ok) => Ok(Value::from(ok)), + Err(e) => Err(convention::ErrorData::new(500, &format!("{:?}", e)[..])), + } + } "get" => { let r = app_state.network.read().unwrap().get(); Ok(Value::from(r)) From 15833104ef6a638254d8b76b297ec6b8fb4b424a Mon Sep 17 00:00:00 2001 From: Mohanson Date: Mon, 15 Apr 2019 14:16:38 +0800 Subject: [PATCH 053/111] Update README.md --- jsonrpc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonrpc/README.md b/jsonrpc/README.md index 35966663..b9a4ceac 100644 --- a/jsonrpc/README.md +++ b/jsonrpc/README.md @@ -27,7 +27,7 @@ $ python tests\test_client.py # Methods - `ping`: Pong immeditely -- `pong`: Wait `n` seconds, and then pong +- `wait`: Wait `n` seconds, and then pong - `get`: Get global count - `inc`: Increment global count From 28d008e97c32381e18dfa029227690d58ab4ca82 Mon Sep 17 00:00:00 2001 From: nathaniel Date: Mon, 15 Apr 2019 10:02:57 -0500 Subject: [PATCH 054/111] clarify use of sleep in async_db --- async_db/src/db.rs | 8 ++++---- async_db/src/main.rs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/async_db/src/db.rs b/async_db/src/db.rs index 4ca80daf..1a0f8658 100644 --- a/async_db/src/db.rs +++ b/async_db/src/db.rs @@ -58,7 +58,7 @@ fn get_hottest_years(conn: Connection) -> Result, Error> { .collect::>()) })?; - sleep(Duration::from_secs(2)); + sleep(Duration::from_secs(2)); //see comments at top of main.rs Ok(annuals) } @@ -84,7 +84,7 @@ fn get_coldest_years(conn: Connection) -> Result, Error> { .collect::>()) })?; - sleep(Duration::from_secs(2)); + sleep(Duration::from_secs(2)); //see comments at top of main.rs Ok(annuals) } @@ -111,7 +111,7 @@ fn get_hottest_months(conn: Connection) -> Result, Error> { .collect::>()) })?; - sleep(Duration::from_secs(2)); + sleep(Duration::from_secs(2)); //see comments at top of main.rs Ok(annuals) } @@ -137,6 +137,6 @@ fn get_coldest_months(conn: Connection) -> Result, Error> { .collect::>()) })?; - sleep(Duration::from_secs(2)); + sleep(Duration::from_secs(2)); //see comments at top of main.rs Ok(annuals) } diff --git a/async_db/src/main.rs b/async_db/src/main.rs index b2293fed..99cc6f8d 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -8,6 +8,8 @@ This project illustrates two examples: 2. An asynchronous handler that executes 4 queries in *parallel*, collecting the results and returning them as a single serialized json object + Note: The use of sleep(Duration::from_secs(2)); in db.rs is to make performance + improvement with parallelism more obvious. */ use std::io; From bc2b17602e45e93e56e2d2f6b7f443a16c73d34e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 16 Apr 2019 15:03:11 -0700 Subject: [PATCH 055/111] fix proxy example --- http-full-proxy/src/main.rs | 19 +++++-------------- template_yarte/Cargo.toml | 4 ++-- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 2d7a8426..9b137bba 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -16,20 +16,11 @@ fn forward( new_url.set_query(req.uri().query()); let forwarded_req = client.request_from(new_url.as_str(), req.head()); - - // if let Some(addr) = req.peer_addr() { - // match forwarded_req.headers_mut().entry("x-forwarded-for") { - // Ok(http::header::Entry::Vacant(entry)) => { - // let addr = format!("{}", addr.ip()); - // entry.insert(addr.parse().unwrap()); - // } - // Ok(http::header::Entry::Occupied(mut entry)) => { - // let addr = format!("{}, {}", entry.get().to_str().unwrap(), addr.ip()); - // entry.insert(addr.parse().unwrap()); - // } - // _ => unreachable!(), - // } - // } + let forwarded_req = if let Some(addr) = req.head().peer_addr { + forwarded_req.header("x-forwarded-for", format!("{}", addr.ip())) + } else { + forwarded_req + }; forwarded_req .send_stream(payload) diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index f7645bc8..24eba8ec 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -19,5 +19,5 @@ yarte = { version = "0.2", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" -actix-http-test = "0.1.0-alpha.3" -actix-http = "0.1.0-alpha.4" +actix-http-test = "0.1.0" +actix-http = "0.1.0" From 52811611d0c4ded08bfecb5410b227affae18f56 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 21 Apr 2019 09:36:31 -0700 Subject: [PATCH 056/111] update to beta.1 --- async_db/src/main.rs | 2 +- async_ex2/Cargo.toml | 2 +- async_ex2/src/appconfig.rs | 2 +- multipart/src/main.rs | 29 +++++++++++++++++++++-------- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/async_db/src/main.rs b/async_db/src/main.rs index 99cc6f8d..78ab4cc7 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -8,7 +8,7 @@ This project illustrates two examples: 2. An asynchronous handler that executes 4 queries in *parallel*, collecting the results and returning them as a single serialized json object - Note: The use of sleep(Duration::from_secs(2)); in db.rs is to make performance + Note: The use of sleep(Duration::from_secs(2)); in db.rs is to make performance improvement with parallelism more obvious. */ use std::io; diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml index ace032b8..2cf14aa0 100644 --- a/async_ex2/Cargo.toml +++ b/async_ex2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2.2" -actix-web = { version="1.0.0-alpha.4", features=["ssl"] } +actix-web = { version="1.0.0-beta.1", features=["ssl"] } actix-multipart = { git="https://github.com/actix/actix-web.git" } bytes = "0.4.12" env_logger = "0.6.1" diff --git a/async_ex2/src/appconfig.rs b/async_ex2/src/appconfig.rs index e38629a6..9393e129 100644 --- a/async_ex2/src/appconfig.rs +++ b/async_ex2/src/appconfig.rs @@ -2,7 +2,7 @@ use actix_web::{error, web}; use crate::handlers::{parts, products}; -pub fn config_app(cfg: &mut web::RouterConfig) { +pub fn config_app(cfg: &mut web::ServiceConfig) { // domain includes: /products/{product_id}/parts/{part_id} cfg.service( web::scope("/products") diff --git a/multipart/src/main.rs b/multipart/src/main.rs index 5505af8e..aa3c8b97 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -13,20 +13,33 @@ pub struct AppState { pub fn save_file(field: Field) -> impl Future { let file_path_string = "upload.png"; - let mut file = match fs::File::create(file_path_string) { + let file = match fs::File::create(file_path_string) { Ok(file) => file, Err(e) => return Either::A(err(error::ErrorInternalServerError(e))), }; Either::B( field - .fold(0i64, move |acc, bytes| { - file.write_all(bytes.as_ref()) - .map(|_| acc + bytes.len() as i64) - .map_err(|e| { - println!("file.write_all failed: {:?}", e); - MultipartError::Payload(error::PayloadError::Io(e)) - }) + .fold((file, 0i64), move |(mut file, mut acc), bytes| { + // fs operations are blocking, we have to execute writes + // on threadpool + web::block(move || { + acc += file + .write_all(bytes.as_ref()) + .map(|_| acc + bytes.len() as i64) + .map_err(|e| { + println!("file.write_all failed: {:?}", e); + MultipartError::Payload(error::PayloadError::Io(e)) + })?; + Ok((file, acc)) + }) + .map_err(|e: error::BlockingError| { + match e { + error::BlockingError::Error(e) => e, + error::BlockingError::Canceled => MultipartError::Incomplete, + } + }) }) + .map(|(_, acc)| acc) .map_err(|e| { println!("save_file failed, {:?}", e); error::ErrorInternalServerError(e) From 3058f53bacff01f5e5a67936a6eba0f7fa7b39d6 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 21 Apr 2019 09:37:29 -0700 Subject: [PATCH 057/111] update simple-auth example --- simple-auth-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index cebfcd04..9fd7c440 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -65,7 +65,7 @@ fn main() -> std::io::Result<()> { .name("auth") .path("/") .domain(domain.as_str()) - .max_age(Duration::days(1)) + .max_age_time(Duration::days(1)) .secure(false), // this can only be true if you have https )) // everything under '/api/' route From f073d9029f985a1466703c35835cdff18d025ad9 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 21 Apr 2019 17:08:16 -0700 Subject: [PATCH 058/111] use actix-multipart 0.1.0-beta.1 --- async_ex2/Cargo.toml | 4 ++-- multipart/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml index 2cf14aa0..6a0f0a4e 100644 --- a/async_ex2/Cargo.toml +++ b/async_ex2/Cargo.toml @@ -8,7 +8,8 @@ workspace = ".." [dependencies] actix-rt = "0.2.2" actix-web = { version="1.0.0-beta.1", features=["ssl"] } -actix-multipart = { git="https://github.com/actix/actix-web.git" } +actix-multipart = "0.1.0-beta.1" +actix-service = "0.3.6" bytes = "0.4.12" env_logger = "0.6.1" futures = "0.1" @@ -18,4 +19,3 @@ serde_json = "1.0.39" time = "0.1.42" validator = "0.8.0" validator_derive = "0.8.0" -actix-service = "0.3.6" diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index a6223938..256683d1 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,8 +10,8 @@ name = "multipart" path = "src/main.rs" [dependencies] -actix-web = "1.0.0-alpha.4" -actix-multipart = { git="https://github.com/actix/actix-web.git" } +actix-web = "1.0.0-beta.1" +actix-multipart = "0.1.0-beta.1" env_logger = "0.6" futures = "0.1.25" From 982ec7bb2f249460fe5a0239918df90b7efb367c Mon Sep 17 00:00:00 2001 From: Sylvain Kerkour Date: Mon, 22 Apr 2019 15:10:25 +0200 Subject: [PATCH 059/111] multipart: fix size result calculation --- multipart/src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/multipart/src/main.rs b/multipart/src/main.rs index aa3c8b97..da7b929a 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -23,13 +23,12 @@ pub fn save_file(field: Field) -> impl Future { // fs operations are blocking, we have to execute writes // on threadpool web::block(move || { - acc += file - .write_all(bytes.as_ref()) - .map(|_| acc + bytes.len() as i64) + file.write_all(bytes.as_ref()) .map_err(|e| { println!("file.write_all failed: {:?}", e); MultipartError::Payload(error::PayloadError::Io(e)) })?; + acc += bytes.len() as i64; Ok((file, acc)) }) .map_err(|e: error::BlockingError| { From 0445615e59872d344a118b830167b595206817e9 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 23 Apr 2019 11:23:46 -0700 Subject: [PATCH 060/111] update jsonwebtoken --- simple-auth-server/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index fe59c1ff..54d2a5e4 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" workspace = ".." [dependencies] -actix = { version = "0.8.0-alpha.2", features = ["http"] } +actix = { version = "0.8.1", features = ["http"] } actix-rt = "0.2.2" -actix-web = "1.0.0-alpha.4" -actix-files = "0.1.0-alpha.4" +actix-web = "1.0.0-beta.1" +actix-files = "0.1.0-beta.1" bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } @@ -17,7 +17,7 @@ diesel = { version = "1.3.3", features = ["postgres", "uuid", "r2d2", "chrono"] dotenv = "0.13.0" derive_more = "0.14" env_logger = "0.6.0" -jsonwebtoken = { git = "https://github.com/Keats/jsonwebtoken.git", branch = "next" } +jsonwebtoken = "6.0.0" futures = "0.1.25" r2d2 = "0.8.3" serde_derive="1.0.80" From d571ee5abb921d15114e91158f3a48b2b6621285 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 25 Apr 2019 11:19:21 -0700 Subject: [PATCH 061/111] explicit Error for middlewares --- middleware/src/redirect.rs | 10 +++++----- middleware/src/simple.rs | 12 +++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/middleware/src/redirect.rs b/middleware/src/redirect.rs index 670caa4a..f5c0e61e 100644 --- a/middleware/src/redirect.rs +++ b/middleware/src/redirect.rs @@ -1,6 +1,6 @@ use actix_service::{Service, Transform}; use actix_web::dev::{ServiceRequest, ServiceResponse}; -use actix_web::{http, HttpResponse}; +use actix_web::{http, Error, HttpResponse}; use futures::future::{ok, Either, FutureResult}; use futures::Poll; @@ -8,12 +8,12 @@ pub struct CheckLogin; impl Transform for CheckLogin where - S: Service>, + S: Service, Error = Error>, S::Future: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; - type Error = S::Error; + type Error = Error; type InitError = (); type Transform = CheckLoginMiddleware; type Future = FutureResult; @@ -28,12 +28,12 @@ pub struct CheckLoginMiddleware { impl Service for CheckLoginMiddleware where - S: Service>, + S: Service, Error = Error>, S::Future: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; - type Error = S::Error; + type Error = Error; type Future = Either>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index 277257e4..faf04cfb 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -1,5 +1,5 @@ use actix_service::{Service, Transform}; -use actix_web::dev::{ServiceRequest, ServiceResponse}; +use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error}; use futures::future::{ok, FutureResult}; use futures::{Future, Poll}; @@ -14,14 +14,13 @@ pub struct SayHi; // `B` - type of response's body impl Transform for SayHi where - S: Service>, + S: Service, Error = Error>, S::Future: 'static, - S::Error: 'static, B: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; - type Error = S::Error; + type Error = Error; type InitError = (); type Transform = SayHiMiddleware; type Future = FutureResult; @@ -37,14 +36,13 @@ pub struct SayHiMiddleware { impl Service for SayHiMiddleware where - S: Service>, + S: Service, Error = Error>, S::Future: 'static, - S::Error: 'static, B: 'static, { type Request = ServiceRequest; type Response = ServiceResponse; - type Error = S::Error; + type Error = Error; type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { From 8de183768c6297f77e741e0fe8adb968a1c74375 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 4 May 2019 21:52:24 -0700 Subject: [PATCH 062/111] upgrade to beta3 --- actix_redis/Cargo.toml | 4 ++-- actix_todo/Cargo.toml | 6 +++--- async_db/Cargo.toml | 2 +- basics/Cargo.toml | 6 +++--- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 ++-- diesel/Cargo.toml | 2 +- diesel/src/main.rs | 30 ++++++++++++++---------------- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- json/src/main.rs | 17 +++++------------ jsonrpc/Cargo.toml | 4 ++-- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 2 +- multipart/Cargo.toml | 2 +- multipart/src/main.rs | 9 ++++----- protobuf/Cargo.toml | 2 +- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 6 +++--- simple-auth-server/Cargo.toml | 2 +- state/Cargo.toml | 2 +- static_index/Cargo.toml | 4 ++-- template_askama/Cargo.toml | 2 +- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 8 ++++---- websocket-tcp-chat/Cargo.toml | 6 +++--- websocket/Cargo.toml | 6 +++--- 33 files changed, 70 insertions(+), 80 deletions(-) diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index 7229262f..bbc6f438 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 6e3acb91..3fae6884 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" -actix-files = "0.1.0-alpha.4" -actix-session = "0.1.0-alpha.4" +actix-web = "1.0.0-beta.3" +actix-files = "0.1.0-beta.1" +actix-session = "0.1.0-beta.2" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 8063ead8..3c73fc49 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" dotenv = "0.10" env_logger = "0.5" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index e16db24a..2a27e7c6 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.4" -actix-files = "0.1.0-alpha.4" -actix-session = "0.1.0-alpha.4" +actix-web = "1.0.0-beta.3" +actix-files = "0.1.0-beta.1" +actix-session = "0.1.0-beta.2" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index 66d02b61..34897fd8 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 2a76fa63..ed47386c 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" -actix-session = "0.1.0-alpha.4" +actix-web = "1.0.0-beta.3" +actix-session = "0.1.0-beta.2" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 5c534ced..47237609 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" bytes = "0.4" env_logger = "0.6" diff --git a/diesel/src/main.rs b/diesel/src/main.rs index fdf3cbc4..80dbc8b4 100644 --- a/diesel/src/main.rs +++ b/diesel/src/main.rs @@ -137,22 +137,20 @@ fn main() -> std::io::Result<()> { // Use of the extractors makes some post conditions simpler such // as size limit protections and built in json validation. .service( - web::resource("/add2").route( - web::post() - .data( - web::JsonConfig::default() - .limit(4096) // <- limit size of the payload - .error_handler(|err, _| { - // <- create custom error response - error::InternalError::from_response( - err, - HttpResponse::Conflict().finish(), - ) - .into() - }), - ) - .to_async(add2), - ), + web::resource("/add2") + .data( + web::JsonConfig::default() + .limit(4096) // <- limit size of the payload + .error_handler(|err, _| { + // <- create custom error response + error::InternalError::from_response( + err, + HttpResponse::Conflict().finish(), + ) + .into() + }), + ) + .route(web::post().to_async(add2)), ) // Manual parsing would allow custom error construction, use of // other parsers *beside* json (for example CBOR, protobuf, xml), and allows diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index 9e0b003f..ef3c168f 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index 1f983684..c2fdcbfa 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 733faa54..8176a1fc 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index 5e7f4f75..21383f37 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.5" +actix-web = "1.0.0-beta.3" clap = "2.32.0" futures = "0.1.25" diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 9afc29ea..5cb4a0e2 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index eab6ddb7..207cc609 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" bytes = "0.4" futures = "0.1" diff --git a/json/src/main.rs b/json/src/main.rs index 9b0d9a57..86f2a242 100644 --- a/json/src/main.rs +++ b/json/src/main.rs @@ -83,19 +83,12 @@ fn main() -> std::io::Result<()> { App::new() // enable logger .wrap(middleware::Logger::default()) + .data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload (global configuration) + .service(web::resource("/extractor").route(web::post().to(index))) .service( - web::resource("/extractor").route( - web::post() - .data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload - .to(index), - ), - ) - .service( - web::resource("/extractor2").route( - web::post() - .data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload - .to_async(extract_item), - ), + web::resource("/extractor2") + .data(web::JsonConfig::default().limit(1024)) // <- limit size of the payload (resource level) + .route(web::post().to_async(extract_item)), ) .service(web::resource("/manual").route(web::post().to_async(index_manual))) .service( diff --git a/jsonrpc/Cargo.toml b/jsonrpc/Cargo.toml index 65410619..720f44a7 100644 --- a/jsonrpc/Cargo.toml +++ b/jsonrpc/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" env_logger = "0.6" futures = "0.1.23" futures-timer = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 71f410ca..54c82588 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index e6d9cc3a..b17594fd 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -7,6 +7,6 @@ workspace = ".." [dependencies] actix-service = "0.3.6" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 256683d1..5fc3e2a8 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,7 +10,7 @@ name = "multipart" path = "src/main.rs" [dependencies] -actix-web = "1.0.0-beta.1" +actix-web = "1.0.0-beta.3" actix-multipart = "0.1.0-beta.1" env_logger = "0.6" diff --git a/multipart/src/main.rs b/multipart/src/main.rs index da7b929a..791b7941 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -23,11 +23,10 @@ pub fn save_file(field: Field) -> impl Future { // fs operations are blocking, we have to execute writes // on threadpool web::block(move || { - file.write_all(bytes.as_ref()) - .map_err(|e| { - println!("file.write_all failed: {:?}", e); - MultipartError::Payload(error::PayloadError::Io(e)) - })?; + file.write_all(bytes.as_ref()).map_err(|e| { + println!("file.write_all failed: {:?}", e); + MultipartError::Payload(error::PayloadError::Io(e)) + })?; acc += bytes.len() as i64; Ok((file, acc)) }) diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index a20640b0..c80df979 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -13,4 +13,4 @@ derive_more = "0.14" prost = "0.2.0" prost-derive = "0.2.0" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index 86e70e3f..f869e4e5 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index fc347f8f..19ac65aa 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" -actix-session = "0.1.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" +actix-session = "0.1.0-beta.2" actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } env_logger = "0.6" diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 54d2a5e4..ec815e94 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -8,7 +8,7 @@ workspace = ".." [dependencies] actix = { version = "0.8.1", features = ["http"] } actix-rt = "0.2.2" -actix-web = "1.0.0-beta.1" +actix-web = "1.0.0-beta.3" actix-files = "0.1.0-beta.1" bcrypt = "0.2.1" diff --git a/state/Cargo.toml b/state/Cargo.toml index 894d49d6..b0be5565 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" futures = "0.1.25" env_logger = "0.6" diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index 196e112d..a5153402 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = "1.0.0-alpha.4" -actix-files = "0.1.0-alpha.4" +actix-web = "1.0.0-beta.3" +actix-files = "0.1.0-beta.1" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 09fc9e81..8cecb147 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" env_logger = "0.6" askama = "0.8" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index 700f4f8a..5c00ba1d 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "0.11" -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 24eba8ec..81d5e9cb 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -12,7 +12,7 @@ env_logger = "0.6" yarte = { version = "0.2", features=["with-actix-web"] } -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" [build-dependencies] yarte = { version = "0.2", features=["with-actix-web"] } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index 19309063..39e779e4 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../../" edition = "2018" [dependencies] -actix-web = "1.0.0-alpha.4" +actix-web = "1.0.0-beta.3" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index e59f220a..fe62f8b7 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -10,10 +10,10 @@ name = "websocket-chat-server" path = "src/main.rs" [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" -actix-web-actors = "1.0.0-alpha.2" -actix-files = "0.1.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" +actix-web-actors = "1.0.0-alpha.3" +actix-files = "0.1.0-beta.1" rand = "0.6" bytes = "0.4" diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index b812bfa0..330357f6 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -14,10 +14,10 @@ name = "websocket-tcp-client" path = "src/client.rs" [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.4" +actix-files = "0.1.0-beta.1" rand = "0.6" bytes = "0.4" diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index 1c67978f..f4767c8e 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -14,10 +14,10 @@ path = "src/main.rs" #path = "src/client.rs" [dependencies] -actix = "0.8.0-alpha.2" -actix-web = "1.0.0-alpha.4" +actix = "0.8.1" +actix-web = "1.0.0-beta.3" actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-alpha.4" +actix-files = "0.1.0-beta.1" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file From 67bc0144bac3155a8cff3d1094e9402cc9953147 Mon Sep 17 00:00:00 2001 From: "huang.xiangdong" Date: Sun, 5 May 2019 15:42:50 +0800 Subject: [PATCH 063/111] fix return home link bug --- basics/static/404.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basics/static/404.html b/basics/static/404.html index c87e1d9f..2d8036c8 100644 --- a/basics/static/404.html +++ b/basics/static/404.html @@ -1,7 +1,7 @@ actix - basics - back to home + back to home

404

From 68509a7eaf4b382aa814d250c0db838c83a2834d Mon Sep 17 00:00:00 2001 From: "huang.xiangdong" Date: Mon, 6 May 2019 15:26:42 +0800 Subject: [PATCH 064/111] use absolute path --- basics/static/404.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basics/static/404.html b/basics/static/404.html index 2d8036c8..8b285668 100644 --- a/basics/static/404.html +++ b/basics/static/404.html @@ -1,7 +1,7 @@ actix - basics - back to home + back to home

404

From cee914225780c9102d8c4a95300702043a632083 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 12 May 2019 11:58:26 -0700 Subject: [PATCH 065/111] upgrade actix-web --- actix_redis/Cargo.toml | 2 +- actix_todo/Cargo.toml | 6 +++--- async_db/Cargo.toml | 2 +- async_ex2/Cargo.toml | 4 ++-- basics/Cargo.toml | 6 +++--- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 ++-- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-full-proxy/src/main.rs | 1 + http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- jsonrpc/Cargo.toml | 2 +- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 4 ++-- multipart/Cargo.toml | 4 ++-- protobuf/Cargo.toml | 2 +- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 4 ++-- rustls/Cargo.toml | 4 ++-- simple-auth-server/Cargo.toml | 4 ++-- state/Cargo.toml | 2 +- static_index/Cargo.toml | 4 ++-- template_askama/Cargo.toml | 2 +- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 6 +++--- tls/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 6 +++--- websocket-tcp-chat/Cargo.toml | 6 +++--- websocket/Cargo.toml | 6 +++--- 34 files changed, 54 insertions(+), 53 deletions(-) diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index bbc6f438..72140b66 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 3fae6884..f7b70adc 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" -actix-files = "0.1.0-beta.1" -actix-session = "0.1.0-beta.2" +actix-web = "1.0.0-beta.5" +actix-files = "0.1.0-beta.4" +actix-session = "0.1.0-beta.4" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 3c73fc49..16121158 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml index 6a0f0a4e..0d7dab09 100644 --- a/async_ex2/Cargo.toml +++ b/async_ex2/Cargo.toml @@ -7,9 +7,9 @@ workspace = ".." [dependencies] actix-rt = "0.2.2" -actix-web = { version="1.0.0-beta.1", features=["ssl"] } +actix-web = { version="1.0.0-beta.4", features=["ssl"] } actix-multipart = "0.1.0-beta.1" -actix-service = "0.3.6" +actix-service = "0.4.0" bytes = "0.4.12" env_logger = "0.6.1" futures = "0.1" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 2a27e7c6..6f200774 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.3" -actix-files = "0.1.0-beta.1" -actix-session = "0.1.0-beta.2" +actix-web = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" +actix-session = "0.1.0-beta.4" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index 34897fd8..8024c93d 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index ed47386c..0d926be8 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" -actix-session = "0.1.0-beta.2" +actix-web = "1.0.0-beta.4" +actix-session = "0.1.0-beta.4" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 47237609..3bc1e55b 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index ef3c168f..e892153f 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index c2fdcbfa..ed9467dc 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 8176a1fc..59ea15e8 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index 21383f37..a1939948 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" clap = "2.32.0" futures = "0.1.25" diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 9b137bba..68a7d815 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -87,6 +87,7 @@ fn main() -> std::io::Result<()> { HttpServer::new(move || { App::new() + .data(Client::new()) .data(forward_url.clone()) .wrap(middleware::Logger::default()) .default_service(web::route().to_async(forward)) diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 5cb4a0e2..718a346b 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index 207cc609..7375e334 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" bytes = "0.4" futures = "0.1" diff --git a/jsonrpc/Cargo.toml b/jsonrpc/Cargo.toml index 720f44a7..8b5978ba 100644 --- a/jsonrpc/Cargo.toml +++ b/jsonrpc/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.6" futures = "0.1.23" futures-timer = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 54c82588..0d6c0f79 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index b17594fd..8b9334f4 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-service = "0.3.6" -actix-web = "1.0.0-beta.3" +actix-service = "0.4.0" +actix-web = "1.0.0-beta.4" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 5fc3e2a8..4c909d41 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,8 +10,8 @@ name = "multipart" path = "src/main.rs" [dependencies] -actix-web = "1.0.0-beta.3" -actix-multipart = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-multipart = "0.1.0-beta.4" env_logger = "0.6" futures = "0.1.25" diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index c80df979..ed6c0c6b 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -13,4 +13,4 @@ derive_more = "0.14" prost = "0.2.0" prost-derive = "0.2.0" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index f869e4e5..f57cdf85 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 19ac65aa..6e1181a9 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" -actix-session = "0.1.0-beta.2" +actix-web = "1.0.0-beta.4" +actix-session = "0.1.0-beta.4" actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } env_logger = "0.6" diff --git a/rustls/Cargo.toml b/rustls/Cargo.toml index 6abb0157..33d04e5a 100644 --- a/rustls/Cargo.toml +++ b/rustls/Cargo.toml @@ -12,5 +12,5 @@ path = "src/main.rs" [dependencies] env_logger = "0.5" rustls = "0.15" -actix-web = { version = "1.0.0-alpha.4", features=["rust-tls"] } -actix-files = "0.1.0-alpha.4" +actix-web = { version = "1.0.0-beta.4", features=["rust-tls"] } +actix-files = "0.1.0-beta.4" diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index ec815e94..dab0dc5c 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -8,8 +8,8 @@ workspace = ".." [dependencies] actix = { version = "0.8.1", features = ["http"] } actix-rt = "0.2.2" -actix-web = "1.0.0-beta.3" -actix-files = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } diff --git a/state/Cargo.toml b/state/Cargo.toml index b0be5565..62e83ad2 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" futures = "0.1.25" env_logger = "0.6" diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index a5153402..bac404db 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = "1.0.0-beta.3" -actix-files = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 8cecb147..378098c5 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" env_logger = "0.6" askama = "0.8" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index 5c00ba1d..b49959ca 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "0.11" -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 81d5e9cb..0c31b1f3 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -12,12 +12,12 @@ env_logger = "0.6" yarte = { version = "0.2", features=["with-actix-web"] } -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" [build-dependencies] yarte = { version = "0.2", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" -actix-http-test = "0.1.0" -actix-http = "0.1.0" +actix-http-test = "0.2.0" +actix-http = "0.2.0" diff --git a/tls/Cargo.toml b/tls/Cargo.toml index 65302c68..7541ee45 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -11,6 +11,6 @@ path = "src/main.rs" [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.4", features=["ssl"] } +actix-web = { version="1.0.0-beta.4", features=["ssl"] } env_logger = "0.6" openssl = { version="0.10" } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index 39e779e4..9ca67022 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../../" edition = "2018" [dependencies] -actix-web = "1.0.0-beta.3" +actix-web = "1.0.0-beta.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index fe62f8b7..73b5866d 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -11,9 +11,9 @@ path = "src/main.rs" [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" -actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-web-actors = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" rand = "0.6" bytes = "0.4" diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index 330357f6..85755904 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -15,9 +15,9 @@ path = "src/client.rs" [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" -actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-web-actors = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" rand = "0.6" bytes = "0.4" diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index f4767c8e..89d64a80 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -15,9 +15,9 @@ path = "src/main.rs" [dependencies] actix = "0.8.1" -actix-web = "1.0.0-beta.3" -actix-web-actors = "1.0.0-alpha.3" -actix-files = "0.1.0-beta.1" +actix-web = "1.0.0-beta.4" +actix-web-actors = "1.0.0-beta.4" +actix-files = "0.1.0-beta.4" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file From e07bbfe01c843e8c01f29b2029266220e3eac1f1 Mon Sep 17 00:00:00 2001 From: zeljic Date: Sun, 12 May 2019 23:11:58 +0200 Subject: [PATCH 066/111] fix streaming issue in http-full-proxy example --- http-full-proxy/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 68a7d815..4ab76df8 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -32,7 +32,7 @@ fn forward( { client_resp.header(header_name.clone(), header_value.clone()); } - client_resp.streaming(res) + HttpResponse::Ok().streaming(res) }) } From e771c058151873e8f838f1c607041baa831a8c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90or=C4=91e=20Zelji=C4=87?= Date: Thu, 16 May 2019 00:03:08 +0200 Subject: [PATCH 067/111] Revert "fix streaming issue in http-full-proxy example" --- http-full-proxy/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 4ab76df8..68a7d815 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -32,7 +32,7 @@ fn forward( { client_resp.header(header_name.clone(), header_value.clone()); } - HttpResponse::Ok().streaming(res) + client_resp.streaming(res) }) } From fdf061610d6afd01af82848dc9f0961b94d7997b Mon Sep 17 00:00:00 2001 From: Stefan Puhlmann Date: Tue, 21 May 2019 22:09:27 +0200 Subject: [PATCH 068/111] Adapting protobuf example to use actix_protobuf --- protobuf/Cargo.toml | 8 +-- protobuf/client.py | 2 +- protobuf/src/main.rs | 42 ++++++++------- protobuf/src/protobuf.rs | 109 --------------------------------------- 4 files changed, 29 insertions(+), 132 deletions(-) delete mode 100644 protobuf/src/protobuf.rs diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index ed6c0c6b..1a401de5 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -10,7 +10,9 @@ bytes = "0.4" futures = "0.1" env_logger = "0.6" derive_more = "0.14" -prost = "0.2.0" -prost-derive = "0.2.0" +prost = "0.4.0" +prost-derive = "0.4.0" -actix-web = "1.0.0-beta.4" +actix = "0.8.1" +actix-web = "1.0.0-rc" +actix-protobuf = "0.4.0" diff --git a/protobuf/client.py b/protobuf/client.py index ab91365d..965f11b4 100644 --- a/protobuf/client.py +++ b/protobuf/client.py @@ -46,7 +46,7 @@ async def fetch(session): obj = test_pb2.MyObj() obj.number = 9 obj.name = 'USB' - async with session.post('http://localhost:8080/', data=obj.SerializeToString(), + async with session.post('http://localhost:8081/', data=obj.SerializeToString(), headers={"content-type": "application/protobuf"}) as resp: print(resp.status) data = await resp.read() diff --git a/protobuf/src/main.rs b/protobuf/src/main.rs index 043fb59d..56cbb35b 100644 --- a/protobuf/src/main.rs +++ b/protobuf/src/main.rs @@ -1,12 +1,16 @@ +extern crate actix; +extern crate actix_protobuf; +extern crate actix_web; +extern crate bytes; +extern crate env_logger; +extern crate prost; #[macro_use] extern crate prost_derive; -use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; -use futures::Future; -mod protobuf; -use protobuf::ProtoBufResponseBuilder; +use actix_protobuf::*; +use actix_web::*; -#[derive(Clone, Debug, PartialEq, Message)] +#[derive(Clone, PartialEq, Message)] pub struct MyObj { #[prost(int32, tag = "1")] pub number: i32, @@ -14,25 +18,25 @@ pub struct MyObj { pub name: String, } -/// This handler uses `ProtoBufMessage` for loading protobuf object. -fn index(pl: web::Payload) -> impl Future { - protobuf::ProtoBufMessage::new(pl) - .from_err() // convert all errors into `Error` - .and_then(|val: MyObj| { - println!("model: {:?}", val); - Ok(HttpResponse::Ok().protobuf(val)?) // <- send response - }) +fn index(msg: ProtoBuf) -> Result { + println!("model: {:?}", msg); + HttpResponse::Ok().protobuf(msg.0) // <- send response } -fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_web=info,actix_server=info"); +fn main() { + ::std::env::set_var("RUST_LOG", "actix_web=info,actix_server=info"); env_logger::init(); + let sys = actix::System::new("protobuf-example"); HttpServer::new(|| { App::new() .wrap(middleware::Logger::default()) - .service(web::resource("/").route(web::post().to_async(index))) - }) - .bind("127.0.0.1:8080")? - .run() + .service(web::resource("/").route(web::post().to(index))) + }).bind("127.0.0.1:8081") + .unwrap() + .shutdown_timeout(1) + .start(); + + println!("Started http server: 127.0.0.1:8081"); + let _ = sys.run(); } diff --git a/protobuf/src/protobuf.rs b/protobuf/src/protobuf.rs deleted file mode 100644 index edde6250..00000000 --- a/protobuf/src/protobuf.rs +++ /dev/null @@ -1,109 +0,0 @@ -use bytes::BytesMut; -use futures::{Future, Poll, Stream}; - -use bytes::{Bytes, IntoBuf}; -use derive_more::{Display, From}; -use prost::DecodeError as ProtoBufDecodeError; -use prost::EncodeError as ProtoBufEncodeError; -use prost::Message; - -use actix_web::dev::HttpResponseBuilder; -use actix_web::error::{Error, PayloadError, ResponseError}; -use actix_web::http::header::CONTENT_TYPE; -use actix_web::{HttpRequest, HttpResponse, Responder}; - -#[derive(Debug, Display, From)] -pub enum ProtoBufPayloadError { - /// Payload size is bigger than 256k - #[display(fmt = "Payload size is bigger than 256k")] - Overflow, - /// Content type error - #[display(fmt = "Content type error")] - ContentType, - /// Serialize error - #[display(fmt = "ProtoBud serialize error: {}", _0)] - Serialize(ProtoBufEncodeError), - /// Deserialize error - #[display(fmt = "ProtoBud deserialize error: {}", _0)] - Deserialize(ProtoBufDecodeError), - /// Payload error - #[display(fmt = "Error that occur during reading payload: {}", _0)] - Payload(PayloadError), -} - -impl ResponseError for ProtoBufPayloadError { - fn error_response(&self) -> HttpResponse { - match *self { - ProtoBufPayloadError::Overflow => HttpResponse::PayloadTooLarge().into(), - _ => HttpResponse::BadRequest().into(), - } - } -} - -#[derive(Debug)] -pub struct ProtoBuf(pub T); - -impl Responder for ProtoBuf { - type Error = Error; - type Future = Result; - - fn respond_to(self, _: &HttpRequest) -> Result { - let mut buf = Vec::new(); - self.0 - .encode(&mut buf) - .map_err(|e| Error::from(ProtoBufPayloadError::Serialize(e))) - .and_then(|()| { - Ok(HttpResponse::Ok() - .content_type("application/protobuf") - .body(buf) - .into()) - }) - } -} - -pub struct ProtoBufMessage { - fut: Box>, -} - -impl ProtoBufMessage { - /// Create `ProtoBufMessage` for request. - pub fn new(pl: S) -> Self - where - S: Stream + 'static, - { - let fut = pl - .map_err(|e| ProtoBufPayloadError::Payload(e)) - .fold(BytesMut::new(), move |mut body, chunk| { - body.extend_from_slice(&chunk); - Ok::<_, ProtoBufPayloadError>(body) - }) - .and_then(|body| Ok(::decode(&mut body.into_buf())?)); - - ProtoBufMessage { fut: Box::new(fut) } - } -} - -impl Future for ProtoBufMessage where { - type Item = U; - type Error = ProtoBufPayloadError; - - fn poll(&mut self) -> Poll { - self.fut.poll() - } -} - -pub trait ProtoBufResponseBuilder { - fn protobuf(&mut self, value: T) -> Result; -} - -impl ProtoBufResponseBuilder for HttpResponseBuilder { - fn protobuf(&mut self, value: T) -> Result { - self.header(CONTENT_TYPE, "application/protobuf"); - - let mut body = Vec::new(); - value - .encode(&mut body) - .map_err(|e| ProtoBufPayloadError::Serialize(e))?; - Ok(self.body(body)) - } -} From 25f7ce87b4b1fe76754f20c4fa68166e0f457210 Mon Sep 17 00:00:00 2001 From: Stefano Probst Date: Fri, 24 May 2019 20:34:08 +0200 Subject: [PATCH 069/111] Fix bug in database script Fix error that occurs if script is used like in the async_db readme. Error before this change: ``` bash $ LANG=C bash db/setup_db.sh db/setup_db.sh: line 2: db.sql: No such file or directory Error: cannot open "nyc_centralpark_weather.csv ``` --- async_db/db/setup_db.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/async_db/db/setup_db.sh b/async_db/db/setup_db.sh index 41b73f89..1d5abb02 100755 --- a/async_db/db/setup_db.sh +++ b/async_db/db/setup_db.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash -sqlite3 weather.db < db.sql -sqlite3 -csv weather.db ".import nyc_centralpark_weather.csv nyc_weather" +cd $(dirname "$0") +sqlite3 ../weather.db < db.sql +sqlite3 -csv ../weather.db ".import nyc_centralpark_weather.csv nyc_weather" From 511ab8ce5159bb21ccf39b74d404242eca900bb5 Mon Sep 17 00:00:00 2001 From: blackjune Date: Sat, 25 May 2019 22:22:43 +0800 Subject: [PATCH 070/111] Fix bug in state type Fix bug in state type ```rust let counter = Arc::new(Mutex::new(0)); ``` may not be usize Error before this change: ``` App data is not configured, to configure use App::data() ``` --- state/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/src/main.rs b/state/src/main.rs index 3ebb38a9..a11d5da2 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -28,7 +28,7 @@ fn main() -> io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let counter = Arc::new(Mutex::new(0)); + let counter = Arc::new(Mutex::new(0usize)); //move is necessary to give closure below ownership of counter HttpServer::new(move || { From 4e3a42d77d23ac59b58b6e0d17efd12c61a06c9d Mon Sep 17 00:00:00 2001 From: dowwie Date: Sat, 1 Jun 2019 09:24:54 -0400 Subject: [PATCH 071/111] changed order of logging middleware, which must register last --- basics/src/main.rs | 4 ++-- cookie-auth/src/main.rs | 2 +- redis-session/src/main.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/basics/src/main.rs b/basics/src/main.rs index 5d74e3d9..b7406f99 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -82,10 +82,10 @@ fn main() -> io::Result<()> { HttpServer::new(|| { App::new() - // enable logger - .wrap(middleware::Logger::default()) // cookie session middleware .wrap(CookieSession::signed(&[0; 32]).secure(false)) + // enable logger + .wrap(middleware::Logger::default()) // register favicon .service(favicon) // register simple route, handle all methods diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 9d1f8577..2e428014 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -22,12 +22,12 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - .wrap(middleware::Logger::default()) .wrap(IdentityService::new( CookieIdentityPolicy::new(&[0; 32]) .name("auth-example") .secure(false), )) + .wrap(middleware::Logger::default()) .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/logout").to(logout)) .service(web::resource("/").route(web::get().to(index))) diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 0c49c6bf..2705866f 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -26,10 +26,10 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - // enable logger - .wrap(middleware::Logger::default()) // redis session middleware .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) + // enable logger + .wrap(middleware::Logger::default()) // register simple route, handle all methods .service(web::resource("/").to(index)) }) From a8b49dfaec0c2e28fb486d50164ecdece93cc1ac Mon Sep 17 00:00:00 2001 From: dowwie Date: Sat, 1 Jun 2019 09:27:34 -0400 Subject: [PATCH 072/111] updated code comment about log middleware --- basics/src/main.rs | 2 +- cookie-auth/src/main.rs | 1 + redis-session/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/basics/src/main.rs b/basics/src/main.rs index b7406f99..7a4edcb1 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -84,7 +84,7 @@ fn main() -> io::Result<()> { App::new() // cookie session middleware .wrap(CookieSession::signed(&[0; 32]).secure(false)) - // enable logger + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) // register favicon .service(favicon) diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 2e428014..f8d9fc0b 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -27,6 +27,7 @@ fn main() -> std::io::Result<()> { .name("auth-example") .secure(false), )) + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/logout").to(logout)) diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 2705866f..ba840b42 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -28,7 +28,7 @@ fn main() -> std::io::Result<()> { App::new() // redis session middleware .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) - // enable logger + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) // register simple route, handle all methods .service(web::resource("/").to(index)) From aa5750cafc9d6bc96e098c338b70fa618149ffd5 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 6 Jun 2019 16:47:40 +0600 Subject: [PATCH 073/111] update actix-web to 1.0.0 --- actix_redis/Cargo.toml | 4 ++-- actix_todo/Cargo.toml | 6 +++--- async_db/Cargo.toml | 4 ++-- async_ex1/Cargo.toml | 4 ++-- async_ex2/Cargo.toml | 6 +++--- basics/Cargo.toml | 8 ++++---- cookie-auth/Cargo.toml | 2 +- cookie-session/Cargo.toml | 4 ++-- diesel/Cargo.toml | 2 +- error_handling/Cargo.toml | 2 +- form/Cargo.toml | 2 +- hello-world/Cargo.toml | 2 +- http-full-proxy/Cargo.toml | 2 +- http-proxy/Cargo.toml | 2 +- json/Cargo.toml | 2 +- jsonrpc/Cargo.toml | 4 ++-- juniper/Cargo.toml | 2 +- middleware/Cargo.toml | 4 ++-- multipart/Cargo.toml | 4 ++-- protobuf/Cargo.toml | 4 ++-- r2d2/Cargo.toml | 2 +- redis-session/Cargo.toml | 6 +++--- rustls/Cargo.toml | 4 ++-- simple-auth-server/Cargo.toml | 6 +++--- state/Cargo.toml | 2 +- state/src/main.rs | 8 ++++---- static_index/Cargo.toml | 4 ++-- template_askama/Cargo.toml | 2 +- template_tera/Cargo.toml | 2 +- template_yarte/Cargo.toml | 4 ++-- tls/Cargo.toml | 2 +- web-cors/backend/Cargo.toml | 2 +- websocket-chat/Cargo.toml | 8 ++++---- websocket-tcp-chat/Cargo.toml | 8 ++++---- websocket/Cargo.toml | 8 ++++---- 35 files changed, 69 insertions(+), 69 deletions(-) diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index 72140b66..2633ef23 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" actix-redis = { git="https://github.com/actix/actix-redis.git" } futures = "0.1.23" redis-async = "0.4.0" diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index f7b70adc..754918b8 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -6,9 +6,9 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.5" -actix-files = "0.1.0-beta.4" -actix-session = "0.1.0-beta.4" +actix-web = "1.0.0" +actix-files = "0.1.1" +actix-session = "0.1.0" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index 16121158..b7ef39fb 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix-rt = "0.2" -actix-web = "1.0.0-beta.4" +actix-rt = "0.2.2" +actix-web = "1.0.0" dotenv = "0.10" env_logger = "0.5" diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml index a87eec91..e5b97163 100644 --- a/async_ex1/Cargo.toml +++ b/async_ex1/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix-rt = "0.2" -actix-web = { version="1.0.0-alpha.4", features=["ssl"] } +actix-rt = "0.2.2" +actix-web = { version="1.0.0", features=["ssl"] } futures = "0.1" serde = "1.0.43" diff --git a/async_ex2/Cargo.toml b/async_ex2/Cargo.toml index 0d7dab09..c1492b9f 100644 --- a/async_ex2/Cargo.toml +++ b/async_ex2/Cargo.toml @@ -7,9 +7,9 @@ workspace = ".." [dependencies] actix-rt = "0.2.2" -actix-web = { version="1.0.0-beta.4", features=["ssl"] } -actix-multipart = "0.1.0-beta.1" -actix-service = "0.4.0" +actix-web = { version="1.0.0", features=["ssl"] } +actix-multipart = "0.1.1" +actix-service = "0.4.1" bytes = "0.4.12" env_logger = "0.6.1" futures = "0.1" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 6f200774..8dcf58ca 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -6,10 +6,10 @@ workspace = ".." edition = "2018" [dependencies] -actix-rt = "0.2" -actix-web = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" -actix-session = "0.1.0-beta.4" +actix-rt = "0.2.2" +actix-web = "1.0.0" +actix-files = "0.1.1" +actix-session = "0.1.0" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index 8024c93d..dbc4d11f 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" env_logger = "0.6" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 0d926be8..1e10ae47 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" -actix-session = "0.1.0-beta.4" +actix-web = "1.0.0" +actix-session = "0.1.0" futures = "0.1" time = "0.1" diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml index 3bc1e55b..5065ff33 100644 --- a/diesel/Cargo.toml +++ b/diesel/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" bytes = "0.4" env_logger = "0.6" diff --git a/error_handling/Cargo.toml b/error_handling/Cargo.toml index e892153f..808e7335 100644 --- a/error_handling/Cargo.toml +++ b/error_handling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" derive_more = "0.14.0" futures = "0.1.23" diff --git a/form/Cargo.toml b/form/Cargo.toml index ed9467dc..7a09f74a 100644 --- a/form/Cargo.toml +++ b/form/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" serde = "1.0" serde_derive = "1.0" diff --git a/hello-world/Cargo.toml b/hello-world/Cargo.toml index 59ea15e8..396062bd 100644 --- a/hello-world/Cargo.toml +++ b/hello-world/Cargo.toml @@ -6,5 +6,5 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" env_logger = "0.6" diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml index a1939948..ddfe7b8a 100644 --- a/http-full-proxy/Cargo.toml +++ b/http-full-proxy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" clap = "2.32.0" futures = "0.1.25" diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 718a346b..bcb80397 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" env_logger = "0.5" futures = "0.1" diff --git a/json/Cargo.toml b/json/Cargo.toml index 7375e334..d7196f25 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" bytes = "0.4" futures = "0.1" diff --git a/jsonrpc/Cargo.toml b/jsonrpc/Cargo.toml index 8b5978ba..8b1a3dcf 100644 --- a/jsonrpc/Cargo.toml +++ b/jsonrpc/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" workspace = ".." [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" env_logger = "0.6" futures = "0.1.23" futures-timer = "0.1" diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 0d6c0f79..d3c02049 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" env_logger = "0.6" futures = "0.1" serde = "1.0" diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index 8b9334f4..76ecbf1c 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" workspace = ".." [dependencies] -actix-service = "0.4.0" -actix-web = "1.0.0-beta.4" +actix-service = "0.4.1" +actix-web = "1.0.0" futures = "0.1.25" env_logger = "0.6" \ No newline at end of file diff --git a/multipart/Cargo.toml b/multipart/Cargo.toml index 4c909d41..00089b01 100644 --- a/multipart/Cargo.toml +++ b/multipart/Cargo.toml @@ -10,8 +10,8 @@ name = "multipart" path = "src/main.rs" [dependencies] -actix-web = "1.0.0-beta.4" -actix-multipart = "0.1.0-beta.4" +actix-web = "1.0.0" +actix-multipart = "0.1.1" env_logger = "0.6" futures = "0.1.25" diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index 1a401de5..b9f69d92 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -13,6 +13,6 @@ derive_more = "0.14" prost = "0.4.0" prost-derive = "0.4.0" -actix = "0.8.1" -actix-web = "1.0.0-rc" +actix = "0.8.2" +actix-web = "1.0.0" actix-protobuf = "0.4.0" diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index f57cdf85..bfc51465 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -7,7 +7,7 @@ workspace = ".." [dependencies] actix-rt = "0.2" -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" futures = "0.1" env_logger = "0.6" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 6e1181a9..74943def 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -6,8 +6,8 @@ workspace = ".." edition = "2018" [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" -actix-session = "0.1.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" +actix-session = "0.1.0" actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } env_logger = "0.6" diff --git a/rustls/Cargo.toml b/rustls/Cargo.toml index 33d04e5a..8e709301 100644 --- a/rustls/Cargo.toml +++ b/rustls/Cargo.toml @@ -12,5 +12,5 @@ path = "src/main.rs" [dependencies] env_logger = "0.5" rustls = "0.15" -actix-web = { version = "1.0.0-beta.4", features=["rust-tls"] } -actix-files = "0.1.0-beta.4" +actix-web = { version = "1.0.0", features=["rust-tls"] } +actix-files = "0.1.0" diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index dab0dc5c..fa2396e1 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" workspace = ".." [dependencies] -actix = { version = "0.8.1", features = ["http"] } +actix = "0.8.2" actix-rt = "0.2.2" -actix-web = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" +actix-web = "1.0.0" +actix-files = "0.1.1" bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } diff --git a/state/Cargo.toml b/state/Cargo.toml index 62e83ad2..ee4cbf33 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" futures = "0.1.25" env_logger = "0.6" diff --git a/state/src/main.rs b/state/src/main.rs index a11d5da2..3f5d721a 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -12,12 +12,12 @@ //! Check [user guide](https://actix.rs/book/actix-web/sec-2-application.html) for more info. use std::io; -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer}; /// simple handle -fn index(state: web::Data>>, req: HttpRequest) -> HttpResponse { +fn index(state: web::Data>, req: HttpRequest) -> HttpResponse { println!("{:?}", req); *(state.lock().unwrap()) += 1; @@ -28,12 +28,12 @@ fn main() -> io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let counter = Arc::new(Mutex::new(0usize)); + let counter = web::Data::new(Mutex::new(0usize)); //move is necessary to give closure below ownership of counter HttpServer::new(move || { App::new() - .data(counter.clone()) // <- create app with shared state + .register_data(counter.clone()) // <- create app with shared state // enable logger .wrap(middleware::Logger::default()) // register simple handler, handle all methods diff --git a/static_index/Cargo.toml b/static_index/Cargo.toml index bac404db..7cb6c402 100644 --- a/static_index/Cargo.toml +++ b/static_index/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" futures = "0.1" env_logger = "0.5" -actix-web = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" +actix-web = "1.0.0" +actix-files = "0.1.1" diff --git a/template_askama/Cargo.toml b/template_askama/Cargo.toml index 378098c5..6d9cb6b8 100644 --- a/template_askama/Cargo.toml +++ b/template_askama/Cargo.toml @@ -6,7 +6,7 @@ workspace = ".." edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" env_logger = "0.6" askama = "0.8" diff --git a/template_tera/Cargo.toml b/template_tera/Cargo.toml index b49959ca..cbf2d300 100644 --- a/template_tera/Cargo.toml +++ b/template_tera/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] env_logger = "0.6" tera = "0.11" -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 0c31b1f3..be056ced 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -12,7 +12,7 @@ env_logger = "0.6" yarte = { version = "0.2", features=["with-actix-web"] } -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" [build-dependencies] yarte = { version = "0.2", features=["with-actix-web"] } @@ -20,4 +20,4 @@ yarte = { version = "0.2", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" actix-http-test = "0.2.0" -actix-http = "0.2.0" +actix-http = "0.2.3" diff --git a/tls/Cargo.toml b/tls/Cargo.toml index 7541ee45..f68f361b 100644 --- a/tls/Cargo.toml +++ b/tls/Cargo.toml @@ -11,6 +11,6 @@ path = "src/main.rs" [dependencies] actix-rt = "0.2" -actix-web = { version="1.0.0-beta.4", features=["ssl"] } +actix-web = { version="1.0.0", features=["ssl"] } env_logger = "0.6" openssl = { version="0.10" } diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index 9ca67022..493132eb 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../../" edition = "2018" [dependencies] -actix-web = "1.0.0-beta.4" +actix-web = "1.0.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/websocket-chat/Cargo.toml b/websocket-chat/Cargo.toml index 73b5866d..fb5817f5 100644 --- a/websocket-chat/Cargo.toml +++ b/websocket-chat/Cargo.toml @@ -10,10 +10,10 @@ name = "websocket-chat-server" path = "src/main.rs" [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" -actix-web-actors = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" +actix-web-actors = "1.0.0" +actix-files = "0.1.1" rand = "0.6" bytes = "0.4" diff --git a/websocket-tcp-chat/Cargo.toml b/websocket-tcp-chat/Cargo.toml index 85755904..dd100b89 100644 --- a/websocket-tcp-chat/Cargo.toml +++ b/websocket-tcp-chat/Cargo.toml @@ -14,10 +14,10 @@ name = "websocket-tcp-client" path = "src/client.rs" [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" -actix-web-actors = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" +actix-web-actors = "1.0.0" +actix-files = "0.1.1" rand = "0.6" bytes = "0.4" diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index 89d64a80..71838883 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -14,10 +14,10 @@ path = "src/main.rs" #path = "src/client.rs" [dependencies] -actix = "0.8.1" -actix-web = "1.0.0-beta.4" -actix-web-actors = "1.0.0-beta.4" -actix-files = "0.1.0-beta.4" +actix = "0.8.2" +actix-web = "1.0.0" +actix-web-actors = "1.0.0" +actix-files = "0.1.1" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file From f7dd2e62363880588a02da9c7e97c11c395b7c57 Mon Sep 17 00:00:00 2001 From: "Clifford T. Matthews" Date: Thu, 6 Jun 2019 15:20:25 -0600 Subject: [PATCH 074/111] Fixes trivial typos. --- middleware/README.md | 2 +- middleware/src/simple.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/middleware/README.md b/middleware/README.md index 056ce654..1cd2b732 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -1,7 +1,7 @@ ## Middleware example ```bash -cd form +cd middleware cargo run # Started http server: 127.0.0.1:8080 ``` diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index faf04cfb..789eedab 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -3,10 +3,10 @@ use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error}; use futures::future::{ok, FutureResult}; use futures::{Future, Poll}; -// There are two step in middleware processing. -// 1. Middleware initialization, middleware factory get called with +// There are two steps in middleware processing. +// 1. Middleware initialization, middleware factory gets called with // next service in chain as parameter. -// 2. Middleware's call method get called with normal request. +// 2. Middleware's call method gets called with normal request. pub struct SayHi; // Middleware factory is `Transform` trait from actix-service crate From f1a34d534c28700cee021ad3b0b100cb598f5052 Mon Sep 17 00:00:00 2001 From: grey Date: Thu, 6 Jun 2019 15:30:54 -0700 Subject: [PATCH 075/111] add unused validation to async_ex1 example --- async_ex1/src/main.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index 1bb4fd2d..a3acde76 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -10,7 +10,7 @@ // 2. validating user-submitted parameters using the 'validator' crate // 2. actix-web client features: // - POSTing json body -// 3. chaining futures into a single response used by an asynch endpoint +// 3. chaining futures into a single response used by an async endpoint #[macro_use] extern crate validator_derive; @@ -20,9 +20,12 @@ extern crate serde_derive; use std::collections::HashMap; use std::io; -use actix_web::client::Client; -use actix_web::web::BytesMut; -use actix_web::{web, App, Error, HttpResponse, HttpServer}; +use actix_web::{ + client::Client, + web::{self, BytesMut}, + error::ErrorBadRequest, + App, Error, HttpResponse, HttpServer, +}; use futures::{Future, Stream}; use validator::Validate; @@ -46,12 +49,13 @@ struct HttpBinResponse { url: String, } -/// post json to httpbin, get it back in the response body, return deserialized +/// validate data, post json to httpbin, get it back in the response body, return deserialized fn step_x( data: SomeData, client: &Client, ) -> impl Future { - client + let validation = futures::future::result(data.validate()).map_err(ErrorBadRequest); + let post_response = client .post("https://httpbin.org/post") .send_json(&data) .map_err(Error::from) // <- convert SendRequestError to an Error @@ -65,7 +69,9 @@ fn step_x( let body: HttpBinResponse = serde_json::from_slice(&body).unwrap(); body.json }) - }) + }); + + validation.and_then(|_| post_response) } fn create_something( From 72a58b7ca8b253cdc214052078526de66123f775 Mon Sep 17 00:00:00 2001 From: grey Date: Fri, 7 Jun 2019 13:30:14 -0700 Subject: [PATCH 076/111] cargo fmt --- async_ex1/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs index a3acde76..25fa3bc5 100644 --- a/async_ex1/src/main.rs +++ b/async_ex1/src/main.rs @@ -22,8 +22,8 @@ use std::io; use actix_web::{ client::Client, - web::{self, BytesMut}, error::ErrorBadRequest, + web::{self, BytesMut}, App, Error, HttpResponse, HttpServer, }; use futures::{Future, Stream}; From 006b7f3d08334e5792d22671c7d11c405c67998f Mon Sep 17 00:00:00 2001 From: Alexandru Tiniuc Date: Sat, 8 Jun 2019 18:47:39 +0100 Subject: [PATCH 077/111] adds Handlebars example Closes #122 --- Cargo.toml | 1 + template_handlebars/Cargo.toml | 10 ++++ template_handlebars/src/README.md | 7 +++ template_handlebars/src/main.rs | 59 +++++++++++++++++++ .../static/templates/index.html | 12 ++++ .../static/templates/user.html | 12 ++++ 6 files changed, 101 insertions(+) create mode 100644 template_handlebars/Cargo.toml create mode 100644 template_handlebars/src/README.md create mode 100644 template_handlebars/src/main.rs create mode 100644 template_handlebars/static/templates/index.html create mode 100644 template_handlebars/static/templates/user.html diff --git a/Cargo.toml b/Cargo.toml index 14ad4224..a35948e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ members = [ "template_askama", "template_tera", "template_yarte", + "template_handlebars", "tls", #"unix-socket", "web-cors/backend", diff --git a/template_handlebars/Cargo.toml b/template_handlebars/Cargo.toml new file mode 100644 index 00000000..11fb0c58 --- /dev/null +++ b/template_handlebars/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "template_handlebars" +version = "0.1.0" +authors = ["Alexandru Tiniuc "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +handlebars = "2.0.0-beta.2" +serde_json = "1.0" \ No newline at end of file diff --git a/template_handlebars/src/README.md b/template_handlebars/src/README.md new file mode 100644 index 00000000..88139535 --- /dev/null +++ b/template_handlebars/src/README.md @@ -0,0 +1,7 @@ +# Handlebars + +This is an example of how to use Actix Web with the [Handlebars templating language](https://crates.io/crates/handlebars), which is currently the most popular crate that achieves this. After starting the server with `cargo run`, you may visit the following pages: + +- http://localhost:8080 +- http://localhost:8080/Emma/documents +- http://localhost:8080/Bob/passwordds \ No newline at end of file diff --git a/template_handlebars/src/main.rs b/template_handlebars/src/main.rs new file mode 100644 index 00000000..e49c7ad0 --- /dev/null +++ b/template_handlebars/src/main.rs @@ -0,0 +1,59 @@ +#[macro_use] +extern crate actix_web; + +#[macro_use] +extern crate serde_json; + +use actix_web::web; +use actix_web::{App, HttpResponse, HttpServer}; + +use handlebars::Handlebars; + +use std::sync::Arc; + +use std::io; + +// Macro documentation can be found in the actix_web_codegen crate +#[get("/")] +fn index(hb: web::Data>) -> HttpResponse { + let data = json!({ + "name": "Handlebars" + }); + let body = hb.render("index", &data).unwrap(); + + HttpResponse::Ok().body(body) +} + +#[get("/{user}/{data}")] +fn user( + hb: web::Data>, + info: web::Path<(String, String)>, +) -> HttpResponse { + let data = json!({ + "user": info.0, + "data": info.1 + }); + let body = hb.render("user", &data).unwrap(); + + HttpResponse::Ok().body(body) +} + +fn main() -> io::Result<()> { + // Handlebars uses a repository for the compiled templates. This object must be + // shared between the application threads, and is therefore passed to the + // Application Builder as an atomic reference-counted pointer. + let mut handlebars = Handlebars::new(); + handlebars + .register_templates_directory(".html", "./static/templates") + .unwrap(); + let handlebars_ref = web::Data::new(Arc::new(handlebars)); + + HttpServer::new(move || { + App::new() + .register_data(handlebars_ref.clone()) + .service(index) + .service(user) + }) + .bind("127.0.0.1:8080")? + .run() +} diff --git a/template_handlebars/static/templates/index.html b/template_handlebars/static/templates/index.html new file mode 100644 index 00000000..867c114e --- /dev/null +++ b/template_handlebars/static/templates/index.html @@ -0,0 +1,12 @@ + + + + + {{name}} Example + + + +

{{name}} example

+

This is an example of how to use {{name}} with Actix-Web.

+ + \ No newline at end of file diff --git a/template_handlebars/static/templates/user.html b/template_handlebars/static/templates/user.html new file mode 100644 index 00000000..59e2f1fa --- /dev/null +++ b/template_handlebars/static/templates/user.html @@ -0,0 +1,12 @@ + + + + + {{user}}'s homepage + + + +

Welcome back, {{user}}

+

Here's your {{data}}.

+ + \ No newline at end of file From 114056bc76d7568e774c8c6d99e309850350b1cb Mon Sep 17 00:00:00 2001 From: Arve Seljebu Date: Mon, 10 Jun 2019 18:06:56 +0200 Subject: [PATCH 078/111] resolve issue 139 --- http-proxy/Cargo.toml | 2 +- http-proxy/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index bcb80397..2a7beb8e 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -15,7 +15,7 @@ path = "src/server.rs" [dependencies] actix-rt = "0.2" -actix-web = "1.0.0" +actix-web = { version = "1.0.0", features=["ssl"] } env_logger = "0.5" futures = "0.1" diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index e500bbee..ff45ef97 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -24,7 +24,7 @@ fn streaming( ) -> impl Future> { // send client request client - .get("https://www.rust-lang.org/en-US/") + .get("https://www.rust-lang.org/") .send() // <- connect to host and send request .map_err(Error::from) // <- convert SendRequestError to an Error .and_then(|resp| { From 65adce90f8f96da19ebb62a9effd0f67db795950 Mon Sep 17 00:00:00 2001 From: krircc Date: Tue, 11 Jun 2019 17:47:04 +0800 Subject: [PATCH 079/111] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 82bf29da..07b36afa 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,7 @@ A curated list of examples related to actix. ## from community * [RutHub](https://www.ruthub.com/): A service for sharing read list powered by actix-web + diesel, [repo](https://github.com/danloh/rut-server-rust). -* [Rust-webapp-starter -](https://github.com/rustlang-cn/Rust-webapp-starter) : Rust single page webapp written in actix-web with vuejs. -* [Rust中文社区](http://47.104.146.58/) : A CN online community forum written in Actix-web with vuejs [source](https://github.com/rustlang-cn/ruster). +* [OUISRC](http://ouisrc.xyz/) : Welcome to OUISRC, let us Gain more in exploration and interaction(https://github.com/rustlang-cn/ruster). * [Roseline](https://github.com/DoumanAsh/roseline.rs) : A personal web site and discord & IRC bot to access simple SQLite database. Demonstrates usage of various actix and actix-web concepts. * [Actix Auth Server](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-1/) : Auth web micro-service with rust using actix-web - complete tutorial. See code in [examples/simple-auth-server](https://github.com/actix/examples/tree/master/simple-auth-server) ## Contribute From 238e68de653c784f03ff95f88fa618d1a176ef3c Mon Sep 17 00:00:00 2001 From: krircc Date: Tue, 11 Jun 2019 17:47:37 +0800 Subject: [PATCH 080/111] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07b36afa..cdf13ac2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A curated list of examples related to actix. ## from community * [RutHub](https://www.ruthub.com/): A service for sharing read list powered by actix-web + diesel, [repo](https://github.com/danloh/rut-server-rust). -* [OUISRC](http://ouisrc.xyz/) : Welcome to OUISRC, let us Gain more in exploration and interaction(https://github.com/rustlang-cn/ruster). +* [OUISRC](http://ouisrc.xyz/) : Welcome to OUISRC, let us Gain more in exploration and interaction. * [Roseline](https://github.com/DoumanAsh/roseline.rs) : A personal web site and discord & IRC bot to access simple SQLite database. Demonstrates usage of various actix and actix-web concepts. * [Actix Auth Server](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-1/) : Auth web micro-service with rust using actix-web - complete tutorial. See code in [examples/simple-auth-server](https://github.com/actix/examples/tree/master/simple-auth-server) ## Contribute From a1d799a3f28cf0c50a7fcb8a91e17dac899c2f4d Mon Sep 17 00:00:00 2001 From: Pirmin Kalberer Date: Wed, 12 Jun 2019 23:03:20 +0200 Subject: [PATCH 081/111] Read SQLite path from .env and fix DATABASE_URL --- diesel/.env | 2 +- diesel/README.md | 2 +- diesel/src/main.rs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/diesel/.env b/diesel/.env index 1fbc5af7..186be7ce 100644 --- a/diesel/.env +++ b/diesel/.env @@ -1 +1 @@ -DATABASE_URL=file:test.db +DATABASE_URL=test.db diff --git a/diesel/README.md b/diesel/README.md index a989377e..a0143c38 100644 --- a/diesel/README.md +++ b/diesel/README.md @@ -9,7 +9,7 @@ Diesel's `Getting Started` guide using SQLite for Actix web ```bash cargo install diesel_cli --no-default-features --features sqlite cd examples/diesel -echo "DATABASE_URL=file:test.db" > .env +echo "DATABASE_URL=test.db" > .env diesel migration run ``` diff --git a/diesel/src/main.rs b/diesel/src/main.rs index 80dbc8b4..36453495 100644 --- a/diesel/src/main.rs +++ b/diesel/src/main.rs @@ -13,6 +13,7 @@ use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer}; use bytes::BytesMut; use diesel::prelude::*; use diesel::r2d2::{self, ConnectionManager}; +use dotenv; use futures::future::{err, Either}; use futures::{Future, Stream}; @@ -120,8 +121,10 @@ fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - // Start 3 db executor actors - let manager = ConnectionManager::::new("test.db"); + dotenv::dotenv().ok(); + + let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL"); + let manager = ConnectionManager::::new(connspec); let pool = r2d2::Pool::builder() .build(manager) .expect("Failed to create pool."); From e7ed6755a5f3b7cb13524feb35e584914572e48b Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 17 Jun 2019 12:48:03 +0600 Subject: [PATCH 082/111] use cors and identity crates --- README.md | 1 - cookie-auth/Cargo.toml | 1 + cookie-auth/src/main.rs | 4 ++-- simple-auth-server/Cargo.toml | 3 ++- simple-auth-server/src/auth_handler.rs | 4 ++-- simple-auth-server/src/auth_routes.rs | 2 +- simple-auth-server/src/main.rs | 6 ++---- web-cors/backend/Cargo.toml | 1 + web-cors/backend/src/main.rs | 5 ++--- 9 files changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index cdf13ac2..b42550bc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ A curated list of examples related to actix. ## from community -* [RutHub](https://www.ruthub.com/): A service for sharing read list powered by actix-web + diesel, [repo](https://github.com/danloh/rut-server-rust). * [OUISRC](http://ouisrc.xyz/) : Welcome to OUISRC, let us Gain more in exploration and interaction. * [Roseline](https://github.com/DoumanAsh/roseline.rs) : A personal web site and discord & IRC bot to access simple SQLite database. Demonstrates usage of various actix and actix-web concepts. * [Actix Auth Server](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-1/) : Auth web micro-service with rust using actix-web - complete tutorial. See code in [examples/simple-auth-server](https://github.com/actix/examples/tree/master/simple-auth-server) diff --git a/cookie-auth/Cargo.toml b/cookie-auth/Cargo.toml index dbc4d11f..12f8cf51 100644 --- a/cookie-auth/Cargo.toml +++ b/cookie-auth/Cargo.toml @@ -7,4 +7,5 @@ workspace = ".." [dependencies] actix-web = "1.0.0" +actix-identity = "0.1.0" env_logger = "0.6" diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index f8d9fc0b..8d3b3442 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -1,5 +1,5 @@ -use actix_web::middleware::identity::Identity; -use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService}; +use actix_identity::Identity; +use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{middleware, web, App, HttpResponse, HttpServer}; fn index(id: Identity) -> String { diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index fa2396e1..2edffbb3 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -8,8 +8,9 @@ workspace = ".." [dependencies] actix = "0.8.2" actix-rt = "0.2.2" -actix-web = "1.0.0" +actix-web = "1.0.2" actix-files = "0.1.1" +actix-identity= "0.1.0" bcrypt = "0.2.1" chrono = { version = "0.4.6", features = ["serde"] } diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 444063a6..769bc762 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,6 +1,6 @@ use actix::{Handler, Message}; -use actix_web::{dev::Payload, Error, HttpRequest}; -use actix_web::{middleware::identity::Identity, FromRequest}; +use actix_web::{dev::Payload, Error, HttpRequest, FromRequest}; +use actix_identity::Identity; use bcrypt::verify; use diesel::prelude::*; diff --git a/simple-auth-server/src/auth_routes.rs b/simple-auth-server/src/auth_routes.rs index 269c3a67..caed66ca 100644 --- a/simple-auth-server/src/auth_routes.rs +++ b/simple-auth-server/src/auth_routes.rs @@ -1,5 +1,5 @@ use actix::Addr; -use actix_web::middleware::identity::Identity; +use actix_identity::Identity; use actix_web::{web, Error, HttpRequest, HttpResponse, Responder, ResponseError}; use futures::Future; diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index 9fd7c440..45d1ab2d 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -7,10 +7,8 @@ extern crate serde_derive; use actix::prelude::*; use actix_files as fs; -use actix_web::middleware::{ - identity::{CookieIdentityPolicy, IdentityService}, - Logger, -}; +use actix_identity::{CookieIdentityPolicy, IdentityService}; +use actix_web::middleware::Logger; use actix_web::{web, App, HttpServer}; use chrono::Duration; use diesel::{r2d2::ConnectionManager, PgConnection}; diff --git a/web-cors/backend/Cargo.toml b/web-cors/backend/Cargo.toml index 493132eb..6800e5d6 100644 --- a/web-cors/backend/Cargo.toml +++ b/web-cors/backend/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] actix-web = "1.0.0" +actix-cors = "0.1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/web-cors/backend/src/main.rs b/web-cors/backend/src/main.rs index c009db8e..ed7b71b6 100644 --- a/web-cors/backend/src/main.rs +++ b/web-cors/backend/src/main.rs @@ -1,9 +1,8 @@ #[macro_use] extern crate serde_derive; -use actix_web::{ - http::header, middleware::cors::Cors, middleware::Logger, web, App, HttpServer, -}; +use actix_cors::Cors; +use actix_web::{http::header, middleware::Logger, web, App, HttpServer}; mod user; From 748d4516ebb53148c66df9a447a680092c5d5665 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 22 Jun 2019 09:07:39 +0200 Subject: [PATCH 083/111] Avoid double Arc inside template_handlebars (#147) --- template_handlebars/src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/template_handlebars/src/main.rs b/template_handlebars/src/main.rs index e49c7ad0..b3003ae6 100644 --- a/template_handlebars/src/main.rs +++ b/template_handlebars/src/main.rs @@ -9,13 +9,11 @@ use actix_web::{App, HttpResponse, HttpServer}; use handlebars::Handlebars; -use std::sync::Arc; - use std::io; // Macro documentation can be found in the actix_web_codegen crate #[get("/")] -fn index(hb: web::Data>) -> HttpResponse { +fn index(hb: web::Data) -> HttpResponse { let data = json!({ "name": "Handlebars" }); @@ -26,7 +24,7 @@ fn index(hb: web::Data>) -> HttpResponse { #[get("/{user}/{data}")] fn user( - hb: web::Data>, + hb: web::Data, info: web::Path<(String, String)>, ) -> HttpResponse { let data = json!({ @@ -46,7 +44,7 @@ fn main() -> io::Result<()> { handlebars .register_templates_directory(".html", "./static/templates") .unwrap(); - let handlebars_ref = web::Data::new(Arc::new(handlebars)); + let handlebars_ref = web::Data::new(handlebars); HttpServer::new(move || { App::new() From 733eb93a97ed2d6630f518a0fbab84a46afb3762 Mon Sep 17 00:00:00 2001 From: Kai Yao Date: Sat, 22 Jun 2019 02:08:18 -0500 Subject: [PATCH 084/111] Added json_error example. (#146) --- Cargo.toml | 1 + json_error/Cargo.toml | 13 +++++++++++ json_error/src/main.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 json_error/Cargo.toml create mode 100644 json_error/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index a35948e5..f99180a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "http-proxy", "http-full-proxy", "json", + "json_error", "jsonrpc", "juniper", "middleware", diff --git a/json_error/Cargo.toml b/json_error/Cargo.toml new file mode 100644 index 00000000..59f6ff8e --- /dev/null +++ b/json_error/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "json_error" +version = "0.1.0" +authors = ["Kai Yao "] +edition = "2018" + +[dependencies] +actix = "0.8" +actix-web = "1.0" +failure = "0.1" +futures = "0.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/json_error/src/main.rs b/json_error/src/main.rs new file mode 100644 index 00000000..64ae7856 --- /dev/null +++ b/json_error/src/main.rs @@ -0,0 +1,53 @@ +// This example is meant to show how to automatically generate a json error response when something goes wrong. + +use actix::System; +use actix_web::http::StatusCode; +use actix_web::web::{get, resource, HttpRequest, HttpResponse}; +use actix_web::{App, HttpServer, ResponseError}; +use futures::future::err; +use futures::Future; +use serde::Serialize; +use serde_json::{json, to_string_pretty}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::io; + +#[derive(Debug, Serialize)] +struct Error { + msg: String, + status: u16, +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}", to_string_pretty(self).unwrap()) + } +} + +impl ResponseError for Error { + // builds the actual response to send back when an error occurs + fn render_response(&self) -> HttpResponse { + let err_json = json!({ "error": self.msg }); + HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json) + } +} + +fn index(_: HttpRequest) -> impl Future { + err(Error { + msg: "an example error message".to_string(), + status: 400, + }) +} + +fn main() -> io::Result<()> { + let sys = System::new("json_error_example"); + let ip_address = "127.0.0.1:8000"; + + HttpServer::new(|| App::new().service(resource("/").route(get().to_async(index)))) + .bind(ip_address) + .expect("Can not bind to port 8000") + .start(); + + println!("Running server on {}", ip_address); + + sys.run() +} From b0d3c652b22cc6db70bc8e792793ceba69639aa3 Mon Sep 17 00:00:00 2001 From: Niels Nielsen Date: Sat, 22 Jun 2019 09:08:45 +0200 Subject: [PATCH 085/111] Fix error message for failed connection (#144) --- actix_todo/src/db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actix_todo/src/db.rs b/actix_todo/src/db.rs index 579b0b5d..2bba1446 100644 --- a/actix_todo/src/db.rs +++ b/actix_todo/src/db.rs @@ -14,7 +14,7 @@ pub fn init_pool(database_url: &str) -> Result { } fn get_conn(pool: &PgPool) -> Result { - pool.get().map_err(|_| "can get connection") + pool.get().map_err(|_| "Can't get connection") } pub fn get_all_tasks(pool: &PgPool) -> Result, &'static str> { From 58675a683b56f15bf99889c834541cc064ff3cc2 Mon Sep 17 00:00:00 2001 From: Julian Tescher Date: Fri, 28 Jun 2019 01:52:12 -0700 Subject: [PATCH 086/111] Do not decompress proxied responses (#151) If you decompress a proxied response that was encoded, the `content-encoding` header will be passed through but a plaintext body will be returned. --- http-full-proxy/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index 68a7d815..bcb788c3 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -15,7 +15,7 @@ fn forward( new_url.set_path(req.uri().path()); new_url.set_query(req.uri().query()); - let forwarded_req = client.request_from(new_url.as_str(), req.head()); + let forwarded_req = client.request_from(new_url.as_str(), req.head()).no_decompress(); let forwarded_req = if let Some(addr) = req.head().peer_addr { forwarded_req.header("x-forwarded-for", format!("{}", addr.ip())) } else { From ed24f61cca004717d00eaf4c88f14787c563682b Mon Sep 17 00:00:00 2001 From: Dany Marcoux Date: Fri, 28 Jun 2019 10:53:08 +0200 Subject: [PATCH 087/111] Add openSUSE instructions for diesel example (#149) --- diesel/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/diesel/README.md b/diesel/README.md index a0143c38..13d45f08 100644 --- a/diesel/README.md +++ b/diesel/README.md @@ -7,6 +7,7 @@ Diesel's `Getting Started` guide using SQLite for Actix web ### init database sqlite ```bash +# if opensuse: sudo zypper install sqlite3-devel cargo install diesel_cli --no-default-features --features sqlite cd examples/diesel echo "DATABASE_URL=test.db" > .env @@ -18,6 +19,7 @@ diesel migration run ```bash # if ubuntu : sudo apt-get install libsqlite3-dev # if fedora : sudo dnf install libsqlite3x-devel +# if opensuse: sudo zypper install libsqlite3-0 cd examples/diesel cargo run (or ``cargo watch -x run``) # Started http server: 127.0.0.1:8080 @@ -32,6 +34,7 @@ cargo run (or ``cargo watch -x run``) ```bash # if ubuntu : sudo apt-get install sqlite3 # if fedora : sudo dnf install sqlite3x +# if opensuse: sudo zypper install sqlite3 sqlite3 test.db sqlite> .tables sqlite> select * from users; From 7c747c5006e04b5e4cd71b6f9a305ad8cd772ceb Mon Sep 17 00:00:00 2001 From: Juan Aguilar Date: Mon, 1 Jul 2019 06:02:14 +0200 Subject: [PATCH 088/111] Bump yarte version to 0.2.1 (#153) --- template_yarte/Cargo.toml | 6 ++--- template_yarte/README.md | 2 +- template_yarte/src/main.rs | 46 ++++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index be056ced..67f31b33 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "template_yarte" version = "0.0.1" -authors = ["Rust-iendo Barcelona "] +authors = ["Rust-iendo "] publish = false edition = "2018" @@ -12,12 +12,10 @@ env_logger = "0.6" yarte = { version = "0.2", features=["with-actix-web"] } -actix-web = "1.0.0" +actix-web = "1.0" [build-dependencies] yarte = { version = "0.2", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" -actix-http-test = "0.2.0" -actix-http = "0.2.3" diff --git a/template_yarte/README.md b/template_yarte/README.md index 0f3d2756..1aabc641 100644 --- a/template_yarte/README.md +++ b/template_yarte/README.md @@ -1,6 +1,6 @@ # yarte -Example of composition with partials and `with-actix-web` feature +Minimal example of using template [yarte](https://gitlab.com/r-iendo/yarte) that displays a form. ```bash cargo test diff --git a/template_yarte/src/main.rs b/template_yarte/src/main.rs index d65a091d..6a7faa0c 100644 --- a/template_yarte/src/main.rs +++ b/template_yarte/src/main.rs @@ -30,25 +30,24 @@ fn main() -> std::io::Result<()> { #[cfg(test)] mod test { use super::*; - use actix_http::HttpService; - use actix_http_test::TestServer; - use actix_web::{http, App}; + use actix_web::{http, test as atest}; use bytes::Bytes; #[test] fn test() { - let mut srv = TestServer::new(|| HttpService::new(App::new().service(index))); + let mut app = atest::init_service(App::new().service(index)); - let req = srv.get("/"); - let mut response = srv.block_on(req.send()).unwrap(); - assert!(response.status().is_success()); + let req = atest::TestRequest::with_uri("/").to_request(); + let resp = atest::call_service(&mut app, req); + + assert!(resp.status().is_success()); assert_eq!( - response.headers().get(http::header::CONTENT_TYPE).unwrap(), + resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/html" ); - let bytes = srv.block_on(response.body()).unwrap(); + let bytes = atest::read_body(resp); assert_eq!( bytes, Bytes::from_static( @@ -67,16 +66,17 @@ mod test { ) ); - let req = srv.get("/?name=foo&lastname=bar"); - let mut response = srv.block_on(req.send()).unwrap(); - assert!(response.status().is_success()); + let req = atest::TestRequest::with_uri("/?name=foo&lastname=bar").to_request(); + let resp = atest::call_service(&mut app, req); + + assert!(resp.status().is_success()); assert_eq!( - response.headers().get(http::header::CONTENT_TYPE).unwrap(), + resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/html" ); - let bytes = srv.block_on(response.body()).unwrap(); + let bytes = atest::read_body(resp); assert_eq!( bytes, Bytes::from_static( @@ -90,20 +90,22 @@ mod test { ) ); - let req = srv.get("/?name=foo"); - let mut response = srv.block_on(req.send()).unwrap(); - assert!(response.status().is_server_error()); + let req = atest::TestRequest::with_uri("/?name=foo").to_request(); + let resp = atest::call_service(&mut app, req); - let req = srv.get("/?lastname=bar"); - let mut response = srv.block_on(req.send()).unwrap(); - assert!(response.status().is_success()); + assert!(resp.status().is_server_error()); + + let req = atest::TestRequest::with_uri("/?lastname=bar").to_request(); + let resp = atest::call_service(&mut app, req); + + assert!(resp.status().is_success()); assert_eq!( - response.headers().get(http::header::CONTENT_TYPE).unwrap(), + resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/html" ); - let bytes = srv.block_on(response.body()).unwrap(); + let bytes = atest::read_body(resp); assert_eq!( bytes, Bytes::from_static( From 82786d44619e1b79f7a2c3568c54f7388ccca8f4 Mon Sep 17 00:00:00 2001 From: Arve Seljebu Date: Mon, 1 Jul 2019 06:02:51 +0200 Subject: [PATCH 089/111] Full proxy omit content length (#152) * omit content-length header in http-full-proxy * cargo fmt --- http-full-proxy/src/main.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs index bcb788c3..a68b46f1 100644 --- a/http-full-proxy/src/main.rs +++ b/http-full-proxy/src/main.rs @@ -15,7 +15,9 @@ fn forward( new_url.set_path(req.uri().path()); new_url.set_query(req.uri().query()); - let forwarded_req = client.request_from(new_url.as_str(), req.head()).no_decompress(); + let forwarded_req = client + .request_from(new_url.as_str(), req.head()) + .no_decompress(); let forwarded_req = if let Some(addr) = req.head().peer_addr { forwarded_req.header("x-forwarded-for", format!("{}", addr.ip())) } else { @@ -27,8 +29,10 @@ fn forward( .map_err(Error::from) .map(|res| { let mut client_resp = HttpResponse::build(res.status()); - for (header_name, header_value) in - res.headers().iter().filter(|(h, _)| *h != "connection") + for (header_name, header_value) in res + .headers() + .iter() + .filter(|(h, _)| *h != "connection" && *h != "content-length") { client_resp.header(header_name.clone(), header_value.clone()); } From 3f286b5b6075d794ba9a4d1b898e31e75074c0b5 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Date: Thu, 11 Jul 2019 10:47:22 +0200 Subject: [PATCH 090/111] Update yarte version to 0.3 (#155) --- template_yarte/Cargo.toml | 4 ++-- template_yarte/README.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/template_yarte/Cargo.toml b/template_yarte/Cargo.toml index 67f31b33..0069a0df 100644 --- a/template_yarte/Cargo.toml +++ b/template_yarte/Cargo.toml @@ -10,12 +10,12 @@ workspace = ".." [dependencies] env_logger = "0.6" -yarte = { version = "0.2", features=["with-actix-web"] } +yarte = { version = "0.3", features=["with-actix-web"] } actix-web = "1.0" [build-dependencies] -yarte = { version = "0.2", features=["with-actix-web"] } +yarte = { version = "0.3", features=["with-actix-web"] } [dev-dependencies] bytes = "0.4" diff --git a/template_yarte/README.md b/template_yarte/README.md index 1aabc641..21de4169 100644 --- a/template_yarte/README.md +++ b/template_yarte/README.md @@ -2,10 +2,11 @@ Minimal example of using template [yarte](https://gitlab.com/r-iendo/yarte) that displays a form. +[Template benchmarks in stable](https://gitlab.com/botika/template-benchmarks-rs) + ```bash cargo test cargo run ``` > open `localhost:8080` - From 59df61db6f76c72ca0b3767d60b79a6b52c55d9b Mon Sep 17 00:00:00 2001 From: Arve Seljebu Date: Thu, 11 Jul 2019 10:47:41 +0200 Subject: [PATCH 091/111] update users sessions link (#154) --- cookie-session/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookie-session/src/main.rs b/cookie-session/src/main.rs index 497f01da..72f00cf3 100644 --- a/cookie-session/src/main.rs +++ b/cookie-session/src/main.rs @@ -3,7 +3,7 @@ //! //! [Redis session example](https://github.com/actix/examples/tree/master/redis-session) //! -//! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions) +//! [User guide](https://actix.rs/docs/middleware/#user-sessions) use actix_session::{CookieSession, Session}; use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result}; From 4aa663e7943ae597c0e3759b8017a5e8a176a67f Mon Sep 17 00:00:00 2001 From: Guoli Lyu Date: Thu, 11 Jul 2019 16:48:14 +0800 Subject: [PATCH 092/111] feat: update ws client example to actix-web 1.0 (#143) --- websocket/Cargo.toml | 8 +++-- websocket/src/client.rs | 72 +++++++++++++++++++++++++++++------------ 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/websocket/Cargo.toml b/websocket/Cargo.toml index 71838883..891ef14e 100644 --- a/websocket/Cargo.toml +++ b/websocket/Cargo.toml @@ -9,15 +9,17 @@ workspace = ".." name = "websocket-server" path = "src/main.rs" -#[[bin]] -#name = "websocket-client" -#path = "src/client.rs" +[[bin]] +name = "websocket-client" +path = "src/client.rs" [dependencies] actix = "0.8.2" +actix-codec = "0.1.2" actix-web = "1.0.0" actix-web-actors = "1.0.0" actix-files = "0.1.1" +awc = "0.2.1" env_logger = "0.6" futures = "0.1" bytes = "0.4" \ No newline at end of file diff --git a/websocket/src/client.rs b/websocket/src/client.rs index 11f827bb..04a683ad 100644 --- a/websocket/src/client.rs +++ b/websocket/src/client.rs @@ -2,26 +2,39 @@ use std::time::Duration; use std::{io, thread}; +use actix::io::SinkWrite; use actix::*; -use actix_web::client::{Client, ClientWriter, Message, ProtocolError}; -use futures::Future; +use actix_codec::{AsyncRead, AsyncWrite, Framed}; +use awc::{ + error::WsProtocolError, + ws::{Codec, Frame, Message}, + Client, +}; +use futures::{ + lazy, + stream::{SplitSink, Stream}, + Future, +}; fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); let _ = env_logger::init(); let sys = actix::System::new("ws-example"); - Arbiter::spawn( - Client::new("http://127.0.0.1:8080/ws/") + Arbiter::spawn(lazy(|| { + Client::new() + .ws("http://127.0.0.1:8080/ws/") .connect() .map_err(|e| { println!("Error: {}", e); () }) - .map(|(reader, writer)| { + .map(|(response, framed)| { + println!("{:?}", response); + let (sink, stream) = framed.split(); let addr = ChatClient::create(|ctx| { - ChatClient::add_stream(reader, ctx); - ChatClient(writer) + ChatClient::add_stream(stream, ctx); + ChatClient(SinkWrite::new(sink, ctx)) }); // start console loop @@ -35,18 +48,23 @@ fn main() { }); () - }), - ); + }) + })); let _ = sys.run(); } -struct ChatClient(ClientWriter); +struct ChatClient(SinkWrite>>) +where + T: AsyncRead + AsyncWrite; #[derive(Message)] struct ClientCommand(String); -impl Actor for ChatClient { +impl Actor for ChatClient +where + T: AsyncRead + AsyncWrite, +{ type Context = Context; fn started(&mut self, ctx: &mut Context) { @@ -62,10 +80,13 @@ impl Actor for ChatClient { } } -impl ChatClient { +impl ChatClient +where + T: AsyncRead + AsyncWrite, +{ fn hb(&self, ctx: &mut Context) { ctx.run_later(Duration::new(1, 0), |act, ctx| { - act.0.ping(""); + act.0.write(Message::Ping(String::new())).unwrap(); act.hb(ctx); // client should also check for a timeout here, similar to the @@ -75,24 +96,30 @@ impl ChatClient { } /// Handle stdin commands -impl Handler for ChatClient { +impl Handler for ChatClient +where + T: AsyncRead + AsyncWrite, +{ type Result = (); - fn handle(&mut self, msg: ClientCommand, ctx: &mut Context) { - self.0.text(msg.0) + fn handle(&mut self, msg: ClientCommand, _ctx: &mut Context) { + self.0.write(Message::Text(msg.0)).unwrap(); } } /// Handle server websocket messages -impl StreamHandler for ChatClient { - fn handle(&mut self, msg: Message, ctx: &mut Context) { +impl StreamHandler for ChatClient +where + T: AsyncRead + AsyncWrite, +{ + fn handle(&mut self, msg: Frame, _ctx: &mut Context) { match msg { - Message::Text(txt) => println!("Server: {:?}", txt), + Frame::Text(txt) => println!("Server: {:?}", txt), _ => (), } } - fn started(&mut self, ctx: &mut Context) { + fn started(&mut self, _ctx: &mut Context) { println!("Connected"); } @@ -101,3 +128,8 @@ impl StreamHandler for ChatClient { ctx.stop() } } + +impl actix::io::WriteHandler for ChatClient where + T: AsyncRead + AsyncWrite +{ +} From 93275d79865abd3601f67cda3790fb05868a3150 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 11 Jul 2019 15:02:25 +0600 Subject: [PATCH 093/111] update chat-broker example and fmt --- Cargo.toml | 2 +- basics/src/main.rs | 2 +- cookie-auth/src/main.rs | 2 +- json_error/src/main.rs | 44 +++++++++++++------------- protobuf/src/main.rs | 3 +- redis-session/src/main.rs | 2 +- simple-auth-server/src/auth_handler.rs | 2 +- template_handlebars/src/main.rs | 5 +-- websocket-chat-broker/Cargo.toml | 13 +++++--- websocket-chat-broker/src/main.rs | 33 +++++++------------ websocket-chat-broker/src/server.rs | 4 +-- 11 files changed, 51 insertions(+), 61 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f99180a2..edcf2b57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,6 @@ members = [ "web-cors/backend", "websocket", "websocket-chat", - #"websocket-chat-broker", + "websocket-chat-broker", "websocket-tcp-chat", ] diff --git a/basics/src/main.rs b/basics/src/main.rs index 7a4edcb1..cace43ae 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -84,7 +84,7 @@ fn main() -> io::Result<()> { App::new() // cookie session middleware .wrap(CookieSession::signed(&[0; 32]).secure(false)) - // enable logger - always register actix-web Logger middleware last + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) // register favicon .service(favicon) diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 8d3b3442..59634c53 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -27,7 +27,7 @@ fn main() -> std::io::Result<()> { .name("auth-example") .secure(false), )) - // enable logger - always register actix-web Logger middleware last + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/logout").to(logout)) diff --git a/json_error/src/main.rs b/json_error/src/main.rs index 64ae7856..6af1c10f 100644 --- a/json_error/src/main.rs +++ b/json_error/src/main.rs @@ -13,41 +13,41 @@ use std::io; #[derive(Debug, Serialize)] struct Error { - msg: String, - status: u16, + msg: String, + status: u16, } impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, "{}", to_string_pretty(self).unwrap()) - } + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}", to_string_pretty(self).unwrap()) + } } impl ResponseError for Error { - // builds the actual response to send back when an error occurs - fn render_response(&self) -> HttpResponse { - let err_json = json!({ "error": self.msg }); - HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json) - } + // builds the actual response to send back when an error occurs + fn render_response(&self) -> HttpResponse { + let err_json = json!({ "error": self.msg }); + HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json) + } } fn index(_: HttpRequest) -> impl Future { - err(Error { - msg: "an example error message".to_string(), - status: 400, - }) + err(Error { + msg: "an example error message".to_string(), + status: 400, + }) } fn main() -> io::Result<()> { - let sys = System::new("json_error_example"); - let ip_address = "127.0.0.1:8000"; + let sys = System::new("json_error_example"); + let ip_address = "127.0.0.1:8000"; - HttpServer::new(|| App::new().service(resource("/").route(get().to_async(index)))) - .bind(ip_address) - .expect("Can not bind to port 8000") - .start(); + HttpServer::new(|| App::new().service(resource("/").route(get().to_async(index)))) + .bind(ip_address) + .expect("Can not bind to port 8000") + .start(); - println!("Running server on {}", ip_address); + println!("Running server on {}", ip_address); - sys.run() + sys.run() } diff --git a/protobuf/src/main.rs b/protobuf/src/main.rs index 56cbb35b..7cce23b0 100644 --- a/protobuf/src/main.rs +++ b/protobuf/src/main.rs @@ -32,7 +32,8 @@ fn main() { App::new() .wrap(middleware::Logger::default()) .service(web::resource("/").route(web::post().to(index))) - }).bind("127.0.0.1:8081") + }) + .bind("127.0.0.1:8081") .unwrap() .shutdown_timeout(1) .start(); diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index ba840b42..7dfe2132 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -28,7 +28,7 @@ fn main() -> std::io::Result<()> { App::new() // redis session middleware .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) - // enable logger - always register actix-web Logger middleware last + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) // register simple route, handle all methods .service(web::resource("/").to(index)) diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 769bc762..22112b7b 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,6 +1,6 @@ use actix::{Handler, Message}; -use actix_web::{dev::Payload, Error, HttpRequest, FromRequest}; use actix_identity::Identity; +use actix_web::{dev::Payload, Error, FromRequest, HttpRequest}; use bcrypt::verify; use diesel::prelude::*; diff --git a/template_handlebars/src/main.rs b/template_handlebars/src/main.rs index b3003ae6..7d1f97bd 100644 --- a/template_handlebars/src/main.rs +++ b/template_handlebars/src/main.rs @@ -23,10 +23,7 @@ fn index(hb: web::Data) -> HttpResponse { } #[get("/{user}/{data}")] -fn user( - hb: web::Data, - info: web::Path<(String, String)>, -) -> HttpResponse { +fn user(hb: web::Data, info: web::Path<(String, String)>) -> HttpResponse { let data = json!({ "user": info.0, "data": info.1 diff --git a/websocket-chat-broker/Cargo.toml b/websocket-chat-broker/Cargo.toml index 3b61d476..7f1ecab8 100644 --- a/websocket-chat-broker/Cargo.toml +++ b/websocket-chat-broker/Cargo.toml @@ -2,17 +2,20 @@ name = "websocket-broker-example" version = "0.1.0" authors = ["Chris Ricketts "] -workspace = "../" +edition = "2018" +workspace = ".." [[bin]] name = "server" path = "src/main.rs" [dependencies] -rand = "*" +rand = "0.6" futures = "0.1.24" -actix = "0.7" -actix-web = "0.7" -actix-broker = "0.1.4" +actix = "0.8.2" +actix-web = "1.0" +actix-files = "0.1" +actix-web-actors = "1.0" +actix-broker = "0.2.0" log = "0.4.5" simple_logger = "0.5.0" diff --git a/websocket-chat-broker/src/main.rs b/websocket-chat-broker/src/main.rs index 4ddc3bc7..00c6ad2d 100644 --- a/websocket-chat-broker/src/main.rs +++ b/websocket-chat-broker/src/main.rs @@ -1,24 +1,18 @@ #[macro_use] -extern crate actix; -extern crate actix_broker; -extern crate actix_web; -extern crate futures; -extern crate rand; -#[macro_use] extern crate log; -extern crate simple_logger; use actix::fut; use actix::prelude::*; use actix_broker::BrokerIssue; -use actix_web::server::HttpServer; -use actix_web::{fs, ws, App, Error, HttpRequest, HttpResponse}; +use actix_files::Files; +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web_actors::ws; mod server; use server::*; -fn chat_route(req: &HttpRequest<()>) -> Result { - ws::start(req, WsChatSession::default()) +fn chat_route(req: HttpRequest, stream: web::Payload) -> Result { + ws::start(WsChatSession::default(), &req, stream) } #[derive(Default)] @@ -34,7 +28,7 @@ impl WsChatSession { // First send a leave message for the current room let leave_msg = LeaveRoom(self.room.clone(), self.id); // issue_sync comes from having the `BrokerIssue` trait in scope. - self.issue_sync(leave_msg, ctx); + self.issue_system_sync(leave_msg, ctx); // Then send a join message for the new room let join_msg = JoinRoom( room_name.to_owned(), @@ -79,7 +73,7 @@ impl WsChatSession { ); let msg = SendMessage(self.room.clone(), self.id, content); // issue_async comes from having the `BrokerIssue` trait in scope. - self.issue_async(msg); + self.issue_system_async(msg); } } @@ -147,24 +141,19 @@ impl StreamHandler for WsChatSession { } } -fn main() { +fn main() -> std::io::Result<()> { let sys = actix::System::new("websocket-broker-example"); simple_logger::init_with_level(log::Level::Info).unwrap(); HttpServer::new(move || { App::new() - .resource("/ws/", |r| r.route().f(chat_route)) - .handler( - "/", - fs::StaticFiles::new("./static/") - .unwrap() - .index_file("index.html"), - ) + .service(web::resource("/ws/").to(chat_route)) + .service(Files::new("/", "./static/").index_file("index.html")) }) .bind("127.0.0.1:8080") .unwrap() .start(); info!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + sys.run() } diff --git a/websocket-chat-broker/src/server.rs b/websocket-chat-broker/src/server.rs index 87a6052b..198b6c85 100644 --- a/websocket-chat-broker/src/server.rs +++ b/websocket-chat-broker/src/server.rs @@ -81,8 +81,8 @@ impl Actor for WsChatServer { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { - self.subscribe_async::(ctx); - self.subscribe_async::(ctx); + self.subscribe_system_async::(ctx); + self.subscribe_system_async::(ctx); } } From 8c019519b99fc5f2e4f1cb060e6cd301beca15dc Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 11 Jul 2019 15:11:05 +0600 Subject: [PATCH 094/111] update redis examples --- actix_redis/Cargo.toml | 4 ++-- redis-session/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actix_redis/Cargo.toml b/actix_redis/Cargo.toml index 2633ef23..f1534fe3 100644 --- a/actix_redis/Cargo.toml +++ b/actix_redis/Cargo.toml @@ -7,8 +7,8 @@ workspace = ".." [dependencies] actix = "0.8.2" -actix-web = "1.0.0" -actix-redis = { git="https://github.com/actix/actix-redis.git" } +actix-web = "1.0.3" +actix-redis = "0.6" futures = "0.1.23" redis-async = "0.4.0" serde = "1.0.71" diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 74943def..7a6c64b1 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix = "0.8.2" -actix-web = "1.0.0" +actix-web = "1.0.3" actix-session = "0.1.0" -actix-redis = { git = "https://github.com/actix/actix-redis.git", features = ["web"] } +actix-redis = { version = "0.6", features = ["web"] } env_logger = "0.6" From 99c9e145c1ed3b48862a4d2eae0dc191719e7bce Mon Sep 17 00:00:00 2001 From: dowwie Date: Thu, 11 Jul 2019 15:10:09 -0400 Subject: [PATCH 095/111] updated redis-session with comprehensive example and tests --- redis-session/Cargo.toml | 13 +- redis-session/README.md | 0 redis-session/src/main.rs | 254 +++++++++++++++++++++++++++++++++++--- 3 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 redis-session/README.md diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index 7a6c64b1..eceeb0f6 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -1,13 +1,18 @@ [package] -name = "redis-session" +name = "redis_session_test" version = "0.1.0" authors = ["Nikolay Kim "] workspace = ".." edition = "2018" [dependencies] -actix = "0.8.2" actix-web = "1.0.3" -actix-session = "0.1.0" -actix-redis = { version = "0.6", features = ["web"] } +actix-session = "0.2.0" +actix-redis = { version = "0.6.0", features = ["web"] } env_logger = "0.6" +serde = { version = "^1.0", features = ["derive"] } +actix-service = "0.4.1" +actix-http-test = "0.2.2" +actix-http = "0.2.5" +serde_json = "1.0.40" +time = "0.1.42" diff --git a/redis-session/README.md b/redis-session/README.md new file mode 100644 index 00000000..e69de29b diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 7dfe2132..944c3b9e 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -1,23 +1,66 @@ -//! Example of redis based session +//! Example of login and logout using redis-based sessions +//! +//! Every request gets a session, corresponding to a cache entry and cookie. +//! At login, the session key changes and session state in cache re-assigns. +//! At logout, session state in cache is removed and cookie is invalidated. //! -//! [User guide](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions) use actix_redis::RedisSession; use actix_session::Session; -use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Result}; +use actix_web::{middleware, web, App, HttpResponse, HttpServer, Result, + web::{resource, get, post}}; +use serde::{Deserialize, Serialize}; -/// simple handler -fn index(req: HttpRequest, session: Session) -> Result { - println!("{:?}", req); - // session - if let Some(count) = session.get::("counter")? { - println!("SESSION value: {}", count); - session.set("counter", count + 1)?; +#[derive(Serialize, Deserialize, Debug, PartialEq)] +pub struct IndexResponse { + user_id: Option, + counter: i32 +} + +fn index(session: Session) -> Result { + let user_id: Option = session.get::("user_id").unwrap(); + let counter: i32 = session.get::("counter") + .unwrap_or(Some(0)) + .unwrap_or(0); + + Ok(HttpResponse::Ok().json(IndexResponse{user_id, counter})) +} + + +fn do_something(session: Session) -> Result { + let user_id: Option = session.get::("user_id").unwrap(); + let counter: i32 = session.get::("counter") + .unwrap_or(Some(0)) + .map_or(1, |inner| inner + 1); + session.set("counter", counter)?; + + Ok(HttpResponse::Ok().json(IndexResponse{user_id, counter})) +} + +#[derive(Deserialize)] +struct Identity { + user_id: String +} +fn login(user_id: web::Json, session: Session) -> Result { + let id = user_id.into_inner().user_id; + session.set("user_id", &id)?; + session.renew(); + + let counter: i32 = session.get::("counter") + .unwrap_or(Some(0)) + .unwrap_or(0); + + Ok(HttpResponse::Ok().json(IndexResponse{user_id: Some(id), counter})) +} + +fn logout(session: Session) -> Result { + let id: Option = session.get("user_id")?; + if let Some(x) = id{ + session.purge(); + Ok(format!("Logged out: {}", x).into()) } else { - session.set("counter", 1)?; + Ok("Could not log out anonymous user".into()) } - - Ok("Welcome!".into()) } fn main() -> std::io::Result<()> { @@ -28,11 +71,190 @@ fn main() -> std::io::Result<()> { App::new() // redis session middleware .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) - // enable logger - always register actix-web Logger middleware last + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) - // register simple route, handle all methods - .service(web::resource("/").to(index)) + .service(resource("/").route(get().to(index))) + .service(resource("/do_something").route(post().to(do_something))) + .service(resource("/login").route(post().to(login))) + .service(resource("/logout").route(post().to(logout))) }) .bind("127.0.0.1:8080")? .run() } + + +#[cfg(test)] +mod test { + use super::*; + use actix_http::{HttpService, httpmessage::HttpMessage}; + use actix_http_test::{TestServer, block_on}; + use actix_web::{middleware, App, web::{resource, get, post}}; + use serde_json::json; + use time; + + #[test] + fn test_workflow() { + // Step 1: GET index + // - set-cookie actix-session will be in response (session cookie #1) + // - response should be: {"counter": 0, "user_id": None} + // Step 2: GET index, including session cookie #1 in request + // - set-cookie will *not* be in response + // - response should be: {"counter": 0, "user_id": None} + // Step 3: POST to do_something, including session cookie #1 in request + // - adds new session state in redis: {"counter": 1} + // - response should be: {"counter": 1, "user_id": None} + // Step 4: POST again to do_something, including session cookie #1 in request + // - updates session state in redis: {"counter": 2} + // - response should be: {"counter": 2, "user_id": None} + // Step 5: POST to login, including session cookie #1 in request + // - set-cookie actix-session will be in response (session cookie #2) + // - updates session state in redis: {"counter": 2, "user_id": "ferris"} + // Step 6: GET index, including session cookie #2 in request + // - response should be: {"counter": 2, "user_id": "ferris"} + // Step 7: POST again to do_something, including session cookie #2 in request + // - updates session state in redis: {"counter": 3, "user_id": "ferris"} + // - response should be: {"counter": 2, "user_id": None} + // Step 8: GET index, including session cookie #1 in request + // - set-cookie actix-session will be in response (session cookie #3) + // - response should be: {"counter": 0, "user_id": None} + // Step 9: POST to logout, including session cookie #2 + // - set-cookie actix-session will be in response with session cookie #2 + // invalidation logic + // Step 10: GET index, including session cookie #2 in request + // - set-cookie actix-session will be in response (session cookie #3) + // - response should be: {"counter": 0, "user_id": None} + + let mut srv = + TestServer::new(|| { + HttpService::new( + App::new() + .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32]) + .cookie_name("test-session")) + .wrap(middleware::Logger::default()) + .service(resource("/").route(get().to(index))) + .service(resource("/do_something").route(post().to(do_something))) + .service(resource("/login").route(post().to(login))) + .service(resource("/logout").route(post().to(logout))) + ) + }); + + + // Step 1: GET index + // - set-cookie actix-session will be in response (session cookie #1) + // - response should be: {"counter": 0, "user_id": None} + let req_1a = srv.get("/").send(); + let mut resp_1 = srv.block_on(req_1a).unwrap(); + let cookie_1 = resp_1.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session") + .unwrap(); + let result_1 = block_on(resp_1.json::()).unwrap(); + assert_eq!(result_1, IndexResponse{user_id: None, counter: 0}); + + + // Step 2: GET index, including session cookie #1 in request + // - set-cookie will *not* be in response + // - response should be: {"counter": 0, "user_id": None} + let req_2 = srv.get("/").cookie(cookie_1.clone()).send(); + let resp_2 = srv.block_on(req_2).unwrap(); + let cookie_2 = resp_2.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session"); + assert_eq!(cookie_2, None); + + + // Step 3: POST to do_something, including session cookie #1 in request + // - adds new session state in redis: {"counter": 1} + // - response should be: {"counter": 1, "user_id": None} + let req_3 = srv.post("/do_something").cookie(cookie_1.clone()).send(); + let mut resp_3 = srv.block_on(req_3).unwrap(); + let result_3 = block_on(resp_3.json::()).unwrap(); + assert_eq!(result_3, IndexResponse{user_id: None, counter: 1}); + + + // Step 4: POST again to do_something, including session cookie #1 in request + // - updates session state in redis: {"counter": 2} + // - response should be: {"counter": 2, "user_id": None} + let req_4 = srv.post("/do_something").cookie(cookie_1.clone()).send(); + let mut resp_4 = srv.block_on(req_4).unwrap(); + let result_4 = block_on(resp_4.json::()).unwrap(); + assert_eq!(result_4, IndexResponse{user_id: None, counter: 2}); + + + // Step 5: POST to login, including session cookie #1 in request + // - set-cookie actix-session will be in response (session cookie #2) + // - updates session state in redis: {"counter": 2, "user_id": "ferris"} + let req_5 = srv.post("/login") + .cookie(cookie_1.clone()) + .send_json(&json!({"user_id": "ferris"})); + let mut resp_5 = srv.block_on(req_5).unwrap(); + let cookie_2 = resp_5.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session") + .unwrap(); + assert_eq!(true, cookie_1.value().to_string() != cookie_2.value().to_string()); + + let result_5 = block_on(resp_5.json::()).unwrap(); + assert_eq!(result_5, IndexResponse{user_id: Some("ferris".into()), counter: 2}); + + + // Step 6: GET index, including session cookie #2 in request + // - response should be: {"counter": 2, "user_id": "ferris"} + let req_6 = srv.get("/") + .cookie(cookie_2.clone()) + .send(); + let mut resp_6 = srv.block_on(req_6).unwrap(); + let result_6 = block_on(resp_6.json::()).unwrap(); + assert_eq!(result_6, IndexResponse{user_id: Some("ferris".into()), counter: 2}); + + + // Step 7: POST again to do_something, including session cookie #2 in request + // - updates session state in redis: {"counter": 3, "user_id": "ferris"} + // - response should be: {"counter": 2, "user_id": None} + let req_7 = srv.post("/do_something").cookie(cookie_2.clone()).send(); + let mut resp_7 = srv.block_on(req_7).unwrap(); + let result_7 = block_on(resp_7.json::()).unwrap(); + assert_eq!(result_7, IndexResponse{user_id: Some("ferris".into()), counter: 3}); + + + // Step 8: GET index, including session cookie #1 in request + // - set-cookie actix-session will be in response (session cookie #3) + // - response should be: {"counter": 0, "user_id": None} + let req_8 = srv.get("/") + .cookie(cookie_1.clone()) + .send(); + let mut resp_8 = srv.block_on(req_8).unwrap(); + let cookie_3 = resp_8.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session") + .unwrap(); + let result_8 = block_on(resp_8.json::()).unwrap(); + assert_eq!(result_8, IndexResponse{user_id: None, counter: 0}); + assert!(cookie_3.value().to_string() != cookie_2.value().to_string()); + + + // Step 9: POST to logout, including session cookie #2 + // - set-cookie actix-session will be in response with session cookie #2 + // invalidation logic + let req_9 = srv.post("/logout") + .cookie(cookie_2.clone()) + .send(); + let resp_9 = srv.block_on(req_9).unwrap(); + let cookie_4 = resp_9.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session") + .unwrap(); + assert!(&time::now().tm_year != &cookie_4.expires().map(|t| t.tm_year).unwrap()); + + + // Step 10: GET index, including session cookie #2 in request + // - set-cookie actix-session will be in response (session cookie #3) + // - response should be: {"counter": 0, "user_id": None} + let req_10 = srv.get("/") + .cookie(cookie_2.clone()) + .send(); + let mut resp_10 = srv.block_on(req_10).unwrap(); + let result_10 = block_on(resp_10.json::()).unwrap(); + assert_eq!(result_10, IndexResponse{user_id: None, counter: 0}); + + let cookie_5 = resp_10.cookies().unwrap().clone() + .into_iter().find(|c| c.name() == "test-session") + .unwrap(); + assert!(cookie_5.value().to_string() != cookie_2.value().to_string()); + } +} \ No newline at end of file From 858376ecda607f21b9cfba063563c41f4a42b675 Mon Sep 17 00:00:00 2001 From: dowwie Date: Thu, 11 Jul 2019 15:27:17 -0400 Subject: [PATCH 096/111] renamed package --- redis-session/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redis-session/Cargo.toml b/redis-session/Cargo.toml index eceeb0f6..edd40825 100644 --- a/redis-session/Cargo.toml +++ b/redis-session/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "redis_session_test" +name = "redis_session" version = "0.1.0" authors = ["Nikolay Kim "] workspace = ".." From 7525903fe690b9b3c9a67ff252d02f70ff5ec65b Mon Sep 17 00:00:00 2001 From: Harry Gill Date: Thu, 18 Jul 2019 12:55:14 +0100 Subject: [PATCH 097/111] Update to new actix 1.0 api, drop actix-rt (#158) --- simple-auth-server/Cargo.toml | 33 +++---- simple-auth-server/README.md | 20 ++-- .../migrations/2018-10-09-101948_users/up.sql | 2 +- simple-auth-server/src/auth_handler.rs | 90 +++++++++++------- simple-auth-server/src/auth_routes.rs | 34 ------- simple-auth-server/src/email_service.rs | 19 ++-- simple-auth-server/src/errors.rs | 25 +++-- simple-auth-server/src/invitation_handler.rs | 68 ++++++++------ simple-auth-server/src/invitation_routes.rs | 22 ----- simple-auth-server/src/main.rs | 72 +++++--------- simple-auth-server/src/models.rs | 50 +++++----- simple-auth-server/src/register_handler.rs | 93 ++++++++++--------- simple-auth-server/src/register_routes.rs | 25 ----- simple-auth-server/src/schema.rs | 2 +- simple-auth-server/src/utils.rs | 83 +++++------------ 15 files changed, 264 insertions(+), 374 deletions(-) delete mode 100644 simple-auth-server/src/auth_routes.rs delete mode 100644 simple-auth-server/src/invitation_routes.rs delete mode 100644 simple-auth-server/src/register_routes.rs diff --git a/simple-auth-server/Cargo.toml b/simple-auth-server/Cargo.toml index 2edffbb3..9a96ced1 100644 --- a/simple-auth-server/Cargo.toml +++ b/simple-auth-server/Cargo.toml @@ -6,23 +6,20 @@ edition = "2018" workspace = ".." [dependencies] -actix = "0.8.2" -actix-rt = "0.2.2" -actix-web = "1.0.2" -actix-files = "0.1.1" -actix-identity= "0.1.0" - -bcrypt = "0.2.1" +actix-identity = "0.1.0" +actix-web = "1.0.3" +argonautica = "0.2.0" chrono = { version = "0.4.6", features = ["serde"] } -diesel = { version = "1.3.3", features = ["postgres", "uuid", "r2d2", "chrono"] } -dotenv = "0.13.0" -derive_more = "0.14" -env_logger = "0.6.0" -jsonwebtoken = "6.0.0" -futures = "0.1.25" -r2d2 = "0.8.3" -serde_derive="1.0.80" -serde_json="1.0" -serde="1.0" +derive_more = "0.15.0" +diesel = { version = "1.4.2", features = ["postgres","uuidv07", "r2d2", "chrono"] } +dotenv = "0.14.1" +env_logger = "0.6" +futures = "0.1" +r2d2 = "0.8" +lazy_static = "1.3.0" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" sparkpost = "0.5.2" -uuid = { version = "0.6.5", features = ["serde", "v4"] } +uuid = { version = "0.7", features = ["serde", "v4"] } + diff --git a/simple-auth-server/README.md b/simple-auth-server/README.md index 4c6048e1..dc25484a 100644 --- a/simple-auth-server/README.md +++ b/simple-auth-server/README.md @@ -1,21 +1,22 @@ +## Auth Web Microservice with rust using Actix-Web 1.0 + ##### Flow of the event would look like this: - Registers with email address ➡ Receive an 📨 with a link to verify - Follow the link ➡ register with same email and a password -- Login with email and password ➡ Get verified and receive jwt token +- Login with email and password ➡ Get verified and receive auth cookie -##### Crates we are going to use +##### Crates Used -- [actix](https://crates.io/crates/actix) // Actix is a Rust actors framework. - [actix-web](https://crates.io/crates/actix-web) // Actix web is a simple, pragmatic and extremely fast web framework for Rust. -- [bcrypt](https://crates.io/crates/bcrypt) // Easily hash and verify passwords using bcrypt. +- [argonautica](https://docs.rs/argonautica) // crate for hashing passwords using the cryptographically-secure Argon2 hashing algorithm. - [chrono](https://crates.io/crates/chrono) // Date and time library for Rust. - [diesel](https://crates.io/crates/diesel) // A safe, extensible ORM and Query Builder for PostgreSQL, SQLite, and MySQL. - [dotenv](https://crates.io/crates/dotenv) // A dotenv implementation for Rust. +- [derive_more](https://crates.io/crates/derive_more) // Convenience macros to derive tarits easily - [env_logger](https://crates.io/crates/env_logger) // A logging implementation for log which is configured via an environment variable. -- [failure](https://crates.io/crates/failure) // Experimental error handling abstraction. -- [jsonwebtoken](https://crates.io/crates/jsonwebtoken) // Create and parse JWT in a strongly typed way. - [futures](https://crates.io/crates/futures) // An implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces. +- [lazy_static](https://docs.rs/lazy_static) // A macro for declaring lazily evaluated statics. - [r2d2](https://crates.io/crates/r2d2) // A generic connection pool. - [serde](https://crates.io/crates/serde) // A generic serialization/deserialization framework. - [serde_json](https://crates.io/crates/serde_json) // A JSON serialization file format. @@ -24,9 +25,6 @@ - [uuid](https://crates.io/crates/uuid) // A library to generate and parse UUIDs. -Read the full tutorial series on [hgill.io](https://hgill.io) - -- [Auth Web Microservice with rust using Actix-Web - Complete Tutorial Part 1](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-1/) -- [Auth Web Microservice with rust using Actix-Web - Complete Tutorial Part 2](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-2/) -- [Auth Web Microservice with rust using Actix-Web - Complete Tutorial Part 3](https://hgill.io/posts/auth-microservice-rust-actix-web-diesel-complete-tutorial-part-3/) +Read the full tutorial series on [gill.net.in](https://gill.net.in) +- [Auth Web Microservice with rust using Actix-Web 1.0 - Complete Tutorial](https://gill.net.in/posts/auth-microservice-rust-actix-web1.0-diesel-complete-tutorial/) diff --git a/simple-auth-server/migrations/2018-10-09-101948_users/up.sql b/simple-auth-server/migrations/2018-10-09-101948_users/up.sql index 890b6676..daf25276 100644 --- a/simple-auth-server/migrations/2018-10-09-101948_users/up.sql +++ b/simple-auth-server/migrations/2018-10-09-101948_users/up.sql @@ -1,6 +1,6 @@ -- Your SQL goes here CREATE TABLE users ( email VARCHAR(100) NOT NULL UNIQUE PRIMARY KEY, - password VARCHAR(64) NOT NULL, --bcrypt hash + hash VARCHAR(122) NOT NULL, --argon hash created_at TIMESTAMP NOT NULL ); diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 22112b7b..7f0f47d8 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,12 +1,14 @@ -use actix::{Handler, Message}; use actix_identity::Identity; -use actix_web::{dev::Payload, Error, FromRequest, HttpRequest}; -use bcrypt::verify; +use actix_web::{ + dev::Payload, error::BlockingError, web, Error, FromRequest, HttpRequest, HttpResponse, +}; use diesel::prelude::*; +use diesel::PgConnection; +use futures::Future; use crate::errors::ServiceError; -use crate::models::{DbExecutor, SlimUser, User}; -use crate::utils::decode_token; +use crate::models::{Pool, SlimUser, User}; +use crate::utils::verify; #[derive(Debug, Deserialize)] pub struct AuthData { @@ -14,34 +16,6 @@ pub struct AuthData { pub password: String, } -impl Message for AuthData { - type Result = Result; -} - -impl Handler for DbExecutor { - type Result = Result; - fn handle(&mut self, msg: AuthData, _: &mut Self::Context) -> Self::Result { - use crate::schema::users::dsl::{email, users}; - let conn: &PgConnection = &self.0.get().unwrap(); - - let mut items = users.filter(email.eq(&msg.email)).load::(conn)?; - - if let Some(user) = items.pop() { - match verify(&msg.password, &user.password) { - Ok(matching) => { - if matching { - return Ok(user.into()); - } - } - Err(_) => (), - } - } - Err(ServiceError::BadRequest( - "Username and Password don't match".into(), - )) - } -} - // we need the same data // simple aliasing makes the intentions clear and its more readable pub type LoggedUser = SlimUser; @@ -53,9 +27,55 @@ impl FromRequest for LoggedUser { fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future { if let Some(identity) = Identity::from_request(req, pl)?.identity() { - let user: SlimUser = decode_token(&identity)?; - return Ok(user as LoggedUser); + let user: LoggedUser = serde_json::from_str(&identity)?; + return Ok(user); } Err(ServiceError::Unauthorized.into()) } } + +pub fn logout(id: Identity) -> HttpResponse { + id.forget(); + HttpResponse::Ok().finish() +} + +pub fn login( + auth_data: web::Json, + id: Identity, + pool: web::Data, +) -> impl Future { + web::block(move || query(auth_data.into_inner(), pool)).then( + move |res: Result>| match res { + Ok(user) => { + let user_string = serde_json::to_string(&user).unwrap(); + id.remember(user_string); + Ok(HttpResponse::Ok().finish()) + } + Err(err) => match err { + BlockingError::Error(service_error) => Err(service_error), + BlockingError::Canceled => Err(ServiceError::InternalServerError), + }, + }, + ) +} + +pub fn get_me(logged_user: LoggedUser) -> HttpResponse { + HttpResponse::Ok().json(logged_user) +} +/// Diesel query +fn query(auth_data: AuthData, pool: web::Data) -> Result { + use crate::schema::users::dsl::{email, users}; + let conn: &PgConnection = &pool.get().unwrap(); + let mut items = users + .filter(email.eq(&auth_data.email)) + .load::(conn)?; + + if let Some(user) = items.pop() { + if let Ok(matching) = verify(&user.hash, &auth_data.password) { + if matching { + return Ok(user.into()); + } + } + } + Err(ServiceError::Unauthorized) +} diff --git a/simple-auth-server/src/auth_routes.rs b/simple-auth-server/src/auth_routes.rs deleted file mode 100644 index caed66ca..00000000 --- a/simple-auth-server/src/auth_routes.rs +++ /dev/null @@ -1,34 +0,0 @@ -use actix::Addr; -use actix_identity::Identity; -use actix_web::{web, Error, HttpRequest, HttpResponse, Responder, ResponseError}; -use futures::Future; - -use crate::auth_handler::{AuthData, LoggedUser}; -use crate::models::DbExecutor; -use crate::utils::create_token; - -pub fn login( - auth_data: web::Json, - id: Identity, - db: web::Data>, -) -> impl Future { - db.send(auth_data.into_inner()) - .from_err() - .and_then(move |res| match res { - Ok(user) => { - let token = create_token(&user)?; - id.remember(token); - Ok(HttpResponse::Ok().into()) - } - Err(err) => Ok(err.error_response()), - }) -} - -pub fn logout(id: Identity) -> impl Responder { - id.forget(); - HttpResponse::Ok() -} - -pub fn get_me(logged_user: LoggedUser) -> HttpResponse { - HttpResponse::Ok().json(logged_user) -} diff --git a/simple-auth-server/src/email_service.rs b/simple-auth-server/src/email_service.rs index 290d37ab..1583e042 100644 --- a/simple-auth-server/src/email_service.rs +++ b/simple-auth-server/src/email_service.rs @@ -1,16 +1,18 @@ +// email_service.rs +use crate::errors::ServiceError; use crate::models::Invitation; use sparkpost::transmission::{ EmailAddress, Message, Options, Recipient, Transmission, TransmissionResponse, }; -fn get_api_key() -> String { - std::env::var("SPARKPOST_API_KEY").expect("SPARKPOST_API_KEY must be set") +lazy_static::lazy_static! { +static ref API_KEY: String = std::env::var("SPARKPOST_API_KEY").expect("SPARKPOST_API_KEY must be set"); } -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"); +pub fn send_invitation(invitation: &Invitation) -> Result<(), ServiceError> { + let tm = Transmission::new_eu(API_KEY.as_str()); + 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")); @@ -53,13 +55,16 @@ pub fn send_invitation(invitation: &Invitation) { Ok(res) => match res { TransmissionResponse::ApiResponse(api_res) => { println!("API Response: \n {:#?}", api_res); + Ok(()) } TransmissionResponse::ApiError(errors) => { println!("Response Errors: \n {:#?}", &errors); + Err(ServiceError::InternalServerError) } }, Err(error) => { - println!("error \n {:#?}", error); + println!("Send Email Error: \n {:#?}", error); + Err(ServiceError::InternalServerError) } } } diff --git a/simple-auth-server/src/errors.rs b/simple-auth-server/src/errors.rs index bac56094..c6ade0ff 100644 --- a/simple-auth-server/src/errors.rs +++ b/simple-auth-server/src/errors.rs @@ -1,8 +1,8 @@ use actix_web::{error::ResponseError, HttpResponse}; use derive_more::Display; -use diesel::result::{DatabaseErrorKind, Error}; +use diesel::result::{DatabaseErrorKind, Error as DBError}; use std::convert::From; -use uuid::ParseError; +use uuid::parser::ParseError; #[derive(Debug, Display)] pub enum ServiceError { @@ -19,15 +19,13 @@ pub enum ServiceError { // impl ResponseError trait allows to convert our errors into http responses with appropriate data impl ResponseError for ServiceError { fn error_response(&self) -> HttpResponse { - match *self { + 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::BadRequest(ref message) => HttpResponse::BadRequest() + .json(message), + ServiceError::Unauthorized => HttpResponse::Unauthorized() + .json("Unauthorized"), } } } @@ -40,15 +38,14 @@ impl From for ServiceError { } } -impl From for ServiceError { - fn from(error: Error) -> ServiceError { +impl From for ServiceError { + fn from(error: DBError) -> ServiceError { // Right now we just care about UniqueViolation from diesel // But this would be helpful to easily map errors as our app grows match error { - Error::DatabaseError(kind, info) => { + DBError::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 diff --git a/simple-auth-server/src/invitation_handler.rs b/simple-auth-server/src/invitation_handler.rs index b0a8ceb7..26246471 100644 --- a/simple-auth-server/src/invitation_handler.rs +++ b/simple-auth-server/src/invitation_handler.rs @@ -1,38 +1,50 @@ -use actix::{Handler, Message}; -use chrono::{Duration, Local}; -use diesel::{self, prelude::*}; -use uuid::Uuid; +use actix_web::{error::BlockingError, web, HttpResponse}; +use diesel::{prelude::*, PgConnection}; +use futures::Future; +use crate::email_service::send_invitation; use crate::errors::ServiceError; -use crate::models::{DbExecutor, Invitation}; +use crate::models::{Invitation, Pool}; #[derive(Deserialize)] -pub struct CreateInvitation { +pub struct InvitationData { pub email: String, } -impl Message for CreateInvitation { - type Result = Result; +pub fn post_invitation( + invitation_data: web::Json, + pool: web::Data, +) -> impl Future { + // run diesel blocking code + web::block(move || create_invitation(invitation_data.into_inner().email, pool)).then(|res| { + match res { + Ok(_) => Ok(HttpResponse::Ok().finish()), + Err(err) => match err { + BlockingError::Error(service_error) => Err(service_error), + BlockingError::Canceled => Err(ServiceError::InternalServerError), + }, + } + }) } -impl Handler for DbExecutor { - type Result = Result; - - fn handle(&mut self, msg: CreateInvitation, _: &mut Self::Context) -> Self::Result { - use crate::schema::invitations::dsl::*; - let conn: &PgConnection = &self.0.get().unwrap(); - - // creating a new Invitation object with expired at time that is 24 hours from now - let new_invitation = Invitation { - id: Uuid::new_v4(), - email: msg.email.clone(), - expires_at: Local::now().naive_local() + Duration::hours(24), - }; - - let inserted_invitation = diesel::insert_into(invitations) - .values(&new_invitation) - .get_result(conn)?; - - Ok(inserted_invitation) - } +fn create_invitation( + eml: String, + pool: web::Data, +) -> Result<(), crate::errors::ServiceError> { + let invitation = dbg!(query(eml, pool)?); + send_invitation(&invitation) +} + +/// Diesel query +fn query(eml: String, pool: web::Data) -> Result { + use crate::schema::invitations::dsl::invitations; + + let new_invitation : Invitation = eml.into(); + let conn: &PgConnection = &pool.get().unwrap(); + + let inserted_invitation = diesel::insert_into(invitations) + .values(&new_invitation) + .get_result(conn)?; + + Ok(inserted_invitation) } diff --git a/simple-auth-server/src/invitation_routes.rs b/simple-auth-server/src/invitation_routes.rs deleted file mode 100644 index ea76bca2..00000000 --- a/simple-auth-server/src/invitation_routes.rs +++ /dev/null @@ -1,22 +0,0 @@ -use actix::Addr; -use actix_web::{web, Error, HttpResponse, ResponseError}; -use futures::future::Future; - -use crate::email_service::send_invitation; -use crate::invitation_handler::CreateInvitation; -use crate::models::DbExecutor; - -pub fn register_email( - signup_invitation: web::Json, - db: web::Data>, -) -> impl Future { - db.send(signup_invitation.into_inner()) - .from_err() - .and_then(|db_response| match db_response { - Ok(invitation) => { - send_invitation(&invitation); - Ok(HttpResponse::Ok().into()) - } - Err(err) => Ok(err.error_response()), - }) -} diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index 45d1ab2d..aaccf080 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -1,98 +1,72 @@ -#![allow(unused_imports)] - #[macro_use] extern crate diesel; #[macro_use] extern crate serde_derive; -use actix::prelude::*; -use actix_files as fs; use actix_identity::{CookieIdentityPolicy, IdentityService}; -use actix_web::middleware::Logger; -use actix_web::{web, App, HttpServer}; -use chrono::Duration; -use diesel::{r2d2::ConnectionManager, PgConnection}; -use dotenv::dotenv; +use actix_web::{middleware, web, App, HttpServer}; +use diesel::prelude::*; +use diesel::r2d2::{self, ConnectionManager}; 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; -use crate::models::DbExecutor; - fn main() -> std::io::Result<()> { - dotenv().ok(); + dotenv::dotenv().ok(); std::env::set_var( "RUST_LOG", "simple-auth-server=debug,actix_web=info,actix_server=info", ); env_logger::init(); - let sys = actix_rt::System::new("example"); - let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); // create db connection pool let manager = ConnectionManager::::new(database_url); - let pool = r2d2::Pool::builder() + let pool: models::Pool = r2d2::Pool::builder() .build(manager) .expect("Failed to create pool."); + let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string()); - let address: Addr = - SyncArbiter::start(4, move || DbExecutor(pool.clone())); - + // Start http server HttpServer::new(move || { - // 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()); - App::new() - .data(address.clone()) - .wrap(Logger::default()) + .data(pool.clone()) + // enable logger + .wrap(middleware::Logger::default()) .wrap(IdentityService::new( - CookieIdentityPolicy::new(secret.as_bytes()) + CookieIdentityPolicy::new(utils::SECRET_KEY.as_bytes()) .name("auth") .path("/") .domain(domain.as_str()) - .max_age_time(Duration::days(1)) + .max_age_time(chrono::Duration::days(1)) .secure(false), // this can only be true if you have https )) + .data(web::JsonConfig::default().limit(4096)) // everything under '/api/' route .service( web::scope("/api") - // routes for authentication .service( - web::resource("/auth") - .route(web::post().to_async(auth_routes::login)) - .route(web::delete().to(auth_routes::logout)) - .route(web::get().to_async(auth_routes::get_me)), + web::resource("/invitation") + .route(web::post().to_async(invitation_handler::post_invitation)), ) - // routes to invitation - .service( - web::resource("/invitation").route( - web::post().to_async(invitation_routes::register_email), - ), - ) - // routes to register as a user after the .service( web::resource("/register/{invitation_id}") - .route(web::post().to_async(register_routes::register_user)), + .route(web::post().to_async(register_handler::register_user)), + ) + .service( + web::resource("/auth") + .route(web::post().to_async(auth_handler::login)) + .route(web::delete().to(auth_handler::logout)) + .route(web::get().to(auth_handler::get_me)), ), ) - // serve static files - .service(fs::Files::new("/", "./static/").index_file("index.html")) }) .bind("127.0.0.1:3000")? - .start(); - - sys.run() + .run() } diff --git a/simple-auth-server/src/models.rs b/simple-auth-server/src/models.rs index 76dcfac7..dc07509b 100644 --- a/simple-auth-server/src/models.rs +++ b/simple-auth-server/src/models.rs @@ -1,37 +1,23 @@ -use actix::{Actor, SyncContext}; -use chrono::{Local, NaiveDateTime}; -use diesel::pg::PgConnection; -use diesel::r2d2::{ConnectionManager, Pool}; -use std::convert::From; -use uuid::Uuid; +use super::schema::*; +use diesel::{r2d2::ConnectionManager, PgConnection}; -use crate::schema::{invitations, users}; - -/// This is db executor actor. can be run in parallel -pub struct DbExecutor(pub Pool>); - -// Actors communicate exclusively by exchanging messages. -// The sending actor can optionally wait for the response. -// Actors are not referenced directly, but by means of addresses. -// Any rust type can be an actor, it only needs to implement the Actor trait. -impl Actor for DbExecutor { - type Context = SyncContext; -} +// type alias to use in multiple places +pub type Pool = r2d2::Pool>; #[derive(Debug, Serialize, Deserialize, Queryable, Insertable)] #[table_name = "users"] pub struct User { pub email: String, - pub password: String, - pub created_at: NaiveDateTime, + pub hash: String, + pub created_at: chrono::NaiveDateTime, } impl User { - pub fn with_details(email: String, password: String) -> Self { + pub fn from_details, T: Into>(email: S, pwd: T) -> Self { User { - email, - password, - created_at: Local::now().naive_local(), + email: email.into(), + hash: pwd.into(), + created_at: chrono::Local::now().naive_local(), } } } @@ -39,9 +25,21 @@ impl User { #[derive(Debug, Serialize, Deserialize, Queryable, Insertable)] #[table_name = "invitations"] pub struct Invitation { - pub id: Uuid, + pub id: uuid::Uuid, pub email: String, - pub expires_at: NaiveDateTime, + pub expires_at: chrono::NaiveDateTime, +} + +// any type that implements Into can be used to create Invitation +impl From for Invitation where + T: Into { + fn from(email: T) -> Self { + Invitation { + id: uuid::Uuid::new_v4(), + email: email.into(), + expires_at: chrono::Local::now().naive_local() + chrono::Duration::hours(24), + } + } } #[derive(Debug, Serialize, Deserialize)] diff --git a/simple-auth-server/src/register_handler.rs b/simple-auth-server/src/register_handler.rs index 04fe164e..2b43a006 100644 --- a/simple-auth-server/src/register_handler.rs +++ b/simple-auth-server/src/register_handler.rs @@ -1,58 +1,65 @@ -use actix::{Handler, Message}; -use chrono::Local; +use actix_web::{error::BlockingError, web, HttpResponse}; use diesel::prelude::*; -use uuid::Uuid; +use futures::Future; use crate::errors::ServiceError; -use crate::models::{DbExecutor, Invitation, SlimUser, User}; +use crate::models::{Invitation, Pool, SlimUser, User}; use crate::utils::hash_password; - // UserData is used to extract data from a post request by the client #[derive(Debug, Deserialize)] pub struct UserData { pub password: String, } -// to be used to send data via the Actix actor system -#[derive(Debug)] -pub struct RegisterUser { - pub invitation_id: String, - pub password: String, +pub fn register_user( + invitation_id: web::Path, + user_data: web::Json, + pool: web::Data, +) -> impl Future { + web::block(move || { + query( + invitation_id.into_inner(), + user_data.into_inner().password, + pool, + ) + }) + .then(|res| match res { + Ok(user) => Ok(HttpResponse::Ok().json(&user)), + Err(err) => match err { + BlockingError::Error(service_error) => Err(service_error), + BlockingError::Canceled => Err(ServiceError::InternalServerError), + }, + }) } -impl Message for RegisterUser { - type Result = Result; -} +fn query( + invitation_id: String, + password: String, + pool: web::Data, +) -> Result { + use crate::schema::invitations::dsl::{id, invitations}; + use crate::schema::users::dsl::users; + let invitation_id = uuid::Uuid::parse_str(&invitation_id)?; -impl Handler for DbExecutor { - type Result = Result; - fn handle(&mut self, msg: RegisterUser, _: &mut Self::Context) -> Self::Result { - use crate::schema::invitations::dsl::{id, invitations}; - use crate::schema::users::dsl::users; - let conn: &PgConnection = &self.0.get().unwrap(); - - // try parsing the string provided by the user as url parameter - // 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)) - .load::(conn) - .map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into())) - .and_then(|mut result| { - if let Some(invitation) = result.pop() { - // if invitation is not expired - if invitation.expires_at > Local::now().naive_local() { - // 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)?; - - return Ok(inserted_user.into()); - } + let conn: &PgConnection = &pool.get().unwrap(); + invitations + .filter(id.eq(invitation_id)) + .load::(conn) + .map_err(|_db_error| ServiceError::BadRequest("Invalid Invitation".into())) + .and_then(|mut result| { + if let Some(invitation) = result.pop() { + // if invitation is not expired + if invitation.expires_at > chrono::Local::now().naive_local() { + // try hashing the password, else return the error that will be converted to ServiceError + let password: String = hash_password(&password)?; + dbg!(&password); + let user = User::from_details(invitation.email, password); + let inserted_user: User = + diesel::insert_into(users).values(&user).get_result(conn)?; + dbg!(&inserted_user); + return Ok(inserted_user.into()); } - Err(ServiceError::BadRequest("Invalid Invitation".into())) - }) - } + } + Err(ServiceError::BadRequest("Invalid Invitation".into())) + }) } diff --git a/simple-auth-server/src/register_routes.rs b/simple-auth-server/src/register_routes.rs deleted file mode 100644 index 19b3866f..00000000 --- a/simple-auth-server/src/register_routes.rs +++ /dev/null @@ -1,25 +0,0 @@ -use actix::Addr; -use actix_web::{web, Error, HttpResponse, ResponseError}; -use futures::Future; - -use crate::models::DbExecutor; -use crate::register_handler::{RegisterUser, UserData}; - -pub fn register_user( - invitation_id: web::Path, - user_data: web::Json, - db: web::Data>, -) -> impl Future { - let msg = RegisterUser { - // into_inner() returns the inner string value from Path - invitation_id: invitation_id.into_inner(), - password: user_data.password.clone(), - }; - - 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()), - }) -} diff --git a/simple-auth-server/src/schema.rs b/simple-auth-server/src/schema.rs index 95c37038..8c48962f 100644 --- a/simple-auth-server/src/schema.rs +++ b/simple-auth-server/src/schema.rs @@ -9,7 +9,7 @@ table! { table! { users (email) { email -> Varchar, - password -> Varchar, + hash -> Varchar, created_at -> Timestamp, } } diff --git a/simple-auth-server/src/utils.rs b/simple-auth-server/src/utils.rs index 37035277..ce2e66a9 100644 --- a/simple-auth-server/src/utils.rs +++ b/simple-auth-server/src/utils.rs @@ -1,67 +1,30 @@ -use bcrypt::{hash, DEFAULT_COST}; -use chrono::{Duration, Local}; -use jsonwebtoken::{decode, encode, Header, Validation}; - use crate::errors::ServiceError; -use crate::models::SlimUser; +use argonautica::{Hasher, Verifier}; -pub fn hash_password(plain: &str) -> Result { - // get the hashing cost from the env variable or use default - let hashing_cost: u32 = match std::env::var("HASH_ROUNDS") { - Ok(cost) => cost.parse().unwrap_or(DEFAULT_COST), - _ => DEFAULT_COST, - }; - println!("{}", &hashing_cost); - hash(plain, hashing_cost).map_err(|_| ServiceError::InternalServerError) +lazy_static::lazy_static! { +pub static ref SECRET_KEY: String = std::env::var("SECRET_KEY").unwrap_or_else(|_| "0123".repeat(8)); } -#[derive(Debug, Serialize, Deserialize)] -struct Claims { - // issuer - iss: String, - // subject - sub: String, - //issued at - iat: i64, - // expiry - exp: i64, - // user email - email: String, +// WARNING THIS IS ONLY FOR DEMO PLEASE DO MORE RESEARCH FOR PRODUCTION USE +pub fn hash_password(password: &str) -> Result { + Hasher::default() + .with_password(password) + .with_secret_key(SECRET_KEY.as_str()) + .hash() + .map_err(|err| { + dbg!(err); + ServiceError::InternalServerError + }) } -// struct to get converted to token and back -impl Claims { - fn with_email(email: &str) -> Self { - Claims { - iss: "localhost".into(), - sub: "auth".into(), - email: email.to_owned(), - iat: Local::now().timestamp(), - exp: (Local::now() + Duration::hours(24)).timestamp(), - } - } -} - -impl From for SlimUser { - fn from(claims: Claims) -> Self { - SlimUser { - email: claims.email, - } - } -} - -pub fn create_token(data: &SlimUser) -> Result { - let claims = Claims::with_email(data.email.as_str()); - encode(&Header::default(), &claims, get_secret().as_ref()) - .map_err(|_err| ServiceError::InternalServerError) -} - -pub fn decode_token(token: &str) -> Result { - decode::(token, get_secret().as_ref(), &Validation::default()) - .map(|data| Ok(data.claims.into())) - .map_err(|_err| ServiceError::Unauthorized)? -} - -fn get_secret() -> String { - std::env::var("JWT_SECRET").unwrap_or_else(|_| "my secret".into()) +pub fn verify(hash: &str, password: &str) -> Result { + Verifier::default() + .with_hash(hash) + .with_password(password) + .with_secret_key(SECRET_KEY.as_str()) + .verify() + .map_err(|err| { + dbg!(err); + ServiceError::Unauthorized + }) } From 44053504ad39b2bb023712c7577a06091629ad41 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 18 Jul 2019 18:03:19 +0600 Subject: [PATCH 098/111] reenable uds example; cargo fmt --- Cargo.toml | 2 +- redis-session/src/main.rs | 261 ++++++++++++------- simple-auth-server/src/auth_handler.rs | 3 +- simple-auth-server/src/email_service.rs | 4 +- simple-auth-server/src/errors.rs | 13 +- simple-auth-server/src/invitation_handler.rs | 15 +- simple-auth-server/src/main.rs | 15 +- simple-auth-server/src/models.rs | 6 +- unix-socket/Cargo.toml | 6 +- unix-socket/README.md | 2 +- unix-socket/src/main.rs | 35 +-- 11 files changed, 216 insertions(+), 146 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index edcf2b57..0caeb8da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ members = [ "template_yarte", "template_handlebars", "tls", - #"unix-socket", + "unix-socket", "web-cors/backend", "websocket", "websocket-chat", diff --git a/redis-session/src/main.rs b/redis-session/src/main.rs index 944c3b9e..e85b59e0 100644 --- a/redis-session/src/main.rs +++ b/redis-session/src/main.rs @@ -6,56 +6,63 @@ //! use actix_redis::RedisSession; use actix_session::Session; -use actix_web::{middleware, web, App, HttpResponse, HttpServer, Result, - web::{resource, get, post}}; +use actix_web::{ + middleware, web, + web::{get, post, resource}, + App, HttpResponse, HttpServer, Result, +}; use serde::{Deserialize, Serialize}; - #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct IndexResponse { user_id: Option, - counter: i32 + counter: i32, } fn index(session: Session) -> Result { let user_id: Option = session.get::("user_id").unwrap(); - let counter: i32 = session.get::("counter") - .unwrap_or(Some(0)) - .unwrap_or(0); + let counter: i32 = session + .get::("counter") + .unwrap_or(Some(0)) + .unwrap_or(0); - Ok(HttpResponse::Ok().json(IndexResponse{user_id, counter})) + Ok(HttpResponse::Ok().json(IndexResponse { user_id, counter })) } - fn do_something(session: Session) -> Result { let user_id: Option = session.get::("user_id").unwrap(); - let counter: i32 = session.get::("counter") - .unwrap_or(Some(0)) - .map_or(1, |inner| inner + 1); + let counter: i32 = session + .get::("counter") + .unwrap_or(Some(0)) + .map_or(1, |inner| inner + 1); session.set("counter", counter)?; - Ok(HttpResponse::Ok().json(IndexResponse{user_id, counter})) + Ok(HttpResponse::Ok().json(IndexResponse { user_id, counter })) } #[derive(Deserialize)] struct Identity { - user_id: String + user_id: String, } fn login(user_id: web::Json, session: Session) -> Result { let id = user_id.into_inner().user_id; session.set("user_id", &id)?; session.renew(); - let counter: i32 = session.get::("counter") - .unwrap_or(Some(0)) - .unwrap_or(0); + let counter: i32 = session + .get::("counter") + .unwrap_or(Some(0)) + .unwrap_or(0); - Ok(HttpResponse::Ok().json(IndexResponse{user_id: Some(id), counter})) + Ok(HttpResponse::Ok().json(IndexResponse { + user_id: Some(id), + counter, + })) } fn logout(session: Session) -> Result { let id: Option = session.get("user_id")?; - if let Some(x) = id{ + if let Some(x) = id { session.purge(); Ok(format!("Logged out: {}", x).into()) } else { @@ -71,7 +78,7 @@ fn main() -> std::io::Result<()> { App::new() // redis session middleware .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32])) - // enable logger - always register actix-web Logger middleware last + // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) .service(resource("/").route(get().to(index))) .service(resource("/do_something").route(post().to(do_something))) @@ -82,29 +89,32 @@ fn main() -> std::io::Result<()> { .run() } - #[cfg(test)] mod test { use super::*; - use actix_http::{HttpService, httpmessage::HttpMessage}; - use actix_http_test::{TestServer, block_on}; - use actix_web::{middleware, App, web::{resource, get, post}}; + use actix_http::{httpmessage::HttpMessage, HttpService}; + use actix_http_test::{block_on, TestServer}; + use actix_web::{ + middleware, + web::{get, post, resource}, + App, + }; use serde_json::json; use time; #[test] fn test_workflow() { - // Step 1: GET index + // Step 1: GET index // - set-cookie actix-session will be in response (session cookie #1) // - response should be: {"counter": 0, "user_id": None} // Step 2: GET index, including session cookie #1 in request // - set-cookie will *not* be in response // - response should be: {"counter": 0, "user_id": None} // Step 3: POST to do_something, including session cookie #1 in request - // - adds new session state in redis: {"counter": 1} + // - adds new session state in redis: {"counter": 1} // - response should be: {"counter": 1, "user_id": None} // Step 4: POST again to do_something, including session cookie #1 in request - // - updates session state in redis: {"counter": 2} + // - updates session state in redis: {"counter": 2} // - response should be: {"counter": 2, "user_id": None} // Step 5: POST to login, including session cookie #1 in request // - set-cookie actix-session will be in response (session cookie #2) @@ -124,86 +134,124 @@ mod test { // - set-cookie actix-session will be in response (session cookie #3) // - response should be: {"counter": 0, "user_id": None} - let mut srv = - TestServer::new(|| { - HttpService::new( - App::new() - .wrap(RedisSession::new("127.0.0.1:6379", &[0; 32]) - .cookie_name("test-session")) - .wrap(middleware::Logger::default()) - .service(resource("/").route(get().to(index))) - .service(resource("/do_something").route(post().to(do_something))) - .service(resource("/login").route(post().to(login))) - .service(resource("/logout").route(post().to(logout))) - ) - }); + let mut srv = TestServer::new(|| { + HttpService::new( + App::new() + .wrap( + RedisSession::new("127.0.0.1:6379", &[0; 32]) + .cookie_name("test-session"), + ) + .wrap(middleware::Logger::default()) + .service(resource("/").route(get().to(index))) + .service(resource("/do_something").route(post().to(do_something))) + .service(resource("/login").route(post().to(login))) + .service(resource("/logout").route(post().to(logout))), + ) + }); - - // Step 1: GET index + // Step 1: GET index // - set-cookie actix-session will be in response (session cookie #1) // - response should be: {"counter": 0, "user_id": None} let req_1a = srv.get("/").send(); let mut resp_1 = srv.block_on(req_1a).unwrap(); - let cookie_1 = resp_1.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session") - .unwrap(); + let cookie_1 = resp_1 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session") + .unwrap(); let result_1 = block_on(resp_1.json::()).unwrap(); - assert_eq!(result_1, IndexResponse{user_id: None, counter: 0}); - + assert_eq!( + result_1, + IndexResponse { + user_id: None, + counter: 0 + } + ); // Step 2: GET index, including session cookie #1 in request // - set-cookie will *not* be in response // - response should be: {"counter": 0, "user_id": None} let req_2 = srv.get("/").cookie(cookie_1.clone()).send(); let resp_2 = srv.block_on(req_2).unwrap(); - let cookie_2 = resp_2.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session"); + let cookie_2 = resp_2 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session"); assert_eq!(cookie_2, None); - // Step 3: POST to do_something, including session cookie #1 in request - // - adds new session state in redis: {"counter": 1} + // - adds new session state in redis: {"counter": 1} // - response should be: {"counter": 1, "user_id": None} let req_3 = srv.post("/do_something").cookie(cookie_1.clone()).send(); let mut resp_3 = srv.block_on(req_3).unwrap(); let result_3 = block_on(resp_3.json::()).unwrap(); - assert_eq!(result_3, IndexResponse{user_id: None, counter: 1}); - + assert_eq!( + result_3, + IndexResponse { + user_id: None, + counter: 1 + } + ); // Step 4: POST again to do_something, including session cookie #1 in request - // - updates session state in redis: {"counter": 2} + // - updates session state in redis: {"counter": 2} // - response should be: {"counter": 2, "user_id": None} let req_4 = srv.post("/do_something").cookie(cookie_1.clone()).send(); let mut resp_4 = srv.block_on(req_4).unwrap(); let result_4 = block_on(resp_4.json::()).unwrap(); - assert_eq!(result_4, IndexResponse{user_id: None, counter: 2}); - + assert_eq!( + result_4, + IndexResponse { + user_id: None, + counter: 2 + } + ); // Step 5: POST to login, including session cookie #1 in request // - set-cookie actix-session will be in response (session cookie #2) // - updates session state in redis: {"counter": 2, "user_id": "ferris"} - let req_5 = srv.post("/login") - .cookie(cookie_1.clone()) - .send_json(&json!({"user_id": "ferris"})); + let req_5 = srv + .post("/login") + .cookie(cookie_1.clone()) + .send_json(&json!({"user_id": "ferris"})); let mut resp_5 = srv.block_on(req_5).unwrap(); - let cookie_2 = resp_5.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session") - .unwrap(); - assert_eq!(true, cookie_1.value().to_string() != cookie_2.value().to_string()); + let cookie_2 = resp_5 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session") + .unwrap(); + assert_eq!( + true, + cookie_1.value().to_string() != cookie_2.value().to_string() + ); let result_5 = block_on(resp_5.json::()).unwrap(); - assert_eq!(result_5, IndexResponse{user_id: Some("ferris".into()), counter: 2}); - + assert_eq!( + result_5, + IndexResponse { + user_id: Some("ferris".into()), + counter: 2 + } + ); // Step 6: GET index, including session cookie #2 in request // - response should be: {"counter": 2, "user_id": "ferris"} - let req_6 = srv.get("/") - .cookie(cookie_2.clone()) - .send(); + let req_6 = srv.get("/").cookie(cookie_2.clone()).send(); let mut resp_6 = srv.block_on(req_6).unwrap(); let result_6 = block_on(resp_6.json::()).unwrap(); - assert_eq!(result_6, IndexResponse{user_id: Some("ferris".into()), counter: 2}); - + assert_eq!( + result_6, + IndexResponse { + user_id: Some("ferris".into()), + counter: 2 + } + ); // Step 7: POST again to do_something, including session cookie #2 in request // - updates session state in redis: {"counter": 3, "user_id": "ferris"} @@ -211,50 +259,71 @@ mod test { let req_7 = srv.post("/do_something").cookie(cookie_2.clone()).send(); let mut resp_7 = srv.block_on(req_7).unwrap(); let result_7 = block_on(resp_7.json::()).unwrap(); - assert_eq!(result_7, IndexResponse{user_id: Some("ferris".into()), counter: 3}); - + assert_eq!( + result_7, + IndexResponse { + user_id: Some("ferris".into()), + counter: 3 + } + ); // Step 8: GET index, including session cookie #1 in request // - set-cookie actix-session will be in response (session cookie #3) // - response should be: {"counter": 0, "user_id": None} - let req_8 = srv.get("/") - .cookie(cookie_1.clone()) - .send(); + let req_8 = srv.get("/").cookie(cookie_1.clone()).send(); let mut resp_8 = srv.block_on(req_8).unwrap(); - let cookie_3 = resp_8.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session") - .unwrap(); + let cookie_3 = resp_8 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session") + .unwrap(); let result_8 = block_on(resp_8.json::()).unwrap(); - assert_eq!(result_8, IndexResponse{user_id: None, counter: 0}); + assert_eq!( + result_8, + IndexResponse { + user_id: None, + counter: 0 + } + ); assert!(cookie_3.value().to_string() != cookie_2.value().to_string()); - // Step 9: POST to logout, including session cookie #2 // - set-cookie actix-session will be in response with session cookie #2 // invalidation logic - let req_9 = srv.post("/logout") - .cookie(cookie_2.clone()) - .send(); + let req_9 = srv.post("/logout").cookie(cookie_2.clone()).send(); let resp_9 = srv.block_on(req_9).unwrap(); - let cookie_4 = resp_9.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session") - .unwrap(); + let cookie_4 = resp_9 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session") + .unwrap(); assert!(&time::now().tm_year != &cookie_4.expires().map(|t| t.tm_year).unwrap()); - // Step 10: GET index, including session cookie #2 in request // - set-cookie actix-session will be in response (session cookie #3) // - response should be: {"counter": 0, "user_id": None} - let req_10 = srv.get("/") - .cookie(cookie_2.clone()) - .send(); + let req_10 = srv.get("/").cookie(cookie_2.clone()).send(); let mut resp_10 = srv.block_on(req_10).unwrap(); let result_10 = block_on(resp_10.json::()).unwrap(); - assert_eq!(result_10, IndexResponse{user_id: None, counter: 0}); - - let cookie_5 = resp_10.cookies().unwrap().clone() - .into_iter().find(|c| c.name() == "test-session") - .unwrap(); + assert_eq!( + result_10, + IndexResponse { + user_id: None, + counter: 0 + } + ); + + let cookie_5 = resp_10 + .cookies() + .unwrap() + .clone() + .into_iter() + .find(|c| c.name() == "test-session") + .unwrap(); assert!(cookie_5.value().to_string() != cookie_2.value().to_string()); } -} \ No newline at end of file +} diff --git a/simple-auth-server/src/auth_handler.rs b/simple-auth-server/src/auth_handler.rs index 7f0f47d8..9c75efc0 100644 --- a/simple-auth-server/src/auth_handler.rs +++ b/simple-auth-server/src/auth_handler.rs @@ -1,6 +1,7 @@ use actix_identity::Identity; use actix_web::{ - dev::Payload, error::BlockingError, web, Error, FromRequest, HttpRequest, HttpResponse, + dev::Payload, error::BlockingError, web, Error, FromRequest, HttpRequest, + HttpResponse, }; use diesel::prelude::*; use diesel::PgConnection; diff --git a/simple-auth-server/src/email_service.rs b/simple-auth-server/src/email_service.rs index 1583e042..4f22497f 100644 --- a/simple-auth-server/src/email_service.rs +++ b/simple-auth-server/src/email_service.rs @@ -11,8 +11,8 @@ static ref API_KEY: String = std::env::var("SPARKPOST_API_KEY").expect("SPARKPOS pub fn send_invitation(invitation: &Invitation) -> Result<(), ServiceError> { let tm = Transmission::new_eu(API_KEY.as_str()); - 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")); diff --git a/simple-auth-server/src/errors.rs b/simple-auth-server/src/errors.rs index c6ade0ff..1cea664b 100644 --- a/simple-auth-server/src/errors.rs +++ b/simple-auth-server/src/errors.rs @@ -22,10 +22,12 @@ impl ResponseError for ServiceError { 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::BadRequest(ref message) => { + HttpResponse::BadRequest().json(message) + } + ServiceError::Unauthorized => { + HttpResponse::Unauthorized().json("Unauthorized") + } } } } @@ -45,7 +47,8 @@ impl From for ServiceError { match error { DBError::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 diff --git a/simple-auth-server/src/invitation_handler.rs b/simple-auth-server/src/invitation_handler.rs index 26246471..11b137bd 100644 --- a/simple-auth-server/src/invitation_handler.rs +++ b/simple-auth-server/src/invitation_handler.rs @@ -16,15 +16,15 @@ pub fn post_invitation( pool: web::Data, ) -> impl Future { // run diesel blocking code - web::block(move || create_invitation(invitation_data.into_inner().email, pool)).then(|res| { - match res { + web::block(move || create_invitation(invitation_data.into_inner().email, pool)).then( + |res| match res { Ok(_) => Ok(HttpResponse::Ok().finish()), Err(err) => match err { BlockingError::Error(service_error) => Err(service_error), BlockingError::Canceled => Err(ServiceError::InternalServerError), }, - } - }) + }, + ) } fn create_invitation( @@ -36,10 +36,13 @@ fn create_invitation( } /// Diesel query -fn query(eml: String, pool: web::Data) -> Result { +fn query( + eml: String, + pool: web::Data, +) -> Result { use crate::schema::invitations::dsl::invitations; - let new_invitation : Invitation = eml.into(); + let new_invitation: Invitation = eml.into(); let conn: &PgConnection = &pool.get().unwrap(); let inserted_invitation = diesel::insert_into(invitations) diff --git a/simple-auth-server/src/main.rs b/simple-auth-server/src/main.rs index aaccf080..7271ec3e 100644 --- a/simple-auth-server/src/main.rs +++ b/simple-auth-server/src/main.rs @@ -31,7 +31,8 @@ fn main() -> std::io::Result<()> { let pool: models::Pool = r2d2::Pool::builder() .build(manager) .expect("Failed to create pool."); - let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string()); + let domain: String = + std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string()); // Start http server HttpServer::new(move || { @@ -51,13 +52,13 @@ fn main() -> std::io::Result<()> { // everything under '/api/' route .service( web::scope("/api") + .service(web::resource("/invitation").route( + web::post().to_async(invitation_handler::post_invitation), + )) .service( - web::resource("/invitation") - .route(web::post().to_async(invitation_handler::post_invitation)), - ) - .service( - web::resource("/register/{invitation_id}") - .route(web::post().to_async(register_handler::register_user)), + web::resource("/register/{invitation_id}").route( + web::post().to_async(register_handler::register_user), + ), ) .service( web::resource("/auth") diff --git a/simple-auth-server/src/models.rs b/simple-auth-server/src/models.rs index dc07509b..1f5d9695 100644 --- a/simple-auth-server/src/models.rs +++ b/simple-auth-server/src/models.rs @@ -31,8 +31,10 @@ pub struct Invitation { } // any type that implements Into can be used to create Invitation -impl From for Invitation where - T: Into { +impl From for Invitation +where + T: Into, +{ fn from(email: T) -> Self { Invitation { id: uuid::Uuid::new_v4(), diff --git a/unix-socket/Cargo.toml b/unix-socket/Cargo.toml index 423ac7b1..0eba6e2e 100644 --- a/unix-socket/Cargo.toml +++ b/unix-socket/Cargo.toml @@ -2,11 +2,11 @@ name = "unix-socket" version = "0.1.0" authors = ["Messense Lv "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] env_logger = "0.5" tokio-uds = "0.2" -actix = "0.7" -actix-web = "0.7" +actix-web = { version = "1.0.5", features = ["uds"] } diff --git a/unix-socket/README.md b/unix-socket/README.md index 03b0066a..94870320 100644 --- a/unix-socket/README.md +++ b/unix-socket/README.md @@ -7,7 +7,7 @@ Hello world! Although this will only one thread for handling incoming connections according to the -[documentation](https://actix.github.io/actix-web/actix_web/struct.HttpServer.html#method.start_incoming). +[documentation](https://actix.github.io/actix-web/actix_web/struct.HttpServer.html#method.bind_uds). And it does not delete the socket file (`/tmp/actix-uds.socket`) when stopping the server so it will fail to start next time you run it unless you delete diff --git a/unix-socket/src/main.rs b/unix-socket/src/main.rs index 6a3e3ed3..055b597c 100644 --- a/unix-socket/src/main.rs +++ b/unix-socket/src/main.rs @@ -1,31 +1,22 @@ -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate tokio_uds; +use actix_web::{middleware, web, App, HttpRequest, HttpServer}; -use actix::*; -use actix_web::{middleware, server, App, HttpRequest}; -use tokio_uds::UnixListener; - -fn index(_req: &HttpRequest) -> &'static str { +fn index(_req: HttpRequest) -> &'static str { "Hello world!" } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); +fn main() -> std::io::Result<()> { + ::std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); env_logger::init(); - let sys = actix::System::new("unix-socket"); - let listener = UnixListener::bind("/tmp/actix-uds.socket").expect("bind failed"); - server::new(|| { + HttpServer::new(|| { App::new() - // enable logger - .middleware(middleware::Logger::default()) - .resource("/index.html", |r| r.f(|_| "Hello world!")) - .resource("/", |r| r.f(index)) + // enable logger - always register actix-web Logger middleware last + .wrap(middleware::Logger::default()) + .service( + web::resource("/index.html").route(web::get().to(|| "Hello world!")), + ) + .service(web::resource("/").to(index)) }) - .start_incoming(listener.incoming(), false); - - println!("Started http server: /tmp/actix-uds.socket"); - let _ = sys.run(); + .bind_uds("/tmp/actix-uds.socket")? + .run() } From ffb1b40dc2286ef2f5eae4139cb51d952e79b6f9 Mon Sep 17 00:00:00 2001 From: Cristian Re Date: Fri, 9 Aug 2019 18:19:18 -0300 Subject: [PATCH 099/111] Fix client.py paths --- multipart/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multipart/client.py b/multipart/client.py index 95905760..d82c54dd 100644 --- a/multipart/client.py +++ b/multipart/client.py @@ -12,7 +12,7 @@ async def req1(): writer.append_json({'passed': True}) resp = await aiohttp.ClientSession().request( - "post", 'http://localhost:8080/multipart', + "post", 'http://localhost:8080/', data=writer, headers=writer.headers) print(resp) assert 200 == resp.status @@ -25,7 +25,7 @@ async def req2(): writer.append(open('src/main.rs')) resp = await aiohttp.ClientSession().request( - "post", 'http://localhost:8080/multipart', + "post", 'http://localhost:8080/', data=writer, headers=writer.headers) print(resp) assert 200 == resp.status From d27b9478362049e8ba09d5095f0c6057c022e376 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 11 Aug 2019 01:13:02 +0900 Subject: [PATCH 100/111] Ignore example's png --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 532edaeb..dbdafba7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ Cargo.lock .idea/** .history/ + +# For multipart example +upload.png From 7c34cf235bfc187253b2808f897377e22d1c5ec3 Mon Sep 17 00:00:00 2001 From: Cristian Re Date: Tue, 13 Aug 2019 11:29:16 -0300 Subject: [PATCH 101/111] implement client with bash --- multipart/README.md | 15 ++++++++------- multipart/client.py | 36 ------------------------------------ multipart/client.sh | 11 +++++++++++ multipart/example.png | 5 +++++ 4 files changed, 24 insertions(+), 43 deletions(-) delete mode 100644 multipart/client.py create mode 100755 multipart/client.sh create mode 100644 multipart/example.png diff --git a/multipart/README.md b/multipart/README.md index 0da2dbf8..5eb57b38 100644 --- a/multipart/README.md +++ b/multipart/README.md @@ -12,13 +12,14 @@ cargo run (or ``cargo watch -x run``) # Started http server: 127.0.0.1:8080 ``` -### client +### browser -- ``pip install aiohttp`` -- ``python client.py`` +- go to ``http://localhost:8080`` +- upload file +- you should see the action reflected in server console + +### client (optional) + +- ``./client.sh`` - you must see in server console multipart fields -if ubuntu : - -- ``pip3 install aiohttp`` -- ``python3 client.py`` diff --git a/multipart/client.py b/multipart/client.py deleted file mode 100644 index d82c54dd..00000000 --- a/multipart/client.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -# This script could be used for actix-web multipart example test -# just start server and run client.py - -import asyncio -import aiohttp - -async def req1(): - with aiohttp.MultipartWriter() as writer: - writer.append('test') - writer.append_json({'passed': True}) - - resp = await aiohttp.ClientSession().request( - "post", 'http://localhost:8080/', - data=writer, headers=writer.headers) - print(resp) - assert 200 == resp.status - - -async def req2(): - with aiohttp.MultipartWriter() as writer: - writer.append('test') - writer.append_json({'passed': True}) - writer.append(open('src/main.rs')) - - resp = await aiohttp.ClientSession().request( - "post", 'http://localhost:8080/', - data=writer, headers=writer.headers) - print(resp) - assert 200 == resp.status - - -loop = asyncio.get_event_loop() -loop.run_until_complete(req1()) -loop.run_until_complete(req2()) diff --git a/multipart/client.sh b/multipart/client.sh new file mode 100755 index 00000000..10d82343 --- /dev/null +++ b/multipart/client.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +function SubmitFile () { + curl -X POST \ + -H "Content-Type: multipart/related" \ + --form "data=@example.png;type=image/png" http://localhost:8080 +} + +SubmitFile & SubmitFile & SubmitFile & +SubmitFile & SubmitFile & SubmitFile & +SubmitFile & SubmitFile & SubmitFile diff --git a/multipart/example.png b/multipart/example.png new file mode 100644 index 00000000..284b8a2f --- /dev/null +++ b/multipart/example.png @@ -0,0 +1,5 @@ +------------------------------4ebf00fbcf09 +Content-Disposition: form-data; name="example" + +test +------------------------------4ebf00fbcf09-- From b358d6634499972f36daab40a0ee29c0840a1437 Mon Sep 17 00:00:00 2001 From: Cristian Re Date: Tue, 13 Aug 2019 12:10:52 -0300 Subject: [PATCH 102/111] replace png file for a real png --- multipart/example.png | Bin 141 -> 1190 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/multipart/example.png b/multipart/example.png index 284b8a2fe2ef0bb7f69aa9c5b4647521e2c5a96b..2899104018929d26690630a2c54602e9ead5f35d 100644 GIT binary patch literal 1190 zcmaJ=OQ_X#5dO^QanevSsIX8ODvA>~3?)mtSMNo~!XzAADPHZ|5}I>;oIuMKUMv-q zY8DnrQH#JkMg-Pm;i5niB5EU%PAvivi9`rOeAM(myH@_-_u71XuW7fhw;tsCE|5>uev@%`bK4 zwOYN-wqEOc=f=P0x+GI4?ox3Gn;+;EmNEG-}yJc0ZhfJXI76i zUqAo{3IvdV98_R{1?=F00xD3477Q?fIjj&s2*MGC1X7TWtOf}sC`VNv5<+l75rIgE zoT!LFEW}P+q#zYiCoM9N37L}>1t^5VDT)%5Lg|#%u%i+xr>Z_p2*Vl01SVl}reX%O zFgtUxf>l_Zwb;NWY|d63;1CYyC{Az+r*l@Lm`k{vtNPL*3Rjd8ltjsuN*T(c?8>DI zRZ(@-QiGbPxmsyJLo{5YG@&V)u33$XTB7Az)wdI3a6=ivNQ~U5jA1OsZd|4?6;n4Y zGnk2)o0SDD#KJAg5|(1=menLB*=p*7{LW#CFp=DC$jSG$V z3aRjhaYM9HD!oB(K&zz6o7W$Qx{ovyaEgbAR&PIZ@3W6~Zy1_3`{Is|XT3c!_~6LA z_h;@I9=dzo;GHAi-}cv=JLj(Ty;ac0Xuzbu+Lx!~5*pa1&V;fHqbJ$7Nu`Y9X7zFGbHRKb+RpDbVV zz>)91JbCTxTkrk;V(-$z^GkpG=<3+HLwCJ=wR>X!p4oTM*Oy+o^!Ka$t^9ER38T|8br$6F6vU2#-CF>{t17flp3IG5A delta 6 NcmZ3+*~>Vg7XSzQ0$Tt8 From bc7e9f5e6b7b65698b2acffefcbce1d02d94728e Mon Sep 17 00:00:00 2001 From: Rotem Yaari Date: Mon, 19 Aug 2019 21:42:31 +0300 Subject: [PATCH 103/111] Remove old http-proxy, use the full version as the official http-proxy example (closes #164) --- Cargo.toml | 1 - http-full-proxy/Cargo.toml | 15 ----- http-full-proxy/README.md | 10 --- http-full-proxy/src/main.rs | 102 ----------------------------- http-proxy/Cargo.toml | 19 ++---- http-proxy/README.md | 17 ++--- http-proxy/src/main.rs | 124 +++++++++++++++++++++++++----------- http-proxy/src/server.rs | 20 ------ 8 files changed, 100 insertions(+), 208 deletions(-) delete mode 100644 http-full-proxy/Cargo.toml delete mode 100644 http-full-proxy/README.md delete mode 100644 http-full-proxy/src/main.rs delete mode 100644 http-proxy/src/server.rs diff --git a/Cargo.toml b/Cargo.toml index 0caeb8da..806ec6ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ members = [ "form", "hello-world", "http-proxy", - "http-full-proxy", "json", "json_error", "jsonrpc", diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml deleted file mode 100644 index ddfe7b8a..00000000 --- a/http-full-proxy/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "http-full-proxy" -version = "0.1.0" -authors = ["Rotem Yaari"] -workspace = ".." -edition = "2018" - -[dependencies] -actix-rt = "0.2" -actix-web = "1.0.0" - -clap = "2.32.0" -futures = "0.1.25" -failure = "0.1.3" -url = "1.7.1" diff --git a/http-full-proxy/README.md b/http-full-proxy/README.md deleted file mode 100644 index 55a6a680..00000000 --- a/http-full-proxy/README.md +++ /dev/null @@ -1,10 +0,0 @@ -## HTTP Full proxy example - -This proxy forwards all types of requests, including ones with body, to another HTTP server, -returning the response to the client. - -To start: - -``` shell -cargo run -``` diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs deleted file mode 100644 index a68b46f1..00000000 --- a/http-full-proxy/src/main.rs +++ /dev/null @@ -1,102 +0,0 @@ -use actix_web::client::Client; -use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; -use clap::{value_t, Arg}; -use futures::Future; -use std::net::ToSocketAddrs; -use url::Url; - -fn forward( - req: HttpRequest, - payload: web::Payload, - url: web::Data, - client: web::Data, -) -> impl Future { - let mut new_url = url.get_ref().clone(); - new_url.set_path(req.uri().path()); - new_url.set_query(req.uri().query()); - - let forwarded_req = client - .request_from(new_url.as_str(), req.head()) - .no_decompress(); - let forwarded_req = if let Some(addr) = req.head().peer_addr { - forwarded_req.header("x-forwarded-for", format!("{}", addr.ip())) - } else { - forwarded_req - }; - - forwarded_req - .send_stream(payload) - .map_err(Error::from) - .map(|res| { - let mut client_resp = HttpResponse::build(res.status()); - for (header_name, header_value) in res - .headers() - .iter() - .filter(|(h, _)| *h != "connection" && *h != "content-length") - { - client_resp.header(header_name.clone(), header_value.clone()); - } - client_resp.streaming(res) - }) -} - -fn main() -> std::io::Result<()> { - let matches = clap::App::new("HTTP Proxy") - .arg( - Arg::with_name("listen_addr") - .takes_value(true) - .value_name("LISTEN ADDR") - .index(1) - .required(true), - ) - .arg( - Arg::with_name("listen_port") - .takes_value(true) - .value_name("LISTEN PORT") - .index(2) - .required(true), - ) - .arg( - Arg::with_name("forward_addr") - .takes_value(true) - .value_name("FWD ADDR") - .index(3) - .required(true), - ) - .arg( - Arg::with_name("forward_port") - .takes_value(true) - .value_name("FWD PORT") - .index(4) - .required(true), - ) - .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()); - - let forwarded_addr = matches.value_of("forward_addr").unwrap(); - let forwarded_port = - value_t!(matches, "forward_port", u16).unwrap_or_else(|e| e.exit()); - - let forward_url = Url::parse(&format!( - "http://{}", - (forwarded_addr, forwarded_port) - .to_socket_addrs() - .unwrap() - .next() - .unwrap() - )) - .unwrap(); - - HttpServer::new(move || { - App::new() - .data(Client::new()) - .data(forward_url.clone()) - .wrap(middleware::Logger::default()) - .default_service(web::route().to_async(forward)) - }) - .bind((listen_addr, listen_port))? - .system_exit() - .run() -} diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 2a7beb8e..a2c8740c 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -1,21 +1,14 @@ [package] name = "http-proxy" version = "0.1.0" -authors = ["Nikolay Kim "] -edition = "2018" +authors = ["Nikolay Kim ", "Rotem Yaari "] workspace = ".." - -[[bin]] -name = "proxy" -path = "src/main.rs" - -[[bin]] -name = "proxy-example-server" -path = "src/server.rs" +edition = "2018" [dependencies] actix-rt = "0.2" actix-web = { version = "1.0.0", features=["ssl"] } - -env_logger = "0.5" -futures = "0.1" +clap = "2.32.0" +futures = "0.1.25" +failure = "0.1.3" +url = "1.7.1" diff --git a/http-proxy/README.md b/http-proxy/README.md index 2bc8272a..5badaca8 100644 --- a/http-proxy/README.md +++ b/http-proxy/README.md @@ -1,13 +1,10 @@ -## Http proxy example +## HTTP Full proxy example -To start proxy server: +This is a relatively simple HTTP proxy, forwarding HTTP requests to another HTTP server, including +request body, headers, and streaming uploads. -```sh -cargo run --bin proxy -``` - -To start local backend server: - -```sh -cargo run --bin proxy-example-server +To start: + +``` shell +cargo run ``` diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index ff45ef97..a68b46f1 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -1,52 +1,102 @@ use actix_web::client::Client; -use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use clap::{value_t, Arg}; use futures::Future; +use std::net::ToSocketAddrs; +use url::Url; -/// Stream client request response and then send body to a server response -fn index(client: web::Data) -> impl Future { - client - .get("http://127.0.0.1:8081/") - .send() - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then(|mut 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 - Ok(HttpResponse::Ok().body(body)) - }) - }) -} - -/// streaming client request to a streaming server response -fn streaming( +fn forward( + req: HttpRequest, + payload: web::Payload, + url: web::Data, client: web::Data, -) -> impl Future> { - // send client request - client - .get("https://www.rust-lang.org/") - .send() // <- connect to host and send request - .map_err(Error::from) // <- convert SendRequestError to an Error - .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 - .streaming(resp)) +) -> impl Future { + let mut new_url = url.get_ref().clone(); + new_url.set_path(req.uri().path()); + new_url.set_query(req.uri().query()); + + let forwarded_req = client + .request_from(new_url.as_str(), req.head()) + .no_decompress(); + let forwarded_req = if let Some(addr) = req.head().peer_addr { + forwarded_req.header("x-forwarded-for", format!("{}", addr.ip())) + } else { + forwarded_req + }; + + forwarded_req + .send_stream(payload) + .map_err(Error::from) + .map(|res| { + let mut client_resp = HttpResponse::build(res.status()); + for (header_name, header_value) in res + .headers() + .iter() + .filter(|(h, _)| *h != "connection" && *h != "content-length") + { + client_resp.header(header_name.clone(), header_value.clone()); + } + client_resp.streaming(res) }) } fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); - env_logger::init(); + let matches = clap::App::new("HTTP Proxy") + .arg( + Arg::with_name("listen_addr") + .takes_value(true) + .value_name("LISTEN ADDR") + .index(1) + .required(true), + ) + .arg( + Arg::with_name("listen_port") + .takes_value(true) + .value_name("LISTEN PORT") + .index(2) + .required(true), + ) + .arg( + Arg::with_name("forward_addr") + .takes_value(true) + .value_name("FWD ADDR") + .index(3) + .required(true), + ) + .arg( + Arg::with_name("forward_port") + .takes_value(true) + .value_name("FWD PORT") + .index(4) + .required(true), + ) + .get_matches(); - HttpServer::new(|| { + 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 forwarded_addr = matches.value_of("forward_addr").unwrap(); + let forwarded_port = + value_t!(matches, "forward_port", u16).unwrap_or_else(|e| e.exit()); + + let forward_url = Url::parse(&format!( + "http://{}", + (forwarded_addr, forwarded_port) + .to_socket_addrs() + .unwrap() + .next() + .unwrap() + )) + .unwrap(); + + HttpServer::new(move || { App::new() .data(Client::new()) + .data(forward_url.clone()) .wrap(middleware::Logger::default()) - .service(web::resource("/streaming").to_async(streaming)) - .service(web::resource("/").to_async(index)) + .default_service(web::route().to_async(forward)) }) - .bind("127.0.0.1:8080")? + .bind((listen_addr, listen_port))? + .system_exit() .run() } diff --git a/http-proxy/src/server.rs b/http-proxy/src/server.rs deleted file mode 100644 index a8e7559e..00000000 --- a/http-proxy/src/server.rs +++ /dev/null @@ -1,20 +0,0 @@ -use actix_web::{middleware, web, App, HttpResponse, HttpServer, Responder}; - -fn index(body: web::Bytes) -> impl Responder { - HttpResponse::Ok().body(body) -} - -fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); - env_logger::init(); - - HttpServer::new(|| { - App::new() - // enable logger - .wrap(middleware::Logger::default()) - .service(web::resource("/index.html").to(|| "Hello world!")) - .service(web::resource("/").to(index)) - }) - .bind("127.0.0.1:8081")? - .run() -} From bb639d5fe382659898a8ec09fe35175d70ea30c5 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 2 Sep 2019 18:20:15 +0900 Subject: [PATCH 104/111] Prevent jobs from being terminated on Travis (#167) * Prevent jobs from being terminated * Fix installing clippy * Fix command * Run Clippy on nightly --- .travis.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25f7f0ee..f3e3603a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,13 @@ sudo: false dist: trusty cache: - cargo: true apt: true + directories: + - $HOME/.cargo + - $HOME/.rustup + +before_cache: + - rm -rf $HOME/.cargo/registry matrix: include: @@ -28,9 +33,13 @@ before_install: before_script: - | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then - ( ( cargo install clippy && export CLIPPY=true ) || export CLIPPY=false ); + rustup component add clippy --toolchain=nightly fi - export PATH=$PATH:~/.cargo/bin script: - cargo check --all + - | + if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then + cargo clippy + fi From f232b6c684bebbba7eb139a242cc1ae91312d4df Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 5 Sep 2019 00:04:57 +0900 Subject: [PATCH 105/111] Fix clippy warnings (#168) --- async_ex2/src/appconfig.rs | 2 +- async_ex2/src/handlers/parts.rs | 8 ++------ async_ex2/src/handlers/products.rs | 8 ++------ basics/src/main.rs | 2 +- cookie-auth/src/main.rs | 5 ++++- jsonrpc/src/main.rs | 16 +++++++++++----- middleware/src/simple.rs | 2 +- state/src/main.rs | 2 +- template_askama/src/main.rs | 2 +- websocket-chat-broker/src/main.rs | 4 ++-- websocket-chat-broker/src/server.rs | 4 ++-- websocket-chat/src/main.rs | 2 +- websocket-chat/src/server.rs | 2 +- websocket-tcp-chat/src/client.rs | 2 +- websocket-tcp-chat/src/main.rs | 4 ++-- websocket-tcp-chat/src/server.rs | 2 +- websocket-tcp-chat/src/session.rs | 10 ++++------ websocket/src/client.rs | 10 +++------- 18 files changed, 41 insertions(+), 46 deletions(-) diff --git a/async_ex2/src/appconfig.rs b/async_ex2/src/appconfig.rs index 9393e129..f007003a 100644 --- a/async_ex2/src/appconfig.rs +++ b/async_ex2/src/appconfig.rs @@ -1,4 +1,4 @@ -use actix_web::{error, web}; +use actix_web::web; use crate::handlers::{parts, products}; diff --git a/async_ex2/src/handlers/parts.rs b/async_ex2/src/handlers/parts.rs index 0dba7b0f..3e3874f4 100644 --- a/async_ex2/src/handlers/parts.rs +++ b/async_ex2/src/handlers/parts.rs @@ -1,9 +1,5 @@ -use actix_multipart::{Field, Multipart, MultipartError}; -use actix_web::{error, web, Error, HttpResponse}; -use futures::{ - future::{err as fut_err, ok as fut_ok, Either}, - Future, Stream, -}; +use actix_web::{web, Error, HttpResponse}; +use futures::{future::ok as fut_ok, Future}; use crate::common::{Part, Product}; diff --git a/async_ex2/src/handlers/products.rs b/async_ex2/src/handlers/products.rs index 1f3d68fd..36b774a4 100644 --- a/async_ex2/src/handlers/products.rs +++ b/async_ex2/src/handlers/products.rs @@ -1,9 +1,5 @@ -use actix_multipart::{Field, Multipart, MultipartError}; -use actix_web::{error, web, Error, HttpResponse}; -use futures::{ - future::{err as fut_err, ok as fut_ok, Either}, - Future, Stream, -}; +use actix_web::{web, Error, HttpResponse}; +use futures::{future::ok as fut_ok, Future}; use crate::common::{Part, Product}; diff --git a/basics/src/main.rs b/basics/src/main.rs index cace43ae..ab98ecba 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -132,7 +132,7 @@ fn main() -> io::Result<()> { .route( web::route() .guard(guard::Not(guard::Get())) - .to(|| HttpResponse::MethodNotAllowed()), + .to(HttpResponse::MethodNotAllowed), ), ) }) diff --git a/cookie-auth/src/main.rs b/cookie-auth/src/main.rs index 59634c53..9da2da57 100644 --- a/cookie-auth/src/main.rs +++ b/cookie-auth/src/main.rs @@ -3,7 +3,10 @@ use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{middleware, web, App, HttpResponse, HttpServer}; fn index(id: Identity) -> String { - format!("Hello {}", id.identity().unwrap_or("Anonymous".to_owned())) + format!( + "Hello {}", + id.identity().unwrap_or_else(|| "Anonymous".to_owned()) + ) } fn login(id: Identity) -> HttpResponse { diff --git a/jsonrpc/src/main.rs b/jsonrpc/src/main.rs index 18ba5545..fd4f0951 100644 --- a/jsonrpc/src/main.rs +++ b/jsonrpc/src/main.rs @@ -86,7 +86,10 @@ fn rpc_select( pub trait ImplNetwork { fn ping(&self) -> String; - fn wait(&self, d: u64) -> Box>>; + fn wait( + &self, + d: u64, + ) -> Box>>; fn get(&self) -> u32; fn inc(&mut self); @@ -107,9 +110,12 @@ impl ImplNetwork for ObjNetwork { String::from("pong") } - fn wait(&self, d: u64) -> Box>> { + fn wait( + &self, + d: u64, + ) -> Box>> { if let Err(e) = Delay::new(Duration::from_secs(d)).wait() { - let e: Box = Box::new(e); + let e: Box = Box::new(e); return Box::new(future::err(e)); }; Box::new(future::ok(String::from("pong"))) @@ -126,11 +132,11 @@ impl ImplNetwork for ObjNetwork { #[derive(Clone)] pub struct AppState { - network: Arc>, + network: Arc>, } impl AppState { - pub fn new(network: Arc>) -> Self { + pub fn new(network: Arc>) -> Self { Self { network } } } diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index 789eedab..a96e156b 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -43,7 +43,7 @@ where type Request = ServiceRequest; type Response = ServiceResponse; type Error = Error; - type Future = Box>; + type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.service.poll_ready() diff --git a/state/src/main.rs b/state/src/main.rs index 3f5d721a..c7f6f947 100644 --- a/state/src/main.rs +++ b/state/src/main.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] +#![allow(clippy::needless_pass_by_value)] //! Application may have multiple data objects that are shared across //! all handlers within same Application. Data could be added //! with `App::data()` method, multiple different data objects could be added. diff --git a/template_askama/src/main.rs b/template_askama/src/main.rs index f1060f8c..f117ab36 100644 --- a/template_askama/src/main.rs +++ b/template_askama/src/main.rs @@ -17,7 +17,7 @@ struct Index; fn index(query: web::Query>) -> Result { let s = if let Some(name) = query.get("name") { UserTemplate { - name: name, + name, text: "Welcome!", } .render() diff --git a/websocket-chat-broker/src/main.rs b/websocket-chat-broker/src/main.rs index 00c6ad2d..4509badf 100644 --- a/websocket-chat-broker/src/main.rs +++ b/websocket-chat-broker/src/main.rs @@ -68,7 +68,7 @@ impl WsChatSession { fn send_msg(&self, msg: &str) { let content = format!( "{}: {}", - self.name.clone().unwrap_or("anon".to_string()), + self.name.clone().unwrap_or_else(|| "anon".to_string()), msg ); let msg = SendMessage(self.room.clone(), self.id, content); @@ -87,7 +87,7 @@ impl Actor for WsChatSession { fn stopped(&mut self, _ctx: &mut Self::Context) { info!( "WsChatSession closed for {}({}) in room {}", - self.name.clone().unwrap_or("anon".to_string()), + self.name.clone().unwrap_or_else(|| "anon".to_string()), self.id, self.room ); diff --git a/websocket-chat-broker/src/server.rs b/websocket-chat-broker/src/server.rs index 198b6c85..946f670a 100644 --- a/websocket-chat-broker/src/server.rs +++ b/websocket-chat-broker/src/server.rs @@ -42,7 +42,7 @@ impl WsChatServer { id: Option, client: Client, ) -> usize { - let mut id = id.unwrap_or_else(|| rand::random::()); + let mut id = id.unwrap_or_else(rand::random::); if let Some(room) = self.rooms.get_mut(room_name) { loop { if room.contains_key(&id) { @@ -94,7 +94,7 @@ impl Handler for WsChatServer { let id = self.add_client_to_room(&room_name, None, client); let join_msg = format!( "{} joined {}", - client_name.unwrap_or("anon".to_string()), + client_name.unwrap_or_else(|| "anon".to_string()), room_name ); self.send_chat_message(&room_name, &join_msg, id); diff --git a/websocket-chat/src/main.rs b/websocket-chat/src/main.rs index ec7da927..f8eee4c3 100644 --- a/websocket-chat/src/main.rs +++ b/websocket-chat/src/main.rs @@ -164,7 +164,7 @@ impl StreamHandler for WsChatSession { // send message to chat server self.addr.do_send(server::ClientMessage { id: self.id, - msg: msg, + msg, room: self.room.clone(), }) } diff --git a/websocket-chat/src/server.rs b/websocket-chat/src/server.rs index 80d62b6d..f8acc451 100644 --- a/websocket-chat/src/server.rs +++ b/websocket-chat/src/server.rs @@ -68,7 +68,7 @@ impl Default for ChatServer { ChatServer { sessions: HashMap::new(), - rooms: rooms, + rooms, rng: rand::thread_rng(), } } diff --git a/websocket-tcp-chat/src/client.rs b/websocket-tcp-chat/src/client.rs index 28313e29..1694c870 100644 --- a/websocket-tcp-chat/src/client.rs +++ b/websocket-tcp-chat/src/client.rs @@ -154,7 +154,7 @@ impl StreamHandler for ChatClient { for room in rooms { println!("{}", room); } - println!(""); + println!(); } _ => (), } diff --git a/websocket-tcp-chat/src/main.rs b/websocket-tcp-chat/src/main.rs index fe73dc8e..7aeaec8e 100644 --- a/websocket-tcp-chat/src/main.rs +++ b/websocket-tcp-chat/src/main.rs @@ -171,7 +171,7 @@ impl StreamHandler for WsChatSession { // send message to chat server self.addr.do_send(server::Message { id: self.id, - msg: msg, + msg, room: self.room.clone(), }) } @@ -212,7 +212,7 @@ impl WsChatSession { } fn main() -> std::io::Result<()> { - let _ = env_logger::init(); + env_logger::init(); let sys = actix::System::new("websocket-example"); // Start chat server actor diff --git a/websocket-tcp-chat/src/server.rs b/websocket-tcp-chat/src/server.rs index c30b928b..b7a1a3db 100644 --- a/websocket-tcp-chat/src/server.rs +++ b/websocket-tcp-chat/src/server.rs @@ -66,7 +66,7 @@ impl Default for ChatServer { ChatServer { sessions: HashMap::new(), - rooms: rooms, + rooms, rng: rand::thread_rng(), } } diff --git a/websocket-tcp-chat/src/session.rs b/websocket-tcp-chat/src/session.rs index 27478794..711b3287 100644 --- a/websocket-tcp-chat/src/session.rs +++ b/websocket-tcp-chat/src/session.rs @@ -138,10 +138,10 @@ impl ChatSession { ) -> ChatSession { ChatSession { id: 0, - addr: addr, + addr, hb: Instant::now(), room: "Main".to_owned(), - framed: framed, + framed, } } @@ -187,10 +187,8 @@ impl TcpServer { // implement stream handler `StreamHandler<(TcpStream, // net::SocketAddr), io::Error>` TcpServer::create(|ctx| { - ctx.add_message_stream( - listener.incoming().map_err(|_| ()).map(|s| TcpConnect(s)), - ); - TcpServer { chat: chat } + ctx.add_message_stream(listener.incoming().map_err(|_| ()).map(TcpConnect)); + TcpServer { chat } }); } } diff --git a/websocket/src/client.rs b/websocket/src/client.rs index 04a683ad..0a9eee35 100644 --- a/websocket/src/client.rs +++ b/websocket/src/client.rs @@ -18,7 +18,7 @@ use futures::{ fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); - let _ = env_logger::init(); + env_logger::init(); let sys = actix::System::new("ws-example"); Arbiter::spawn(lazy(|| { @@ -27,7 +27,6 @@ fn main() { .connect() .map_err(|e| { println!("Error: {}", e); - () }) .map(|(response, framed)| { println!("{:?}", response); @@ -46,8 +45,6 @@ fn main() { } addr.do_send(ClientCommand(cmd)); }); - - () }) })); @@ -113,9 +110,8 @@ where T: AsyncRead + AsyncWrite, { fn handle(&mut self, msg: Frame, _ctx: &mut Context) { - match msg { - Frame::Text(txt) => println!("Server: {:?}", txt), - _ => (), + if let Frame::Text(txt) = msg { + println!("Server: {:?}", txt) } } From 948054f1e4d581c6f2122ef984d9b6be308c264c Mon Sep 17 00:00:00 2001 From: Sven-Hendrik Haase Date: Wed, 11 Sep 2019 14:04:33 +0200 Subject: [PATCH 106/111] Add middleware example with wrap_fn --- middleware/src/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 0496db27..647d710e 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -1,4 +1,6 @@ use actix_web::{web, App, HttpServer}; +use actix_service::Service; +use futures::future::Future; #[allow(dead_code)] mod redirect; @@ -13,6 +15,14 @@ fn main() -> std::io::Result<()> { App::new() .wrap(redirect::CheckLogin) .wrap(simple::SayHi) + .wrap_fn(|req, srv| { + println!("Hi from start. You requested: {}", req.path()); + + srv.call(req).map(|res| { + println!("Hi from response"); + res + }) + }) .service(web::resource("/login").to(|| { "You are on /login. Go to src/redirect.rs to change this behavior." })) From 0f692a3bfb1bdf1791e8e0efaf00676379b9160c Mon Sep 17 00:00:00 2001 From: Sven-Hendrik Haase Date: Wed, 11 Sep 2019 15:12:08 +0200 Subject: [PATCH 107/111] Add middleware example for reading the Request body --- middleware/Cargo.toml | 3 +- middleware/README.md | 1 - middleware/src/main.rs | 3 ++ middleware/src/read_body.rs | 70 +++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 middleware/src/read_body.rs diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index 76ecbf1c..da904716 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -9,4 +9,5 @@ workspace = ".." actix-service = "0.4.1" actix-web = "1.0.0" futures = "0.1.25" -env_logger = "0.6" \ No newline at end of file +env_logger = "0.6" +bytes = "0.4" diff --git a/middleware/README.md b/middleware/README.md index 1cd2b732..9c901cb6 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -8,4 +8,3 @@ cargo run Look in `src/main.rs` and comment the different middlewares in/out to see how they function. - diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 0496db27..5beb0a9b 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -3,6 +3,8 @@ use actix_web::{web, App, HttpServer}; #[allow(dead_code)] mod redirect; #[allow(dead_code)] +mod read_body; +#[allow(dead_code)] mod simple; fn main() -> std::io::Result<()> { @@ -12,6 +14,7 @@ fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(redirect::CheckLogin) + .wrap(read_body::Logging) .wrap(simple::SayHi) .service(web::resource("/login").to(|| { "You are on /login. Go to src/redirect.rs to change this behavior." diff --git a/middleware/src/read_body.rs b/middleware/src/read_body.rs new file mode 100644 index 00000000..48aed2cc --- /dev/null +++ b/middleware/src/read_body.rs @@ -0,0 +1,70 @@ +use actix_service::{Service, Transform}; +use actix_web::error::PayloadError; +use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage}; +use bytes::BytesMut; +use futures::future::{ok, FutureResult}; +use futures::stream::Stream; +use futures::{Future, Poll}; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct Logging; + +impl Transform for Logging +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type InitError = (); + type Transform = LoggingMiddleware; + type Future = FutureResult; + + fn new_transform(&self, service: S) -> Self::Future { + ok(LoggingMiddleware { + service: Rc::new(RefCell::new(service)), + }) + } +} + +pub struct LoggingMiddleware { + // This is special: We need this to avoid lifetime issues. + service: Rc>, +} + +impl Service for LoggingMiddleware +where + S: Service, Error = Error> + + 'static, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type Future = Box>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, mut req: ServiceRequest) -> Self::Future { + let mut svc = self.service.clone(); + + Box::new( + req.take_payload() + .fold(BytesMut::new(), move |mut body, chunk| { + body.extend_from_slice(&chunk); + Ok::<_, PayloadError>(body) + }) + .map_err(|e| e.into()) + .and_then(move |bytes| { + println!("request body: {:?}", bytes); + svc.call(req).and_then(|res| Ok(res)) + }), + ) + } +} From d0fed9f0784119f329394032af38aa18c77c3577 Mon Sep 17 00:00:00 2001 From: Sven-Hendrik Haase Date: Wed, 11 Sep 2019 16:49:00 +0200 Subject: [PATCH 108/111] Add better README for middleware example --- middleware/README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/middleware/README.md b/middleware/README.md index 9c901cb6..401b9fd9 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -1,4 +1,8 @@ -## Middleware example +# middleware examples + +This example showcases a bunch of different uses of middlewares. See also the [Middleware guide](https://actix.rs/docs/middleware/).. + +## Usage ```bash cd middleware @@ -8,3 +12,18 @@ cargo run Look in `src/main.rs` and comment the different middlewares in/out to see how they function. + +## Middlewares + +### redirect::CheckLogin + +A middleware implementing a request guard which sketches a rough approximation of what a login could look like. + +### read_body::Logging + +A middleware demonstrating how to read out the incoming request body. + +### simple::SayHi + +A minimal middleware demonstrating the sequence of operations in an actix middleware. +There is a second version of the same middleware using `wrap_fn` which shows how easily a middleware can be implemented in actix. From 77dd2cc4e30695d1ee44fea529680a4d2b85ea24 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 13 Sep 2019 17:15:26 +0900 Subject: [PATCH 109/111] Fix favicon link (#172) --- basics/static/404.html | 21 ++++++++++++++------- basics/static/welcome.html | 19 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/basics/static/404.html b/basics/static/404.html index 8b285668..e140a1d9 100644 --- a/basics/static/404.html +++ b/basics/static/404.html @@ -1,7 +1,14 @@ -actix - basics - - - back to home -

404

- - + + + + + actix - basics + + + + + back to home +

404

+ + + \ No newline at end of file diff --git a/basics/static/welcome.html b/basics/static/welcome.html index 48bf3cfe..a5c76c81 100644 --- a/basics/static/welcome.html +++ b/basics/static/welcome.html @@ -1,6 +1,13 @@ -actix - basics - - -

Welcome

- - + + + + + actix - basics + + + + +

Welcome

+ + + \ No newline at end of file From 2b4e360adc94d8f1d55bc77675af6d679b3e2b5f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 14 Sep 2019 18:01:05 +0900 Subject: [PATCH 110/111] Update actix-session to 0.2.0 (#174) --- actix_todo/Cargo.toml | 2 +- basics/Cargo.toml | 2 +- cookie-session/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actix_todo/Cargo.toml b/actix_todo/Cargo.toml index 754918b8..4812c25c 100644 --- a/actix_todo/Cargo.toml +++ b/actix_todo/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] actix-web = "1.0.0" actix-files = "0.1.1" -actix-session = "0.1.0" +actix-session = "0.2.0" dotenv = "0.13.0" env_logger = "0.5.10" futures = "0.1.22" diff --git a/basics/Cargo.toml b/basics/Cargo.toml index 8dcf58ca..dd46235f 100644 --- a/basics/Cargo.toml +++ b/basics/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" actix-rt = "0.2.2" actix-web = "1.0.0" actix-files = "0.1.1" -actix-session = "0.1.0" +actix-session = "0.2.0" futures = "0.1.25" env_logger = "0.5" diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 1e10ae47..3599cd91 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] actix-web = "1.0.0" -actix-session = "0.1.0" +actix-session = "0.2.0" futures = "0.1" time = "0.1" From d9ca7cb0550c85c2220ddcaca45a4fdd28b6ce93 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 14 Sep 2019 19:37:39 +0900 Subject: [PATCH 111/111] Make cookie-session example clarify (#175) --- cookie-session/Cargo.toml | 1 + cookie-session/README.md | 7 +++++++ cookie-session/src/main.rs | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 cookie-session/README.md diff --git a/cookie-session/Cargo.toml b/cookie-session/Cargo.toml index 3599cd91..a927124e 100644 --- a/cookie-session/Cargo.toml +++ b/cookie-session/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] actix-web = "1.0.0" actix-session = "0.2.0" +actix-rt = "0.2.5" futures = "0.1" time = "0.1" diff --git a/cookie-session/README.md b/cookie-session/README.md new file mode 100644 index 00000000..05e12515 --- /dev/null +++ b/cookie-session/README.md @@ -0,0 +1,7 @@ +## Cookie session example + +```sh +cd cookie-session +cargo run +# Starting http server: 127.0.0.1:8080 +``` diff --git a/cookie-session/src/main.rs b/cookie-session/src/main.rs index 72f00cf3..f0eac8c5 100644 --- a/cookie-session/src/main.rs +++ b/cookie-session/src/main.rs @@ -28,6 +28,7 @@ fn index(session: Session, req: HttpRequest) -> Result<&'static str> { fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); + let sys = actix_rt::System::new("cookie-session"); HttpServer::new(|| { App::new() @@ -38,5 +39,8 @@ fn main() -> std::io::Result<()> { .service(web::resource("/").to(index)) }) .bind("127.0.0.1:8080")? - .run() + .start(); + + println!("Starting http server: 127.0.0.1:8080"); + sys.run() }