error("应用「Manticore Search」未安装"); return 1; } // 注册信号处理器(仅在支持pcntl扩展的环境下) if (extension_loaded('pcntl')) { pcntl_async_signals(true); pcntl_signal(SIGINT, [$this, 'handleSignal']); pcntl_signal(SIGTERM, [$this, 'handleSignal']); } // 检查锁,如果已被占用则退出 $lockInfo = $this->getLock(); if ($lockInfo) { $this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}"); return 1; } $this->setLock(); // 清除索引 if ($this->option('c')) { $this->info('清除索引...'); ManticoreKeyValue::clear(); ManticoreFile::clear(); $this->info("索引删除成功"); $this->releaseLock(); return 0; } $this->info('开始同步文件数据(MVA 方案:allowed_users 自动内联)...'); $this->syncFiles(); $this->info("\n同步完成"); $this->releaseLock(); return 0; } private function getLock(): ?array { $lockKey = md5($this->signature); return Cache::has($lockKey) ? Cache::get($lockKey) : null; } private function setLock(): void { $lockKey = md5($this->signature); Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800); } private function releaseLock(): void { $lockKey = md5($this->signature); Cache::forget($lockKey); } public function handleSignal(int $signal): void { $this->info("\n收到信号,将在当前批次完成后退出..."); $this->shouldStop = true; } /** * 同步文件数据 */ private function syncFiles(): void { $lastKey = "sync:manticoreFileLastId"; $isIncremental = $this->option('i'); $sleepSeconds = intval($this->option('sleep')); $batchSize = $this->option('batch'); $maxFileSize = ManticoreFile::getMaxFileSize(); $round = 0; do { $round++; $lastId = $isIncremental ? intval(ManticoreKeyValue::get($lastKey, 0)) : 0; if ($round === 1) { if ($lastId > 0) { $this->info("\n增量同步文件数据(从ID {$lastId} 开始)..."); } else { $this->info("\n全量同步文件数据..."); } } $count = File::where('id', '>', $lastId) ->where('type', '!=', 'folder') ->where('size', '<=', $maxFileSize) ->count(); if ($count === 0) { if ($round === 1) { $this->info("无待同步数据"); } break; } $this->info("[第 {$round} 轮] 待同步 {$count} 个文件"); $num = 0; $total = 0; do { if ($this->shouldStop) { break; } $files = File::where('id', '>', $lastId) ->where('type', '!=', 'folder') ->where('size', '<=', $maxFileSize) ->orderBy('id') ->limit($batchSize) ->get(); if ($files->isEmpty()) { break; } $num += count($files); $progress = $count > 0 ? round($num / $count * 100, 2) : 100; $this->info("{$num}/{$count} ({$progress}%) 文件ID {$files->first()->id} ~ {$files->last()->id}"); $this->setLock(); $syncCount = ManticoreFile::batchSync($files); $total += $syncCount; $lastId = $files->last()->id; ManticoreKeyValue::set($lastKey, $lastId); } while (count($files) == $batchSize && !$this->shouldStop); $this->info("[第 {$round} 轮] 完成,同步 {$total} 个,最后ID {$lastId}"); if ($isIncremental && !$this->shouldStop) { $newCount = File::where('id', '>', $lastId) ->where('type', '!=', 'folder') ->where('size', '<=', $maxFileSize) ->count(); if ($newCount > 0) { $this->info("发现 {$newCount} 个新文件,{$sleepSeconds} 秒后继续..."); sleep($sleepSeconds); continue; } } break; } while (!$this->shouldStop); $this->info("同步文件结束(共 {$round} 轮)- 最后ID: " . ManticoreKeyValue::get($lastKey, 0)); $this->info("已索引文件数量: " . ManticoreFile::getIndexedCount()); } }