Project restructure + lazy loading dependency stuff.

This commit is contained in:
flash 2025-01-22 13:30:21 +00:00
parent 740a957e1a
commit 28b719bead
31 changed files with 339 additions and 191 deletions

6
composer.lock generated
View file

@ -174,11 +174,11 @@
},
{
"name": "flashwave/index",
"version": "v0.2501.220016",
"version": "v0.2501.221237",
"source": {
"type": "git",
"url": "https://patchii.net/flash/index.git",
"reference": "94107b7130a95e04c35291bdfcae4daeabc40abd"
"reference": "fee9a65e3bca341be7401fe2e21b795630f15f2a"
},
"require": {
"ext-mbstring": "*",
@ -225,7 +225,7 @@
],
"description": "Composer package for the common library for my projects.",
"homepage": "https://railgun.sh/index",
"time": "2025-01-22T00:16:30+00:00"
"time": "2025-01-22T12:38:11+00:00"
},
{
"name": "guzzlehttp/psr7",

View file

@ -34,5 +34,4 @@ if($cfg->hasValues('sentry:dsn'))
});
})($cfg->scopeTo('sentry'));
$db = DbBackends::create($cfg->getString('database:dsn', 'null:'));
$db->execute('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';');
$mince = new MinceContext($cfg);

View file

@ -1,85 +1,6 @@
<?php
namespace Mince;
use RuntimeException;
use Flashii\{FlashiiClient,FlashiiUrls};
use Flashii\Credentials\MisuzuCredentials;
use Index\{CsrfToken,Dependencies};
use Index\Http\Routing\HttpRouter;
use Index\Templating\TplEnvironment;
use Index\Urls\{ArrayUrlRegistry,UrlRegistry};
require_once __DIR__ . '/../mince.php';
// replace this with id.flashii.net shit
$authToken = (string)filter_input(INPUT_COOKIE, 'msz_auth');
$flashii = new FlashiiClient('Mince', new MisuzuCredentials($authToken), new FlashiiUrls(
$cfg->getString('apii:api', FlashiiUrls::PROD_API_URL)
));
$deps = new Dependencies;
$deps->register($db);
$deps->register(AccountLinks::class);
$deps->register(ArrayUrlRegistry::class);
$deps->register(Authorisations::class);
$deps->register(Capes::class);
$deps->register(Servers::class);
$deps->register(Skins::class);
$deps->register(new TplEnvironment(MCR_DIR_TPL, ['Mince'], debug: MCR_DEBUG));
$deps->register(Users::class);
$deps->register(Verifications::class);
$users = $deps->resolve(Users::class);
try {
$authInfo = $flashii->v1()->me();
$deps->register($authInfo);
$users->syncApiUser($authInfo);
$userInfo = $users->getUser($authInfo->getId());
} catch(RuntimeException $ex) {
$authInfo = $sUserInfo = null;
}
$deps->register($csrfp = new CsrfToken(
$cfg->getString('csrfp:secret', 'wowof'),
$authInfo === null ? $_SERVER['REMOTE_ADDR'] : $authToken
));
$templating = $deps->resolve(TplEnvironment::class);
$templating->addGlobal('globals', [
'title' => 'Flashii Minecraft Servers',
'is_authed' => $userInfo !== null,
'user' => $userInfo,
'csrfp' => $csrfp->createToken(),
]);
$accountLinks = $deps->resolve(AccountLinks::class);
$authorisations = $deps->resolve(Authorisations::class);
$authorisations->prune();
$verifications = $deps->resolve(Verifications::class);
$verifications->prune();
$urls = $deps->resolve(UrlRegistry::class);
$templating->addFunction('url', $urls->format(...));
$router = new HttpRouter(errorHandler: new RouterErrorHandler($templating));
$router->use('/', function($response, $request) { $response->setPoweredBy('Mince'); });
$router->register($deps->construct(RpcRoutes::class, secretKey: $cfg->getString('rpc:secret'), clientsUrl: $cfg->getString('urls:clients')));
$homeRoutes = $deps->construct(HomeRoutes::class, loginUrl: $cfg->getString('site:login'));
$router->register($homeRoutes);
$urls->register($homeRoutes);
$clientRoutes = $deps->construct(ClientsRoutes::class);
$router->register($clientRoutes);
$urls->register($clientRoutes);
$skinsRoutes = $deps->construct(SkinsRoutes::class, baseUrl: $cfg->getString('urls:skins_base'));
$router->register($skinsRoutes);
$urls->register($skinsRoutes);
MojangInterop::registerRoutes($router);
$router->dispatch();
$mince->createRouting()->dispatch();

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Clients;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -1,12 +1,13 @@
<?php
namespace Mince;
namespace Mince\Clients;
use InvalidArgumentException;
use RuntimeException;
use Index\Db\{DbConnection,DbStatementCache};
use Mince\Users\UserInfo;
use Ramsey\Uuid\UuidInterface;
class AccountLinks {
class AccountLinksData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Clients;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -1,12 +1,12 @@
<?php
namespace Mince;
namespace Mince\Clients;
use InvalidArgumentException;
use RuntimeException;
use Index\Db\{DbConnection,DbStatementCache};
use Ramsey\Uuid\UuidInterface;
class Authorisations {
class AuthorisationsData {
private DbStatementCache $cache;
public function __construct(

View file

@ -0,0 +1,31 @@
<?php
namespace Mince\Clients;
use Index\Dependencies;
use Index\Http\Routing\{RouteHandler,Router};
use Index\Urls\{UrlRegistry,UrlSource};
class ClientsContext implements RouteHandler, UrlSource {
public private(set) AccountLinksData $accountLinks;
public private(set) AuthorisationsData $authorisations;
public private(set) VerificationsData $verifications;
public private(set) ClientsRoutes $routes;
public function __construct(Dependencies $deps) {
// TODO: the prune calls should be in a cron script
$this->accountLinks = $deps->constructLazy(AccountLinksData::class);
$this->authorisations = $deps->constructLazy(AuthorisationsData::class);
$this->authorisations->prune();
$this->verifications = $deps->constructLazy(VerificationsData::class);
$this->verifications->prune();
$this->routes = $deps->constructLazy(ClientsRoutes::class);
}
public function registerRoutes(Router $router): void {
$router->register($this->routes);
}
public function registerUrls(UrlRegistry $registry): void {
$registry->register($this->routes);
}
}

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Clients;
use InvalidArgumentException;
use RuntimeException;
@ -17,9 +17,7 @@ class ClientsRoutes implements RouteHandler, UrlSource {
public function __construct(
private TplEnvironment $templating,
private UrlRegistry $urls,
private AccountLinks $accountLinks,
private Authorisations $authorisations,
private Verifications $verifications,
private ClientsContext $clientsCtx,
private CsrfToken $csrfp,
private ?V1User $authInfo
) {}
@ -67,8 +65,8 @@ class ClientsRoutes implements RouteHandler, UrlSource {
}
try {
$linkInfo = $this->accountLinks->getLink(userInfo: $this->authInfo->getId());
$clients = iterator_to_array($this->authorisations->getAuthorisations($linkInfo), false);
$linkInfo = $this->clientsCtx->accountLinks->getLink(userInfo: $this->authInfo->getId());
$clients = iterator_to_array($this->clientsCtx->authorisations->getAuthorisations($linkInfo), false);
$template->setVars([
'link' => $linkInfo,
@ -82,7 +80,7 @@ class ClientsRoutes implements RouteHandler, UrlSource {
#[HttpPost('/clients/link')]
#[UrlFormat('clients:link', '/clients/link')]
public function postLink(HttpResponseBuilder $response, HttpRequest $request) {
if($this->accountLinks->checkHasLink($this->authInfo->getId())) {
if($this->clientsCtx->accountLinks->checkHasLink($this->authInfo->getId())) {
$response->redirect($this->urls->format('clients:index', ['error' => 'link:already']));
return;
}
@ -96,15 +94,15 @@ class ClientsRoutes implements RouteHandler, UrlSource {
$code = strtr(strtoupper($code), '0189', 'OIBG');
try {
$verifyInfo = $this->verifications->getVerification(code: $code);
$verifyInfo = $this->clientsCtx->verifications->getVerification(code: $code);
} catch(RuntimeException $ex) {
$response->redirect($this->urls->format('clients:index', ['error' => 'link:code']));
return;
}
$this->verifications->deleteVerification($verifyInfo);
$this->accountLinks->createLink($this->authInfo->getId(), $verifyInfo);
$this->authorisations->createAuthorisation($verifyInfo, grant: true);
$this->clientsCtx->verifications->deleteVerification($verifyInfo);
$this->clientsCtx->accountLinks->createLink($this->authInfo->getId(), $verifyInfo);
$this->clientsCtx->authorisations->createAuthorisation($verifyInfo, grant: true);
$response->redirect($this->urls->format('clients:index'));
}
@ -112,7 +110,7 @@ class ClientsRoutes implements RouteHandler, UrlSource {
#[HttpPost('/clients/unlink')]
#[UrlFormat('clients:unlink', '/clients/unlink')]
public function postUnlink(HttpResponseBuilder $response) {
$this->accountLinks->deleteLink(userInfo: $this->authInfo->getId());
$this->clientsCtx->accountLinks->deleteLink(userInfo: $this->authInfo->getId());
$response->redirect($this->urls->format('clients:index'));
}
@ -124,13 +122,13 @@ class ClientsRoutes implements RouteHandler, UrlSource {
return 404;
try {
$linkInfo = $this->accountLinks->getLink(userInfo: $this->authInfo->getId());
$linkInfo = $this->clientsCtx->accountLinks->getLink(userInfo: $this->authInfo->getId());
} catch(RuntimeException $ex) {
return 403;
}
try {
$authInfo = $this->authorisations->getAuthorisation(authId: $authId);
$authInfo = $this->clientsCtx->authorisations->getAuthorisation(authId: $authId);
} catch(RuntimeException $ex) {
return 403;
}
@ -140,7 +138,7 @@ class ClientsRoutes implements RouteHandler, UrlSource {
if($authInfo->granted)
return 404;
$this->authorisations->setAuthorisationGranted($authInfo);
$this->clientsCtx->authorisations->setAuthorisationGranted($authInfo);
$response->redirect($this->urls->format('clients:index'));
}
@ -153,18 +151,18 @@ class ClientsRoutes implements RouteHandler, UrlSource {
return 404;
try {
$linkInfo = $this->accountLinks->getLink(userInfo: $this->authInfo->getId());
$linkInfo = $this->clientsCtx->accountLinks->getLink(userInfo: $this->authInfo->getId());
} catch(RuntimeException $ex) {
return 403;
}
if($authId === 'all') {
$this->authorisations->deleteAuthorisations(uuid: $linkInfo);
$this->clientsCtx->authorisations->deleteAuthorisations(uuid: $linkInfo);
} elseif($authId === 'pending') {
$this->authorisations->deleteAuthorisations(uuid: $linkInfo, pending: true);
$this->clientsCtx->authorisations->deleteAuthorisations(uuid: $linkInfo, pending: true);
} else {
try {
$authInfo = $this->authorisations->getAuthorisation(authId: $authId);
$authInfo = $this->clientsCtx->authorisations->getAuthorisation(authId: $authId);
} catch(RuntimeException $ex) {
return 403;
}
@ -172,7 +170,7 @@ class ClientsRoutes implements RouteHandler, UrlSource {
if($authInfo->uuidRaw !== $linkInfo->uuidRaw)
return 403;
$this->authorisations->deleteAuthorisations(authInfo: $authInfo);
$this->clientsCtx->authorisations->deleteAuthorisations(authInfo: $authInfo);
}
$response->redirect($this->urls->format('clients:index'));

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Clients;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Clients;
use InvalidArgumentException;
use RuntimeException;
@ -7,7 +7,7 @@ use Index\XString;
use Index\Db\{DbConnection,DbStatementCache};
use Ramsey\Uuid\UuidInterface;
class Verifications {
class VerificationsData {
private const CODE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
private DbStatementCache $cache;

28
src/DatabaseContext.php Normal file
View file

@ -0,0 +1,28 @@
<?php
namespace Mince;
use Index\Config\Config;
use Index\Db\{DbBackends,DbConnection};
use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo};
class DatabaseContext {
public private(set) DbConnection $conn;
public function __construct(Config $config) {
$this->conn = DbBackends::create($config->getString('dsn', 'null:'));
$this->conn->execute('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';');
}
public function getQueryCount(): int {
$result = $this->conn->query('SHOW SESSION STATUS LIKE "Questions"');
return $result->next() ? $result->getInteger(1) : 0;
}
public function createMigrationManager(): DbMigrationManager {
return new DbMigrationManager($this->conn);
}
public function createMigrationRepo(): DbMigrationRepo {
return new FsDbMigrationRepo(MCR_DIR_MIG);
}
}

View file

@ -6,6 +6,7 @@ use Index\Http\HttpResponseBuilder;
use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerCommon};
use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
use Index\Templating\TplEnvironment;
use Mince\Servers\ServersContext;
class HomeRoutes implements RouteHandler, UrlSource {
use RouteHandlerCommon, UrlSourceCommon;
@ -13,7 +14,7 @@ class HomeRoutes implements RouteHandler, UrlSource {
public function __construct(
private TplEnvironment $templating,
private UrlRegistry $urls,
private Servers $servers,
private ServersContext $serversCtx,
private ?V1User $authInfo,
private string $loginUrl
) {}
@ -22,7 +23,7 @@ class HomeRoutes implements RouteHandler, UrlSource {
#[UrlFormat('index', '/')]
public function getIndex() {
return $this->templating->render('index', [
'servers' => iterator_to_array($this->servers->getServers(deleted: false), false),
'servers' => iterator_to_array($this->serversCtx->servers->getServers(deleted: false), false),
]);
}

89
src/MinceContext.php Normal file
View file

@ -0,0 +1,89 @@
<?php
namespace Mince;
use Flashii\{FlashiiClient,FlashiiUrls};
use Flashii\Credentials\MisuzuCredentials;
use Index\{CsrfToken,Dependencies};
use Index\Config\Config;
use Index\Db\DbConnection;
use Index\Http\{HttpResponseBuilder,HttpRequest};
use Index\Http\Routing\RouteHandler;
use Index\Templating\TplEnvironment;
use Index\Urls\UrlSource;
class MinceContext {
public private(set) Dependencies $deps;
public private(set) DatabaseContext $dbCtx;
public private(set) Clients\ClientsContext $clientsCtx;
public private(set) Servers\ServersContext $serversCtx;
public private(set) Skins\SkinsContext $skinsCtx;
public private(set) Users\UsersContext $usersCtx;
public function __construct(
private Config $config
) {
$this->deps = new Dependencies;
$this->deps->register($this->deps);
$this->deps->register($config);
$this->deps->register($this->dbCtx = $this->deps->construct(DatabaseContext::class, config: $config->scopeTo('database')));
$this->deps->register($this->dbCtx->conn);
$this->deps->register($this->clientsCtx = $this->deps->constructLazy(Clients\ClientsContext::class));
$this->deps->register($this->serversCtx = $this->deps->constructLazy(Servers\ServersContext::class));
$this->deps->register($this->skinsCtx = $this->deps->constructLazy(Skins\SkinsContext::class));
$this->deps->register($this->usersCtx = $this->deps->constructLazy(Users\UsersContext::class));
}
public function createRouting(): RoutingContext {
$this->deps->register($templating = new TplEnvironment(MCR_DIR_TPL, ['Mince'], debug: MCR_DEBUG));
$routingCtx = $this->deps->construct(RoutingContext::class);
$templating->addFunction('url', $routingCtx->urls->format(...));
$this->deps->register($routingCtx->router);
$this->deps->register($routingCtx->urls);
$routingCtx->router->use('/', function(HttpResponseBuilder $response, HttpRequest $request) use ($templating) {
$authToken = (string)$request->getCookie('msz_auth');
if(empty($authToken)) {
$csrfSecret = $request->remoteAddress;
$userInfo = null;
} else {
$flashii = new FlashiiClient('Mince', new MisuzuCredentials($authToken), new FlashiiUrls(
$this->config->getString('apii:api', FlashiiUrls::PROD_API_URL)
));
try {
$authInfo = $flashii->v1()->me();
$this->deps->register($authInfo);
$this->usersCtx->users->syncApiUser($authInfo);
$userInfo = $this->usersCtx->users->getUser($authInfo->getId());
$csrfSecret = $authToken;
} catch(RuntimeException $ex) {
$userInfo = null;
}
}
$this->deps->register($csrfToken = new CsrfToken(
$this->config->getString('csrfp:secret', 'wowof'), $csrfSecret
));
$templating->addGlobal('globals', [
'title' => 'Flashii Minecraft Servers',
'is_authed' => $userInfo !== null,
'user' => $userInfo,
'csrfp' => $csrfToken->createToken(),
]);
});
$routingCtx->register($this->deps->construct(RpcRoutes::class, secretKey: $this->config->getString('rpc:secret'), clientsUrl: $this->config->getString('urls:clients')));
$routingCtx->register($this->deps->construct(HomeRoutes::class, loginUrl: $this->config->getString('site:login')));
$handlers = array_unique($this->deps->all(RouteHandler::class) + $this->deps->all(UrlSource::class), SORT_REGULAR);
foreach($handlers as $handler)
$routingCtx->register($handler);
MojangInterop::registerRoutes($routingCtx->router);
return $routingCtx;
}
}

30
src/RoutingContext.php Normal file
View file

@ -0,0 +1,30 @@
<?php
namespace Mince;
use Index\Http\{HttpResponseBuilder,HttpRequest};
use Index\Http\Routing\{HttpRouter,Router,RouteHandler};
use Index\Urls\{ArrayUrlRegistry,UrlRegistry,UrlSource};
use Index\Templating\TplEnvironment;
class RoutingContext {
public private(set) UrlRegistry $urls;
public private(set) HttpRouter $router;
public function __construct(TplEnvironment $templating) {
$this->urls = new ArrayUrlRegistry;
$this->router = new HttpRouter(errorHandler: new RoutingErrorHandler($templating));
$this->router->use('/', fn(HttpResponseBuilder $resp) => $resp->setPoweredBy('Mince'));
}
public function register(RouteHandler|UrlSource $handler): void {
if($handler instanceof RouteHandler)
$this->router->register($handler);
if($handler instanceof UrlSource)
$this->urls->register($handler);
}
/** @param mixed[] $args */
public function dispatch(?HttpRequest $request = null, array $args = []): void {
$this->router->dispatch($request, $args);
}
}

View file

@ -4,7 +4,7 @@ namespace Mince;
use Index\Http\{HttpErrorHandler,HttpResponseBuilder,HttpRequest};
use Index\Templating\TplEnvironment;
class RouterErrorHandler implements HttpErrorHandler {
class RoutingErrorHandler implements HttpErrorHandler {
public function __construct(
private TplEnvironment $templating
) {}

View file

@ -7,16 +7,16 @@ use RuntimeException;
use Stringable;
use Index\Http\{FormHttpContent,HttpResponseBuilder,HttpRequest};
use Index\Http\Routing\{HttpMiddleware,HttpPost,RouteHandler,RouteHandlerCommon};
use Mince\Clients\ClientsContext;
use Mince\Users\UsersContext;
use Ramsey\Uuid\Uuid;
class RpcRoutes implements RouteHandler {
use RouteHandlerCommon;
public function __construct(
private Users $users,
private AccountLinks $accountLinks,
private Authorisations $authorisations,
private Verifications $verifications,
private UsersContext $usersCtx,
private ClientsContext $clientsCtx,
#[\SensitiveParameter] private string $secretKey,
private string $clientsUrl
) {}
@ -97,17 +97,17 @@ class RpcRoutes implements RouteHandler {
return self::createErrorPayload('auth:uuid', 'Provided UUID isn\'t an offline ID nor a Mojang ID.');
try {
$linkInfo = $this->accountLinks->getLink(uuid: $uuid);
$linkInfo = $this->clientsCtx->accountLinks->getLink(uuid: $uuid);
} catch(RuntimeException $ex) {
$linkInfo = null;
}
if($linkInfo !== null) {
try {
$authInfo = $this->authorisations->getAuthorisation(uuid: $linkInfo, remoteAddr: $addr);
$authInfo = $this->clientsCtx->authorisations->getAuthorisation(uuid: $linkInfo, remoteAddr: $addr);
if($authInfo->granted) {
$this->authorisations->markAuthorisationUsed($authInfo);
$this->clientsCtx->authorisations->markAuthorisationUsed($authInfo);
return self::createPayload('auth:ok');
}
} catch(RuntimeException $ex) {
@ -115,13 +115,13 @@ class RpcRoutes implements RouteHandler {
}
try {
$userInfo = $this->users->getUser(userId: $linkInfo->userId);
$userInfo = $this->usersCtx->users->getUser(userId: $linkInfo->userId);
} catch(RuntimeException $ex) {
return 500;
}
if($authInfo === null)
$this->authorisations->createAuthorisation($uuid, $addr);
$this->clientsCtx->authorisations->createAuthorisation($uuid, $addr);
return self::createPayload('auth:authorise', [
'user_id' => $userInfo->id,
@ -132,10 +132,10 @@ class RpcRoutes implements RouteHandler {
}
try {
$verifyInfo = $this->verifications->getVerification(uuid: $uuid, remoteAddr: $addr);
$verifyInfo = $this->clientsCtx->verifications->getVerification(uuid: $uuid, remoteAddr: $addr);
$verifyCode = $verifyInfo->code;
} catch(RuntimeException $ex) {
$verifyCode = $this->verifications->createVerification($uuid, $name, $addr);
$verifyCode = $this->clientsCtx->verifications->createVerification($uuid, $name, $addr);
}
return self::createPayload('auth:link', [

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Servers;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -0,0 +1,12 @@
<?php
namespace Mince\Servers;
use Index\Dependencies;
class ServersContext {
public private(set) ServersData $servers;
public function __construct(Dependencies $deps) {
$this->servers = $deps->constructLazy(ServersData::class);
}
}

View file

@ -1,9 +1,9 @@
<?php
namespace Mince;
namespace Mince\Servers;
use Index\Db\{DbConnection,DbStatementCache};
class Servers {
class ServersData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Skins;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -1,11 +1,13 @@
<?php
namespace Mince;
namespace Mince\Skins;
use InvalidArgumentException;
use RuntimeException;
use Index\Db\{DbConnection,DbStatementCache};
use Mince\Clients\AccountLinkInfo;
use Mince\Users\UserInfo;
class Capes {
class CapesData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Skins;
use Carbon\CarbonImmutable;
use Index\Db\DbResult;

View file

@ -0,0 +1,27 @@
<?php
namespace Mince\Skins;
use Index\Dependencies;
use Index\Config\Config;
use Index\Http\Routing\{RouteHandler,Router};
use Index\Urls\{UrlRegistry,UrlSource};
class SkinsContext implements RouteHandler, UrlSource {
public private(set) CapesData $capes;
public private(set) SkinsData $skins;
public private(set) SkinsRoutes $routes;
public function __construct(Dependencies $deps, Config $config) {
$this->capes = $deps->constructLazy(CapesData::class);
$this->skins = $deps->constructLazy(SkinsData::class);
$this->routes = $deps->constructLazy(SkinsRoutes::class, baseUrl: $config->getString('urls:skins_base'));
}
public function registerRoutes(Router $router): void {
$router->register($this->routes);
}
public function registerUrls(UrlRegistry $registry): void {
$registry->register($this->routes);
}
}

View file

@ -1,11 +1,13 @@
<?php
namespace Mince;
namespace Mince\Skins;
use InvalidArgumentException;
use RuntimeException;
use Index\Db\{DbConnection,DbStatementCache};
use Mince\Clients\AccountLinkInfo;
use Mince\Users\UserInfo;
class Skins {
class SkinsData {
public const MODELS = ['classic', 'slim'];
private DbStatementCache $cache;

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Skins;
use Imagick;
use ImagickException;
@ -13,6 +13,8 @@ use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler,RouteHandle
use Index\Json\JsonHttpContent;
use Index\Templating\TplEnvironment;
use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
use Mince\MojangInterop;
use Mince\Clients\{AccountLinkInfo,ClientsContext};
use Ramsey\Uuid\{Uuid,UuidInterface};
class SkinsRoutes implements RouteHandler, UrlSource {
@ -26,9 +28,8 @@ class SkinsRoutes implements RouteHandler, UrlSource {
public function __construct(
private TplEnvironment $templating,
private UrlRegistry $urls,
private AccountLinks $accountLinks,
private Skins $skins,
private Capes $capes,
private SkinsContext $skinsCtx,
private ClientsContext $clientsCtx,
private CsrfToken $csrfp,
private ?V1User $authInfo,
private string $baseUrl
@ -40,8 +41,8 @@ class SkinsRoutes implements RouteHandler, UrlSource {
}
public function checkHash(string $hash): bool {
return $this->skins->checkHash($hash)
|| $this->capes->checkHash($hash);
return $this->skinsCtx->skins->checkHash($hash)
|| $this->skinsCtx->capes->checkHash($hash);
}
public function getLocalPath(string $hash): string {
@ -64,7 +65,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
return 403;
try {
$this->linkInfo = $this->accountLinks->getLink(userInfo: $this->authInfo->getId());
$this->linkInfo = $this->clientsCtx->accountLinks->getLink(userInfo: $this->authInfo->getId());
} catch(RuntimeException $ex) {
$response->redirect($this->urls->format('clients:index'));
return true;
@ -93,9 +94,9 @@ class SkinsRoutes implements RouteHandler, UrlSource {
#[HttpGet('/skins')]
#[UrlFormat('skins:index', '/skins', ['error' => '<error>'])]
public function getSkins(HttpResponseBuilder $response, HttpRequest $request) {
$skinInfo = $this->skins->getSkin($this->linkInfo);
$skinInfo = $this->skinsCtx->skins->getSkin($this->linkInfo);
$skinPath = $skinInfo === null ? null : $this->getRemotePath($skinInfo->hash, false);
$capeInfo = $this->capes->getCape($this->linkInfo);
$capeInfo = $this->skinsCtx->capes->getCape($this->linkInfo);
$capePath = $capeInfo === null ? null : $this->getRemotePath($capeInfo->hash, false);
$template = $this->templating->load('skins/index', [
@ -133,7 +134,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
$texture = $request->content->getUploadedFile('texture');
$model = (string)$request->content->getParam('model');
if(!in_array($model, Skins::MODELS)) {
if(!in_array($model, SkinsData::MODELS)) {
$response->redirect($this->urls->format('skins:index', ['error' => 'skin:model']));
return;
}
@ -143,7 +144,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
return;
}
$skinInfo = $this->skins->getSkin($this->linkInfo);
$skinInfo = $this->skinsCtx->skins->getSkin($this->linkInfo);
$tmpPath = $texture->localFileName;
$hasNewFile = is_file($tmpPath);
@ -172,7 +173,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
// apply new skin
if($hasNewFile && !is_file($localPath))
$texture->moveTo($localPath);
$this->skins->updateSkin($this->linkInfo, $hash, $model);
$this->skinsCtx->skins->updateSkin($this->linkInfo, $hash, $model);
} finally {
// see about deleting the old one
if($skinInfo !== null)
@ -190,9 +191,9 @@ class SkinsRoutes implements RouteHandler, UrlSource {
#[HttpPost('/skins/delete-skin')]
#[UrlFormat('skins:skin:delete', '/skins/delete-skin')]
public function postDeleteSkin(HttpResponseBuilder $response) {
$skinInfo = $this->skins->getSkin($this->linkInfo);
$skinInfo = $this->skinsCtx->skins->getSkin($this->linkInfo);
if($skinInfo !== null) {
$this->skins->deleteSkin(userInfo: $this->linkInfo);
$this->skinsCtx->skins->deleteSkin(userInfo: $this->linkInfo);
$this->deleteLocalFileMaybe($skinInfo->hash);
}
@ -231,13 +232,13 @@ class SkinsRoutes implements RouteHandler, UrlSource {
try {
// get previous cape
$capeInfo = $this->capes->getCape($this->linkInfo);
$capeInfo = $this->skinsCtx->capes->getCape($this->linkInfo);
try {
// apply new cape
if(!is_file($localPath))
$texture->moveTo($localPath);
$this->capes->updateCape($this->linkInfo, $hash);
$this->skinsCtx->capes->updateCape($this->linkInfo, $hash);
} finally {
// see about deleting the old one
if($capeInfo !== null)
@ -254,9 +255,9 @@ class SkinsRoutes implements RouteHandler, UrlSource {
#[HttpPost('/skins/delete-cape')]
#[UrlFormat('skins:cape:delete', '/skins/delete-cape')]
public function postDeleteCape(HttpResponseBuilder $response) {
$capeInfo = $this->capes->getCape($this->linkInfo);
$capeInfo = $this->skinsCtx->capes->getCape($this->linkInfo);
if($capeInfo !== null) {
$this->capes->deleteCape(userInfo: $this->linkInfo);
$this->skinsCtx->capes->deleteCape(userInfo: $this->linkInfo);
$this->deleteLocalFileMaybe($capeInfo->hash);
}
@ -298,7 +299,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
$hash = hash_file('sha256', $tmpFile);
$localPath = $this->getLocalPath($hash);
rename($tmpFile, $localPath);
$this->skins->updateSkin($this->linkInfo, $hash, $model);
$this->skinsCtx->skins->updateSkin($this->linkInfo, $hash, $model);
} finally {
if(is_file($tmpFile))
unlink($tmpFile);
@ -317,7 +318,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
$hash = hash_file('sha256', $tmpFile);
$localPath = $this->getLocalPath($hash);
rename($tmpFile, $localPath);
$this->capes->updateCape($this->linkInfo, $hash);
$this->skinsCtx->capes->updateCape($this->linkInfo, $hash);
} finally {
if(is_file($tmpFile))
unlink($tmpFile);
@ -338,14 +339,14 @@ class SkinsRoutes implements RouteHandler, UrlSource {
return 204;
try {
$linkInfo = $this->accountLinks->getLink(uuid: $uuid);
$linkInfo = $this->clientsCtx->accountLinks->getLink(uuid: $uuid);
} catch(RuntimeException $ex) {
return 204;
}
$textures = [];
$skinInfo = $this->skins->getSkin($linkInfo);
$skinInfo = $this->skinsCtx->skins->getSkin($linkInfo);
if($skinInfo !== null) {
$texture = ['url' => $this->getRemotePath($skinInfo->hash, true)];
if(!$skinInfo->classic)
@ -353,7 +354,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
$textures['SKIN'] = $texture;
}
$capeInfo = $this->capes->getCape($linkInfo);
$capeInfo = $this->skinsCtx->capes->getCape($linkInfo);
if($capeInfo !== null)
$textures['CAPE'] = ['url' => $this->getRemotePath($capeInfo->hash, true)];
@ -430,7 +431,7 @@ class SkinsRoutes implements RouteHandler, UrlSource {
#[HttpGet('/users/profiles/minecraft/([A-Za-z0-9_]+)')]
public function getUsersMinecraftProfile(HttpResponseBuilder $response, HttpRequest $request, string $name) {
try {
$linkInfo = $this->accountLinks->getLink(name: $name);
$linkInfo = $this->clientsCtx->accountLinks->getLink(name: $name);
} catch(RuntimeException $ex) {
$response->statusCode = 404;
return [
@ -450,12 +451,12 @@ class SkinsRoutes implements RouteHandler, UrlSource {
#[HttpGet('/s3s3MinecraftSkins/([A-Za-z0-9_]+).png')]
public function getS3MinecraftSkin(HttpResponseBuilder $response, HttpRequest $request, string $name) {
try {
$linkInfo = $this->accountLinks->getLink(name: $name);
$linkInfo = $this->clientsCtx->accountLinks->getLink(name: $name);
} catch(RuntimeException $ex) {
return 404;
}
$skinInfo = $this->skins->getSkin($linkInfo);
$skinInfo = $this->skinsCtx->skins->getSkin($linkInfo);
if($skinInfo === null)
return 404;

View file

@ -1,5 +1,5 @@
<?php
namespace Mince;
namespace Mince\Users;
use Index\Colour\{Colour,ColourRgb};
use Index\Db\DbResult;

View file

@ -0,0 +1,12 @@
<?php
namespace Mince\Users;
use Index\Dependencies;
class UsersContext {
public private(set) UsersData $users;
public function __construct(Dependencies $deps) {
$this->users = $deps->constructLazy(UsersData::class);
}
}

View file

@ -1,11 +1,11 @@
<?php
namespace Mince;
namespace Mince\Users;
use RuntimeException;
use Flashii\V1\Users\V1User;
use Index\Db\{DbConnection,DbStatementCache};
class Users {
class UsersData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {

View file

@ -4,31 +4,25 @@ use Index\Db\Migration\{DbMigrationManager,FsDbMigrationRepo};
require_once __DIR__ . '/../mince.php';
try {
touch(MCR_ROOT . '/.migrating');
chmod(MCR_ROOT . '/.migrating', 0777);
echo 'Creating migration manager...' . PHP_EOL;
$manager = $mince->dbCtx->createMigrationManager();
echo 'Creating migration manager...' . PHP_EOL;
$manager = new DbMigrationManager($db);
echo 'Preparing to run migrations...' . PHP_EOL;
$manager->init();
echo 'Preparing to run migrations...' . PHP_EOL;
$manager->init();
echo 'Creating migration repository...' . PHP_EOL;
$repo = $mince->dbCtx->createMigrationRepo();
echo 'Creating migration repository...' . PHP_EOL;
$repo = new FsDbMigrationRepo(MCR_DIR_MIG);
echo 'Running migrations...' . PHP_EOL;
$completed = $manager->processMigrations($repo);
echo 'Running migrations...' . PHP_EOL;
$completed = $manager->processMigrations($repo);
if(empty($completed)) {
echo 'There were no migrations to run!' . PHP_EOL;
} else {
echo 'The following migrations have been completed:' . PHP_EOL;
foreach($completed as $migration)
echo ' - ' . $migration . PHP_EOL;
}
echo PHP_EOL;
} finally {
unlink(MCR_ROOT . '/.migrating');
if(empty($completed)) {
echo 'There were no migrations to run!' . PHP_EOL;
} else {
echo 'The following migrations have been completed:' . PHP_EOL;
foreach($completed as $migration)
echo ' - ' . $migration . PHP_EOL;
}
echo PHP_EOL;

View file

@ -4,9 +4,9 @@ use Index\Db\Migration\DbMigrationManager;
require_once __DIR__ . '/../mince.php';
$repo = new FsDbMigrationRepo(MCR_DIR_MIG);
$repo = $mince->dbCtx->createMigrationRepo();
$baseName = implode(' ', array_slice($argv, 1));
$manager = new DbMigrationManager($db);
$manager = $mince->dbCtx->createMigrationManager();
try {
$names = $manager->createNames($baseName);