forked from Goko/JingTian-Rclone
Compare commits
3 Commits
feature/wi
...
1101f188e8
| Author | SHA1 | Date | |
|---|---|---|---|
| 1101f188e8 | |||
| f79712e8bd | |||
| a145e82ffa |
@@ -1,25 +0,0 @@
|
|||||||
# JingTian rclone Configuration Template
|
|
||||||
#
|
|
||||||
# This file is auto-generated by setup.ps1
|
|
||||||
# Manual edits may be overwritten.
|
|
||||||
#
|
|
||||||
# Remote: SFTP connection to Ubuntu sync server
|
|
||||||
# Used for syncing BenjaminTeam folder
|
|
||||||
|
|
||||||
[jingtian-server]
|
|
||||||
type = sftp
|
|
||||||
host = {{SERVER_HOST}}
|
|
||||||
user = {{SERVER_USER}}
|
|
||||||
key_file = {{SSH_KEY_PATH}}
|
|
||||||
shell_type = unix
|
|
||||||
|
|
||||||
# Optional settings (uncomment to enable):
|
|
||||||
#
|
|
||||||
# # Limit bandwidth (in KiB/s)
|
|
||||||
# bwlimit = 10M
|
|
||||||
#
|
|
||||||
# # Use compression
|
|
||||||
# use_insecure_cipher = false
|
|
||||||
#
|
|
||||||
# # Connection timeout
|
|
||||||
# conn_timeout = 30s
|
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
# JingTian rclone Server Setup Script
|
# JingTian rclone Server Setup Script
|
||||||
# Run this on the Ubuntu VM that will receive synced files
|
# Run this on the Ubuntu VM that will receive synced files
|
||||||
#
|
#
|
||||||
# Usage: sudo bash setup.sh
|
# Usage: sudo bash setup.sh [PUBLIC_IP]
|
||||||
|
#
|
||||||
|
# If PUBLIC_IP is provided, it will be shown in the connection details.
|
||||||
|
# Otherwise, the script will try to detect it or use the first local IP.
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -13,6 +16,7 @@ DATA_DIR="/data/jingtian/BenjaminTeam"
|
|||||||
RCLONE_USER="rclone-sync"
|
RCLONE_USER="rclone-sync"
|
||||||
SSH_KEY_NAME="jingtian_rclone"
|
SSH_KEY_NAME="jingtian_rclone"
|
||||||
SSH_KEY_DIR="/home/$RCLONE_USER/.ssh"
|
SSH_KEY_DIR="/home/$RCLONE_USER/.ssh"
|
||||||
|
PUBLIC_IP="${1:-}"
|
||||||
|
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "JingTian rclone Server Setup"
|
echo "JingTian rclone Server Setup"
|
||||||
@@ -24,37 +28,9 @@ if [ "$EUID" -ne 0 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Step 1: Create data directory
|
# Step 1: Create dedicated user for rclone sync (FIRST, so we can set ownership correctly)
|
||||||
echo ""
|
echo ""
|
||||||
echo "[1/5] Creating data directory..."
|
echo "[1/5] Creating dedicated sync user: $RCLONE_USER..."
|
||||||
mkdir -p "$DATA_DIR"
|
|
||||||
mkdir -p "$DATA_DIR/_LLM_Sync"
|
|
||||||
|
|
||||||
# Create the same folder structure as client
|
|
||||||
mkdir -p "$DATA_DIR/Admin/E-Signature"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/General Matter"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/IPD e-filing"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/JT Logo"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/Letterhead"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/Matter Open"
|
|
||||||
mkdir -p "$DATA_DIR/Admin/Template"
|
|
||||||
mkdir -p "$DATA_DIR/BD&M/2025 GCP"
|
|
||||||
mkdir -p "$DATA_DIR/BD&M/HKPC"
|
|
||||||
mkdir -p "$DATA_DIR/BD&M/WKCDA WKProcure"
|
|
||||||
mkdir -p "$DATA_DIR/Billing/Draft Bills"
|
|
||||||
mkdir -p "$DATA_DIR/Billing/Invoice Templates"
|
|
||||||
mkdir -p "$DATA_DIR/Billing/Issued Bills"
|
|
||||||
mkdir -p "$DATA_DIR/Client"
|
|
||||||
mkdir -p "$DATA_DIR/Free Schedules/Price List"
|
|
||||||
mkdir -p "$DATA_DIR/Free Schedules/Emails"
|
|
||||||
mkdir -p "$DATA_DIR/IP"
|
|
||||||
mkdir -p "$DATA_DIR/Precedent"
|
|
||||||
|
|
||||||
echo " Created: $DATA_DIR"
|
|
||||||
|
|
||||||
# Step 2: Create dedicated user for rclone sync
|
|
||||||
echo ""
|
|
||||||
echo "[2/5] Creating dedicated sync user: $RCLONE_USER..."
|
|
||||||
if id "$RCLONE_USER" &>/dev/null; then
|
if id "$RCLONE_USER" &>/dev/null; then
|
||||||
echo " User $RCLONE_USER already exists, skipping..."
|
echo " User $RCLONE_USER already exists, skipping..."
|
||||||
else
|
else
|
||||||
@@ -62,10 +38,44 @@ else
|
|||||||
echo " Created user: $RCLONE_USER"
|
echo " Created user: $RCLONE_USER"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set ownership of data directory
|
# Step 2: Create data directory structure with correct ownership from the start
|
||||||
chown -R "$RCLONE_USER:$RCLONE_USER" "$DATA_DIR"
|
echo ""
|
||||||
chmod -R 755 "$DATA_DIR"
|
echo "[2/5] Creating data directory..."
|
||||||
echo " Set ownership of $DATA_DIR to $RCLONE_USER"
|
|
||||||
|
# Create parent directories with root, then hand off to rclone-sync
|
||||||
|
mkdir -p /data/jingtian
|
||||||
|
chown root:root /data
|
||||||
|
chown -R "$RCLONE_USER:$RCLONE_USER" /data/jingtian
|
||||||
|
|
||||||
|
# Create BenjaminTeam structure as rclone-sync user
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/_LLM_Sync"
|
||||||
|
|
||||||
|
# Create the same folder structure as client
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/E-Signature"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/General Matter"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/IPD e-filing"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/JT Logo"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/Letterhead"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/Matter Open"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Admin/Template"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/BD&M/2025 GCP"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/BD&M/HKPC"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/BD&M/WKCDA WKProcure"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Billing/Draft Bills"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Billing/Invoice Templates"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Billing/Issued Bills"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Client"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Free Schedules/Price List"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Free Schedules/Emails"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/IP"
|
||||||
|
sudo -u "$RCLONE_USER" mkdir -p "$DATA_DIR/Precedent"
|
||||||
|
|
||||||
|
echo " Created: $DATA_DIR"
|
||||||
|
|
||||||
|
# Verify ownership
|
||||||
|
echo " Verifying ownership..."
|
||||||
|
ls -la /data/jingtian/ | head -5
|
||||||
|
|
||||||
# Step 3: Generate SSH key pair for rclone
|
# Step 3: Generate SSH key pair for rclone
|
||||||
echo ""
|
echo ""
|
||||||
@@ -111,6 +121,12 @@ else
|
|||||||
echo " Installed: $(rclone version | head -1)"
|
echo " Installed: $(rclone version | head -1)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Determine the IP to show
|
||||||
|
if [ -z "$PUBLIC_IP" ]; then
|
||||||
|
# Try to get public IP, fall back to first local IP
|
||||||
|
PUBLIC_IP=$(curl -s --max-time 5 ifconfig.me 2>/dev/null || hostname -I | awk '{print $1}')
|
||||||
|
fi
|
||||||
|
|
||||||
# Print summary
|
# Print summary
|
||||||
echo ""
|
echo ""
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
@@ -134,7 +150,7 @@ echo "Save this key to: windows/rclone-key"
|
|||||||
echo "It will be used by Windows clients to connect."
|
echo "It will be used by Windows clients to connect."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Connection details for Windows rclone config:"
|
echo "Connection details for Windows rclone config:"
|
||||||
echo " Host: $(hostname -I | awk '{print $1}')"
|
echo " Host: $PUBLIC_IP"
|
||||||
echo " User: $RCLONE_USER"
|
echo " User: $RCLONE_USER"
|
||||||
echo " Path: $DATA_DIR"
|
echo " Path: $DATA_DIR"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
7
windows/rclone-key
Normal file
7
windows/rclone-key
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACBhGez4Yaqdq5kS2nLWDMje+Ay48G9pkTUgVHByrVrHOAAAAJjg45Xm4OOV
|
||||||
|
5gAAAAtzc2gtZWQyNTUxOQAAACBhGez4Yaqdq5kS2nLWDMje+Ay48G9pkTUgVHByrVrHOA
|
||||||
|
AAAEAw5C+98JLaNZakWuw88val82lV8ZgLzNLXcbh35aAVCWEZ7Phhqp2rmRLactYMyN74
|
||||||
|
DLjwb2mRNSBUcHKtWsc4AAAAFGppbmd0aWFuLXJjbG9uZS1zeW5jAQ==
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
#Requires -RunAsAdministrator
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
JingTian rclone Client Setup Script for Windows
|
|
||||||
|
|
||||||
.DESCRIPTION
|
|
||||||
This script sets up rclone sync on a Windows client machine to sync
|
|
||||||
the BenjaminTeam folder with the remote Ubuntu server.
|
|
||||||
|
|
||||||
.PARAMETER ServerHost
|
|
||||||
The IP address or hostname of the Ubuntu sync server.
|
|
||||||
Default: 20.240.140.78
|
|
||||||
|
|
||||||
.PARAMETER ServerUser
|
|
||||||
The SSH username on the Ubuntu server.
|
|
||||||
Default: rclone-sync
|
|
||||||
|
|
||||||
.PARAMETER ServerPath
|
|
||||||
The remote path on the Ubuntu server.
|
|
||||||
Default: /data/jingtian/BenjaminTeam
|
|
||||||
|
|
||||||
.PARAMETER LocalPath
|
|
||||||
The local BenjaminTeam folder path. If not specified, the script will
|
|
||||||
attempt to auto-detect or prompt the user.
|
|
||||||
|
|
||||||
.PARAMETER SyncInterval
|
|
||||||
Sync interval in minutes for the scheduled task.
|
|
||||||
Default: 5
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
.\setup.ps1
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
.\setup.ps1 -LocalPath "D:\Work\BenjaminTeam" -SyncInterval 10
|
|
||||||
#>
|
|
||||||
|
|
||||||
param(
|
|
||||||
[string]$ServerHost = "20.240.140.78",
|
|
||||||
[string]$ServerUser = "rclone-sync",
|
|
||||||
[string]$ServerPath = "/data/jingtian/BenjaminTeam",
|
|
||||||
[string]$LocalPath = "",
|
|
||||||
[int]$SyncInterval = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
||||||
$RcloneKeySource = Join-Path $ScriptDir "rclone-key"
|
|
||||||
$RcloneKeyDest = "$env:USERPROFILE\.ssh\jingtian_rclone"
|
|
||||||
$RcloneConfigDir = "$env:APPDATA\rclone"
|
|
||||||
$RcloneConfigFile = "$RcloneConfigDir\rclone.conf"
|
|
||||||
$SyncScriptPath = Join-Path $ScriptDir "sync.ps1"
|
|
||||||
$LogDir = "$env:LOCALAPPDATA\JingTian\logs"
|
|
||||||
|
|
||||||
# Styling
|
|
||||||
function Write-Header {
|
|
||||||
param([string]$Text)
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "===========================================" -ForegroundColor Cyan
|
|
||||||
Write-Host $Text -ForegroundColor Cyan
|
|
||||||
Write-Host "===========================================" -ForegroundColor Cyan
|
|
||||||
}
|
|
||||||
|
|
||||||
function Write-Step {
|
|
||||||
param([string]$Step, [string]$Text)
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "[$Step] $Text" -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
function Write-Success {
|
|
||||||
param([string]$Text)
|
|
||||||
Write-Host " [OK] $Text" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
function Write-Info {
|
|
||||||
param([string]$Text)
|
|
||||||
Write-Host " $Text" -ForegroundColor Gray
|
|
||||||
}
|
|
||||||
|
|
||||||
function Write-ErrorMsg {
|
|
||||||
param([string]$Text)
|
|
||||||
Write-Host " [ERROR] $Text" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# MAIN SCRIPT
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
Write-Header "JingTian rclone Client Setup"
|
|
||||||
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Server: $ServerHost" -ForegroundColor White
|
|
||||||
Write-Host "User: $ServerUser" -ForegroundColor White
|
|
||||||
Write-Host "Remote: $ServerPath" -ForegroundColor White
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 1: Check/Install Git
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "1/7" "Checking Git installation..."
|
|
||||||
|
|
||||||
$gitPath = "C:\Program Files\Git\bin\git.exe"
|
|
||||||
if (Test-Path $gitPath) {
|
|
||||||
$gitVersion = & $gitPath --version
|
|
||||||
Write-Success "Git already installed: $gitVersion"
|
|
||||||
} else {
|
|
||||||
Write-Info "Git not found. Installing..."
|
|
||||||
|
|
||||||
$gitInstaller = "$env:TEMP\git-installer.exe"
|
|
||||||
$gitUrl = "https://github.com/git-for-windows/git/releases/download/v2.43.0.windows.1/Git-2.43.0-64-bit.exe"
|
|
||||||
|
|
||||||
Write-Info "Downloading Git installer..."
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
Invoke-WebRequest -Uri $gitUrl -OutFile $gitInstaller
|
|
||||||
|
|
||||||
Write-Info "Installing Git (this may take a few minutes)..."
|
|
||||||
Start-Process -FilePath $gitInstaller -ArgumentList '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS=icons,ext\reg\shellhere,assoc,assoc_sh' -Wait
|
|
||||||
|
|
||||||
if (Test-Path $gitPath) {
|
|
||||||
Write-Success "Git installed successfully"
|
|
||||||
} else {
|
|
||||||
Write-ErrorMsg "Git installation failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 2: Check/Install rclone
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "2/7" "Checking rclone installation..."
|
|
||||||
|
|
||||||
$rclonePath = "$env:LOCALAPPDATA\rclone\rclone.exe"
|
|
||||||
$rclonePathAlt = "C:\rclone\rclone.exe"
|
|
||||||
|
|
||||||
if (Test-Path $rclonePath) {
|
|
||||||
$rcloneVersion = & $rclonePath version | Select-Object -First 1
|
|
||||||
Write-Success "rclone already installed: $rcloneVersion"
|
|
||||||
} elseif (Test-Path $rclonePathAlt) {
|
|
||||||
$rclonePath = $rclonePathAlt
|
|
||||||
$rcloneVersion = & $rclonePath version | Select-Object -First 1
|
|
||||||
Write-Success "rclone already installed: $rcloneVersion"
|
|
||||||
} else {
|
|
||||||
Write-Info "rclone not found. Installing..."
|
|
||||||
|
|
||||||
$rcloneZip = "$env:TEMP\rclone.zip"
|
|
||||||
$rcloneExtract = "$env:TEMP\rclone-extract"
|
|
||||||
$rcloneInstallDir = "$env:LOCALAPPDATA\rclone"
|
|
||||||
$rcloneUrl = "https://downloads.rclone.org/rclone-current-windows-amd64.zip"
|
|
||||||
|
|
||||||
Write-Info "Downloading rclone..."
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
Invoke-WebRequest -Uri $rcloneUrl -OutFile $rcloneZip
|
|
||||||
|
|
||||||
Write-Info "Extracting rclone..."
|
|
||||||
if (Test-Path $rcloneExtract) { Remove-Item -Recurse -Force $rcloneExtract }
|
|
||||||
Expand-Archive -Path $rcloneZip -DestinationPath $rcloneExtract
|
|
||||||
|
|
||||||
# Find the extracted folder (it has version in the name)
|
|
||||||
$extractedFolder = Get-ChildItem -Path $rcloneExtract -Directory | Select-Object -First 1
|
|
||||||
|
|
||||||
# Create install directory and copy rclone
|
|
||||||
if (-not (Test-Path $rcloneInstallDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $rcloneInstallDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
Copy-Item -Path "$($extractedFolder.FullName)\rclone.exe" -Destination $rclonePath -Force
|
|
||||||
|
|
||||||
# Clean up
|
|
||||||
Remove-Item -Recurse -Force $rcloneZip, $rcloneExtract
|
|
||||||
|
|
||||||
if (Test-Path $rclonePath) {
|
|
||||||
Write-Success "rclone installed to $rclonePath"
|
|
||||||
} else {
|
|
||||||
Write-ErrorMsg "rclone installation failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 3: Detect/Confirm BenjaminTeam folder
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "3/7" "Locating BenjaminTeam folder..."
|
|
||||||
|
|
||||||
if ($LocalPath -and (Test-Path $LocalPath)) {
|
|
||||||
Write-Success "Using specified path: $LocalPath"
|
|
||||||
} else {
|
|
||||||
# Common locations to search
|
|
||||||
$searchPaths = @(
|
|
||||||
"$env:USERPROFILE\Documents\BenjaminTeam",
|
|
||||||
"$env:USERPROFILE\Documents\Benjamin Team",
|
|
||||||
"D:\BenjaminTeam",
|
|
||||||
"D:\Benjamin Team",
|
|
||||||
"C:\BenjaminTeam",
|
|
||||||
"C:\Benjamin Team"
|
|
||||||
)
|
|
||||||
|
|
||||||
$foundPath = $null
|
|
||||||
foreach ($path in $searchPaths) {
|
|
||||||
if (Test-Path $path) {
|
|
||||||
$foundPath = $path
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($foundPath) {
|
|
||||||
Write-Info "Found BenjaminTeam folder at: $foundPath"
|
|
||||||
$confirm = Read-Host " Use this path? (Y/n)"
|
|
||||||
if ($confirm -eq "" -or $confirm -match "^[Yy]") {
|
|
||||||
$LocalPath = $foundPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not $LocalPath -or -not (Test-Path $LocalPath)) {
|
|
||||||
Write-Info "Could not auto-detect BenjaminTeam folder."
|
|
||||||
$LocalPath = Read-Host " Enter the full path to your BenjaminTeam folder"
|
|
||||||
|
|
||||||
if (-not (Test-Path $LocalPath)) {
|
|
||||||
Write-ErrorMsg "Path does not exist: $LocalPath"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Success "Using path: $LocalPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure _LLM_Sync folder exists
|
|
||||||
$llmSyncPath = Join-Path $LocalPath "_LLM_Sync"
|
|
||||||
if (-not (Test-Path $llmSyncPath)) {
|
|
||||||
New-Item -ItemType Directory -Path $llmSyncPath -Force | Out-Null
|
|
||||||
Write-Info "Created _LLM_Sync folder"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 4: Setup SSH key
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "4/7" "Setting up SSH key..."
|
|
||||||
|
|
||||||
# Create .ssh directory if it doesn't exist
|
|
||||||
$sshDir = "$env:USERPROFILE\.ssh"
|
|
||||||
if (-not (Test-Path $sshDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $sshDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
# Copy the SSH key
|
|
||||||
if (-not (Test-Path $RcloneKeySource)) {
|
|
||||||
Write-ErrorMsg "SSH key not found at: $RcloneKeySource"
|
|
||||||
Write-Info "Make sure the rclone-key file is in the same directory as this script."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Copy-Item -Path $RcloneKeySource -Destination $RcloneKeyDest -Force
|
|
||||||
Write-Success "SSH key copied to $RcloneKeyDest"
|
|
||||||
|
|
||||||
# Test SSH connection
|
|
||||||
Write-Info "Testing SSH connection to $ServerHost..."
|
|
||||||
$sshTest = & ssh -o StrictHostKeyChecking=accept-new -o BatchMode=yes -i $RcloneKeyDest "$ServerUser@$ServerHost" "echo 'SSH_OK'" 2>&1
|
|
||||||
|
|
||||||
if ($sshTest -match "SSH_OK") {
|
|
||||||
Write-Success "SSH connection successful"
|
|
||||||
} else {
|
|
||||||
Write-ErrorMsg "SSH connection failed: $sshTest"
|
|
||||||
Write-Info "Please check the server is running and the key is correct."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 5: Configure rclone
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "5/7" "Configuring rclone..."
|
|
||||||
|
|
||||||
# Create rclone config directory
|
|
||||||
if (-not (Test-Path $RcloneConfigDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $RcloneConfigDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate rclone config
|
|
||||||
$rcloneConfig = @"
|
|
||||||
[jingtian-server]
|
|
||||||
type = sftp
|
|
||||||
host = $ServerHost
|
|
||||||
user = $ServerUser
|
|
||||||
key_file = $RcloneKeyDest
|
|
||||||
shell_type = unix
|
|
||||||
"@
|
|
||||||
|
|
||||||
# Write config file
|
|
||||||
Set-Content -Path $RcloneConfigFile -Value $rcloneConfig -Encoding ASCII
|
|
||||||
Write-Success "rclone config written to $RcloneConfigFile"
|
|
||||||
|
|
||||||
# Test rclone connection
|
|
||||||
Write-Info "Testing rclone connection..."
|
|
||||||
$rcloneTest = & $rclonePath lsd "jingtian-server:$ServerPath" 2>&1
|
|
||||||
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Success "rclone connection successful"
|
|
||||||
Write-Info "Remote folders:"
|
|
||||||
$rcloneTest | ForEach-Object { Write-Info " $_" }
|
|
||||||
} else {
|
|
||||||
Write-ErrorMsg "rclone connection failed: $rcloneTest"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 6: Create log directory
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "6/7" "Setting up logging..."
|
|
||||||
|
|
||||||
if (-not (Test-Path $LogDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
Write-Success "Log directory: $LogDir"
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Step 7: Create Scheduled Task
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Step "7/7" "Creating scheduled sync task..."
|
|
||||||
|
|
||||||
$taskName = "JingTian-Sync"
|
|
||||||
$taskDescription = "Syncs BenjaminTeam folder with remote server every $SyncInterval minutes"
|
|
||||||
|
|
||||||
# Remove existing task if it exists
|
|
||||||
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
||||||
if ($existingTask) {
|
|
||||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
|
||||||
Write-Info "Removed existing scheduled task"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create the scheduled task
|
|
||||||
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$SyncScriptPath`" -LocalPath `"$LocalPath`" -RclonePath `"$rclonePath`" -LogDir `"$LogDir`""
|
|
||||||
|
|
||||||
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $SyncInterval) -RepetitionDuration (New-TimeSpan -Days 9999)
|
|
||||||
|
|
||||||
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest
|
|
||||||
|
|
||||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
|
|
||||||
|
|
||||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description $taskDescription | Out-Null
|
|
||||||
|
|
||||||
Write-Success "Scheduled task created: $taskName"
|
|
||||||
Write-Info "Sync will run every $SyncInterval minutes"
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Summary
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
Write-Header "Setup Complete!"
|
|
||||||
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Configuration Summary:" -ForegroundColor White
|
|
||||||
Write-Host " Local Path: $LocalPath" -ForegroundColor Gray
|
|
||||||
Write-Host " Remote: $ServerUser@$ServerHost`:$ServerPath" -ForegroundColor Gray
|
|
||||||
Write-Host " Sync Interval: Every $SyncInterval minutes" -ForegroundColor Gray
|
|
||||||
Write-Host " Log Directory: $LogDir" -ForegroundColor Gray
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Sync Behavior:" -ForegroundColor White
|
|
||||||
Write-Host " - Main folders: One-way sync (Windows -> Server)" -ForegroundColor Gray
|
|
||||||
Write-Host " - _LLM_Sync: Bidirectional sync" -ForegroundColor Gray
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "To manually trigger a sync, run:" -ForegroundColor White
|
|
||||||
Write-Host " .\sync.ps1" -ForegroundColor Cyan
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "To check sync logs:" -ForegroundColor White
|
|
||||||
Write-Host " Get-Content `"$LogDir\sync.log`" -Tail 50" -ForegroundColor Cyan
|
|
||||||
Write-Host ""
|
|
||||||
235
windows/sync.ps1
235
windows/sync.ps1
@@ -1,235 +0,0 @@
|
|||||||
<#
|
|
||||||
.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
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user