diff --git a/CHANGES.md b/CHANGES.md index 907703d35..153f19be1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Changes +## 0.4.0 (2018-05-08) + +* Actix web 0.6 compatibility + ## 0.3.0 (2018-04-10) * Actix web 0.5 compatibility diff --git a/Cargo.toml b/Cargo.toml index 3c37af72e..c12075685 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-redis" -version = "0.3.0" +version = "0.4.0" authors = ["Nikolay Kim "] description = "Redis integration for actix framework" license = "MIT/Apache-2.0" @@ -38,7 +38,7 @@ tokio-core = "0.1" redis-async = "0.0" # actix web session -actix-web = { version="0.5", optional=true } +actix-web = { version="0.6", optional=true } cookie = { version="0.10", features=["percent-encode", "secure"], optional=true } http = { version="0.1", optional=true } rand = { version="0.3", optional=true } diff --git a/README.md b/README.md index 5ed02fbad..4fe12b66c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Redis integration for actix framework. * [API Documentation (Releases)](https://docs.rs/actix-redis/) * [Chat on gitter](https://gitter.im/actix/actix) * Cargo package: [actix-redis](https://crates.io/crates/actix-redis) -* Minimum supported Rust version: 1.21 or later +* Minimum supported Rust version: 1.24 or later ## Redis session backend @@ -23,12 +23,12 @@ Note that whatever you write into your session is visible by the user (but not m Constructor panics if key length is less than 32 bytes. -```rust,ignore +```rust extern crate actix_web; extern crate actix_redis; -use actix_web::{App, server}; -use actix_web::middleware::{Logger, SessionStorage}; +use actix_web::{App, server, middleware}; +use actix_web::middleware::session::SessionStorage; use actix_redis::RedisSessionBackend; fn main() { @@ -39,7 +39,7 @@ fn main() { server::new( || App::new() // enable logger - .middleware(Logger::default()) + .middleware(middleware::Logger::default()) // cookie session middleware .middleware(SessionStorage::new( RedisSessionBackend::new("127.0.0.1:6379", &[0; 32]) diff --git a/examples/basic.rs b/examples/basic.rs index 87e0049c8..ef31724a4 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,16 +1,15 @@ #![allow(unused_variables)] -#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))] +#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] extern crate actix; -extern crate actix_web; extern crate actix_redis; +extern crate actix_web; extern crate env_logger; extern crate futures; -use actix_web::{server, middleware, App, HttpRequest, HttpResponse, Result}; -use actix_web::middleware::RequestSession; use actix_redis::RedisSessionBackend; - +use actix_web::middleware::RequestSession; +use actix_web::{middleware, server, App, HttpRequest, HttpResponse, Result}; /// simple handler fn index(mut req: HttpRequest) -> Result { @@ -19,7 +18,7 @@ fn index(mut req: HttpRequest) -> Result { // session if let Some(count) = req.session().get::("counter")? { println!("SESSION value: {}", count); - req.session().set("counter", count+1)?; + req.session().set("counter", count + 1)?; } else { req.session().set("counter", 1)?; } @@ -32,8 +31,8 @@ fn main() { env_logger::init(); let sys = actix::System::new("basic-example"); - server::new( - || App::new() + server::new(|| { + App::new() // enable logger .middleware(middleware::Logger::default()) // cookie session middleware @@ -41,8 +40,9 @@ fn main() { RedisSessionBackend::new("127.0.0.1:6379", &[0; 32]) )) // register simple route, handle all methods - .resource("/", |r| r.f(index))) - .bind("0.0.0.0:8080").unwrap() + .resource("/", |r| r.f(index)) + }).bind("0.0.0.0:8080") + .unwrap() .threads(1) .start(); diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..6db67ed28 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +max_width = 89 +reorder_imports = true +wrap_comments = true +fn_args_density = "Compressed" +#use_small_heuristics = false diff --git a/src/lib.rs b/src/lib.rs index cbcd9f502..71a2c86a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,12 +6,12 @@ //! * [Chat on gitter](https://gitter.im/actix/actix) //! * Cargo package: [actix-redis](https://crates.io/crates/actix-redis) //! * Minimum supported Rust version: 1.21 or later -//! +//! extern crate actix; extern crate backoff; extern crate futures; -extern crate tokio_io; extern crate tokio_core; +extern crate tokio_io; #[macro_use] extern crate log; #[macro_use] @@ -22,34 +22,34 @@ extern crate failure; mod redis; pub use redis::{Command, RedisActor}; -#[cfg(feature="web")] +#[cfg(feature = "web")] extern crate actix_web; -#[cfg(feature="web")] +#[cfg(feature = "web")] extern crate cookie; -#[cfg(feature="web")] -extern crate rand; -#[cfg(feature="web")] +#[cfg(feature = "web")] extern crate http; -#[cfg(feature="web")] +#[cfg(feature = "web")] +extern crate rand; +#[cfg(feature = "web")] extern crate serde; -#[cfg(feature="web")] +#[cfg(feature = "web")] extern crate serde_json; -#[cfg(feature="web")] +#[cfg(feature = "web")] mod session; -#[cfg(feature="web")] +#[cfg(feature = "web")] pub use session::RedisSessionBackend; /// General purpose actix redis error #[derive(Fail, Debug)] pub enum Error { - #[fail(display="Redis error {}", _0)] + #[fail(display = "Redis error {}", _0)] Redis(redis_async::error::Error), /// Receiving message during reconnecting - #[fail(display="Redis: Not connected")] + #[fail(display = "Redis: Not connected")] NotConnected, /// Cancel all waters when connection get dropped - #[fail(display="Redis: Disconnected")] + #[fail(display = "Redis: Disconnected")] Disconnected, } @@ -63,5 +63,5 @@ impl From for Error { } // re-export -pub use redis_async::resp::RespValue; pub use redis_async::error::Error as RespError; +pub use redis_async::resp::RespValue; diff --git a/src/redis.rs b/src/redis.rs index 0289e84ce..2fd6ab8c4 100644 --- a/src/redis.rs +++ b/src/redis.rs @@ -1,22 +1,21 @@ -use std::io; use std::collections::VecDeque; +use std::io; -use actix::prelude::*; use actix::actors::{Connect, Connector}; -use backoff::ExponentialBackoff; +use actix::prelude::*; use backoff::backoff::Backoff; -use futures::Future; +use backoff::ExponentialBackoff; use futures::unsync::oneshot; -use tokio_io::AsyncRead; -use tokio_io::io::WriteHalf; -use tokio_io::codec::FramedRead; -use tokio_core::net::TcpStream; +use futures::Future; use redis_async::error::Error as RespError; use redis_async::resp::{RespCodec, RespValue}; +use tokio_core::net::TcpStream; +use tokio_io::codec::FramedRead; +use tokio_io::io::WriteHalf; +use tokio_io::AsyncRead; use Error; - /// Command for send data to Redis #[derive(Debug)] pub struct Command(pub RespValue); @@ -38,11 +37,11 @@ impl RedisActor { pub fn start>(addr: S) -> Addr { let addr = addr.into(); - Supervisor::start(|_| { - RedisActor { addr: addr, - cell: None, - backoff: ExponentialBackoff::default(), - queue: VecDeque::new() } + Supervisor::start(|_| RedisActor { + addr: addr, + cell: None, + backoff: ExponentialBackoff::default(), + queue: VecDeque::new(), }) } } @@ -51,7 +50,8 @@ impl Actor for RedisActor { type Context = Context; fn started(&mut self, ctx: &mut Context) { - Connector::from_registry().send(Connect::host(self.addr.as_str())) + Connector::from_registry() + .send(Connect::host(self.addr.as_str())) .into_actor(self) .map(|res, act, ctx| match res { Ok(stream) => { @@ -67,7 +67,7 @@ impl Actor for RedisActor { ctx.add_stream(FramedRead::new(r, RespCodec)); act.backoff.reset(); - }, + } Err(err) => { error!("Can not connect to redis server: {}", err); // re-connect with backoff time. @@ -103,15 +103,16 @@ impl Supervised for RedisActor { } impl actix::io::WriteHandler for RedisActor { - fn error(&mut self, err: io::Error, _: &mut Self::Context) -> Running { - warn!("Redis connection dropped: {} error: {}", self.addr, err); + warn!( + "Redis connection dropped: {} error: {}", + self.addr, err + ); Running::Stop } } impl StreamHandler for RedisActor { - fn error(&mut self, err: RespError, _: &mut Self::Context) -> Running { if let Some(tx) = self.queue.pop_front() { let _ = tx.send(Err(err.into())); @@ -138,6 +139,9 @@ impl Handler for RedisActor { let _ = tx.send(Err(Error::NotConnected)); } - Box::new(rx.map_err(|_| Error::Disconnected).and_then(|res| res)) + Box::new( + rx.map_err(|_| Error::Disconnected) + .and_then(|res| res), + ) } } diff --git a/src/session.rs b/src/session.rs index efc1733c9..011f1ad58 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,21 +1,21 @@ -use std::rc::Rc; -use std::iter::FromIterator; use std::collections::HashMap; +use std::iter::FromIterator; +use std::rc::Rc; -use serde_json; -use rand::{self, Rng}; -use futures::Future; -use futures::future::{Either, ok as FutOk, err as FutErr}; -use redis_async::resp::RespValue; -use cookie::{CookieJar, Cookie, Key}; -use http::header::{self, HeaderValue}; use actix::prelude::*; -use actix_web::{error, Error, Result, HttpRequest, HttpResponse}; -use actix_web::middleware::{SessionImpl, SessionBackend, Response as MiddlewareResponse}; +use actix_web::middleware::session::{SessionBackend, SessionImpl}; +use actix_web::middleware::Response as MiddlewareResponse; +use actix_web::{error, Error, HttpRequest, HttpResponse, Result}; +use cookie::{Cookie, CookieJar, Key}; +use futures::future::{err as FutErr, ok as FutOk, Either}; +use futures::Future; +use http::header::{self, HeaderValue}; +use rand::{self, Rng}; +use redis_async::resp::RespValue; +use serde_json; use redis::{Command, RedisActor}; - /// Session that stores data in redis pub struct RedisSession { changed: bool, @@ -25,7 +25,6 @@ pub struct RedisSession { } impl SessionImpl for RedisSession { - fn get(&self, key: &str) -> Option<&str> { self.state.get(key).map(|s| s.as_str()) } @@ -47,8 +46,11 @@ impl SessionImpl for RedisSession { fn write(&self, resp: HttpResponse) -> Result { if self.changed { - Ok(MiddlewareResponse::Future( - self.inner.update(&self.state, resp, self.value.as_ref()))) + Ok(MiddlewareResponse::Future(self.inner.update( + &self.state, + resp, + self.value.as_ref(), + ))) } else { Ok(MiddlewareResponse::Done(resp)) } @@ -58,10 +60,11 @@ impl SessionImpl for RedisSession { /// Use redis as session storage. /// /// You need to pass an address of the redis server and random value to the -/// constructor of `RedisSessionBackend`. This is private key for cookie session, -/// When this value is changed, all session data is lost. +/// constructor of `RedisSessionBackend`. This is private key for cookie +/// session, When this value is changed, all session data is lost. /// -/// Note that whatever you write into your session is visible by the user (but not modifiable). +/// Note that whatever you write into your session is visible by the user (but +/// not modifiable). /// /// Constructor panics if key length is less than 32 bytes. pub struct RedisSessionBackend(Rc); @@ -71,11 +74,12 @@ impl RedisSessionBackend { /// /// * `addr` - address of the redis server pub fn new>(addr: S, key: &[u8]) -> RedisSessionBackend { - RedisSessionBackend( - Rc::new(Inner{key: Key::from_master(key), - ttl: "7200".to_owned(), - addr: RedisActor::start(addr), - name: "actix-session".to_owned()})) + RedisSessionBackend(Rc::new(Inner { + key: Key::from_master(key), + ttl: "7200".to_owned(), + addr: RedisActor::start(addr), + name: "actix-session".to_owned(), + })) } /// Set time to live in seconds for session value @@ -92,9 +96,8 @@ impl RedisSessionBackend { } impl SessionBackend for RedisSessionBackend { - type Session = RedisSession; - type ReadFuture = Box>; + type ReadFuture = Box>; fn from_request(&self, req: &mut HttpRequest) -> Self::ReadFuture { let inner = Rc::clone(&self.0); @@ -105,13 +108,15 @@ impl SessionBackend for RedisSessionBackend { changed: false, inner: inner, state: state, - value: Some(value) } + value: Some(value), + } } else { RedisSession { changed: false, inner: inner, state: HashMap::new(), - value: None } + value: None, + } } })) } @@ -126,8 +131,9 @@ struct Inner { impl Inner { #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] - fn load(&self, req: &mut HttpRequest) - -> Box, String)>, Error=Error>> + fn load( + &self, req: &mut HttpRequest, + ) -> Box, String)>, Error = Error>> { if let Ok(cookies) = req.cookies() { for cookie in cookies { @@ -137,31 +143,42 @@ impl Inner { if let Some(cookie) = jar.signed(&self.key).get(&self.name) { let value = cookie.value().to_owned(); return Box::new( - self.addr.send(Command(resp_array!["GET", cookie.value()])) + self.addr + .send(Command(resp_array!["GET", cookie.value()])) .map_err(Error::from) .and_then(move |res| match res { Ok(val) => { match val { - RespValue::Error(err) => + RespValue::Error(err) => { return Err( - error::ErrorInternalServerError(err).into()), - RespValue::SimpleString(s) => - if let Ok(val) = serde_json::from_str(&s) { - return Ok(Some((val, value))) - }, - RespValue::BulkString(s) => { - if let Ok(val) = serde_json::from_slice(&s) { - return Ok(Some((val, value))) + error::ErrorInternalServerError(err) + .into(), + ) + } + RespValue::SimpleString(s) => { + if let Ok(val) = serde_json::from_str(&s) + { + return Ok(Some((val, value))); } - }, + } + RespValue::BulkString(s) => { + if let Ok(val) = + serde_json::from_slice(&s) + { + return Ok(Some((val, value))); + } + } _ => (), } Ok(None) - }, - Err(err) => Err(error::ErrorInternalServerError(err).into()) - })) + } + Err(err) => { + Err(error::ErrorInternalServerError(err).into()) + } + }), + ); } else { - return Box::new(FutOk(None)) + return Box::new(FutOk(None)); } } } @@ -169,10 +186,10 @@ impl Inner { Box::new(FutOk(None)) } - fn update(&self, state: &HashMap, - mut resp: HttpResponse, - value: Option<&String>) -> Box> - { + fn update( + &self, state: &HashMap, mut resp: HttpResponse, + value: Option<&String>, + ) -> Box> { let (value, jar) = if let Some(value) = value { (value.clone(), None) } else { @@ -190,25 +207,28 @@ impl Inner { (value, Some(jar)) }; - Box::new( - match serde_json::to_string(state) { - Err(e) => Either::A(FutErr(e.into())), - Ok(body) => Either::B( - self.addr.send(Command(resp_array!["SET", value, body,"EX", &self.ttl])) - .map_err(Error::from) - .and_then(move |res| match res { - Ok(_) => { - if let Some(jar) = jar { - for cookie in jar.delta() { - let val = HeaderValue::from_str( - &cookie.to_string())?; - resp.headers_mut().append(header::SET_COOKIE, val); - } + Box::new(match serde_json::to_string(state) { + Err(e) => Either::A(FutErr(e.into())), + Ok(body) => Either::B( + self.addr + .send(Command(resp_array![ + "SET", value, body, "EX", &self.ttl + ])) + .map_err(Error::from) + .and_then(move |res| match res { + Ok(_) => { + if let Some(jar) = jar { + for cookie in jar.delta() { + let val = + HeaderValue::from_str(&cookie.to_string())?; + resp.headers_mut().append(header::SET_COOKIE, val); } - Ok(resp) - }, - Err(err) => Err(error::ErrorInternalServerError(err).into()) - })) - }) + } + Ok(resp) + } + Err(err) => Err(error::ErrorInternalServerError(err).into()), + }), + ), + }) } } diff --git a/tests/test_redis.rs b/tests/test_redis.rs index f19cfcec5..a3d650e45 100644 --- a/tests/test_redis.rs +++ b/tests/test_redis.rs @@ -2,11 +2,11 @@ extern crate actix; extern crate actix_redis; #[macro_use] extern crate redis_async; -extern crate futures; extern crate env_logger; +extern crate futures; use actix::prelude::*; -use actix_redis::{RedisActor, Command, Error, RespValue}; +use actix_redis::{Command, Error, RedisActor, RespValue}; use futures::Future; #[test] @@ -31,7 +31,6 @@ fn test_error_connect() { sys.run(); } - #[test] fn test_redis() { env_logger::init(); @@ -46,20 +45,23 @@ fn test_redis() { .then(move |res| match res { Ok(Ok(resp)) => { assert_eq!(resp, RespValue::SimpleString("OK".to_owned())); - addr2.send(Command(resp_array!["GET", "test"])) + addr2 + .send(Command(resp_array!["GET", "test"])) .then(|res| { match res { Ok(Ok(resp)) => { println!("RESP: {:?}", resp); assert_eq!( - resp, RespValue::BulkString((&b"value"[..]).into())); - }, + resp, + RespValue::BulkString((&b"value"[..]).into()) + ); + } _ => panic!("Should not happen {:?}", res), } Arbiter::system().do_send(actix::msgs::SystemExit(0)); Ok(()) }) - }, + } _ => panic!("Should not happen {:?}", res), }) });