mirror of
https://github.com/kuaifan/dootask.git
synced 2026-10-29 22:10:42 +00:00
fix(push): 退出登录时系统配置模式的推送设备同步向 DooPush 解绑
users/logout 先按 token 哈希删除本地推送设备,App 随后的 remove 找不到记录而漏发解绑; 统一由 DeviceRegistry::forgetHash 清理并解绑,解绑请求超时缩短为 3 秒,不拖慢退出。
This commit is contained in:
parent
531129f48d
commit
a74778f77e
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\AppPush\DeviceRegistry;
|
||||
use App\Module\Base;
|
||||
use App\Module\Doo;
|
||||
use App\Module\Lock;
|
||||
@ -306,7 +307,7 @@ class UserDevice extends AbstractModel
|
||||
}
|
||||
if (isset($hash)) {
|
||||
Cache::forget(self::ck($hash));
|
||||
AppPushDevice::whereDeviceHash($hash)->delete();
|
||||
DeviceRegistry::forgetHash($hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,14 +47,20 @@ class DeviceRegistry
|
||||
return;
|
||||
}
|
||||
// 与 UserDevice::check()/forget() 共用 TOKEN MD5 算法,不依赖 token 解码。
|
||||
$channels = AppPushDevice::whereIn('channel', [AppPush::CHANNEL_SYSTEM, AppPush::CHANNEL_CUSTOM])
|
||||
->whereDeviceId($deviceId)->whereDeviceHash(md5($token))->pluck('channel')->all();
|
||||
if (!$channels) {
|
||||
return;
|
||||
}
|
||||
AppPushDevice::whereIn('channel', $channels)->whereDeviceId($deviceId)->whereDeviceHash(md5($token))->delete();
|
||||
if (in_array(AppPush::CHANNEL_SYSTEM, $channels, true)) {
|
||||
app(DooPushClient::class)->unbindDevice($deviceId);
|
||||
self::forgetHash(md5($token), $deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按登录 token 哈希清理推送设备(退出登录、踢下线等),系统配置的设备同时解除租户绑定
|
||||
*/
|
||||
public static function forgetHash(string $hash, ?string $deviceId = null): void
|
||||
{
|
||||
$query = AppPushDevice::whereIn('channel', [AppPush::CHANNEL_SYSTEM, AppPush::CHANNEL_CUSTOM])->whereDeviceHash($hash)
|
||||
->when($deviceId !== null, fn ($q) => $q->whereDeviceId($deviceId));
|
||||
$systemIds = (clone $query)->whereChannel(AppPush::CHANNEL_SYSTEM)->pluck('device_id')->all();
|
||||
$query->delete();
|
||||
foreach ($systemIds as $id) {
|
||||
app(DooPushClient::class)->unbindDevice($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,9 +154,10 @@ class DooPushClient
|
||||
try {
|
||||
$tenant = $this->tenant(false);
|
||||
if ($tenant) {
|
||||
// 在退出登录请求中同步执行:只请求一次且缩短超时,网络异常时不拖慢退出。
|
||||
$this->send('DELETE', $this->systemUrl('/tenant/devices/' . rawurlencode($deviceId)), [
|
||||
'Authorization' => 'Bearer ' . $tenant['tenant_secret'],
|
||||
], [], 0, 1);
|
||||
], [], 0, 1, 3);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
info('[DooPush] unbind failed: ' . $e->getMessage());
|
||||
@ -235,13 +236,13 @@ class DooPushClient
|
||||
/**
|
||||
* 发送请求,网络错误或 5xx 时最多重试2次;返回 [HTTP 状态码(网络失败为 0), 响应 JSON]
|
||||
*/
|
||||
private function send(string $method, string $url, array $headers, array $body, int $userid = 0, int $attempts = 3): array
|
||||
private function send(string $method, string $url, array $headers, array $body, int $userid = 0, int $attempts = 3, int $timeout = 10): array
|
||||
{
|
||||
$status = 0;
|
||||
$result = [];
|
||||
for ($attempt = 1; $attempt <= $attempts; $attempt++) {
|
||||
try {
|
||||
$response = $this->request($url, $headers, $body, $method);
|
||||
$response = $this->request($url, $headers, $body, $method, $timeout);
|
||||
$result = Base::json2array($response['data'] ?? '');
|
||||
$status = Base::isSuccess($response) ? (int)($response['msg'] ?? 0) : 0;
|
||||
if ($status >= 200 && $status < 300 && in_array($result['code'] ?? 0, [200, 201], true)) {
|
||||
@ -266,7 +267,7 @@ class DooPushClient
|
||||
return [$status >= 200 && $status < 300 ? 0 : $status, $result];
|
||||
}
|
||||
|
||||
protected function request(string $url, array $headers, array $body, string $method = 'POST'): array
|
||||
protected function request(string $url, array $headers, array $body, string $method = 'POST', int $timeout = 10): array
|
||||
{
|
||||
$post = $method === 'POST' ? json_encode($body, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR) : '';
|
||||
$options = [
|
||||
@ -276,6 +277,6 @@ class DooPushClient
|
||||
if ($method !== 'POST') {
|
||||
$options['CURLOPT_CUSTOMREQUEST'] = $method;
|
||||
}
|
||||
return Ihttp::ihttp_request($url, $post, array_merge($headers, $options), 10);
|
||||
return Ihttp::ihttp_request($url, $post, array_merge($headers, $options), $timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,6 +383,21 @@ class AppPushTest extends TestCase
|
||||
$this->assertSame('https://push.test/api/v1/apps/10/tenant/devices/77005', $client->requests[0]['url']);
|
||||
}
|
||||
|
||||
public function test_logout_forget_unbinds_system_devices(): void
|
||||
{
|
||||
$client = $this->systemMode('dp_ts_live');
|
||||
$token = 'logout-system-token';
|
||||
$this->device(910103, '77006', ['channel' => AppPush::CHANNEL_SYSTEM, 'device_hash' => md5($token)]);
|
||||
$this->device(910103, '96102', ['device_hash' => md5($token)]);
|
||||
UserDevice::forget($token);
|
||||
$this->assertFalse(AppPushDevice::whereDeviceHash(md5($token))->exists());
|
||||
// 仅系统配置的设备需要向 DooPush 解绑,自定义通道的设备只删本地记录。
|
||||
$this->assertCount(1, $client->requests);
|
||||
$this->assertSame('DELETE', $client->requests[0]['method']);
|
||||
$this->assertSame('https://push.test/api/v1/apps/10/tenant/devices/77006', $client->requests[0]['url']);
|
||||
$this->assertSame(3, $client->requests[0]['timeout']);
|
||||
}
|
||||
|
||||
public function test_close_mode_does_not_record_devices(): void
|
||||
{
|
||||
$this->settings(['doopush' => 'close']);
|
||||
@ -400,9 +415,9 @@ class RecordingDooPushClient extends DooPushClient
|
||||
|
||||
public function __construct(public array $responses = []) {}
|
||||
|
||||
protected function request(string $url, array $headers, array $body, string $method = 'POST'): array
|
||||
protected function request(string $url, array $headers, array $body, string $method = 'POST', int $timeout = 10): array
|
||||
{
|
||||
$this->requests[] = compact('url', 'headers', 'body', 'method');
|
||||
$this->requests[] = compact('url', 'headers', 'body', 'method', 'timeout');
|
||||
$response = array_shift($this->responses);
|
||||
if ($response instanceof \Throwable) {
|
||||
throw $response;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user