Files
PrivyDrop/frontend/lib/transfer/StateManager.ts
T
2025-09-13 20:01:02 +08:00

188 lines
4.5 KiB
TypeScript

import { PeerState, CustomFile, FolderMeta } from "@/types/webrtc";
// Simplified version no longer depends on TransferConfig's complex configuration
/**
* 🚀 State management class
* Centrally manages all transfer-related state data
*/
export class StateManager {
private peerStates = new Map<string, PeerState>();
private pendingFiles = new Map<string, CustomFile>();
private pendingFolderMeta: Record<string, FolderMeta> = {};
// ===== Peer state management =====
/**
* Get or create peer state
*/
public getPeerState(peerId: string): PeerState {
if (!this.peerStates.has(peerId)) {
this.peerStates.set(peerId, {
isSending: false,
bufferQueue: [],
readOffset: 0,
isReading: false,
currentFolderName: "",
totalBytesSent: {},
progressCallback: null,
});
}
return this.peerStates.get(peerId)!;
}
/**
* Update peer state
*/
public updatePeerState(peerId: string, updates: Partial<PeerState>): void {
const currentState = this.getPeerState(peerId);
Object.assign(currentState, updates);
}
/**
* Reset peer state (when transfer is complete or error occurs)
*/
public resetPeerState(peerId: string): void {
const peerState = this.getPeerState(peerId);
peerState.isSending = false;
peerState.readOffset = 0;
peerState.bufferQueue = [];
peerState.isReading = false;
// Preserve currentFolderName, totalBytesSent, progressCallback
}
/**
* Clear peer state immediately (for graceful disconnect)
*/
public clearPeerState(peerId: string): void {
this.peerStates.delete(peerId);
}
// ===== File management =====
/**
* Add pending file to send
*/
public addPendingFile(fileId: string, file: CustomFile): void {
this.pendingFiles.set(fileId, file);
}
/**
* Get pending file to send
*/
public getPendingFile(fileId: string): CustomFile | undefined {
return this.pendingFiles.get(fileId);
}
/**
* Remove pending file to send
*/
public removePendingFile(fileId: string): void {
this.pendingFiles.delete(fileId);
}
/**
* Get all pending files to send
*/
public getAllPendingFiles(): Map<string, CustomFile> {
return new Map(this.pendingFiles);
}
// ===== Folder metadata management =====
/**
* Add or update folder metadata
*/
public addFileToFolder(
folderName: string,
fileId: string,
fileSize: number
): void {
if (!this.pendingFolderMeta[folderName]) {
this.pendingFolderMeta[folderName] = { totalSize: 0, fileIds: [] };
}
const folderMeta = this.pendingFolderMeta[folderName];
if (!folderMeta.fileIds.includes(fileId)) {
folderMeta.fileIds.push(fileId);
folderMeta.totalSize += fileSize;
}
}
/**
* Get folder metadata
*/
public getFolderMeta(folderName: string): FolderMeta | undefined {
return this.pendingFolderMeta[folderName];
}
/**
* Get all folder metadata
*/
public getAllFolderMeta(): Record<string, FolderMeta> {
return { ...this.pendingFolderMeta };
}
// ===== Progress tracking related state =====
/**
* Update file sent bytes
*/
public updateFileBytesSent(
peerId: string,
fileId: string,
bytes: number
): void {
const peerState = this.getPeerState(peerId);
if (!peerState.totalBytesSent[fileId]) {
peerState.totalBytesSent[fileId] = 0;
}
peerState.totalBytesSent[fileId] += bytes;
}
/**
* Get file sent bytes
*/
public getFileBytesSent(peerId: string, fileId: string): number {
const peerState = this.peerStates.get(peerId);
return peerState?.totalBytesSent[fileId] || 0;
}
/**
* Calculate folder total sent bytes
*/
public getFolderBytesSent(peerId: string, folderName: string): number {
const folderMeta = this.getFolderMeta(folderName);
const peerState = this.peerStates.get(peerId);
if (!folderMeta || !peerState) return 0;
let totalSent = 0;
folderMeta.fileIds.forEach((fileId) => {
totalSent += peerState.totalBytesSent[fileId] || 0;
});
return totalSent;
}
// ===== Cleanup and reset =====
/**
* Clean up all states (when system resets)
*/
public cleanup(): void {
this.peerStates.clear();
this.pendingFiles.clear();
this.pendingFolderMeta = {};
}
/**
* Get state statistics (for debugging)
*/
public getStateStats() {
return {
peerCount: this.peerStates.size,
pendingFileCount: this.pendingFiles.size,
folderCount: Object.keys(this.pendingFolderMeta).length,
};
}
}