Skip to content

Commit

Permalink
GET roll, GET items
Browse files Browse the repository at this point in the history
  • Loading branch information
deciduously committed Jun 27, 2018
1 parent fa003a7 commit 547656f
Show file tree
Hide file tree
Showing 9 changed files with 732 additions and 428 deletions.
840 changes: 648 additions & 192 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@ path = "src/main.rs"

[dependencies]

actix = "0.5"
actix-web = "0.6"
diesel = { version = "*", features = ["sqlite"] }
dotenv = "*"
dotenv_codegen = "*"
futures = "*"
gotham = "*"
gotham_derive = "*"
hyper = "*"
mime = "*"
lazy_static = "*"
r2d2 = "*"
r2d2-diesel = "*"
Expand Down
2 changes: 1 addition & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Command {
let mut ret = Vec::new();
for id in ids {
let mut item = None;
for i in &items {
for i in &items.items {
if i.title == *id {
item = Some(i);
}
Expand Down
147 changes: 21 additions & 126 deletions src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,135 +1,30 @@
use db::*;
use futures::{future, Future, Stream};
use gotham::{handler::{HandlerFuture, IntoHandlerError},
http::response::create_response,
state::{FromState, State}};
use hyper::{Body, Response, StatusCode};
use item::*;
use mime;
use models::*;
use actix_web::{HttpRequest, Responder};
use db::DB_POOL;
use item::get_items;
use roll::*;
use serde_json;

// this signature is the gotham Handler trait
// This is going to be a microservice though - the frontend will be Clojure
// not sure I need this - think about it.
pub fn index(state: State) -> (State, Response) {
let res = create_response(
&state,
StatusCode::Ok,
Some((String::from("dice roller").into_bytes(), mime::TEXT_PLAIN)),
);

(state, res)
// GET /
pub fn index(_req: HttpRequest) -> &'static str {
"dice roller"
}

header! { (AccessControl, "Access-Control-Allow-Origin") => [String] }

pub mod item {
use super::*;

#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct PathExtractor {
item: String,
}

#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct QueryExtractor {
title: String,
damage: String,
}

pub fn index(state: State) -> (State, Response) {
let mut res = {
//let i = PathExtractor::borrow_from(&state);
let connection = DB_POOL
.get()
.expect("Could not get DB conn from thread pool");
let items = get_items(&connection);
create_response(
&state,
StatusCode::Ok,
Some((
serde_json::to_string(&items)
.expect("serialized items")
.into_bytes(),
mime::APPLICATION_JSON,
)),
)
};

{
let headers = res.headers_mut();
headers.set(AccessControl("*".to_string()))
};
(state, res)
}
//header! { (AccessControl, "Access-Control-Allow-Origin") => [String] } // TODO in actix!
// its middleware, see other Actix project

pub fn new_item(mut state: State) -> Box<HandlerFuture> {
let f = Body::take_from(&mut state)
.concat2()
.then(|full_body| match full_body {
Ok(valid_body) => {
let connection = DB_POOL
.get()
.expect("Could not get DB conn from thread pool");
let body_content = String::from_utf8(valid_body.to_vec()).unwrap();
println!("Body: {}", body_content);
// try to add an item from
let new_item: NewItem =
serde_json::from_str(&body_content).expect("properly formed POST body");
// TODO if item already exists, just update instead
create_item(&connection, new_item.title, new_item.damage); // TODO write a fn to take a NewItem instead
println!("NewItem: {:?}", new_item);
let mut res = create_response(&state, StatusCode::Ok, None);
{
let headers = res.headers_mut();
println!("Doing the access contol set on POST");
headers.set(AccessControl("*".to_string()))
};
future::ok((state, res))
}
Err(e) => return future::err((state, e.into_handler_error())),
});
// GET roll/*
// GET items
// POST item {:name blah :damage blah} (or you know, in json)

Box::new(f)
}
// GET roll/*
pub fn roll(req: HttpRequest) -> impl Responder {
let cmd = &req.match_info()["tail"];
println!("cmd: {}", cmd);
let cmds = ((&cmd).split("/").collect::<Vec<&str>>().iter().map(|s| s.to_string())).collect::<Vec<String>>();
roll_strs(&cmds)
}

pub mod roll {
use super::*;

#[derive(Deserialize, StateData, StaticResponseExtender)]
pub struct PathExtractor {
#[serde(rename = "*")]
cmds: Vec<String>,
}

pub fn index(state: State) -> (State, Response) {
let mut res = {
let cmd = PathExtractor::borrow_from(&state);
let outcomes = roll_strs(&cmd.cmds);

create_response(
&state,
StatusCode::Ok,
Some((
serde_json::to_string(&outcomes)
.expect("serialized outcome")
.into_bytes(),
mime::APPLICATION_JSON,
)),
)
};

{
let headers = res.headers_mut();
headers.set(AccessControl("*".to_string()))
};
(state, res)
}
// GET items
pub fn items(req: HttpRequest) -> impl Responder {
let conn = DB_POOL.get().unwrap();
get_items(&conn)
}

//pub fn roll_handler

// You should do a database instead of YAML files, and have a web form for additions instead of editing a YAML file
22 changes: 20 additions & 2 deletions src/item.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use actix_web::{Responder, HttpRequest, HttpResponse, Error};
use db::DB_POOL;
use diesel::{self, prelude::*};
use models::*;
use roll::*;
use serde_json;
use std::{collections::HashMap, io};

//pub type Items = HashMap<String, Roll>; // TODO remove if unnecessary?
Expand All @@ -19,7 +21,7 @@ pub fn create_item<'a>(conn: &SqliteConnection, title: &'a str, damage: &'a str)
.expect("Error saving new item")
}

pub fn get_items(conn: &SqliteConnection) -> Vec<Item> {
pub fn get_items(conn: &SqliteConnection) -> Items {
use schema::items::dsl::*;
let results = items
.limit(5)
Expand All @@ -32,7 +34,23 @@ pub fn get_items(conn: &SqliteConnection) -> Vec<Item> {
println!("{}\n----------\n{}", item.title, item.damage);
ret.push(item);
}
ret
Items{ items: ret}
}

#[derive(Debug, Serialize)]
pub struct Items {
pub items: Vec<Item>,
}

impl Responder for Items {
type Item = HttpResponse;
type Error = Error;

fn respond_to<S>(self, _req: &HttpRequest<S>) -> Result<HttpResponse, Error> {
let body = serde_json::to_string(&self)?;

Ok(HttpResponse::Ok().content_type("application/json").body(body))
}
}

//pub fn get_item_by_name(conn: &SqliteConnection, name: String) -> io::Result<String> {
Expand Down
81 changes: 11 additions & 70 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
extern crate actix;
extern crate actix_web;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate dotenv_codegen;
extern crate futures;
extern crate gotham;
#[macro_use]
extern crate gotham_derive;
#[macro_use]
extern crate hyper;
extern crate mime;
#[macro_use]
extern crate lazy_static;
extern crate r2d2;
Expand All @@ -29,6 +24,7 @@ pub mod roll;
mod router;
pub mod schema;

use actix_web::server::HttpServer;
use roll::roll_strs;
use router::router;
use std::{env,
Expand Down Expand Up @@ -58,12 +54,16 @@ fn addr(root: &str, port: &str) -> String {
}

fn server() {
let port = dotenv!("PORT");
let root = "127.0.0.1";
// Create Actix system
let sys = actix::System::new("roll");

// grab env
let addr = addr("127.0.0.1", dotenv!("PORT"));

let addr = addr(root, port);
// define and run server
println!("Listening for requests at http://{}", addr);
gotham::start(addr, router())
HttpServer::new(|| router()).bind(addr).unwrap().run();
let _ = sys.run();
}

fn main() {
Expand All @@ -83,62 +83,3 @@ fn main() {
roll_strs(&args[1..]);
}
}

#[cfg(test)]
mod tests {
use super::*;
use gotham::test::TestServer;
use hyper::StatusCode;

#[test]
fn index_get_test() {
let test_server = TestServer::new(router()).unwrap();
let response = test_server
.client()
.get("http://localhost")
.perform()
.unwrap();

assert_eq!(response.status(), StatusCode::Ok);

let body = response.read_body().unwrap();
assert_eq!(&body[..], b"dice roller");
}

#[test]
fn index_head_test() {
let test_server = TestServer::new(router()).unwrap();
let response = test_server
.client()
.head("http://localhost")
.perform()
.unwrap();

assert_eq!(response.status(), StatusCode::Ok);
assert!(response.read_body().unwrap().is_empty());
}

#[test]
fn index_delete_test() {
let test_server = TestServer::new(router()).unwrap();
let response = test_server
.client()
.delete("http://localhost")
.perform()
.unwrap();

assert_eq!(response.status(), StatusCode::MethodNotAllowed);
}

#[test]
fn roll_is_extracted_test() {
let test_server = TestServer::new(router()).unwrap();
let response = test_server
.client()
.get("http://localhost/roll/1d6")
.perform()
.unwrap();

assert_eq!(response.status(), StatusCode::Ok);
}
}
5 changes: 4 additions & 1 deletion src/models.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use actix_web::{HttpRequest, HttpResponse, Error, Responder};
use schema::items;
use serde_json;

use std::fmt;

#[derive(Queryable, Serialize)]
#[derive(Debug, Queryable, Serialize)]
pub struct Item {
pub id: i32,
pub title: String,
Expand All @@ -15,6 +17,7 @@ impl fmt::Display for Item {
}
}


#[derive(Debug, Deserialize, Insertable)]
#[table_name = "items"]
pub struct NewItem<'a> {
Expand Down
29 changes: 12 additions & 17 deletions src/roll.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use actix_web::{Error, HttpRequest, HttpResponse, Responder};
use command::validate_input;
//use gotham::{handler::IntoResponse, http::response::create_response, state::State};
//use hyper::{Response, StatusCode};
//use mime;
use rand::{self, Rng};
//use serde_json;
use serde_json;
use std::{fmt, io, str::FromStr};

#[derive(Debug, PartialEq, Serialize)]
Expand Down Expand Up @@ -68,19 +66,16 @@ pub struct Outcomes {
pub outcomes: Vec<Outcome>,
}

//impl IntoResponse for Outcomes {
// fn into_response(self, state: &State) -> Response {
// create_response(
// state,
// StatusCode::Ok,
// Some((serde_json::to_string(&self)
// .expect("serialized product")
// .into_bytes(),
// mime::APPLICATION_JSON,
// )),
// )
// }
//}
impl Responder for Outcomes {
type Item = HttpResponse;
type Error = Error;

fn respond_to<S>(self, _req: &HttpRequest<S>) -> Result<HttpResponse, Error> {
let body = serde_json::to_string(&self)?;

Ok(HttpResponse::Ok().content_type("application/json").body(body))
}
}

pub fn roll_strs(s: &[String]) -> Outcomes {
validate_input(s).unwrap().run()
Expand Down

0 comments on commit 547656f

Please sign in to comment.