major update
This commit is contained in:
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace MintyPHP\Http;
|
||||
|
||||
use MintyPHP\Http\RequestContext;
|
||||
use MintyPHP\Service\Audit\ApiAuditService;
|
||||
use MintyPHP\Service\Security\RateLimiterService;
|
||||
use MintyPHP\Service\Security\SecurityServicesFactory;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
|
||||
class ApiBootstrap
|
||||
{
|
||||
@@ -18,10 +18,26 @@ class ApiBootstrap
|
||||
|
||||
private static bool $initialized = false;
|
||||
private static bool $shutdownRegistered = false;
|
||||
private static ?SecurityServicesFactory $securityServicesFactory = null;
|
||||
private static ?RateLimiterService $rateLimiterService = null;
|
||||
private static ?SettingServicesFactory $settingServicesFactory = null;
|
||||
private static ?SettingGateway $settingGateway = null;
|
||||
/** @var (callable(): ApiAuditService)|null */
|
||||
private static $apiAuditServiceResolver = null;
|
||||
/** @var (callable(): SettingGateway)|null */
|
||||
private static $settingGatewayResolver = null;
|
||||
/** @var (callable(): RateLimiterService)|null */
|
||||
private static $rateLimiterServiceResolver = null;
|
||||
/** @var (callable(): ApiSystemAuditReporter)|null */
|
||||
private static $apiSystemAuditReporterResolver = null;
|
||||
|
||||
public static function configure(
|
||||
callable $apiAuditServiceResolver,
|
||||
callable $settingGatewayResolver,
|
||||
callable $rateLimiterServiceResolver,
|
||||
callable $apiSystemAuditReporterResolver
|
||||
): void {
|
||||
self::$apiAuditServiceResolver = $apiAuditServiceResolver;
|
||||
self::$settingGatewayResolver = $settingGatewayResolver;
|
||||
self::$rateLimiterServiceResolver = $rateLimiterServiceResolver;
|
||||
self::$apiSystemAuditReporterResolver = $apiSystemAuditReporterResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the API request context.
|
||||
@@ -40,8 +56,16 @@ class ApiBootstrap
|
||||
define('MINTY_ALLOW_OUTPUT', true);
|
||||
}
|
||||
|
||||
RequestContext::start([
|
||||
'channel' => 'api',
|
||||
'method' => strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')),
|
||||
'path' => (string) parse_url((string) ($_SERVER['REQUEST_URI'] ?? ''), PHP_URL_PATH),
|
||||
]);
|
||||
header('X-Request-Id: ' . RequestContext::requestHeaderValue());
|
||||
|
||||
self::registerShutdownHandler();
|
||||
\auditServicesFactory()->createApiAuditService()->startRequestContext();
|
||||
self::apiAuditService()->startRequestContext();
|
||||
self::startSystemAuditReporter();
|
||||
self::setCorsHeaders();
|
||||
|
||||
if (strtoupper($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
|
||||
@@ -96,7 +120,8 @@ class ApiBootstrap
|
||||
if ($statusCode <= 0) {
|
||||
$statusCode = 200;
|
||||
}
|
||||
\auditServicesFactory()->createApiAuditService()->finish($statusCode);
|
||||
self::apiAuditService()->finish($statusCode);
|
||||
self::finishSystemAuditReporter($statusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +132,8 @@ class ApiBootstrap
|
||||
if ($statusCode <= 0) {
|
||||
$statusCode = 200;
|
||||
}
|
||||
\auditServicesFactory()->createApiAuditService()->finish($statusCode);
|
||||
self::apiAuditService()->finish($statusCode);
|
||||
self::finishSystemAuditReporter($statusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,7 +141,8 @@ class ApiBootstrap
|
||||
if ($statusCode < 400) {
|
||||
$statusCode = 500;
|
||||
}
|
||||
\auditServicesFactory()->createApiAuditService()->finish($statusCode, 'fatal_error');
|
||||
self::apiAuditService()->finish($statusCode, 'fatal_error');
|
||||
self::finishSystemAuditReporter($statusCode, 'fatal_error');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,29 +235,53 @@ class ApiBootstrap
|
||||
|
||||
private static function settings(): SettingGateway
|
||||
{
|
||||
if (self::$settingGateway instanceof SettingGateway) {
|
||||
return self::$settingGateway;
|
||||
}
|
||||
|
||||
if (!(self::$settingServicesFactory instanceof SettingServicesFactory)) {
|
||||
self::$settingServicesFactory = new SettingServicesFactory();
|
||||
}
|
||||
|
||||
self::$settingGateway = self::$settingServicesFactory->createSettingGateway();
|
||||
return self::$settingGateway;
|
||||
return self::resolveDependency(self::$settingGatewayResolver, SettingGateway::class, 'ApiBootstrap');
|
||||
}
|
||||
|
||||
private static function rateLimiter(): RateLimiterService
|
||||
{
|
||||
if (self::$rateLimiterService instanceof RateLimiterService) {
|
||||
return self::$rateLimiterService;
|
||||
return self::resolveDependency(self::$rateLimiterServiceResolver, RateLimiterService::class, 'ApiBootstrap');
|
||||
}
|
||||
|
||||
private static function apiAuditService(): ApiAuditService
|
||||
{
|
||||
return self::resolveDependency(self::$apiAuditServiceResolver, ApiAuditService::class, 'ApiBootstrap');
|
||||
}
|
||||
|
||||
private static function systemAuditReporter(): ApiSystemAuditReporter
|
||||
{
|
||||
return self::resolveDependency(self::$apiSystemAuditReporterResolver, ApiSystemAuditReporter::class, 'ApiBootstrap');
|
||||
}
|
||||
|
||||
private static function startSystemAuditReporter(): void
|
||||
{
|
||||
try {
|
||||
self::systemAuditReporter()->start();
|
||||
} catch (\Throwable) {
|
||||
// fail-open
|
||||
}
|
||||
}
|
||||
|
||||
private static function finishSystemAuditReporter(int $statusCode, ?string $errorCode = null): void
|
||||
{
|
||||
try {
|
||||
self::systemAuditReporter()->finish($statusCode, $errorCode);
|
||||
} catch (\Throwable) {
|
||||
// fail-open
|
||||
}
|
||||
}
|
||||
|
||||
private static function resolveDependency(mixed $resolver, string $expectedClass, string $consumer): mixed
|
||||
{
|
||||
if (!is_callable($resolver)) {
|
||||
throw new \RuntimeException($consumer . ' is not configured for dependency: ' . $expectedClass);
|
||||
}
|
||||
|
||||
if (!(self::$securityServicesFactory instanceof SecurityServicesFactory)) {
|
||||
self::$securityServicesFactory = new SecurityServicesFactory();
|
||||
$service = $resolver();
|
||||
if (!$service instanceof $expectedClass) {
|
||||
throw new \RuntimeException($consumer . ' resolver returned invalid dependency: ' . $expectedClass);
|
||||
}
|
||||
|
||||
self::$rateLimiterService = self::$securityServicesFactory->createRateLimiterService();
|
||||
return self::$rateLimiterService;
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user