use std::collections::HashMap;
use std::borrow::Cow;
use crate::error::Error;
use std::error::Error as StdError;
use crate::http::form::Error as FormError;
use crate::state::State;
use crate::http::{headers, Request, form::FormData, Response, BodyWriter, StatusCode};
use cookie::{Cookie, CookieJar};
use serde_json;
use serde_urlencoded;
use serde::de::DeserializeOwned;
use std::fs::File;
use std::path::Path;
use url::form_urlencoded;
use std::convert::TryInto;
use futures::{Future, Stream, Async};
use hyper;
use hyper::body::Payload;
use std::sync::Arc;
use std::cell::Ref;
use std::io::prelude::*;
use super::server::ServerConfig;
pub struct Context{
pub(crate) request: Request,
pub(crate) response: Response,
pub(crate) params: HashMap<String, String>,
pub(crate) server_config: Arc<ServerConfig>,
pub(crate) state: State,
pub(crate) cookies: CookieJar,
is_commited: bool,
}
impl Context{
pub fn new(server_config: Arc<ServerConfig>, request:Request, response: Response)->Context{
Context{
params: HashMap::new(),
server_config,
request,
response,
state: State::new(),
is_commited: false,
cookies: CookieJar::new(),
}
}
pub fn request(&self)->&Request{
&self.request
}
pub fn response(&mut self)->&Response{
&self.response
}
pub fn response_mut(&mut self)->&mut Response{
&mut self.response
}
pub fn params(&self)->&HashMap<String, String>{
&self.params
}
pub fn get_param<T>(&self, key:T) -> Option<&String> where T: AsRef<str> {
self.params().get(key.as_ref())
}
#[inline]
pub fn queries(&self)->&HashMap<String, String>{
self.request.queries()
}
#[inline]
pub fn get_query<T>(&self, key:T) -> Option<String> where T: AsRef<str> {
self.request.queries().get(key.as_ref()).map(|s|s.clone())
}
#[inline]
pub fn posts(&self) -> &Result<FormData, FormError> {
self.request.form_data()
}
#[inline]
pub fn get_post<T>(&self, key:T) -> Option<String> where T: AsRef<str> {
self.request.form_data().as_ref().ok().and_then(|ps|ps.get_one_field(key.as_ref()).map(|s|s.clone()))
}
pub fn get_form<T>(&self, key:T) -> Option<String> where T: AsRef<str> {
self.get_post(key.as_ref()).or(self.get_query(key.as_ref()).map(|s|s.clone()))
}
pub fn get_payload(&self) -> Result<String, Error> {
if let Ok(data) = self.request.body_data().as_ref(){
match String::from_utf8(data.to_vec()){
Ok(payload) => Ok(payload),
Err(err) => Err(Error::Utf8(err)),
}
} else {
Err(Error::General("utf8 encode error".to_owned()))
}
}
pub fn get_cookie<T>(&self, name:T) -> Option<&Cookie<'static>>
where T: AsRef<str> {
self.request.cookies().get(name.as_ref())
}
pub fn add_cookie(&mut self, cookie: Cookie<'static>) {
self.cookies.add(cookie);
}
pub fn remove_cookie<T>(&mut self, name: T) where T: Into<Cow<'static, str>> {
self.cookies.remove(Cookie::named(name));
}
pub fn state(&self)->&State {
&self.state
}
pub fn state_mut(&mut self)->&mut State {
&mut self.state
}
pub fn render_json<T:Into<String>>(&mut self, writer: T) {
self.render("application/json", writer.into());
}
pub fn render_html<T:Into<String>>(&mut self, writer: T) {
self.render("text/html", writer.into());
}
pub fn render_text<T:Into<String>>(&mut self, writer: T) {
self.render("text/plain", writer.into());
}
pub fn render_xml<T:Into<String>>(&mut self, writer: T) {
self.render("text/xml", writer.into());
}
pub fn render_binary(&mut self, writer: impl BodyWriter+'static) {
self.render("text/xml", writer);
}
pub fn render_file<T>(&mut self, content_type:T, file: &mut File)->std::io::Result<()> where T: AsRef<str> {
let mut data = Vec::new();
file.read_to_end(&mut data)?;
self.render(content_type, data);
Ok(())
}
pub fn render_file_from_path<T:AsRef<Path>>(&mut self, path: T)->std::io::Result<()> {
let mut file = File::open(path.as_ref())?;
let guess = mime_guess::from_path(path.as_ref());
return self.render_file(guess.first_or_text_plain().to_string(), &mut file);
}
pub fn render<T>(&mut self, content_type:T, writer: impl BodyWriter+'static) where T: AsRef<str> {
self.response.headers.insert("content-type", content_type.as_ref().parse().unwrap());
self.write_body(writer);
}
pub fn send_file(&mut self, file: File) {
}
pub fn send_file_from_path<T>(&mut self, writer: T) where T: AsRef<str> {
}
pub fn redirect_temporary<U: AsRef<str>>(&mut self, url: U) {
self.response.status = Some(StatusCode::MOVED_PERMANENTLY);
self.response.headers.insert(headers::LOCATION, url.as_ref().parse().unwrap());
}
pub fn redirect_found<U: AsRef<str>>(&mut self, url: U) {
self.response.status = Some(StatusCode::FOUND);
self.response.headers.insert(headers::LOCATION, url.as_ref().parse().unwrap());
}
pub fn redirect_other<U: AsRef<str>>(&mut self, url: U) {
self.response.status = Some(StatusCode::SEE_OTHER);
self.response.headers.insert(headers::LOCATION, url.as_ref().parse().unwrap());
}
pub fn write_body(&mut self, writer: impl BodyWriter+'static) {
self.response.body_writers.push(Box::new(writer))
}
pub fn commit(&mut self) {
self.is_commited = true;
}
pub fn is_commited(&self) -> bool{
self.is_commited
}
pub fn not_found(&mut self) {
self.response.status = Some(StatusCode::NOT_FOUND);
self.commit();
}
pub fn unauthorized(&mut self) {
self.response.status = Some(StatusCode::UNAUTHORIZED);
self.commit();
}
pub fn forbidden(&mut self) {
self.response.status = Some(StatusCode::FORBIDDEN);
self.commit();
}
}