diff options
| -rw-r--r-- | .env.sample | 2 | ||||
| -rw-r--r-- | .gitignore | 10 | ||||
| -rw-r--r-- | .htaccess | 3 | ||||
| -rw-r--r-- | .travis.yml | 19 | ||||
| -rw-r--r-- | Cargo.toml | 18 | ||||
| -rw-r--r-- | Dockerfile | 10 | ||||
| -rw-r--r-- | autoload.php | 19 | ||||
| -rw-r--r-- | diesel.toml | 5 | ||||
| -rw-r--r-- | index.php | 30 | ||||
| -rw-r--r-- | private/Controller/Controller.php | 92 | ||||
| -rw-r--r-- | private/Model/Connection.php | 42 | ||||
| -rw-r--r-- | private/Model/Query.php | 71 | ||||
| -rw-r--r-- | private/Model/Result.php | 52 | ||||
| -rw-r--r-- | private/Model/creds.php | 10 | ||||
| -rw-r--r-- | private/View/Main.php | 104 | ||||
| -rw-r--r-- | private/View/Output.php | 28 | ||||
| -rw-r--r-- | src/bin/august-offensive.rs | 45 | ||||
| -rw-r--r-- | src/util/fresh.sql (renamed from private/Model/fresh.sql) | 0 | ||||
| -rw-r--r-- | test/Controller/ControllerTest.php | 97 | ||||
| -rw-r--r-- | test/Model/QueryTest.php | 42 | ||||
| -rw-r--r-- | test/Model/ResultTest.php | 37 | ||||
| -rw-r--r-- | test/View/OutputTest.php | 33 |
22 files changed, 105 insertions, 664 deletions
diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..f2feaf8 --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +DATABASE_URL=postgres://username:password@localhost/august_offensive +BIND_ADDRESS=127.0.0.1:8080
\ No newline at end of file @@ -1 +1,11 @@ .idea +.env* +!.env.sample +Cargo.lock + +migrations/ +target/ + +*.out +*~ +**/*.rs.bk
\ No newline at end of file diff --git a/.htaccess b/.htaccess deleted file mode 100644 index bf7ece5..0000000 --- a/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ -RewriteEngine On -RewriteRule ^api/(.*)$ index.php/api/$1 -RedirectMatch 403 ^/private/.*$ diff --git a/.travis.yml b/.travis.yml index 5061bce..22447f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,15 @@ -language: php -php: - - '7.0' -script: phpunit --bootstrap autoload.php test +language: rust +rust: + - stable + - beta + - nightly +cache: cargo + +matrix: + allow_failures: + - rust: nightly + fast_finish: true + +script: + - cargo build --verbose --all + - cargo test --verbose --all
\ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..26a322f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "august-offensive" +version = "0.1.0" +authors = ["Kevin J Hoerr <kjhoerr@submelon.tech>"] +description = "Turn-based strategy game as a web service" +license = "ISC" +readme = "README.md" +repository = "https://gitlab.com/kjhoerr/august-offensive.git" + +[dependencies] +dotenv = "0.10" +env_logger = "0.5" +error-chain = "^0.12" + +diesel = { version = "1.3.0", features = ["postgres"] } + +actix = "0.7" +actix-web = "^0.7"
\ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..eb6d8ce --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM rust:latest + +WORKDIR /usr/src/august + +COPY . . + +RUN cargo install +EXPOSE 8080 + +CMD ["august-offensive"]
\ No newline at end of file diff --git a/autoload.php b/autoload.php deleted file mode 100644 index b9d471b..0000000 --- a/autoload.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -declare(strict_types=1); - -// Borrowed and modified from PSR-4 Closure Example -spl_autoload_register( - function ($class) { - $prefix = 'AugustOffensive\\'; - $relative_class = substr($class, strlen($prefix)); - - // find file in /private/ in respective namespace path - $file = __DIR__ . '/private/' . str_replace('\\', '/', $relative_class) . '.php'; - - // if the file exists, require it - if (file_exists($file)) { - require $file; - } - } -); diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..92267c8 --- /dev/null +++ b/diesel.toml @@ -0,0 +1,5 @@ +# For documentation on how to configure this file, +# see diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" diff --git a/index.php b/index.php deleted file mode 100644 index c38567d..0000000 --- a/index.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive; - -require_once "autoload.php"; - -use AugustOffensive\View; -use AugustOffensive\Controller; - -// configure content type before anything is output -header("Content-Type: application/" . View\Main::TYPE); - -try { - // initiate connection and build front-end - $connection = Controller\Controller::initiateConnection(); - $view = new View\Main($connection); - - // get results of query from front-end - $result = $view->generateResult(); - - echo $result; -} catch (\Exception $err) { - // catch all exceptions and let the controller generate the error - $error = Controller\Controller::errorResult($err); - - // pass generated error result to output - echo View\Main::generateOutput($error); -} diff --git a/private/Controller/Controller.php b/private/Controller/Controller.php deleted file mode 100644 index 586be15..0000000 --- a/private/Controller/Controller.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Controller; - -use AugustOffensive\Model; - -/** - * Static controller class for interfacing between the view and the model. - */ -class Controller -{ - /** - * Initiates connection with the database. - * - * While errors are ideally handled by the controller, this instantiation - * will likely throw a \PDOException which should be handled by the front- - * end due to this being a fatal error and generally unrecoverable. - * - * @return Model\Connection - */ - public static function initiateConnection (): Model\Connection - { - return new Model\Connection(); - } - - /** - * Creates and returns a Query object. - * - * If the creation results in an error, a different query object is - * returned with the error message. - * - * @param array $path The array that holds the original request structure. - * @param string $request The request method made to the server. - * @param array $content The content object sent by the request. - * - * @return Model\Query - */ - public static function createQuery ( - array $path, - string $request, - array $content - ): Model\Query { - try { - return new Model\Query($path, $request, $content); - } catch (\Exception $err) { - return new Model\Query(array(), "", array("ERROR" => $err->getMessage())); - } - } - - /** - * Creates and returns a Result object. - * - * @param string $resultType The type of result to send back to the client. - * @param array $result The result object to send back to the client. - * - * @return Model\Result - */ - public static function createResult ( - string $resultType, - array $result - ): Model\Result { - try { - return new Model\Result($resultType, $result); - } catch (\Exception $err) { - return new Model\Result("ERROR", array($err->getMessage())); - } - } - - /** - * Obtain the error result based on the exception that was thrown. - * - * @param \Exception $err the error that was thrown. - * - * @return Model\Result - */ - public static function errorResult (\Exception $err): Model\Result - { - $errorType = ""; - // Juggle error: objective is to sort error type - try { - throw $err; - } catch (\PDOException $e) { - $errorType = "DATABASE_ERROR"; - } catch (\Exception $e) { - $errorType = "ERROR"; - } - - return new Model\Result($errorType, array("error" => $err->getMessage())); - } -} diff --git a/private/Model/Connection.php b/private/Model/Connection.php deleted file mode 100644 index 4afa330..0000000 --- a/private/Model/Connection.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Model; - -/** - * Model connection class for connecting to database via PDO. - */ -class Connection -{ - /** @var \PDO $_conn PDO connection to database. */ - private $conn; - /** - * Initiates connection to PostGreSQL database. - * - * @return Connection - */ - public function __construct () - { - // Establish connection to db - // breaks side-effect rule - include 'creds.php'; - - try { - $conn = new \PDO( - "pgsql: host=" . $cred->host . - (($cred->port !== '') ? ";port=" . $cred->port : '') . - ";dbname=" . $cred->dbName, - $cred->login, - $cred->password - ); - // we destroy $cred as quickly as possible - $cred = null; - } catch (\PDOException $err) { - // we destroy $cred as quickly as possible - $cred = null; - throw $err; // throw for Controller to catch - } - return $this; - } -} diff --git a/private/Model/Query.php b/private/Model/Query.php deleted file mode 100644 index 7eca836..0000000 --- a/private/Model/Query.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Model; - -/** - * Query object for storing relevant query information. - */ -class Query -{ - /** @var array $path array of request structure. */ - private $path; - - /** @var string $request type of request made to the server. */ - private $request; - - /** @var array $content structure of information sent to the server. */ - private $content; - - /** - * Store query information. - * - * @param array $path The array that holds the original request structure. - * @param string $request The request method made to the server. - * @param array $content The content object sent by the request. - * - * @return Query - */ - public function __construct ( - array $path, - string $request, - array $content - ) { - $this->path = $path; - $this->request = $request; - $this->content = $content; - - return $this; - } - - /** - * Returns the request path made by the client. - * - * @return array - */ - public function getPath (): array - { - return $this->path; - } - - /** - * Returns the request type made by the client. - * - * @return string - */ - public function getRequest (): string - { - return $this->request; - } - - /** - * Returns the information that is built from outside the request path. - * - * @return array - */ - public function getContent (): array - { - return $this->content; - } -} diff --git a/private/Model/Result.php b/private/Model/Result.php deleted file mode 100644 index ac08821..0000000 --- a/private/Model/Result.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Model; -/** - * Result object for storing information to send back to the client. - */ -class Result -{ - /** @var string $resultType the type of result to return to the client. */ - private $resultType; - - /** @var array $result */ - private $result; - - /** - * Store result information. - * - * @param string $resultType The type of result to send back to the client. - * @param array $result The result object to send back to the client. - * - * @return Result - */ - public function __construct (string $resultType, array $result) - { - $this->resultType = $resultType; - $this->result = $result; - - return $this; - } - - /** - * Returns the result type of the Result. - * - * @return string - */ - public function getResultType (): string - { - return $this->resultType; - } - - /** - * Returns the result array of the Result. - * - * @return array - */ - public function getResult (): array - { - return $this->result; - } -}
\ No newline at end of file diff --git a/private/Model/creds.php b/private/Model/creds.php deleted file mode 100644 index 056d77b..0000000 --- a/private/Model/creds.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -declare(strict_types=1); - -$cred = new \stdClass(); -$cred->host = "localhost"; -$cred->port = "5432"; -$cred->dbName = ""; -$cred->login = ""; -$cred->password = ""; diff --git a/private/View/Main.php b/private/View/Main.php deleted file mode 100644 index c51e91f..0000000 --- a/private/View/Main.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\View; - -use AugustOffensive\Controller; -use AugustOffensive\Model; - -/** - * Outputs the JSON result by communicating with the controller. - */ -class Main -{ - /** @var Model\Query $query the Query object that generated the request. */ - private $query; - - /** @var Model\Result $result the Result object to be sent to the client. */ - private $result; - - /** @var string TYPE The type of output the client should receive. */ - const TYPE = "json"; - - /** - * Prepares the output and environment for the front end of the service. - * - * @param Model\Connection $connection View "Needs to know" model exists. - * - * @return Result - */ - public function __construct (Model\Connection $connection) - { - $this->query = Controller\Controller::createQuery( - explode('/', trim($_SERVER['PATH_INFO'] ?? '/api', '/')), - $_SERVER['REQUEST_METHOD'], - $this->generateContent($_SERVER['REQUEST_METHOD']) - ); - - return $this; - } - - /** - * Generates the content of the query based on the request type. - * - * @param string $request The request method on which to base the content. - * - * @return array - */ - public function generateContent (string $request): array - { - $content; - switch ($request) { - case "GET": // GET should always be empty - case "POST": // POST contains moves, account info, etc. - default: - $content = $_REQUEST; - } - return $content; - } - - /** - * Communicates with the controller to generate the output. - * - * @return string - */ - public function generateResult (): string - { - $path = $this->query->getPath(); - if (count($path) >= 1 && $path[0] === "api" && count($path) >= 2) { - switch (strtolower($path[1])) { - case "callback": - $this->result = Controller\Controller::createResult( - "CALLBACK", - array( - "path" => $path, - "request" => $this->query->getRequest(), - "content" => $this->query->getContent() - ) - ); - break; - default: - $this->result = Controller\Controller::createResult("NOT_UNDERSTOOD", array($path)); - break; - } - } else { - $this->result = Controller\Controller::createResult("NOT_UNDERSTOOD", array($path)); - } - - return self::generateOutput($this->result); - } - - /** - * Creates output of the result based on the defined constant TYPE. - * - * @param Model\Result $result The result to be sent to the client. - * - * @return string - */ - public static function generateOutput (Model\Result $result): string - { - $type = self::TYPE; - return Output::$type($result); - } -} diff --git a/private/View/Output.php b/private/View/Output.php deleted file mode 100644 index af9975e..0000000 --- a/private/View/Output.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\View; - -use AugustOffensive\Model; - -/** - * Output formats for Results that are returned to the client. - */ -class Output -{ - /** - * Formats the result into JSON. - * - * @param Model\Result $result The result to return to the client. - * - * @return string - */ - public static function json (Model\Result $result): string - { - return json_encode(array( - "Result-Type" => $result->getResultType(), - "Content" => $result->getResult() - )); - } -} diff --git a/src/bin/august-offensive.rs b/src/bin/august-offensive.rs new file mode 100644 index 0000000..77ca2f6 --- /dev/null +++ b/src/bin/august-offensive.rs @@ -0,0 +1,45 @@ +extern crate actix; +extern crate actix_web; +extern crate env_logger; +extern crate dotenv; +extern crate diesel; + +use actix_web::{middleware, server, App, HttpRequest}; +use diesel::prelude::*; +use diesel::pg::PgConnection; +use dotenv::dotenv; +use std::env; + +fn index(_req: &HttpRequest) -> &'static str { + "Hello, world!" +} + +// TODO describe change of direction in README +// TODO implement error-chain +// TODO match 0.1.0 functionality +fn main() { + dotenv().ok(); + let db_url = env::var("DATABASE_URL") + .expect("DATABASE_URL must be set"); + let bind_address = env::var("BIND_ADDRESS") + .expect("BIND_ADDRESS must be set"); + + env::set_var("RUST_LOG", "actix_web=info"); + env_logger::init(); + let sys = actix::System::new("hello-world"); + + PgConnection::establish(&db_url) + .expect(&format!("Error connecting to {}", db_url)); + + server::new(|| { + App::new() + .middleware(middleware::Logger::default()) + .resource("/index.html", |r| r.f(index)) + .resource("/", |r| r.f(index)) + }).bind(&bind_address) + .unwrap() + .start(); + + println!("Started http server: {}", bind_address); + let _ = sys.run(); +} diff --git a/private/Model/fresh.sql b/src/util/fresh.sql index f39b360..f39b360 100644 --- a/private/Model/fresh.sql +++ b/src/util/fresh.sql diff --git a/test/Controller/ControllerTest.php b/test/Controller/ControllerTest.php deleted file mode 100644 index 6931bc1..0000000 --- a/test/Controller/ControllerTest.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Controller; - -use PHPUnit\Framework\TestCase; -use AugustOffensive\Model; - -/** - * Integration test: requires DB connection. Expect side effects (use test db if possible). - * - * @covers Controller - */ -final class ControllerTest extends \PHPUnit\Framework\TestCase -{ - public function testDBConnection() - { - /* Disable integration test, for now - try { - $this->assertInstanceOf( - Model\Connection::class, - Controller::initiateConnection() - ); - } catch (\PDOException $err) { - $this->fail("Database not initialized correctly: " . $err->getMessage()); - }*/ - } - - public function testCreateQuery() - { - $path = array("api", "create", "query"); - $request = "DELETE"; - $content = array("c" => "cherry", "d" => "dike"); - $query = Controller::createQuery($path, $request, $content); - - $this->assertInstanceOf( - Model\Query::class, - $query - ); - - $this->assertEquals( - $path, - $query->getPath() - ); - $this->assertEquals( - $request, - $query->getRequest() - ); - $this->assertEquals( - $content, - $query->getContent() - ); - } - - public function testCreateResult() - { - - $resultType = "TYPE"; - $result = array("no", "values"); - $resultObject = Controller::createResult($resultType, $result); - - $this->assertInstanceOf( - Model\Result::class, - $resultObject - ); - - $this->assertEquals( - $resultType, - $resultObject->getResultType() - ); - $this->assertEquals( - $result, - $resultObject->getResult() - ); - } - - public function testErrorResult() - { - $message = "Oh no! Oops!"; - $errorResult = Controller::errorResult(new \Exception($message)); - - $this->assertInstanceOf( - Model\Result::class, - $errorResult - ); - - $this->assertEquals( - "ERROR", - $errorResult->getResultType() - ); - $this->assertEquals( - array("error" => $message), - $errorResult->getResult() - ); - } -} diff --git a/test/Model/QueryTest.php b/test/Model/QueryTest.php deleted file mode 100644 index ef6cda7..0000000 --- a/test/Model/QueryTest.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Model; - -use PHPUnit\Framework\TestCase; - -/** - * @covers Query - */ -final class QueryTest extends \PHPUnit\Framework\TestCase -{ - public function testCanBeCreated() - { - $this->assertInstanceOf( - Query::class, - new Query(array("api", "path"), "GET", array()) - ); - } - - public function testHasAccessibleValues() - { - $path = array("api", "query", "path"); - $request = "PUT"; - $content = array("a" => "apple", "b" => "bearing"); - $query = new Query($path, $request, $content); - - $this->assertEquals( - $path, - $query->getPath() - ); - $this->assertEquals( - $request, - $query->getRequest() - ); - $this->assertEquals( - $content, - $query->getContent() - ); - } -} diff --git a/test/Model/ResultTest.php b/test/Model/ResultTest.php deleted file mode 100644 index 0380182..0000000 --- a/test/Model/ResultTest.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\Model; - -use PHPUnit\Framework\TestCase; - -/** - * @covers Result - */ -final class ResultTest extends \PHPUnit\Framework\TestCase -{ - public function testCanBeCreated() - { - $this->assertInstanceOf( - Result::class, - new Result("TEST_SUCCESS", array("it worked")) - ); - } - - public function testHasAccessibleValues() - { - $resultType = "VISIBLE"; - $result = array("array", "of", "values"); - $resultObject = new Result($resultType, $result); - - $this->assertEquals( - $resultType, - $resultObject->getResultType() - ); - $this->assertEquals( - $result, - $resultObject->getResult() - ); - } -} diff --git a/test/View/OutputTest.php b/test/View/OutputTest.php deleted file mode 100644 index f687ee8..0000000 --- a/test/View/OutputTest.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace AugustOffensive\View; - -use PHPUnit\Framework\TestCase; -use AugustOffensive\Model; - -/** - * @covers Output - */ -final class OutputTest extends \PHPUnit\Framework\TestCase -{ - public function testJSONOutput() - { - $resultType = "JSON_ENCODED"; - $result = array("json", "1.6"); - $resultObject = new Model\Result($resultType, $result); - - // If JSON is properly formatted, we can decode and test the values - $output = json_decode(Output::json($resultObject), true); - - $this->assertEquals( - $resultType, - $output["Result-Type"] - ); - $this->assertEquals( - $result, - $output["Content"] - ); - } -}
\ No newline at end of file |
