use std::convert::AsRef;
use time::Duration;
use outcome::IntoOutcome;
use response::{Response, Responder};
use request::{self, Request, FromRequest};
use http::{Status, Cookie};
const FLASH_COOKIE_NAME: &'static str = "_flash";
#[derive(Debug)]
pub struct Flash<R> {
name: String,
message: String,
responder: R,
}
impl<'r, R: Responder<'r>> Flash<R> {
pub fn new<N: AsRef<str>, M: AsRef<str>>(res: R, name: N, msg: M) -> Flash<R> {
Flash {
name: name.as_ref().to_string(),
message: msg.as_ref().to_string(),
responder: res,
}
}
pub fn success<S: AsRef<str>>(responder: R, msg: S) -> Flash<R> {
Flash::new(responder, "success", msg)
}
pub fn warning<S: AsRef<str>>(responder: R, msg: S) -> Flash<R> {
Flash::new(responder, "warning", msg)
}
pub fn error<S: AsRef<str>>(responder: R, msg: S) -> Flash<R> {
Flash::new(responder, "error", msg)
}
fn cookie(&self) -> Cookie<'static> {
let content = format!("{}{}{}", self.name.len(), self.name, self.message);
Cookie::build(FLASH_COOKIE_NAME, content)
.max_age(Duration::minutes(5))
.path("/")
.finish()
}
}
impl<'r, R: Responder<'r>> Responder<'r> for Flash<R> {
fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
trace_!("Flash: setting message: {}:{}", self.name, self.message);
let cookie = self.cookie();
Response::build_from(self.responder.respond_to(req)?)
.header_adjoin(&cookie)
.ok()
}
}
impl Flash<()> {
fn named(name: &str, msg: &str) -> Flash<()> {
Flash {
name: name.to_string(),
message: msg.to_string(),
responder: (),
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn msg(&self) -> &str {
self.message.as_str()
}
}
impl<'a, 'r> FromRequest<'a, 'r> for Flash<()> {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
trace_!("Flash: attemping to retrieve message.");
let r = request.cookies().get(FLASH_COOKIE_NAME).ok_or(()).and_then(|cookie| {
trace_!("Flash: retrieving message: {:?}", cookie);
let content = cookie.value();
let (len_str, rest) = match content.find(|c: char| !c.is_digit(10)) {
Some(i) => (&content[..i], &content[i..]),
None => (content, ""),
};
let name_len: usize = len_str.parse().map_err(|_| ())?;
let (name, msg) = (&rest[..name_len], &rest[name_len..]);
Ok(Flash::named(name, msg))
});
if r.is_ok() {
let cookie = Cookie::build(FLASH_COOKIE_NAME, "").path("/").finish();
request.cookies().remove(cookie);
}
r.into_outcome(Status::BadRequest)
}
}