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::str::Utf8Error;
|
||||||
|
use core::ops::DerefMut;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
use iron::status;
|
use iron::status;
|
||||||
|
@ -15,15 +18,28 @@ impl From<CollectionError> for IronError {
|
||||||
fn from(err: CollectionError) -> IronError {
|
fn from(err: CollectionError) -> IronError {
|
||||||
match err {
|
match err {
|
||||||
CollectionError::Io(e) => IronError::new(e, status::NotFound),
|
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();
|
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
|
mount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,13 +49,13 @@ fn path_from_request(request: &Request) -> Result<PathBuf, Utf8Error> {
|
||||||
Ok(PathBuf::from(decoded_path.deref()))
|
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);
|
let path = path_from_request(request);
|
||||||
if path.is_err() {
|
if path.is_err() {
|
||||||
return Ok(Response::with(status::BadRequest));
|
return Ok(Response::with(status::BadRequest));
|
||||||
}
|
}
|
||||||
let path = path.unwrap();
|
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);
|
let result_json = json::encode(&browse_result);
|
||||||
if result_json.is_err() {
|
if result_json.is_err() {
|
||||||
|
@ -51,11 +67,11 @@ fn browse(request: &mut Request) -> IronResult<Response> {
|
||||||
Ok(Response::with((status::Ok, result_json)))
|
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);
|
let path = path_from_request(request);
|
||||||
if path.is_err() {
|
if path.is_err() {
|
||||||
return Ok(Response::with((status::BadRequest)));
|
return Ok(Response::with((status::BadRequest)));
|
||||||
}
|
}
|
||||||
collection::flatten(&path.unwrap());
|
collection.flatten(&path.unwrap());
|
||||||
Ok(Response::with((status::Ok, "TODO Flatten data here")))
|
Ok(Response::with((status::Ok, "TODO Flatten data here")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub enum CollectionError
|
||||||
{
|
{
|
||||||
PathDecoding,
|
PathDecoding,
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
ConflictingMount(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for CollectionError {
|
impl From<io::Error> for CollectionError {
|
||||||
|
@ -20,6 +21,7 @@ impl error::Error for CollectionError {
|
||||||
match *self {
|
match *self {
|
||||||
CollectionError::Io(ref err) => err.description(),
|
CollectionError::Io(ref err) => err.description(),
|
||||||
CollectionError::PathDecoding => "Error while decoding a Path as a UTF-8 string",
|
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 {
|
match *self {
|
||||||
CollectionError::Io(ref err) => Some(err),
|
CollectionError::Io(ref err) => Some(err),
|
||||||
CollectionError::PathDecoding => None,
|
CollectionError::PathDecoding => None,
|
||||||
|
CollectionError::ConflictingMount(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +39,7 @@ impl fmt::Display for CollectionError {
|
||||||
match *self {
|
match *self {
|
||||||
CollectionError::Io(ref err) => write!(f, "IO error: {}", err),
|
CollectionError::Io(ref err) => write!(f, "IO error: {}", err),
|
||||||
CollectionError::PathDecoding => write!(f, "Path decoding error"),
|
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;
|
pub use self::error::CollectionError;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod vfs;
|
||||||
|
|
||||||
#[derive(Debug, RustcEncodable)]
|
#[derive(Debug, RustcEncodable)]
|
||||||
pub struct Song {
|
pub struct Song {
|
||||||
|
@ -21,36 +22,50 @@ pub enum CollectionFile {
|
||||||
Song(Song),
|
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
|
impl Collection {
|
||||||
println!("Browsing: {}", full_path);
|
pub fn new() -> Collection {
|
||||||
|
Collection{
|
||||||
let mut out = vec![];
|
vfs: vfs::Vfs::new(),
|
||||||
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(path: &Path) -> Vec<CollectionFile> {
|
impl Collection {
|
||||||
println!("Flatten {:?}", path);
|
pub fn browse(&self, path: &Path) -> Result<Vec<CollectionFile>, CollectionError> {
|
||||||
let out = vec![];
|
|
||||||
out
|
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 staticfile;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
use mount::Mount;
|
use mount::Mount;
|
||||||
use staticfile::Static;
|
use staticfile::Static;
|
||||||
|
@ -13,8 +16,12 @@ mod api;
|
||||||
mod collection;
|
mod collection;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
let collection = collection::Collection::new();
|
||||||
|
let collection = Arc::new(Mutex::new(collection));
|
||||||
|
|
||||||
let mut mount = Mount::new();
|
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.mount("/static/", Static::new("samplemusic/"))
|
||||||
.mount("/api/", api_handler);
|
.mount("/api/", api_handler);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue