feat: add Windows sync script

- Phase 1: One-way sync (Windows -> Server) for main folders
- Phase 2: Bidirectional sync using rclone bisync for _LLM_Sync
- Auto-detects rclone and BenjaminTeam folder paths
- Comprehensive logging to %LOCALAPPDATA%\JingTian\logs
- Supports verbose output with -VerboseOutput flag
This commit is contained in:
2026-02-13 11:17:19 +00:00
parent 45f2c42ea2
commit 157599be4a

235
windows/sync.ps1 Normal file
View File

@@ -0,0 +1,235 @@
<#
.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
}