summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-01-02 20:42:01 +0100
committerDaniel Weipert <git@mail.dweipert.de>2024-01-05 12:33:59 +0100
commitb21316248572cb27ed1f504529ad6680a473022e (patch)
treef8a2f81258cae3b1d2429fb7df5a3287954b683a /src
parentf621d95f89ded05a2e916c5ee363bfe75ea37482 (diff)
gemini
Diffstat (limited to 'src')
-rw-r--r--src/App.php32
-rw-r--r--src/DB.php3
-rw-r--r--src/EventRunner.php2
-rw-r--r--src/View.php12
-rw-r--r--src/gemini/Controller/Building.php44
-rw-r--r--src/gemini/Controller/Unit.php60
-rw-r--r--src/gemini/Controller/User.php118
-rw-r--r--src/gemini/Controller/Village.php167
-rw-r--r--src/gemini/Gemini.php120
-rw-r--r--src/http/Controller/Building.php (renamed from src/Controller/Building.php)4
-rw-r--r--src/http/Controller/Event.php (renamed from src/Controller/Event.php)4
-rw-r--r--src/http/Controller/Login.php (renamed from src/Controller/Login.php)6
-rw-r--r--src/http/Controller/Map.php (renamed from src/Controller/Map.php)2
-rw-r--r--src/http/Controller/Unit.php (renamed from src/Controller/Unit.php)4
-rw-r--r--src/http/Controller/Village.php (renamed from src/Controller/Village.php)4
-rw-r--r--src/http/Http.php37
-rw-r--r--src/http/Router.php (renamed from src/Router.php)4
-rw-r--r--src/http/Support/RouteLoader.php (renamed from src/Support/RouteLoader.php)2
18 files changed, 589 insertions, 36 deletions
diff --git a/src/App.php b/src/App.php
index 7524d38..9516a06 100644
--- a/src/App.php
+++ b/src/App.php
@@ -2,34 +2,32 @@
namespace App;
-use Symfony\Component\HttpFoundation\Request;
+use App\gemini\Gemini;
+use App\http\Http;
class App
{
+ private $appRunner;
+
public function __construct() {
if ($_ENV['APP_ENV'] === 'development') {
error_reporting(E_ALL);
}
- // Session
- session_start();
-
- // DB
- DB::init();
-
- // Router
- Router::init(Request::createFromGlobals());
-
- // View
- View::init();
-
- // Events
- new EventRunner();
+ if (isset($_ENV['GEMINI'])) {
+ $this->appRunner = new Gemini([
+ 'file' => dirname(__DIR__) . '/cert.pem',
+ 'key' => dirname(__DIR__) . '/key.rsa',
+ 'passphrase' => '',
+ ], $_ENV['APP_HOST']);
+ }
+ else {
+ $this->appRunner = new Http();
+ }
}
public function run(): void
{
- $response = Router::execute();
- $response->send();
+ $this->appRunner->run();
}
}
diff --git a/src/DB.php b/src/DB.php
index 82a81c4..f91e934 100644
--- a/src/DB.php
+++ b/src/DB.php
@@ -9,11 +9,12 @@ class DB {
{
$driver = $_ENV['DB_DRIVER'] ?? 'pgsql';
$host = $_ENV['DB_HOST'] ?? 'db';
+ $port = $_ENV['DB_PORT'] ?? 5432;
$dbname = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$password = $_ENV['DB_PASSWORD'];
- self::$connection = new \PDO("pgsql:host=$host;dbname=$dbname", $user, $password);
+ self::$connection = new \PDO("pgsql:host=$host;port=$port;dbname=$dbname", $user, $password);
}
/**
diff --git a/src/EventRunner.php b/src/EventRunner.php
index 7dd773d..2f2fd8b 100644
--- a/src/EventRunner.php
+++ b/src/EventRunner.php
@@ -82,7 +82,7 @@ class EventRunner
}
$diff = (new \DateTime())->diff($lastTick);
- $tickMultiplier = $diff->i;
+ $tickMultiplier = $diff->i + 60*$diff->h + 60*24*$diff->d;
if ($tickMultiplier > 0) {
$villages = DB::fetch(Village::class, 'select id,wood,clay,iron,food from villages');
diff --git a/src/View.php b/src/View.php
index 7862b12..1c29a67 100644
--- a/src/View.php
+++ b/src/View.php
@@ -9,11 +9,14 @@ use Twig\TwigFilter;
class View
{
- private static Environment $twig;
+ public static Environment $twig;
public static function init(): void
{
- $loader = new FilesystemLoader(dirname(__DIR__) . '/views');
+ $loader = new FilesystemLoader(
+ dirname(__DIR__) . '/views/' .
+ (isset($_ENV['GEMINI']) ? 'gemini' : 'http')
+ );
self::$twig = new Environment($loader, [
'debug' => $_ENV['APP_ENV'] === 'development',
]);
@@ -24,8 +27,11 @@ class View
self::$twig->addFilter(new TwigFilter('buildTime', function ($buildTime) {
return @sprintf('%02d:%02d:%02d', $buildTime / 3600, ($buildTime / 60) % 60, $buildTime % 60);
}));
+ }
- self::$twig->addGlobal('session', $_SESSION);
+ public static function addGlobal(string $name, mixed $value): void
+ {
+ self::$twig->addGlobal($name, $value);
}
/**
diff --git a/src/gemini/Controller/Building.php b/src/gemini/Controller/Building.php
new file mode 100644
index 0000000..9827d00
--- /dev/null
+++ b/src/gemini/Controller/Building.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace App\gemini\Controller;
+
+use App\Model\Building as Model;
+use App\Model\Event;
+use App\Model\Event\UpgradeBuilding;
+use App\Model\Village;
+use GeminiFoundation\Request;
+use GeminiFoundation\Response;
+use GeminiFoundation\Status;
+
+class Building
+{
+ //#[Route(path: '/village/{x}/{y}/building/{type}/level-up', methods: ['POST'])]
+ public function levelUp(Request $request): Response
+ {
+ $village = Village::getByCoordinates($request->get('x'), $request->get('y'));
+ $building = Model::getByVillage($village->id, $request->get('type')) ?? Model::getEmpty($village->id, $request->get('type'));
+
+ // resources
+ foreach ($building->getResourceRequirements() as $resourceType => $resourceValue) {
+ $village->{$resourceType} -= $resourceValue;
+ }
+ $village->updateResources();
+
+ // event
+ $event = new Event();
+ $event->time = (new \DateTime())->add(\DateInterval::createFromDateString(
+ $building->getBuildTimeForLevel($building->getEffectiveLevel() + 1) . ' seconds'
+ ));
+ $event->villageId = $building->villageId;
+ $upgradeBuildingEvent = new UpgradeBuilding();
+ $upgradeBuildingEvent->event = $event;
+ $upgradeBuildingEvent->type = $building->type;
+ $upgradeBuildingEvent->dbInsert();
+
+
+ return new Response(
+ statusCode: Status::REDIRECT_TEMPORARY, # correct response code?
+ meta: "/village/{$village->x}/{$village->y}"
+ );
+ }
+}
diff --git a/src/gemini/Controller/Unit.php b/src/gemini/Controller/Unit.php
new file mode 100644
index 0000000..c04079a
--- /dev/null
+++ b/src/gemini/Controller/Unit.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace App\gemini\Controller;
+
+use App\Model\Event;
+use App\Model\Event\TrainUnits;
+use App\Model\Unit as Model;
+use App\Model\Village;
+use GeminiFoundation\Request;
+use GeminiFoundation\Response;
+use GeminiFoundation\Status;
+
+class Unit
+{
+ // #[Route(path: '/village/{x}/{y}/unit/{type}/create', methods: ['POST'])]
+ public function train(Request $request): Response
+ {
+ if (empty($request->get('input'))) {
+ return new Response(statusCode: Status::INPUT, meta: 'Amount');
+ }
+
+ $village = Village::getByCoordinates($request->get('x'), $request->get('y'));
+
+ /**@var Model $unit*/
+ $unit = new (Model::resolveType($request->get('type')))();
+ $unit->type = $request->get('type');
+ $unit->homeVillageId = $village->id;
+
+ $amount = intval($request->get('input'));
+
+ if (! Village::canTrain($village, $unit, $amount)) {
+ return new Response(
+ statusCode: Status::REDIRECT_TEMPORARY,
+ meta: "/village/{$village->x}/{$village->y}"
+ );
+ }
+
+ // resources
+ foreach (Model::getResourceRequirements($unit, $amount) as $resourceType => $resourceValue) {
+ $village->{$resourceType} -= $resourceValue;
+ }
+ $village->updateResources();
+
+ // event
+ $event = new Event();
+ $event->time = (new \DateTime())->add(\DateInterval::createFromDateString($unit->getBuildTime($amount) . ' seconds'));
+ $event->villageId = $village->id;
+ $trainUnitsEvent = new TrainUnits();
+ $trainUnitsEvent->event = $event;
+ $trainUnitsEvent->type = $request->get('type');
+ $trainUnitsEvent->amount = $amount;
+ $trainUnitsEvent->dbInsert();
+
+
+ return new Response(
+ statusCode: Status::REDIRECT_TEMPORARY,
+ meta: "/village/{$village->x}/{$village->y}"
+ );
+ }
+}
diff --git a/src/gemini/Controller/User.php b/src/gemini/Controller/User.php
new file mode 100644
index 0000000..a870b88
--- /dev/null
+++ b/src/gemini/Controller/User.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace App\gemini\Controller;
+
+use App\DB;
+use GeminiFoundation\Request;
+
+class User
+{
+ public function get(Request $request): array|bool
+ {
+ if ($request->getClientCertificate() === null) {
+ return false;
+ }
+
+ return DB::query(
+ <<<SQL
+ select users.id, username, email from users
+ join users_gemini on users.id = users_gemini.user_id
+ where users_gemini.certificate=:fingerprint
+ SQL,
+ ['fingerprint' => $request->getClientCertificate()->getFingerprint()]
+ )->fetch();
+ }
+
+ public function create(Request $request): array|bool
+ {
+ DB::query(
+ 'insert into users (username, password, email) values (:username, :fingerprint, :email)',
+ [
+ 'username' => md5($request->getClientCertificate()->getFingerprint()),
+ 'fingerprint' => $request->getClientCertificate()->getFingerprint(),
+ 'email' => '(no email)',
+ ]
+ );
+ $userId = DB::query('select id from users where password=:password', ['password' => $request->getClientCertificate()->getFingerprint()])->fetchColumn();
+
+ DB::query(
+ 'insert into users_gemini (certificate, user_id) values (:fingerprint, :userId)',
+ ['fingerprint' => $request->getClientCertificate()->getFingerprint(), 'userId' => $userId]
+ );
+
+ // also insert new village at random free coordinates
+ DB::query(
+ 'insert into villages (name, x, y, wood, clay, iron, food, satisfaction) values (:name, :x, :y, :wood, :clay, :iron, :food, :satisfaction)',
+ [
+ 'name' => substr(md5(rand()), 0, 6),
+ 'x' => rand(0, 100),
+ 'y' => rand(0, 100),
+ 'wood' => 500,
+ 'clay' => 500,
+ 'iron' => 500,
+ 'food' => 500,
+ 'satisfaction' => 100,
+ ]
+ );
+ $villageId = DB::query('select id from villages order by id desc limit 1')->fetchColumn();
+
+ DB::query(
+ 'insert into user_villages (user_id, village_id) values (:userId, :villageId)',
+ ['userId' => $userId, 'villageId' => $villageId]
+ );
+
+ // insert base buildings
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'TownHall', 'villageId' => $villageId]
+ );
+
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'Storage', 'villageId' => $villageId]
+ );
+ DB::query(
+ 'insert into village_storage_config (wood, clay, iron, food, village_id) values (:wood, :clay, :iron, :food, :villageId)',
+ ['wood' => 25, 'clay' => 25, 'iron' => 25, 'food' => 25, 'villageId' => $villageId]
+ );
+
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'WoodCutter', 'villageId' => $villageId]
+ );
+ DB::query(
+ 'insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :villageId, :villageId)',
+ ['amount' => 1, 'type' => 'WoodCutter', 'villageId' => $villageId]
+ );
+
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'ClayPit', 'villageId' => $villageId]
+ );
+ DB::query(
+ 'insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :villageId, :villageId)',
+ ['amount' => 1, 'type' => 'PitWorker', 'villageId' => $villageId]
+ );
+
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'IronMine', 'villageId' => $villageId]
+ );
+ DB::query(
+ 'insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :villageId, :villageId)',
+ ['amount' => 1, 'type' => 'Miner', 'villageId' => $villageId]
+ );
+
+ DB::query(
+ 'insert into village_buildings (level, type, village_id) values (:level, :type, :villageId)',
+ ['level' => 1, 'type' => 'Farm', 'villageId' => $villageId]
+ );
+ DB::query(
+ 'insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :villageId, :villageId)',
+ ['amount' => 1, 'type' => 'Farmer', 'villageId' => $villageId]
+ );
+
+
+ return $this->get($request);
+ }
+}
diff --git a/src/gemini/Controller/Village.php b/src/gemini/Controller/Village.php
new file mode 100644
index 0000000..9b27561
--- /dev/null
+++ b/src/gemini/Controller/Village.php
@@ -0,0 +1,167 @@
+<?php
+
+namespace App\gemini\Controller;
+
+use App\DB;
+use App\Guard;
+use App\Model\Event\SendUnits;
+use App\Model\Event\TrainUnits;
+use App\Model\Event\UpgradeBuilding;
+use App\Model\Village as Model;
+use App\View;
+use GeminiFoundation\Request;
+use GeminiFoundation\Response;
+use GeminiFoundation\Status;
+
+class Village
+{
+ // #[Route(path: '/villages', methods: ['GET'])]
+ public function list(): Response
+ {
+ $villages = DB::fetch(
+ Model::class,
+ <<<SQL
+ select * from villages
+ join user_villages on villages.id = user_villages.village_id
+ where user_villages.user_id=:id
+ SQL,
+ ['id' => $_SESSION['user']['id']]
+ );
+
+
+ return new Response(body: View::render('villages.twig', [
+ 'villages' => $villages,
+ ]));
+ }
+
+ //#[Route(path: '/village/{x}/{y}', methods: ['GET'])]
+ public function show(Request $request): Response
+ {
+ $village = Model::getByCoordinates($request->get('x'), $request->get('y'));
+
+ if (! Guard::ownsVillage($village->id)) {
+ return new Response(body: View::render('error.twig', ['message' => 'Insufficient permission']));
+ }
+
+ $events = [];
+
+ $eventsBuilding = DB::query(
+ <<<SQL
+ select * from events_upgrade_building as event
+ left join events on event.event_id = events.id
+ where events.village_id=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ foreach ($eventsBuilding as $row) {
+ $events['UpgradeBuilding'][$row['type']][] = DB::convertToModel(UpgradeBuilding::class, $row);
+ }
+
+ $eventsUnits = DB::query(
+ <<<SQL
+ select * from events_train_units as event
+ left join events on event.event_id = events.id
+ where village_id=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ foreach ($eventsUnits as $row) {
+ $events['TrainUnits'][] = DB::convertToModel(TrainUnits::class, $row);
+ }
+
+ $eventsUnitsSendOwn = DB::query(
+ <<<SQL
+ select * from events_send_units as event
+ left join events on event.event_id = events.id
+ where village_id=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ $eventsUnitsSendOther = DB::query(
+ <<<SQL
+ select * from events_send_units as event
+ left join events on event.event_id = events.id
+ where (destination=:id or source=:id) and village_id!=:id and is_canceled=false
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ foreach ([...$eventsUnitsSendOwn, ...$eventsUnitsSendOther] as $row) {
+ $events['SendUnits'][] = DB::convertToModel(SendUnits::class, $row);;
+ }
+
+ $buildings = [];
+ foreach (Model::getBuildings($village->id, true) as $building) {
+ $buildings[$building->type] = $building;
+ }
+
+
+ return new Response(body: View::render('village.twig', [
+ 'village' => $village,
+ 'events' => $events,
+ 'buildings' => $buildings,
+ 'villages' => DB::fetch(Model::class, "select * from villages where id!=:id", ['id' => $village->id]),
+ ]));
+ }
+
+ // #[Route(path: '/village/{x}/{y}/storage/config', methods: ['POST'])]
+ public function storageConfig(Request $request): Response
+ {
+ $village = Model::getByCoordinates($request->get('x'), $request->get('y'));
+ $type = $request->get('type');
+
+ if (empty($type)) {
+ return new Response(body: View::render('storage.twig', [
+ 'village' => $village,
+ ]));
+ }
+
+ if (empty($request->get('input'))) {
+ return new Response(statusCode: Status::INPUT, meta: "$type percent?");
+ }
+
+ $input = intval($request->get('input'));
+
+ // calculate to max 100%
+ $allTypes = ['wood', 'clay', 'iron', 'food'];
+ $allOtherTypes = array_diff($allTypes, [$type]);
+
+ $storageConfig = $village->getStorageConfig($village->id);
+
+ $values = [];
+ foreach ($allTypes as $resourceType) {
+ $values[$resourceType] = $storageConfig->$resourceType;
+ }
+ $values[$type] = $input;
+
+ $total = 0;
+ foreach ($values as $value) {
+ $total += $value;
+ }
+
+ foreach ($values as $resourceType => $value) {
+ $values[$resourceType] = round(($value / $total) * 100);
+ }
+
+ if ($values[$type] !== $input) {
+ $values[$type] = $input;
+ }
+
+ $newTotal = array_sum($values);
+ $values['food'] += (100 - $newTotal);
+
+ DB::query(
+ <<<SQL
+ update village_storage_config
+ set wood=:wood, clay=:clay, iron=:iron, food=:food
+ where village_id=:id
+ SQL,
+ ['wood' => $values['wood'], 'clay' => $values['clay'], 'iron' => $values['iron'], 'food' => $values['food'], 'id' => $village->id]
+ );
+
+
+ return new Response(
+ statusCode: Status::REDIRECT_TEMPORARY,
+ meta: "/village/{$village->x}/{$village->y}/storage/config"
+ );
+ }
+}
diff --git a/src/gemini/Gemini.php b/src/gemini/Gemini.php
new file mode 100644
index 0000000..41b8716
--- /dev/null
+++ b/src/gemini/Gemini.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace App\gemini;
+
+use App\DB;
+use App\EventRunner;
+use App\View;
+use App\gemini\Controller\Building;
+use App\gemini\Controller\Unit;
+use App\gemini\Controller\User;
+use App\gemini\Controller\Village;
+use GeminiFoundation\Request;
+use GeminiFoundation\Response;
+use GeminiFoundation\Server;
+use GeminiFoundation\Status;
+
+class Gemini
+{
+ private array $certificate;
+ private string $hostname;
+
+ public function __construct(array $certificate, string $hostname)
+ {
+ $this->certificate = $certificate;
+ $this->hostname = $hostname;
+
+ global $_SESSION;
+ $_SESSION = [];
+
+ DB::init();
+
+ View::init();
+ View::addGlobal('session', $_SESSION);
+ }
+
+ public function run(): void
+ {
+ $server = new Server($this->certificate, $this->hostname, [
+ 'client_certificate_support_workaround' => true,
+ ]);
+
+ $server->onRequest(function (Response $response, Request $request) {
+ new EventRunner();
+
+ // auth
+ if ($request->getClientCertificate() === null) {
+ return new Response(
+ statusCode: Status::CLIENT_CERTIFICATE_REQUIRED,
+ meta: 'Attach a client certificate to log in'
+ );
+ }
+
+ $userController = new User();
+ $user = $userController->get($request);
+ if (empty($user)) {
+ $user = $userController->create($request);
+ }
+
+ global $_SESSION;
+ $_SESSION['user'] = [
+ 'id' => $user['id'],
+ 'username' => $user['username'],
+ ];
+ View::addGlobal('session', $_SESSION);
+
+
+ // routes
+ if ($request->getPath() == '/villages') {
+ $villageController = new Village();
+ $response = $villageController->list($request);
+ }
+
+ else if (preg_match('@village/(\d+)/(\d+)/storage/config/?(\w+)?@', $request->getPath(), $routeMatch)) {
+ $request
+ ->set('x', $routeMatch[1])
+ ->set('y', $routeMatch[2]);
+
+ if (isset($routeMatch[3])) {
+ $request->set('type', $routeMatch[3]);
+ }
+
+ $villageController = new Village();
+ $response = $villageController->storageConfig($request);
+ }
+
+ else if (preg_match('@village/(\d+)/(\d+)/building/(\w+)/level-up@', $request->getPath(), $routeMatch)) {
+ $request
+ ->set('x', $routeMatch[1])
+ ->set('y', $routeMatch[2])
+ ->set('type', $routeMatch[3]);
+
+ $buildingController = new Building();
+ $response = $buildingController->levelUp($request);
+ }
+
+ else if (preg_match('@village/(\d+)/(\d+)/unit/(\w+)/create@', $request->getPath(), $routeMatch)) {
+ $request
+ ->set('x', $routeMatch[1])
+ ->set('y', $routeMatch[2])
+ ->set('type', $routeMatch[3]);
+
+ $unitController = new Unit();
+ $response = $unitController->train($request);
+ }
+
+ else if (preg_match('@village/(\d+)/(\d+)@', $request->getPath(), $routeMatch)) {
+ $request
+ ->set('x', $routeMatch[1])
+ ->set('y', $routeMatch[2]);
+
+ $villageController = new Village();
+ $response = $villageController->show($request);
+ }
+
+ return $response;
+ });
+
+ $server->listen();
+ }
+}
diff --git a/src/Controller/Building.php b/src/http/Controller/Building.php
index e141113..4a59f0e 100644
--- a/src/Controller/Building.php
+++ b/src/http/Controller/Building.php
@@ -1,12 +1,12 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\Model\Building as Model;
use App\Model\Event;
use App\Model\Event\UpgradeBuilding;
use App\Model\Village;
-use App\Router;
+use App\http\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
diff --git a/src/Controller/Event.php b/src/http/Controller/Event.php
index 1fd304d..070d449 100644
--- a/src/Controller/Event.php
+++ b/src/http/Controller/Event.php
@@ -1,12 +1,12 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\DB;
use App\Model\Event as Model;
use App\Model\Event\SendUnits;
use App\Model\Village;
-use App\Router;
+use App\http\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
diff --git a/src/Controller/Login.php b/src/http/Controller/Login.php
index 0f360ae..8c04d85 100644
--- a/src/Controller/Login.php
+++ b/src/http/Controller/Login.php
@@ -1,6 +1,6 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\DB;
use App\View;
@@ -21,11 +21,13 @@ class Login
public function login(Request $request): Response
{
$email = $request->get('email');
- $user = DB::query('select id,username,password from users where email=:email', ['email' => $email])->fetch();
+ $user = DB::query('select id,username,password from users where email=:email or username=:email', ['email' => $email])->fetch();
if (empty($user)) {
$password = password_hash($request->get('password'), PASSWORD_DEFAULT);
DB::query('insert into users (username, password, email) values (:username, :password, :email)', ['username' => $email, 'password' => $password, 'email' => $email]);
+
+ // TODO: also insert new village at random free coordinates
} else {
$password = $user['password'];
}
diff --git a/src/Controller/Map.php b/src/http/Controller/Map.php
index 6967470..69d23e1 100644
--- a/src/Controller/Map.php
+++ b/src/http/Controller/Map.php
@@ -1,6 +1,6 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\DB;
use App\View;
diff --git a/src/Controller/Unit.php b/src/http/Controller/Unit.php
index 0508249..c314cda 100644
--- a/src/Controller/Unit.php
+++ b/src/http/Controller/Unit.php
@@ -1,6 +1,6 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\DB;
use App\Model\Event\SendUnits;
@@ -8,7 +8,7 @@ use App\Model\Event\TrainUnits;
use App\Model\Unit as Model;
use App\Model\Event;
use App\Model\Village;
-use App\Router;
+use App\http\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
diff --git a/src/Controller/Village.php b/src/http/Controller/Village.php
index c678779..cd38442 100644
--- a/src/Controller/Village.php
+++ b/src/http/Controller/Village.php
@@ -1,6 +1,6 @@
<?php
-namespace App\Controller;
+namespace App\http\Controller;
use App\DB;
use App\Guard;
@@ -8,7 +8,7 @@ use App\Model\Event\SendUnits;
use App\Model\Event\TrainUnits;
use App\Model\Event\UpgradeBuilding;
use App\Model\Village as Model;
-use App\Router;
+use App\http\Router;
use App\View;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
diff --git a/src/http/Http.php b/src/http/Http.php
new file mode 100644
index 0000000..1867eb4
--- /dev/null
+++ b/src/http/Http.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace App\http;
+
+use App\DB;
+use App\EventRunner;
+use App\http\Router;
+use App\View;
+use Symfony\Component\HttpFoundation\Request;
+
+class Http
+{
+ public function __construct()
+ {
+ // Session
+ session_start();
+
+ // DB
+ DB::init();
+
+ // Router
+ Router::init(Request::createFromGlobals());
+
+ // View
+ View::init();
+ View::addGlobal('session', $_SESSION);
+
+ // Events
+ new EventRunner();
+ }
+
+ public function run(): void
+ {
+ $response = Router::execute();
+ $response->send();
+ }
+}
diff --git a/src/Router.php b/src/http/Router.php
index 8b24000..db75f81 100644
--- a/src/Router.php
+++ b/src/http/Router.php
@@ -1,8 +1,8 @@
<?php
-namespace App;
+namespace App\http;
-use App\Support\RouteLoader;
+use App\http\Support\RouteLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
diff --git a/src/Support/RouteLoader.php b/src/http/Support/RouteLoader.php
index ba124c5..b0e74cb 100644
--- a/src/Support/RouteLoader.php
+++ b/src/http/Support/RouteLoader.php
@@ -1,6 +1,6 @@
<?php
-namespace App\Support;
+namespace App\http\Support;
use Symfony\Component\Routing\Loader\AnnotationClassLoader;
use Symfony\Component\Routing\Route;