Skip to content

Commit

Permalink
aw-server: Add Into trait for DatastoreError to HttpErrorJson
Browse files Browse the repository at this point in the history
  • Loading branch information
johan-bjareholt committed Aug 6, 2020
1 parent d985c51 commit 7a19f34
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 216 deletions.
1 change: 1 addition & 0 deletions aw-datastore/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl fmt::Debug for Datastore {
* TODO:
* - Allow read requests to go straight through a read-only db connection instead of requesting the
* worker thread for better performance?
* TODO: Add an seperate "Import" request which does an import with an transaction
*/

#[allow(clippy::large_enum_variant)]
Expand Down
133 changes: 11 additions & 122 deletions aw-server/src/endpoints/bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,14 @@ use rocket::State;

use crate::endpoints::{HttpErrorJson, ServerState};

use aw_datastore::DatastoreError;

#[get("/")]
pub fn buckets_get(
state: State<ServerState>,
) -> Result<Json<HashMap<String, Bucket>>, HttpErrorJson> {
let datastore = endpoints_get_lock!(state.datastore);
match datastore.get_buckets() {
Ok(bucketlist) => Ok(Json(bucketlist)),
Err(e) => {
let err_msg = format!("Unexpected error: {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
Err(err) => Err(err.into()),
}
}

Expand All @@ -42,17 +36,7 @@ pub fn bucket_get(
let datastore = endpoints_get_lock!(state.datastore);
match datastore.get_bucket(&bucket_id) {
Ok(bucket) => Ok(Json(bucket)),
Err(e) => match e {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
_ => {
let err_msg = format!("Unexpected error: {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(e) => Err(e.into()),
}
}

Expand All @@ -66,34 +50,11 @@ pub fn bucket_new(
if bucket.id != bucket_id {
bucket.id = bucket_id;
}
// Cannot re-use endpoints_get_lock!() here because it returns Err(Status) on failure and this
// function returns a Response
let datastore = match state.datastore.lock() {
Ok(ds) => ds,
Err(e) => {
warn!("Taking datastore lock failed, returning 504: {}", e);
return Err(HttpErrorJson::new(
Status::ServiceUnavailable,
"Takind datastore lock failed".to_string(),
));
}
};
let datastore = endpoints_get_lock!(state.datastore);
let ret = datastore.create_bucket(&bucket);
match ret {
Ok(_) => Ok(()),
Err(err) => match err {
DatastoreError::BucketAlreadyExists => Err(HttpErrorJson::new(
Status::NotModified,
"Bucket already exists".to_string(),
)),
_ => {
warn!("Unexpected error: {:?}", err);
Err(HttpErrorJson::new(
Status::InternalServerError,
format!("{:?}", err),
))
}
},
Err(err) => Err(err.into()),
}
}

Expand Down Expand Up @@ -137,17 +98,7 @@ pub fn bucket_events_get(
let res = datastore.get_events(&bucket_id, starttime, endtime, limit);
match res {
Ok(events) => Ok(Json(events)),
Err(err) => match err {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
e => {
let err_msg = format!("Failed to fetch events: {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}

Expand All @@ -161,17 +112,7 @@ pub fn bucket_events_create(
let res = datastore.insert_events(&bucket_id, &events);
match res {
Ok(events) => Ok(Json(events)),
Err(e) => match e {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
e => {
let err_msg = format!("Failed to create event(s): {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}

Expand All @@ -190,17 +131,7 @@ pub fn bucket_events_heartbeat(
let datastore = endpoints_get_lock!(state.datastore);
match datastore.heartbeat(&bucket_id, heartbeat, pulsetime) {
Ok(e) => Ok(Json(e)),
Err(err) => match err {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
err => {
let err_msg = format!("Heartbeat failed: {:?}", err);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}

Expand All @@ -213,17 +144,7 @@ pub fn bucket_event_count(
let res = datastore.get_event_count(&bucket_id, None, None);
match res {
Ok(eventcount) => Ok(Json(eventcount as u64)),
Err(e) => match e {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
e => {
let err_msg = format!("Failed to count events: {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}

Expand All @@ -236,17 +157,7 @@ pub fn bucket_events_delete_by_id(
let datastore = endpoints_get_lock!(state.datastore);
match datastore.delete_events_by_id(&bucket_id, vec![event_id]) {
Ok(_) => Ok(()),
Err(err) => match err {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
err => {
let err_msg = format!("Delete events by id failed: {:?}", err);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}

Expand All @@ -261,19 +172,7 @@ pub fn bucket_export(
};
let mut bucket = match datastore.get_bucket(&bucket_id) {
Ok(bucket) => bucket,
Err(err) => match err {
DatastoreError::NoSuchBucket => {
return Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
))
}
e => {
let err_msg = format!("Failed to fetch events: {:?}", e);
warn!("{}", err_msg);
return Err(HttpErrorJson::new(Status::InternalServerError, err_msg));
}
},
Err(err) => return Err(err.into()),
};
bucket.events = Some(
datastore
Expand All @@ -298,16 +197,6 @@ pub fn bucket_delete(bucket_id: String, state: State<ServerState>) -> Result<(),
let datastore = endpoints_get_lock!(state.datastore);
match datastore.delete_bucket(&bucket_id) {
Ok(_) => Ok(()),
Err(e) => match e {
DatastoreError::NoSuchBucket => Err(HttpErrorJson::new(
Status::NotFound,
"The requested bucket does not exist".to_string(),
)),
e => {
let err_msg = format!("Failed to delete bucket: {:?}", e);
warn!("{}", err_msg);
Err(HttpErrorJson::new(Status::InternalServerError, err_msg))
}
},
Err(err) => Err(err.into()),
}
}
15 changes: 8 additions & 7 deletions aw-server/src/endpoints/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ pub fn buckets_export(state: State<ServerState>) -> Result<Response, HttpErrorJs
let mut export = BucketsExport {
buckets: HashMap::new(),
};
let mut buckets = datastore.get_buckets().unwrap();
let mut buckets = match datastore.get_buckets() {
Ok(buckets) => buckets,
Err(err) => return Err(err.into()),
};
for (bid, mut bucket) in buckets.drain() {
bucket.events = Some(
// TODO: Remove expect
datastore
.get_events(&bid, None, None, None)
.expect("Failed to get events for bucket"),
);
bucket.events = Some(match datastore.get_events(&bid, None, None, None) {
Ok(events) => events,
Err(err) => return Err(err.into()),
});
export.buckets.insert(bid, bucket);
}

Expand Down
50 changes: 4 additions & 46 deletions aw-server/src/endpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::path::PathBuf;
use std::sync::Mutex;

use gethostname::gethostname;
use rocket::http::Status;
use rocket::response::NamedFile;
use rocket::State;
use rocket_contrib::json::JsonValue;
Expand All @@ -17,58 +16,17 @@ pub struct ServerState {
pub device_id: String,
}

use rocket::http::ContentType;
use rocket::request::Request;
use rocket::response::{self, Responder, Response};
use std::io::Cursor;

#[derive(Serialize, Debug)]
pub struct HttpErrorJson {
#[serde(skip_serializing)]
status: Status,
message: String,
}

impl HttpErrorJson {
pub fn new(status: Status, err: String) -> HttpErrorJson {
HttpErrorJson {
status: status,
message: format!("{}", err),
}
}
}

impl<'r> Responder<'r> for HttpErrorJson {
fn respond_to(self, _: &Request) -> response::Result<'r> {
Response::build()
.status(self.status)
.sized_body(Cursor::new(format!("{{\"message\":\"{}\"}}", self.message)))
.header(ContentType::new("application", "json"))
.ok()
}
}

#[macro_export]
macro_rules! endpoints_get_lock {
( $lock:expr ) => {
match $lock.lock() {
Ok(r) => r,
Err(e) => {
let err_msg = format!("Taking datastore lock failed, returning 504: {}", e);
warn!("{}", err_msg);
return Err(HttpErrorJson::new(Status::ServiceUnavailable, err_msg));
}
}
};
}

#[macro_use]
mod util;
mod bucket;
mod cors;
mod export;
mod import;
mod query;
mod settings;

pub use util::HttpErrorJson;

#[get("/")]
fn root_index(state: State<ServerState>) -> Option<NamedFile> {
NamedFile::open(state.asset_path.join("index.html")).ok()
Expand Down
13 changes: 1 addition & 12 deletions aw-server/src/endpoints/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,8 @@ pub fn query(
let query_code = query_req.0.query.join("\n");
let intervals = &query_req.0.timeperiods;
let mut results = Vec::new();
let datastore = endpoints_get_lock!(state.datastore);
for interval in intervals {
// Cannot re-use endpoints_get_lock!() here because it returns Err(Status) on failure and this
// function returns HttpResponse
let datastore = match state.datastore.lock() {
Ok(ds) => ds,
Err(e) => {
warn!("Taking datastore lock failed, returning 500: {}", e);
return Err(HttpErrorJson::new(
Status::ServiceUnavailable,
"Taking datastore lock failed, see aw-server logs".to_string(),
));
}
};
let result = match aw_query::query(&query_code, &interval, &datastore) {
Ok(data) => data,
Err(e) => {
Expand Down
Loading

0 comments on commit 7a19f34

Please sign in to comment.