Remove outdated edge gateway object classes, add new agent implementation
Transitioned from obsolete gateway object classes (`edge_gateway_shell_action_jobs_o`, `edge_gateway_shell_events_o`, `edge_gateway_shell_sessions_o`, `edge_gateway_update_jobs_o`) to the new agent implementation (`edge-gateway-agent/agent.php`).
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace classes;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class order_bookings_counts_cache
|
||||
{
|
||||
public const PREFIX = 'order_bookings:counts:v1:';
|
||||
|
||||
/**
|
||||
* Optional runtime adapter for tests.
|
||||
*/
|
||||
private static ?object $adapter = null;
|
||||
|
||||
public static function setAdapterForTests(?object $adapter): void
|
||||
{
|
||||
self::$adapter = $adapter;
|
||||
}
|
||||
|
||||
public static function getTtl(): int
|
||||
{
|
||||
$raw = getenv('ORDER_BOOKINGS_COUNTS_CACHE_TTL');
|
||||
if ($raw === false || trim((string)$raw) === '') {
|
||||
return 30;
|
||||
}
|
||||
|
||||
return max(0, (int)$raw);
|
||||
}
|
||||
|
||||
public static function buildKey(array $context): string
|
||||
{
|
||||
$normalized = self::normalizeValue($context);
|
||||
$encoded = json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($encoded)) {
|
||||
$encoded = serialize($normalized);
|
||||
}
|
||||
|
||||
return self::PREFIX . md5($encoded);
|
||||
}
|
||||
|
||||
public static function getCounts(string $key): ?array
|
||||
{
|
||||
$raw = self::redisGet($key);
|
||||
if ($raw === null || $raw === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$decoded = json_decode($raw, true);
|
||||
if (!is_array($decoded)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::normalizeCounts($decoded);
|
||||
}
|
||||
|
||||
public static function storeCounts(string $key, array $counts, ?int $ttl = null): void
|
||||
{
|
||||
$cacheTtl = $ttl ?? self::getTtl();
|
||||
if ($cacheTtl <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$normalized = self::normalizeCounts($counts);
|
||||
if ($normalized === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$encoded = json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($encoded)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::redisSetEx($key, $encoded, $cacheTtl);
|
||||
}
|
||||
|
||||
public static function clearAll(): void
|
||||
{
|
||||
self::clearPattern(self::PREFIX . '*');
|
||||
}
|
||||
|
||||
private static function normalizeCounts(array $counts): ?array
|
||||
{
|
||||
if (!array_key_exists('past', $counts) || !array_key_exists('current', $counts) || !array_key_exists('future', $counts)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'past' => max(0, (int)$counts['past']),
|
||||
'current' => max(0, (int)$counts['current']),
|
||||
'future' => max(0, (int)$counts['future']),
|
||||
];
|
||||
}
|
||||
|
||||
private static function normalizeValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return self::normalizeScalar($value);
|
||||
}
|
||||
|
||||
$normalized = array_map([self::class, 'normalizeValue'], $value);
|
||||
|
||||
if (array_is_list($normalized)) {
|
||||
if (self::isScalarList($normalized)) {
|
||||
sort($normalized);
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
ksort($normalized);
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private static function normalizeScalar(mixed $value): mixed
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (preg_match('/^-?\d+$/', $value) === 1) {
|
||||
return (int)$value;
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return (float)$value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private static function isScalarList(array $value): bool
|
||||
{
|
||||
foreach ($value as $item) {
|
||||
if (is_array($item) || is_object($item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function clearPattern(string $pattern): void
|
||||
{
|
||||
try {
|
||||
$client = self::redisClient();
|
||||
if ($client === null) {
|
||||
return;
|
||||
}
|
||||
$client->clear_keys($pattern);
|
||||
} catch (Throwable) {
|
||||
// Cache invalidation must never break request flow.
|
||||
}
|
||||
}
|
||||
|
||||
private static function redisSetEx(string $key, string $value, int $ttl): void
|
||||
{
|
||||
try {
|
||||
$client = self::redisClient();
|
||||
if ($client === null) {
|
||||
return;
|
||||
}
|
||||
$client->setEx($key, $value, $ttl);
|
||||
} catch (Throwable) {
|
||||
// Best-effort cache write.
|
||||
}
|
||||
}
|
||||
|
||||
private static function redisGet(string $key): ?string
|
||||
{
|
||||
try {
|
||||
$client = self::redisClient();
|
||||
if ($client === null) {
|
||||
return null;
|
||||
}
|
||||
$value = $client->get($key);
|
||||
return is_string($value) ? $value : null;
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static function redisClient(): ?object
|
||||
{
|
||||
if (self::$adapter !== null) {
|
||||
return self::$adapter;
|
||||
}
|
||||
|
||||
try {
|
||||
if (defined('redis')) {
|
||||
$instance = constant('redis');
|
||||
if (is_object($instance)) {
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
return (new redis())->connect();
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user