Accessing external state in api handlers
This commit is contained in:
parent
f067a1c3d1
commit
9c69353f69
5 changed files with 113 additions and 36 deletions
|
@ -1,6 +1,9 @@
|
|||
use core::str::Utf8Error;
|
||||
use core::ops::DerefMut;
|
||||
use std::path::PathBuf;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use iron::prelude::*;
|
||||
use iron::status;
|
||||
|
@ -15,15 +18,28 @@ impl From<CollectionError> for IronError {
|
|||
fn from(err: CollectionError) -> IronError {
|
||||
match err {
|
||||
CollectionError::Io(e) => IronError::new(e, status::NotFound),
|
||||
CollectionError::PathDecoding => IronError::new(err, status::InternalServerError)
|
||||
CollectionError::PathDecoding => IronError::new(err, status::InternalServerError),
|
||||
CollectionError::ConflictingMount(_) => IronError::new(err, status::BadRequest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_api_handler() -> Mount {
|
||||
pub fn get_api_handler(collection: Arc<Mutex<collection::Collection>>) -> Mount {
|
||||
let mut mount = Mount::new();
|
||||
mount.mount("/browse/", self::browse)
|
||||
.mount("/flatten/", self::flatten);
|
||||
{
|
||||
let collection = collection.clone();
|
||||
mount.mount("/browse/", move |request: &mut Request| {
|
||||
let mut acquired_collection = collection.deref().lock().unwrap();
|
||||
self::browse(request, acquired_collection.deref_mut())
|
||||
} );
|
||||
}
|
||||
{
|
||||
let collection = collection.clone();
|
||||
mount.mount("/flatten/", move |request: &mut Request| {
|
||||
let mut acquired_collection = collection.deref().lock().unwrap();
|
||||
self::flatten(request, acquired_collection.deref_mut())
|
||||
} );
|
||||
}
|
||||
mount
|
||||
}
|
||||
|
||||
|
@ -33,13 +49,13 @@ fn path_from_request(request: &Request) -> Result<PathBuf, Utf8Error> {
|
|||
Ok(PathBuf::from(decoded_path.deref()))
|
||||
}
|
||||
|
||||
fn browse(request: &mut Request) -> IronResult<Response> {
|
||||
fn browse(request: &mut Request, collection: &mut collection::Collection) -> IronResult<Response> {
|
||||
let path = path_from_request(request);
|
||||
if path.is_err() {
|
||||
return Ok(Response::with(status::BadRequest));
|
||||
}
|
||||
let path = path.unwrap();
|
||||
let browse_result = try!(collection::browse(&path));
|
||||
let browse_result = try!(collection.browse(&path));
|
||||
|
||||
let result_json = json::encode(&browse_result);
|
||||
if result_json.is_err() {
|
||||
|
@ -51,11 +67,11 @@ fn browse(request: &mut Request) -> IronResult<Response> {
|
|||
Ok(Response::with((status::Ok, result_json)))
|
||||
}
|
||||
|
||||
fn flatten(request: &mut Request) -> IronResult<Response> {
|
||||
fn flatten(request: &mut Request, collection: &mut collection::Collection) -> IronResult<Response> {
|
||||
let path = path_from_request(request);
|
||||
if path.is_err() {
|
||||
return Ok(Response::with((status::BadRequest)));
|
||||
}
|
||||
collection::flatten(&path.unwrap());
|
||||
collection.flatten(&path.unwrap());
|
||||
Ok(Response::with((status::Ok, "TODO Flatten data here")))
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ pub enum CollectionError
|
|||
{
|
||||
PathDecoding,
|
||||
Io(io::Error),
|
||||
ConflictingMount(String),
|
||||
}
|
||||
|
||||
impl From<io::Error> for CollectionError {
|
||||
|
@ -20,6 +21,7 @@ impl error::Error for CollectionError {
|
|||
match *self {
|
||||
CollectionError::Io(ref err) => err.description(),
|
||||
CollectionError::PathDecoding => "Error while decoding a Path as a UTF-8 string",
|
||||
CollectionError::ConflictingMount(_) => "Attempting to mount multiple directories under the same name",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +29,7 @@ impl error::Error for CollectionError {
|
|||
match *self {
|
||||
CollectionError::Io(ref err) => Some(err),
|
||||
CollectionError::PathDecoding => None,
|
||||
CollectionError::ConflictingMount(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +39,7 @@ impl fmt::Display for CollectionError {
|
|||
match *self {
|
||||
CollectionError::Io(ref err) => write!(f, "IO error: {}", err),
|
||||
CollectionError::PathDecoding => write!(f, "Path decoding error"),
|
||||
CollectionError::ConflictingMount(ref name) => write!(f, "Mount point {} already has a target directory", name),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ use std::path::Path;
|
|||
pub use self::error::CollectionError;
|
||||
|
||||
mod error;
|
||||
mod vfs;
|
||||
|
||||
#[derive(Debug, RustcEncodable)]
|
||||
pub struct Song {
|
||||
|
@ -21,36 +22,50 @@ pub enum CollectionFile {
|
|||
Song(Song),
|
||||
}
|
||||
|
||||
pub fn browse(path: &Path) -> Result<Vec<CollectionFile>, CollectionError> {
|
||||
pub struct Collection {
|
||||
vfs: vfs::Vfs,
|
||||
}
|
||||
|
||||
let full_path = "samplemusic/".to_string() + path.to_str().unwrap(); // TMP use mount directories
|
||||
println!("Browsing: {}", full_path);
|
||||
|
||||
let mut out = vec![];
|
||||
for file in try!(fs::read_dir(full_path)) {
|
||||
let file = try!(file);
|
||||
let file_meta = try!(file.metadata());
|
||||
let file_path = file.path().to_owned();
|
||||
if file_meta.is_file() {
|
||||
let path_string = try!(file_path.to_str().ok_or(CollectionError::PathDecoding));
|
||||
let collection_file = CollectionFile::Song(Song {
|
||||
path: path_string.to_string(),
|
||||
});
|
||||
out.push(collection_file);
|
||||
} else if file_meta.is_dir() {
|
||||
let path_string = try!(file_path.to_str().ok_or(CollectionError::PathDecoding));
|
||||
let collection_file = CollectionFile::Directory(Directory {
|
||||
path: path_string.to_string(),
|
||||
});
|
||||
out.push(collection_file);
|
||||
impl Collection {
|
||||
pub fn new() -> Collection {
|
||||
Collection{
|
||||
vfs: vfs::Vfs::new(),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn flatten(path: &Path) -> Vec<CollectionFile> {
|
||||
println!("Flatten {:?}", path);
|
||||
let out = vec![];
|
||||
out
|
||||
impl Collection {
|
||||
pub fn browse(&self, path: &Path) -> Result<Vec<CollectionFile>, CollectionError> {
|
||||
|
||||
let full_path = "samplemusic/".to_string() + path.to_str().unwrap(); // TMP use mount directories
|
||||
println!("Browsing: {}", full_path);
|
||||
|
||||
let mut out = vec![];
|
||||
for file in try!(fs::read_dir(full_path)) {
|
||||
let file = try!(file);
|
||||
let file_meta = try!(file.metadata());
|
||||
let file_path = file.path().to_owned();
|
||||
if file_meta.is_file() {
|
||||
let path_string = try!(file_path.to_str().ok_or(CollectionError::PathDecoding));
|
||||
let collection_file = CollectionFile::Song(Song {
|
||||
path: path_string.to_string(),
|
||||
});
|
||||
out.push(collection_file);
|
||||
} else if file_meta.is_dir() {
|
||||
let path_string = try!(file_path.to_str().ok_or(CollectionError::PathDecoding));
|
||||
let collection_file = CollectionFile::Directory(Directory {
|
||||
path: path_string.to_string(),
|
||||
});
|
||||
out.push(collection_file);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn flatten(&self, path: &Path) -> Vec<CollectionFile> {
|
||||
println!("Flatten {:?}", path);
|
||||
let out = vec![];
|
||||
out
|
||||
}
|
||||
}
|
||||
|
|
35
src/collection/vfs.rs
Normal file
35
src/collection/vfs.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
use collection::error::CollectionError;
|
||||
|
||||
pub struct Vfs {
|
||||
mount_points: HashMap<String, PathBuf>,
|
||||
}
|
||||
|
||||
impl Vfs {
|
||||
pub fn new() -> Vfs {
|
||||
Vfs {
|
||||
mount_points: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mount(&mut self, name: &str, real_path: &Path) -> Result<(), CollectionError>
|
||||
{
|
||||
let name = name.to_string();
|
||||
if self.mount_points.contains_key(&name) {
|
||||
return Err(CollectionError::ConflictingMount(name));
|
||||
}
|
||||
self.mount_points.insert(name, real_path.to_path_buf());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn real_to_virtual(&self, real_path: &Path) -> Result<(), CollectionError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<(), CollectionError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -5,6 +5,9 @@ extern crate rustc_serialize;
|
|||
extern crate staticfile;
|
||||
extern crate url;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use iron::prelude::*;
|
||||
use mount::Mount;
|
||||
use staticfile::Static;
|
||||
|
@ -13,8 +16,12 @@ mod api;
|
|||
mod collection;
|
||||
|
||||
fn main() {
|
||||
|
||||
let collection = collection::Collection::new();
|
||||
let collection = Arc::new(Mutex::new(collection));
|
||||
|
||||
let mut mount = Mount::new();
|
||||
let api_handler = api::get_api_handler();
|
||||
let api_handler = api::get_api_handler( collection );
|
||||
mount.mount("/static/", Static::new("samplemusic/"))
|
||||
.mount("/api/", api_handler);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue