更新
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
/** 一次 HTTP 请求只拉一页;只有归档成功后才推进游标。 */
|
||||
final class ImChatSyncSession
|
||||
{
|
||||
public static function start(array $accounts): array
|
||||
{
|
||||
return [
|
||||
'accounts' => array_values(array_unique($accounts)),
|
||||
'index' => 0, 'side' => 0, 'cursor' => [], 'inserted' => 0, 'errors' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public static function step(array $state, callable $fetchPage, callable $archive): array
|
||||
{
|
||||
if ($state['index'] >= count($state['accounts'])) {
|
||||
return $state;
|
||||
}
|
||||
$account = $state['accounts'][$state['index']];
|
||||
try {
|
||||
$page = $fetchPage($account, $state['cursor']);
|
||||
} catch (\Throwable $e) {
|
||||
// 失败的会话不妨碍其他医生记录落库,下一轮仍从头补拉该会话。
|
||||
$state['errors'][] = $account . ($state['side'] === 0 ? '(医生侧)' : '(患者侧)') . ':' . $e->getMessage();
|
||||
return self::nextSide($state);
|
||||
}
|
||||
|
||||
// 落库异常交由调用者处理,绝不能把未归档的页标记为已同步。
|
||||
$state['inserted'] += $archive($account, $page['msgList']);
|
||||
if ($page['completed']) {
|
||||
$state = self::nextSide($state);
|
||||
} else {
|
||||
$state['cursor'] = $page['cursor'];
|
||||
}
|
||||
return $state;
|
||||
}
|
||||
|
||||
private static function nextSide(array $state): array
|
||||
{
|
||||
$state['cursor'] = [];
|
||||
if ($state['side'] === 0) {
|
||||
$state['side'] = 1;
|
||||
} else {
|
||||
$state['side'] = 0;
|
||||
$state['index']++;
|
||||
}
|
||||
return $state;
|
||||
}
|
||||
|
||||
public static function progress(array $state): array
|
||||
{
|
||||
$checking = array_key_exists('accounts_verified', $state) && !$state['accounts_verified'];
|
||||
$check = $state['account_check'] ?? null;
|
||||
$completed = !$checking && $state['index'] >= count($state['accounts']);
|
||||
return [
|
||||
'completed' => $completed,
|
||||
'phase' => $checking ? 'checking_accounts' : ($completed ? 'completed' : 'syncing'),
|
||||
'checked_accounts' => $check['offset'] ?? 0,
|
||||
'candidate_accounts' => $check ? count($check['candidates']) : 0,
|
||||
'skipped_accounts' => $check ? count($check['missing']) : 0,
|
||||
'inserted' => $state['inserted'],
|
||||
'processed_peers' => $state['index'],
|
||||
'total_peers' => count($state['accounts']),
|
||||
'errors' => $state['errors'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user