File: /home/xedaptot/ai.naniguide.com/app/Library/InMemoryCreditTracker.php
<?php
namespace App\Library;
use App\Library\Exception\OutOfCredits;
use App\Library\Contracts\CreditTrackerInterface;
use Illuminate\Support\Facades\Cache;
use Exception;
class InMemoryCreditTracker implements CreditTrackerInterface
{
public const ZERO = 0;
public const UNLIMITED = -1;
protected $resourceKey;
protected ?string $description;
public function __construct(string $resourceKey, ?string $description = null)
{
$this->resourceKey = $resourceKey;
$this->description = $description;
}
public function getRemainingCredits()
{
$credits = Cache::get($this->resourceKey);
if (empty($credits)) {
return self::ZERO;
}
return (int)$credits;
}
public function test(): void
{
if ($this->getRemainingCredits() == self::ZERO) {
throw new OutOfCredits($this->description ? "Out of credits: {$this->description}" : 'Credits exceeded');
}
}
public function count(): void
{
with_cache_lock($this->resourceKey, function () {
$this->test();
$remainingCredits = $this->getRemainingCredits();
if ($remainingCredits != self::UNLIMITED) {
$remainingCredits -= 1;
Cache::put($this->resourceKey, $remainingCredits);
}
});
}
public function setCredits($amount)
{
if (!is_int($amount)) {
throw new Exception('Invalid value for CreditTracker credits. Try using "(int)$credit": '.$amount);
}
if ($amount < self::UNLIMITED) {
throw new Exception('Invalid value for CreditTracker credits (Integer >= -1): '.$amount);
}
Cache::put($this->resourceKey, $amount);
return $this;
}
public function rollback(): void
{
with_cache_lock($this->resourceKey, function () {
$remainingCredits = $this->getRemainingCredits();
if ($remainingCredits != self::UNLIMITED) {
$remainingCredits += 1;
Cache::put($this->resourceKey, $remainingCredits);
}
});
}
public function isUnlimited(): bool
{
return $this->getRemainingCredits() == self::UNLIMITED;
}
public function isZero()
{
return $this->getRemainingCredits() == self::ZERO;
}
public function topup($amount)
{
with_cache_lock($this->resourceKey, function () use ($amount) {
$remainingCredits = $this->getRemainingCredits();
if ($remainingCredits != self::UNLIMITED) {
$remainingCredits += $amount;
Cache::put($this->resourceKey, $remainingCredits);
} else {
throw new Exception('Cannot topup credits, already UNLIMITED');
}
});
}
}