This commit is contained in:
Your Name
2026-09-09 15:47:48 +08:00
parent bd5d5c5f08
commit cb10e75ead
98 changed files with 7031 additions and 804 deletions
@@ -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'],
];
}
}