90 lines
2.8 KiB
PHP
90 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Onboarding;
|
|
|
|
use App\Models\OnboardingSession;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class OnboardingLockService
|
|
{
|
|
public function acquire(OnboardingSession $session, User $user, int $ttlSeconds = 600): bool
|
|
{
|
|
return DB::transaction(function () use ($session, $user, $ttlSeconds): bool {
|
|
$session = OnboardingSession::query()->lockForUpdate()->findOrFail($session->getKey());
|
|
|
|
if ($this->isLockedByOther($session, $user)) {
|
|
return false;
|
|
}
|
|
|
|
$session->forceFill([
|
|
'locked_by_user_id' => $user->getKey(),
|
|
'locked_until' => Carbon::now()->addSeconds($ttlSeconds),
|
|
])->save();
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public function renew(OnboardingSession $session, User $user, int $ttlSeconds = 600): bool
|
|
{
|
|
return DB::transaction(function () use ($session, $user, $ttlSeconds): bool {
|
|
$session = OnboardingSession::query()->lockForUpdate()->findOrFail($session->getKey());
|
|
|
|
if ((int) $session->locked_by_user_id !== (int) $user->getKey()) {
|
|
return false;
|
|
}
|
|
|
|
$session->forceFill([
|
|
'locked_until' => Carbon::now()->addSeconds($ttlSeconds),
|
|
])->save();
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public function release(OnboardingSession $session, User $user): bool
|
|
{
|
|
return DB::transaction(function () use ($session, $user): bool {
|
|
$session = OnboardingSession::query()->lockForUpdate()->findOrFail($session->getKey());
|
|
|
|
if ((int) $session->locked_by_user_id !== (int) $user->getKey()) {
|
|
return false;
|
|
}
|
|
|
|
$session->forceFill([
|
|
'locked_by_user_id' => null,
|
|
'locked_until' => null,
|
|
])->save();
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public function takeover(OnboardingSession $session, User $newOwner, int $ttlSeconds = 600): void
|
|
{
|
|
DB::transaction(function () use ($session, $newOwner, $ttlSeconds): void {
|
|
$session = OnboardingSession::query()->lockForUpdate()->findOrFail($session->getKey());
|
|
|
|
$session->forceFill([
|
|
'locked_by_user_id' => $newOwner->getKey(),
|
|
'locked_until' => Carbon::now()->addSeconds($ttlSeconds),
|
|
])->save();
|
|
});
|
|
}
|
|
|
|
private function isLockedByOther(OnboardingSession $session, User $user): bool
|
|
{
|
|
if ($session->locked_by_user_id === null || $session->locked_until === null) {
|
|
return false;
|
|
}
|
|
|
|
if ($session->locked_until->isPast()) {
|
|
return false;
|
|
}
|
|
|
|
return (int) $session->locked_by_user_id !== (int) $user->getKey();
|
|
}
|
|
}
|