2015-11-20 01:43:04 +03:00
|
|
|
#[macro_use] extern crate nickel;
|
2015-11-21 18:21:44 +03:00
|
|
|
#[macro_use] extern crate log;
|
2015-11-20 01:43:04 +03:00
|
|
|
extern crate env_logger;
|
2015-11-21 18:21:44 +03:00
|
|
|
extern crate rustorm;
|
|
|
|
extern crate rustc_serialize;
|
2015-11-22 15:01:39 +03:00
|
|
|
extern crate typemap;
|
|
|
|
extern crate plugin;
|
|
|
|
extern crate image;
|
|
|
|
extern crate hyper;
|
|
|
|
extern crate time;
|
2015-11-20 01:43:04 +03:00
|
|
|
|
2015-11-23 08:48:09 +03:00
|
|
|
mod models;
|
2015-11-22 15:01:39 +03:00
|
|
|
use hyper::header::{Expires, HttpDate};
|
2015-11-23 08:48:09 +03:00
|
|
|
use image::open as image_open;
|
|
|
|
use image::{FilterType, ImageFormat};
|
|
|
|
use models::{Photo, Tag, query_for};
|
|
|
|
use nickel::mimes::MediaType;
|
2015-11-22 15:01:39 +03:00
|
|
|
use nickel::{Nickel, Request, Response, Middleware, Continue, MiddlewareResult};
|
2015-11-23 08:48:09 +03:00
|
|
|
use plugin::{Pluggable, Extensible};
|
|
|
|
use rustc_serialize::Encodable;
|
|
|
|
use rustorm::dao::{IsDao, ToValue};
|
2015-11-27 00:47:39 +03:00
|
|
|
use rustorm::database::{Database, DbError};
|
2015-11-23 08:48:09 +03:00
|
|
|
use rustorm::pool::{ManagedPool,Platform};
|
|
|
|
use rustorm::query::Query;
|
2015-11-22 15:01:39 +03:00
|
|
|
use rustorm::table::IsTable;
|
2015-11-23 08:48:09 +03:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use time::Duration;
|
2015-11-22 15:01:39 +03:00
|
|
|
use typemap::Key;
|
2015-11-21 18:21:44 +03:00
|
|
|
|
2015-11-23 08:48:09 +03:00
|
|
|
mod env;
|
|
|
|
use env::dburl;
|
2015-11-21 18:21:44 +03:00
|
|
|
|
2015-11-22 15:01:39 +03:00
|
|
|
struct RustormMiddleware {
|
|
|
|
pool: ManagedPool
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RustormMiddleware {
|
|
|
|
pub fn new(db_url: &str) -> RustormMiddleware {
|
|
|
|
RustormMiddleware {
|
|
|
|
pool: ManagedPool::init(db_url, 5).unwrap(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Key for RustormMiddleware { type Value = Platform; }
|
|
|
|
|
|
|
|
impl<D> Middleware<D> for RustormMiddleware {
|
|
|
|
fn invoke<'mw, 'conn>(&self, req: &mut Request<'mw, 'conn, D>, res: Response<'mw, D>) -> MiddlewareResult<'mw, D> {
|
|
|
|
req.extensions_mut().insert::<RustormMiddleware>(
|
|
|
|
self.pool.connect().unwrap());
|
|
|
|
Ok(Continue(res))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait RustormRequestExtensions {
|
|
|
|
fn db_conn(&self) -> &Database;
|
2015-11-27 00:47:39 +03:00
|
|
|
fn orm_get<T: IsTable + IsDao>(&self, key: &str, val: &ToValue)
|
|
|
|
-> Result<T, DbError>;
|
2015-11-22 15:01:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'b, D> RustormRequestExtensions for Request<'a, 'b, D> {
|
|
|
|
fn db_conn(&self) -> &Database {
|
|
|
|
self.extensions().get::<RustormMiddleware>().unwrap().as_ref()
|
|
|
|
}
|
2015-11-27 00:47:39 +03:00
|
|
|
fn orm_get<T: IsTable + IsDao>(&self, key: &str, val: &ToValue)
|
|
|
|
-> Result<T, DbError> {
|
|
|
|
query_for::<T>().filter_eq(key, val).collect_one(self.db_conn())
|
2015-11-23 08:48:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, RustcEncodable)]
|
|
|
|
struct DetailsData {
|
|
|
|
photo: Photo,
|
|
|
|
tags: Vec<Tag>
|
2015-11-22 15:01:39 +03:00
|
|
|
}
|
|
|
|
|
2015-11-27 00:47:39 +03:00
|
|
|
#[derive(Debug, Clone, RustcEncodable)]
|
|
|
|
struct TagData {
|
|
|
|
tag: Tag,
|
|
|
|
photos: Vec<Photo>
|
|
|
|
}
|
|
|
|
|
2015-11-22 15:01:39 +03:00
|
|
|
fn get_scaled_image(photo: Photo, width: u32, height: u32) -> Vec<u8> {
|
|
|
|
let path = format!("/home/kaj/Bilder/foto/{}", photo.path);
|
|
|
|
info!("Should open {}", path);
|
|
|
|
let img = image_open(path).unwrap();
|
|
|
|
let scaled = img.resize(width, height, FilterType::Nearest);
|
|
|
|
// TODO Put the icon in some kind of cache!
|
|
|
|
let mut buf : Vec<u8> = Vec::new();
|
|
|
|
scaled.save(&mut buf, ImageFormat::JPEG).unwrap();
|
|
|
|
buf
|
|
|
|
}
|
2015-11-20 01:43:04 +03:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
env_logger::init().unwrap();
|
2015-11-21 18:21:44 +03:00
|
|
|
info!("Initalized logger");
|
|
|
|
// NOTE pool will need to be mut if we do db writes?
|
2015-11-22 15:01:39 +03:00
|
|
|
// let pool = ManagedPool::init(&dburl(), 1).unwrap();
|
2015-11-21 18:21:44 +03:00
|
|
|
info!("Initalized pool");
|
|
|
|
|
2015-11-20 01:43:04 +03:00
|
|
|
let mut server = Nickel::new();
|
2015-11-22 15:01:39 +03:00
|
|
|
server.utilize(RustormMiddleware::new(&dburl()));
|
2015-11-20 01:43:04 +03:00
|
|
|
|
|
|
|
server.utilize(router! {
|
2015-11-22 15:01:39 +03:00
|
|
|
get "/" => |req, res| {
|
2015-11-23 08:48:09 +03:00
|
|
|
let photos: Vec<Photo> = query_for::<Photo>().limit(16)
|
2015-11-22 15:01:39 +03:00
|
|
|
.collect(req.db_conn()).unwrap();
|
2015-11-21 18:21:44 +03:00
|
|
|
info!("Got some photos: {:?}", photos);
|
2015-11-20 01:43:04 +03:00
|
|
|
let mut data = HashMap::new();
|
2015-11-21 18:21:44 +03:00
|
|
|
data.insert("photos", &photos);
|
|
|
|
// data.insert("name", "Self".into());
|
2015-11-20 01:43:04 +03:00
|
|
|
return res.render("templates/index.tpl", &data);
|
|
|
|
}
|
2015-11-22 15:01:39 +03:00
|
|
|
get "/details/:id" => |req, res| {
|
2015-11-23 08:48:09 +03:00
|
|
|
if let Ok(id) = req.param("id").unwrap().parse::<i32>() {
|
2015-11-27 00:47:39 +03:00
|
|
|
if let Ok(photo) = req.orm_get::<Photo>("id", &id) {
|
|
|
|
|
|
|
|
let mut q = Query::select();
|
|
|
|
q.only_from(&Tag::table());
|
|
|
|
q.left_join_table("photo_tag", "tag.id", "photo_tag.tag")
|
|
|
|
.filter_eq("photo_tag.photo", &photo.id);
|
|
|
|
let tags = q.collect(req.db_conn()).unwrap();
|
|
|
|
|
|
|
|
return res.render("templates/details.tpl", &DetailsData {
|
|
|
|
photo: photo,
|
|
|
|
tags: tags
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
get "/tag/:tag" => |req, res| {
|
|
|
|
let slug = req.param("tag").unwrap();
|
|
|
|
if let Ok(tag) = req.orm_get::<Tag>("slug", &slug) {
|
|
|
|
|
|
|
|
let mut q = Query::select();
|
|
|
|
q.only_from(&Photo::table());
|
|
|
|
q.left_join_table("photo_tag", "photo.id", "photo_tag.photo")
|
|
|
|
.filter_eq("photo_tag.tag", &tag.id);
|
|
|
|
let photos : Vec<Photo> = q.collect(req.db_conn()).unwrap();
|
|
|
|
return res.render("templates/tag.tpl", &TagData {
|
|
|
|
tag: tag,
|
|
|
|
photos: photos
|
2015-11-23 08:48:09 +03:00
|
|
|
});
|
|
|
|
}
|
2015-11-22 15:01:39 +03:00
|
|
|
}
|
|
|
|
get "/icon/:id" => |req, mut res| {
|
2015-11-23 08:48:09 +03:00
|
|
|
if let Ok(id) = req.param("id").unwrap().parse::<i32>() {
|
2015-11-27 00:47:39 +03:00
|
|
|
if let Ok(photo) = req.orm_get::<Photo>("id", &id) {
|
|
|
|
let buf = get_scaled_image(photo, 200, 180);
|
|
|
|
res.set(MediaType::Jpeg);
|
|
|
|
res.set(Expires(HttpDate(time::now() + Duration::days(14))));
|
|
|
|
return res.send(buf);
|
|
|
|
}
|
2015-11-23 08:48:09 +03:00
|
|
|
}
|
2015-11-22 15:01:39 +03:00
|
|
|
}
|
|
|
|
get "/view/:id" => |req, mut res| {
|
2015-11-23 08:48:09 +03:00
|
|
|
if let Ok(id) = req.param("id").unwrap().parse::<i32>() {
|
2015-11-27 00:47:39 +03:00
|
|
|
if let Ok(photo) = req.orm_get::<Photo>("id", &id) {
|
|
|
|
let buf = get_scaled_image(photo, 800, 600);
|
|
|
|
res.set(MediaType::Jpeg);
|
|
|
|
res.set(Expires(HttpDate(time::now() + Duration::days(14))));
|
|
|
|
return res.send(buf);
|
|
|
|
}
|
2015-11-23 08:48:09 +03:00
|
|
|
}
|
2015-11-22 15:01:39 +03:00
|
|
|
}
|
2015-11-20 01:43:04 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
server.listen("127.0.0.1:6767");
|
|
|
|
}
|