feat(admin): 统一后台 API 资源鉴权并完善投注风控快照与回补

This commit is contained in:
2026-05-19 09:11:50 +08:00
parent 6ef41cee76
commit 4cf561cd57
26 changed files with 1079 additions and 36 deletions

View File

@@ -136,10 +136,10 @@ final class RiskPoolService
$pool = $this->firstOrMakePool($drawId, $number4d);
$key = $this->redisPoolKey($drawId, $number4d);
Redis::eval($this->initLua(), 1, $key, (int) $pool->total_cap_amount, (int) $pool->locked_amount);
Redis::eval($this->initLua(), 1, $key, (int) $pool->total_cap_amount, (int) $pool->locked_amount, (int) $pool->version);
$result = (int) Redis::eval($this->acquireLua(), 1, $key, $amount);
if ($result !== 1) {
$result = $this->normalizeLuaResult(Redis::eval($this->acquireLua(), 1, $key, $amount, (int) $pool->version));
if (($result['code'] ?? null) !== 'OK') {
throw new TicketOperationException('risk_sold_out', ErrorCode::RiskPoolSoldOut->value);
}
@@ -190,7 +190,7 @@ final class RiskPoolService
{
return <<<'LUA'
if redis.call('EXISTS', KEYS[1]) == 0 then
redis.call('HMSET', KEYS[1], 'total', ARGV[1], 'locked', ARGV[2], 'remaining', ARGV[1] - ARGV[2])
redis.call('HMSET', KEYS[1], 'total', ARGV[1], 'locked', ARGV[2], 'remaining', ARGV[1] - ARGV[2], 'version', ARGV[3])
end
return 1
LUA;
@@ -200,13 +200,25 @@ LUA;
{
return <<<'LUA'
local amount = tonumber(ARGV[1])
local expectedVersion = tonumber(ARGV[2])
if amount == nil or amount <= 0 then
return {'INVALID_ARGUMENT', 0, 0, 0}
end
if redis.call('EXISTS', KEYS[1]) == 0 then
return {'POOL_NOT_INITIALIZED', 0, 0, 0}
end
local version = tonumber(redis.call('HGET', KEYS[1], 'version') or '0')
if expectedVersion ~= nil and version ~= expectedVersion then
return {'VERSION_CONFLICT', tonumber(redis.call('HGET', KEYS[1], 'remaining') or '0'), tonumber(redis.call('HGET', KEYS[1], 'locked') or '0'), version}
end
local remaining = tonumber(redis.call('HGET', KEYS[1], 'remaining') or '0')
if remaining < amount then
return 0
return {'INSUFFICIENT_CAP', remaining, tonumber(redis.call('HGET', KEYS[1], 'locked') or '0'), version}
end
redis.call('HINCRBY', KEYS[1], 'locked', amount)
redis.call('HINCRBY', KEYS[1], 'remaining', -amount)
return 1
local locked = redis.call('HINCRBY', KEYS[1], 'locked', amount)
remaining = redis.call('HINCRBY', KEYS[1], 'remaining', -amount)
version = redis.call('HINCRBY', KEYS[1], 'version', 1)
return {'OK', remaining, locked, version}
LUA;
}
@@ -265,6 +277,28 @@ LUA;
}
}
/**
* @return array{code:string, remaining:int, locked:int, version:int}
*/
private function normalizeLuaResult(mixed $result): array
{
if (! is_array($result)) {
return [
'code' => (int) $result === 1 ? 'OK' : 'INSUFFICIENT_CAP',
'remaining' => 0,
'locked' => 0,
'version' => 0,
];
}
return [
'code' => (string) ($result[0] ?? 'INSUFFICIENT_CAP'),
'remaining' => (int) ($result[1] ?? 0),
'locked' => (int) ($result[2] ?? 0),
'version' => (int) ($result[3] ?? 0),
];
}
/**
* @param list<array{number_4d:string, amount:int}> $locks
*/