<# .SYNOPSIS JingTian rclone Sync Script .DESCRIPTION Syncs the local BenjaminTeam folder with the remote Ubuntu server. - Main folders: One-way sync (Windows -> Server) - _LLM_Sync folder: Bidirectional sync .PARAMETER LocalPath Path to the local BenjaminTeam folder. .PARAMETER RclonePath Path to rclone.exe. Default: auto-detect .PARAMETER LogDir Directory for log files. Default: %LOCALAPPDATA%\JingTian\logs .PARAMETER Verbose Show detailed output during sync. #> param( [string]$LocalPath = "", [string]$RclonePath = "", [string]$LogDir = "$env:LOCALAPPDATA\JingTian\logs", [switch]$VerboseOutput ) # Configuration $RemoteName = "jingtian-server" $RemotePath = "/data/jingtian/BenjaminTeam" $LLMSyncFolder = "_LLM_Sync" # Find rclone if not specified if (-not $RclonePath -or -not (Test-Path $RclonePath)) { $possiblePaths = @( "$env:LOCALAPPDATA\rclone\rclone.exe", "C:\rclone\rclone.exe", "rclone.exe" ) foreach ($path in $possiblePaths) { if (Test-Path $path) { $RclonePath = $path break } } } if (-not (Test-Path $RclonePath)) { Write-Error "rclone not found. Please run setup.ps1 first." exit 1 } # Find LocalPath if not specified (check common locations) if (-not $LocalPath -or -not (Test-Path $LocalPath)) { $searchPaths = @( "$env:USERPROFILE\Documents\BenjaminTeam", "$env:USERPROFILE\Documents\Benjamin Team", "D:\BenjaminTeam", "C:\BenjaminTeam" ) foreach ($path in $searchPaths) { if (Test-Path $path) { $LocalPath = $path break } } } if (-not (Test-Path $LocalPath)) { Write-Error "BenjaminTeam folder not found. Please specify -LocalPath" exit 1 } # Setup logging $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" $logFile = Join-Path $LogDir "sync.log" $detailLogFile = Join-Path $LogDir "sync_$timestamp.log" if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null } function Write-Log { param([string]$Message, [string]$Level = "INFO") $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logLine = "[$ts] [$Level] $Message" Add-Content -Path $logFile -Value $logLine if ($VerboseOutput) { switch ($Level) { "ERROR" { Write-Host $logLine -ForegroundColor Red } "WARN" { Write-Host $logLine -ForegroundColor Yellow } "OK" { Write-Host $logLine -ForegroundColor Green } default { Write-Host $logLine } } } } # ============================================================ # MAIN SYNC LOGIC # ============================================================ Write-Log "========== Sync Started ==========" Write-Log "Local: $LocalPath" Write-Log "Remote: ${RemoteName}:${RemotePath}" $syncErrors = @() $startTime = Get-Date # ------------------------------------------------------------ # Phase 1: One-way sync (Windows -> Server) for main folders # Excludes _LLM_Sync which is handled separately # ------------------------------------------------------------ Write-Log "Phase 1: Syncing main folders (Windows -> Server)..." $rcloneArgs = @( "sync", $LocalPath, "${RemoteName}:${RemotePath}", "--exclude", "$LLMSyncFolder/**", "--transfers", "4", "--checkers", "8", "--contimeout", "60s", "--timeout", "300s", "--retries", "3", "--low-level-retries", "10", "--stats", "1m", "--stats-one-line", "--log-file", $detailLogFile, "--log-level", "INFO" ) if ($VerboseOutput) { $rcloneArgs += "--progress" } try { $result = & $RclonePath @rcloneArgs 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "Phase 1 complete: Main folders synced successfully" "OK" } else { Write-Log "Phase 1 warning: rclone exited with code $LASTEXITCODE" "WARN" $syncErrors += "Main folder sync had warnings (exit code: $LASTEXITCODE)" } } catch { Write-Log "Phase 1 error: $_" "ERROR" $syncErrors += "Main folder sync failed: $_" } # ------------------------------------------------------------ # Phase 2: Bidirectional sync for _LLM_Sync folder # Uses rclone bisync for true bidirectional sync # ------------------------------------------------------------ Write-Log "Phase 2: Syncing _LLM_Sync folder (bidirectional)..." $llmLocalPath = Join-Path $LocalPath $LLMSyncFolder $llmRemotePath = "${RemoteName}:${RemotePath}/${LLMSyncFolder}" # Ensure local _LLM_Sync exists if (-not (Test-Path $llmLocalPath)) { New-Item -ItemType Directory -Path $llmLocalPath -Force | Out-Null Write-Log "Created local _LLM_Sync folder" } # Check if bisync has been initialized (look for .rclone-bisync directory) $bisyncStateDir = "$env:USERPROFILE\.cache\rclone\bisync" $bisyncStateFile = Join-Path $bisyncStateDir "*.lst" # For first run, we need to use --resync to initialize $needsResync = $false if (-not (Test-Path $bisyncStateDir) -or -not (Get-ChildItem $bisyncStateFile -ErrorAction SilentlyContinue)) { Write-Log "First bisync run detected, will initialize with --resync" $needsResync = $true } $bisyncArgs = @( "bisync", $llmLocalPath, $llmRemotePath, "--transfers", "4", "--checkers", "8", "--contimeout", "60s", "--timeout", "300s", "--retries", "3", "--log-file", $detailLogFile, "--log-level", "INFO" ) if ($needsResync) { $bisyncArgs += "--resync" $bisyncArgs += "--resync-mode", "newer" } if ($VerboseOutput) { $bisyncArgs += "--progress" } try { $result = & $RclonePath @bisyncArgs 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "Phase 2 complete: _LLM_Sync folder synced successfully" "OK" } else { # bisync can return non-zero for various reasons, check output Write-Log "Phase 2 warning: bisync exited with code $LASTEXITCODE" "WARN" $syncErrors += "_LLM_Sync bisync had warnings (exit code: $LASTEXITCODE)" } } catch { Write-Log "Phase 2 error: $_" "ERROR" $syncErrors += "_LLM_Sync sync failed: $_" } # ------------------------------------------------------------ # Summary # ------------------------------------------------------------ $endTime = Get-Date $duration = $endTime - $startTime Write-Log "========== Sync Completed ==========" Write-Log "Duration: $($duration.TotalSeconds.ToString('F1')) seconds" if ($syncErrors.Count -gt 0) { Write-Log "Completed with $($syncErrors.Count) warning(s):" "WARN" foreach ($err in $syncErrors) { Write-Log " - $err" "WARN" } exit 1 } else { Write-Log "All syncs completed successfully" "OK" exit 0 }