Files
fossbilling-mailgateway/NotificationCooldown.php
T

48 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Box\Mod\Mailgateway;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
class NotificationCooldown
{
private int $seconds;
public function __construct(private Connection $connection, ?int $seconds = null)
{
$this->seconds = $seconds ?? RuntimeConfig::get('notification_cooldown_seconds');
}
/** Atomically reserve a sender's notification slot and queue the email. */
public function run(string $sender, callable $queue): bool
{
$key = hash('sha256', strtolower(trim($sender)));
$now = time();
return $this->connection->transactional(function () use ($key, $now, $queue): bool {
try {
$this->connection->insert('mailgateway_notification', ['sender_key' => $key, 'last_notified_at' => 0]);
} catch (UniqueConstraintViolationException) {
// Existing sender; the conditional update decides who owns the slot.
}
$claimed = $this->connection->executeStatement(
'UPDATE mailgateway_notification SET last_notified_at = ? WHERE sender_key = ? AND last_notified_at <= ?',
[$now, $key, $now - $this->seconds],
);
if ($claimed !== 1) {
return false;
}
if ($queue() === false) {
// Disabled templates do not consume the sender's notification slot.
$this->connection->delete('mailgateway_notification', ['sender_key' => $key]);
return false;
}
return true;
});
}
}