fix: retry failed file transfers on next sync using pending queue in osurg_initials
This commit is contained in:
parent
4a85e07804
commit
0e16ea6052
|
|
@ -118,15 +118,15 @@ public function sync(): array
|
||||||
} else {
|
} else {
|
||||||
$report[] = 'هشدار: peer_cursor پیش نرفت — برخی تغییرات دریافتی اعمال نشد و دفعه بعد retry میشه.';
|
$report[] = 'هشدار: peer_cursor پیش نرفت — برخی تغییرات دریافتی اعمال نشد و دفعه بعد retry میشه.';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->isFtpConfigured()) {
|
if ($this->isFtpConfigured()) {
|
||||||
$this->transferFilesViaFtp($peerChanges, 's2c', $report);
|
$this->transferFilesViaFtp($peerChanges ?? [], 's2c', $report);
|
||||||
} else {
|
} else {
|
||||||
$this->syncFilesViaHttp($peerChanges, $baseUrl, $report);
|
$this->syncFilesViaHttp($peerChanges ?? [], $baseUrl, $report);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$report[] = count($peerChanges) . ' تغییر از سیستم مقابل دریافت شد.';
|
$report[] = count($peerChanges ?? []) . ' تغییر از سیستم مقابل دریافت شد.';
|
||||||
} else {
|
} else {
|
||||||
$report[] = 'خطا در دریافت تغییرات از سیستم مقابل: ' . $pullResponse->status();
|
$report[] = 'خطا در دریافت تغییرات از سیستم مقابل: ' . $pullResponse->status();
|
||||||
}
|
}
|
||||||
|
|
@ -196,20 +196,9 @@ public function applyChanges(array $changes): array
|
||||||
|
|
||||||
private function transferFilesViaFtp(array $changes, string $side, array &$report): void
|
private function transferFilesViaFtp(array $changes, string $side, array &$report): void
|
||||||
{
|
{
|
||||||
if (empty($changes)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$ftp = $this->connectFtp();
|
|
||||||
if (! $ftp) {
|
|
||||||
$report[] = 'خطا در اتصال FTP به سیستم مقابل';
|
|
||||||
Log::error('FTP connection failed in transferFilesViaFtp');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
||||||
$localBase = rtrim(Storage::disk('public')->path(''), '/\\');
|
|
||||||
$remoteBase = rtrim($this->ftpRemotePath, '/\\');
|
|
||||||
|
|
||||||
|
$currentPaths = [];
|
||||||
foreach ($changes as $change) {
|
foreach ($changes as $change) {
|
||||||
$data = $change['changed_data'] ?? [];
|
$data = $change['changed_data'] ?? [];
|
||||||
foreach ($fileFields as $field) {
|
foreach ($fileFields as $field) {
|
||||||
|
|
@ -218,19 +207,39 @@ private function transferFilesViaFtp(array $changes, string $side, array &$repor
|
||||||
}
|
}
|
||||||
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
||||||
foreach ($files as $filePath) {
|
foreach ($files as $filePath) {
|
||||||
if (! $filePath) {
|
if ($filePath) {
|
||||||
continue;
|
$currentPaths[] = ltrim(str_replace('\\', '/', $filePath), '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$filePath = ltrim(str_replace('\\', '/', $filePath), '/');
|
$pendingPaths = $this->getPendingFiles($side);
|
||||||
|
$allPaths = array_values(array_unique(array_merge($pendingPaths, $currentPaths)));
|
||||||
|
|
||||||
|
if (empty($allPaths)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ftp = $this->connectFtp();
|
||||||
|
if (! $ftp) {
|
||||||
|
$report[] = 'خطا در اتصال FTP به سیستم مقابل';
|
||||||
|
Log::error('FTP connection failed in transferFilesViaFtp');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$localBase = rtrim(Storage::disk('public')->path(''), '/\\');
|
||||||
|
$remoteBase = rtrim($this->ftpRemotePath, '/\\');
|
||||||
|
$failedPaths = [];
|
||||||
|
|
||||||
|
foreach ($allPaths as $filePath) {
|
||||||
$localFile = $localBase . '/' . $filePath;
|
$localFile = $localBase . '/' . $filePath;
|
||||||
$remoteFile = $remoteBase . '/' . $filePath;
|
$remoteFile = $remoteBase . '/' . $filePath;
|
||||||
$remoteFolder = dirname($remoteFile);
|
$remoteFolder = dirname($remoteFile);
|
||||||
|
|
||||||
if ($side === 'c2s') {
|
if ($side === 'c2s') {
|
||||||
if (! file_exists($localFile)) {
|
if (! file_exists($localFile)) {
|
||||||
$errorMsg = "فایل [{$filePath}] در سیستم محلی یافت نشد";
|
$report[] = "فایل [{$filePath}] در سیستم محلی یافت نشد ✗";
|
||||||
$report[] = $errorMsg . ' ✗';
|
|
||||||
Log::warning('FTP upload skipped - local file not found', [
|
Log::warning('FTP upload skipped - local file not found', [
|
||||||
'file' => $filePath,
|
'file' => $filePath,
|
||||||
'local_path' => $localFile,
|
'local_path' => $localFile,
|
||||||
|
|
@ -239,40 +248,31 @@ private function transferFilesViaFtp(array $changes, string $side, array &$repor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->createFtpDirectory($ftp, $remoteFolder)) {
|
if (! $this->createFtpDirectory($ftp, $remoteFolder)) {
|
||||||
$errorMsg = "ایجاد پوشه [{$remoteFolder}] برای فایل [{$filePath}] شکست خورد";
|
$report[] = "ایجاد پوشه [{$remoteFolder}] برای فایل [{$filePath}] شکست خورد ✗";
|
||||||
$report[] = $errorMsg . ' ✗';
|
Log::error('FTP mkdir failed', ['file' => $filePath, 'remote_folder' => $remoteFolder]);
|
||||||
Log::error('FTP mkdir failed', [
|
$failedPaths[] = $filePath;
|
||||||
'file' => $filePath,
|
|
||||||
'remote_folder' => $remoteFolder,
|
|
||||||
]);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftp_put($ftp, $remoteFile, $localFile, FTP_BINARY)) {
|
if (ftp_put($ftp, $remoteFile, $localFile, FTP_BINARY)) {
|
||||||
$report[] = "فایل [{$filePath}] ارسال شد (FTP) ✓";
|
$report[] = "فایل [{$filePath}] ارسال شد (FTP) ✓";
|
||||||
Log::info('FTP file uploaded', [
|
Log::info('FTP file uploaded', ['file' => $filePath, 'size' => filesize($localFile)]);
|
||||||
'file' => $filePath,
|
|
||||||
'size' => filesize($localFile),
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
$errorDetail = error_get_last();
|
$errorDetail = error_get_last();
|
||||||
$errorMsg = "فایل [{$filePath}] ارسال نشد (FTP)";
|
$errorMsg = "فایل [{$filePath}] ارسال نشد (FTP)";
|
||||||
if ($errorDetail) {
|
if ($errorDetail) {
|
||||||
$errorMsg .= " - " . $errorDetail['message'];
|
$errorMsg .= ' - ' . $errorDetail['message'];
|
||||||
}
|
}
|
||||||
$report[] = $errorMsg . ' ✗';
|
$report[] = $errorMsg . ' ✗';
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
Log::error('FTP upload failed', [
|
Log::error('FTP upload failed', [
|
||||||
'file' => $filePath,
|
'file' => $filePath, 'local_file' => $localFile,
|
||||||
'local_file' => $localFile,
|
'remote_file' => $remoteFile, 'error' => $errorDetail,
|
||||||
'remote_file' => $remoteFile,
|
|
||||||
'error' => $errorDetail,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (file_exists($localFile)) {
|
if (file_exists($localFile)) {
|
||||||
Log::debug('FTP download skipped - file already exists', [
|
Log::debug('FTP download skipped - file already exists', ['file' => $filePath]);
|
||||||
'file' => $filePath,
|
|
||||||
]);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,37 +280,34 @@ private function transferFilesViaFtp(array $changes, string $side, array &$repor
|
||||||
if (! is_dir($localFolder)) {
|
if (! is_dir($localFolder)) {
|
||||||
if (! mkdir($localFolder, 0755, true)) {
|
if (! mkdir($localFolder, 0755, true)) {
|
||||||
$report[] = "ایجاد پوشه [{$localFolder}] شکست خورد ✗";
|
$report[] = "ایجاد پوشه [{$localFolder}] شکست خورد ✗";
|
||||||
Log::error('Local mkdir failed', [
|
$failedPaths[] = $filePath;
|
||||||
'folder' => $localFolder,
|
Log::error('Local mkdir failed', ['folder' => $localFolder, 'error' => error_get_last()]);
|
||||||
'error' => error_get_last(),
|
|
||||||
]);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftp_get($ftp, $localFile, $remoteFile, FTP_BINARY)) {
|
if (ftp_get($ftp, $localFile, $remoteFile, FTP_BINARY)) {
|
||||||
$report[] = "فایل [{$filePath}] دریافت شد (FTP) ✓";
|
$report[] = "فایل [{$filePath}] دریافت شد (FTP) ✓";
|
||||||
Log::info('FTP file downloaded', [
|
Log::info('FTP file downloaded', ['file' => $filePath, 'size' => filesize($localFile)]);
|
||||||
'file' => $filePath,
|
|
||||||
'size' => filesize($localFile),
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
$errorDetail = error_get_last();
|
$errorDetail = error_get_last();
|
||||||
$errorMsg = "فایل [{$filePath}] دریافت نشد (FTP)";
|
$errorMsg = "فایل [{$filePath}] دریافت نشد (FTP)";
|
||||||
if ($errorDetail) {
|
if ($errorDetail) {
|
||||||
$errorMsg .= " - " . $errorDetail['message'];
|
$errorMsg .= ' - ' . $errorDetail['message'];
|
||||||
}
|
}
|
||||||
$report[] = $errorMsg . ' ✗';
|
$report[] = $errorMsg . ' ✗';
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
Log::error('FTP download failed', [
|
Log::error('FTP download failed', [
|
||||||
'file' => $filePath,
|
'file' => $filePath, 'local_file' => $localFile,
|
||||||
'local_file' => $localFile,
|
'remote_file' => $remoteFile, 'error' => $errorDetail,
|
||||||
'remote_file' => $remoteFile,
|
|
||||||
'error' => $errorDetail,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$this->savePendingFiles($side, $failedPaths);
|
||||||
|
if (! empty($failedPaths)) {
|
||||||
|
$report[] = count($failedPaths) . ' فایل در صف retry دفعه بعد قرار گرفت.';
|
||||||
}
|
}
|
||||||
|
|
||||||
ftp_close($ftp);
|
ftp_close($ftp);
|
||||||
|
|
@ -391,6 +388,7 @@ private function pushFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
{
|
{
|
||||||
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
||||||
|
|
||||||
|
$currentPaths = [];
|
||||||
foreach ($changes as $change) {
|
foreach ($changes as $change) {
|
||||||
$data = $change['changed_data'] ?? [];
|
$data = $change['changed_data'] ?? [];
|
||||||
foreach ($fileFields as $field) {
|
foreach ($fileFields as $field) {
|
||||||
|
|
@ -399,7 +397,20 @@ private function pushFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
}
|
}
|
||||||
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
||||||
foreach ($files as $filePath) {
|
foreach ($files as $filePath) {
|
||||||
if (! $filePath || ! Storage::disk('public')->exists($filePath)) {
|
if ($filePath) {
|
||||||
|
$currentPaths[] = ltrim(str_replace('\\', '/', $filePath), '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pendingPaths = $this->getPendingFiles('c2s');
|
||||||
|
$allPaths = array_values(array_unique(array_merge($pendingPaths, $currentPaths)));
|
||||||
|
$failedPaths = [];
|
||||||
|
|
||||||
|
foreach ($allPaths as $filePath) {
|
||||||
|
if (! Storage::disk('public')->exists($filePath)) {
|
||||||
|
$report[] = "فایل [{$filePath}] در سیستم محلی یافت نشد ✗";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
@ -412,12 +423,17 @@ private function pushFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
$report[] = "فایل [{$filePath}] ارسال شد (HTTP) ✓";
|
$report[] = "فایل [{$filePath}] ارسال شد (HTTP) ✓";
|
||||||
} else {
|
} else {
|
||||||
$report[] = "فایل [{$filePath}] ارسال نشد (HTTP) ✗ " . $response->status();
|
$report[] = "فایل [{$filePath}] ارسال نشد (HTTP) ✗ " . $response->status();
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$report[] = "فایل [{$filePath}] ارسال نشد (HTTP) ✗ " . $e->getMessage();
|
$report[] = "فایل [{$filePath}] ارسال نشد (HTTP) ✗ " . $e->getMessage();
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$this->savePendingFiles('c2s', $failedPaths);
|
||||||
|
if (! empty($failedPaths)) {
|
||||||
|
$report[] = count($failedPaths) . ' فایل در صف retry دفعه بعد قرار گرفت.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,6 +441,7 @@ private function syncFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
{
|
{
|
||||||
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
$fileFields = ['photos_before', 'photos_after', 'videos', 'audio_files'];
|
||||||
|
|
||||||
|
$currentPaths = [];
|
||||||
foreach ($changes as $change) {
|
foreach ($changes as $change) {
|
||||||
$data = $change['changed_data'] ?? [];
|
$data = $change['changed_data'] ?? [];
|
||||||
foreach ($fileFields as $field) {
|
foreach ($fileFields as $field) {
|
||||||
|
|
@ -433,7 +450,19 @@ private function syncFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
}
|
}
|
||||||
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
$files = is_array($data[$field]) ? $data[$field] : json_decode($data[$field], true) ?? [];
|
||||||
foreach ($files as $filePath) {
|
foreach ($files as $filePath) {
|
||||||
if (! $filePath || Storage::disk('public')->exists($filePath)) {
|
if ($filePath) {
|
||||||
|
$currentPaths[] = ltrim(str_replace('\\', '/', $filePath), '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pendingPaths = $this->getPendingFiles('s2c');
|
||||||
|
$allPaths = array_values(array_unique(array_merge($pendingPaths, $currentPaths)));
|
||||||
|
$failedPaths = [];
|
||||||
|
|
||||||
|
foreach ($allPaths as $filePath) {
|
||||||
|
if (Storage::disk('public')->exists($filePath)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
@ -444,12 +473,19 @@ private function syncFilesViaHttp(array $changes, string $baseUrl, array &$repor
|
||||||
if ($response->successful()) {
|
if ($response->successful()) {
|
||||||
Storage::disk('public')->put($filePath, $response->body());
|
Storage::disk('public')->put($filePath, $response->body());
|
||||||
$report[] = "فایل [{$filePath}] دریافت شد (HTTP) ✓";
|
$report[] = "فایل [{$filePath}] دریافت شد (HTTP) ✓";
|
||||||
|
} else {
|
||||||
|
$report[] = "فایل [{$filePath}] دریافت نشد (HTTP) ✗ " . $response->status();
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$report[] = "فایل [{$filePath}] دریافت نشد (HTTP) ✗ " . $e->getMessage();
|
$report[] = "فایل [{$filePath}] دریافت نشد (HTTP) ✗ " . $e->getMessage();
|
||||||
|
$failedPaths[] = $filePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$this->savePendingFiles('s2c', $failedPaths);
|
||||||
|
if (! empty($failedPaths)) {
|
||||||
|
$report[] = count($failedPaths) . ' فایل در صف retry دفعه بعد قرار گرفت.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,6 +520,25 @@ private function applyChange(array $change, string $prefix, array &$report): voi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPendingFiles(string $direction): array
|
||||||
|
{
|
||||||
|
$record = \App\Models\OsurgInitial::where('init_parameter', "sync_pending_{$direction}")->first();
|
||||||
|
if (! $record || ! $record->attachment) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode($record->attachment, true) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function savePendingFiles(string $direction, array $files): void
|
||||||
|
{
|
||||||
|
$files = array_values(array_unique(array_filter($files)));
|
||||||
|
\App\Models\OsurgInitial::updateOrCreate(
|
||||||
|
['init_parameter' => "sync_pending_{$direction}"],
|
||||||
|
['attachment' => empty($files) ? null : json_encode($files, JSON_UNESCAPED_UNICODE)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function saveOurCursor(string $cursor): void
|
private function saveOurCursor(string $cursor): void
|
||||||
{
|
{
|
||||||
\App\Models\OsurgInitial::updateOrCreate(
|
\App\Models\OsurgInitial::updateOrCreate(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue