fix ignore file
This commit is contained in:
parent
76fc488d25
commit
91887ec63d
1 changed files with 162 additions and 0 deletions
162
src/utils/sync-progress.ts
Normal file
162
src/utils/sync-progress.ts
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
/**
|
||||
* Interface for sync progress state
|
||||
* Tracks the progress of batch sync operations
|
||||
*/
|
||||
export interface SyncProgressState {
|
||||
lastSyncedIndex: number;
|
||||
totalProfiles: number;
|
||||
startTime: number;
|
||||
lastUpdate: number;
|
||||
failedProfiles: Array<{ index: number; profileId: string; error: string }>;
|
||||
profileIds: string[]; // Track order of profile IDs for resume
|
||||
}
|
||||
|
||||
/**
|
||||
* SyncProgressManager
|
||||
* Manages persistent storage of sync progress state
|
||||
* Enables resuming from checkpoints after failures
|
||||
*/
|
||||
export class SyncProgressManager {
|
||||
private static readonly FILE_PATH = ".sync-progress.json";
|
||||
|
||||
/**
|
||||
* Save progress state to file
|
||||
* @param state - Current progress state to save
|
||||
*/
|
||||
static save(state: SyncProgressState): void {
|
||||
try {
|
||||
const filePath = path.resolve(process.cwd(), this.FILE_PATH);
|
||||
state.lastUpdate = Date.now();
|
||||
fs.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
|
||||
} catch (error) {
|
||||
console.error("[SyncProgressManager] Error saving progress:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load progress state from file
|
||||
* @returns Progress state if exists, null otherwise
|
||||
*/
|
||||
static load(): SyncProgressState | null {
|
||||
try {
|
||||
const filePath = path.resolve(process.cwd(), this.FILE_PATH);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = fs.readFileSync(filePath, "utf-8");
|
||||
const state = JSON.parse(data) as SyncProgressState;
|
||||
|
||||
// Validate required fields
|
||||
if (
|
||||
typeof state.lastSyncedIndex !== "number" ||
|
||||
typeof state.totalProfiles !== "number" ||
|
||||
!Array.isArray(state.failedProfiles) ||
|
||||
!Array.isArray(state.profileIds)
|
||||
) {
|
||||
console.warn("[SyncProgressManager] Invalid progress file, starting fresh");
|
||||
return null;
|
||||
}
|
||||
|
||||
return state;
|
||||
} catch (error) {
|
||||
console.error("[SyncProgressManager] Error loading progress:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear progress file
|
||||
* Called on successful completion or when starting fresh
|
||||
*/
|
||||
static clear(): void {
|
||||
try {
|
||||
const filePath = path.resolve(process.cwd(), this.FILE_PATH);
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
console.log("[SyncProgressManager] Progress file cleared");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[SyncProgressManager] Error clearing progress:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get progress percentage
|
||||
* @param state - Current progress state
|
||||
* @returns Percentage complete (0-100)
|
||||
*/
|
||||
static getProgressPercent(state: SyncProgressState): number {
|
||||
if (state.totalProfiles === 0) return 0;
|
||||
return Math.round((state.lastSyncedIndex / state.totalProfiles) * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format elapsed time as readable string
|
||||
* @param startTime - Start timestamp in milliseconds
|
||||
* @returns Formatted time string (e.g., "2h 30m 15s")
|
||||
*/
|
||||
static formatElapsedTime(startTime: number): string {
|
||||
const elapsed = Date.now() - startTime;
|
||||
const seconds = Math.floor(elapsed / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
|
||||
const parts: string[] = [];
|
||||
if (hours > 0) parts.push(`${hours}h`);
|
||||
if (minutes % 60 > 0) parts.push(`${minutes % 60}m`);
|
||||
if (seconds % 60 > 0 || parts.length === 0) parts.push(`${seconds % 60}s`);
|
||||
|
||||
return parts.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Log current progress to console
|
||||
* @param state - Current progress state
|
||||
*/
|
||||
static logProgress(state: SyncProgressState): void {
|
||||
const percent = this.getProgressPercent(state);
|
||||
const elapsed = this.formatElapsedTime(state.startTime);
|
||||
const failed = state.failedProfiles.length;
|
||||
|
||||
console.log(
|
||||
`[Sync Progress] ${percent}% (${state.lastSyncedIndex}/${state.totalProfiles}) | Elapsed: ${elapsed} | Failed: ${failed}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add failed profile to state
|
||||
* @param state - Progress state to update
|
||||
* @param index - Profile index
|
||||
* @param profileId - Profile ID that failed
|
||||
* @param error - Error message
|
||||
*/
|
||||
static addFailedProfile(
|
||||
state: SyncProgressState,
|
||||
index: number,
|
||||
profileId: string,
|
||||
error: string,
|
||||
): void {
|
||||
state.failedProfiles.push({ index, profileId, error });
|
||||
this.save(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize new progress state
|
||||
* @param profileIds - Array of profile IDs to sync
|
||||
* @returns New progress state
|
||||
*/
|
||||
static initialize(profileIds: string[]): SyncProgressState {
|
||||
return {
|
||||
lastSyncedIndex: 0,
|
||||
totalProfiles: profileIds.length,
|
||||
startTime: Date.now(),
|
||||
lastUpdate: Date.now(),
|
||||
failedProfiles: [],
|
||||
profileIds,
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue