fix: linting and compilation errors after file system IPC changes

This commit is contained in:
Johannes Millan 2025-11-28 14:39:14 +01:00
parent 6112467dbe
commit 1e826698aa
7 changed files with 77 additions and 22 deletions

View file

@ -49,6 +49,8 @@ export interface ElectronAPI {
fileSyncRemove(args: { filePath: string }): Promise<unknown | Error>;
fileSyncListFiles(args: { dirPath: string }): Promise<string[] | Error>; // NEW
checkDirExists(args: { dirPath: string }): Promise<true | Error>;
pickDirectory(): Promise<string | undefined>;

View file

@ -43,6 +43,7 @@ export enum IPC {
FILE_SYNC_LOAD = 'FILE_SYNC_LOAD',
FILE_SYNC_SAVE = 'FILE_SYNC_SAVE',
FILE_SYNC_REMOVE = 'FILE_SYNC_REMOVE',
FILE_SYNC_LIST_FILES = 'FILE_SYNC_LIST_FILES', // NEW
FILE_SYNC_GET_REV_AND_CLIENT_UPDATE = 'FILE_SYNC_GET_REV_AND_CLIENT_UPDATE',
CHECK_DIR_EXISTS = 'CHECK_DIR_EXISTS',

View file

@ -88,35 +88,61 @@ export class OperationLogSyncService {
return;
}
// TODO: Download manifest.json (as per plan Section 4.3.2)
// For now, assume a simple list of op files.
// This will need actual file listing and manifest handling.
// For MVP, just assume we can list "ops_*.json" files from remote.
// This will require an extension to the SyncProviderServiceInterface to list files.
// Or we will get manifest.json from existing sync service.
// Check if syncProvider supports listFiles
if (!syncProvider.listFiles) {
PFLog.warn(
'OperationLogSyncService: Active sync provider does not support listFiles. Skipping OL download.',
);
return;
}
// Placeholder: For now, we will skip manifest and just log.
PFLog.warn(
'OperationLogSyncService: Skipping manifest download. Actual implementation will need manifest.',
);
const OPS_DIR = 'ops/';
let remoteOpFileNames: string[] = [];
try {
remoteOpFileNames = await syncProvider.listFiles(OPS_DIR);
// Filter only relevant op files
remoteOpFileNames = remoteOpFileNames.filter(
(name) => name.startsWith('ops_') && name.endsWith('.json'),
);
} catch (e) {
PFLog.error('OperationLogSyncService: Failed to list remote operation files', e);
return;
}
if (remoteOpFileNames.length === 0) {
PFLog.normal('OperationLogSyncService: No remote operation files found.');
return;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const appliedOpIds = await this.opLogStore.getAppliedOpIds();
const appliedFrontierByEntity = await this.opLogStore.getEntityFrontier();
// Placeholder for fetching remote op files
// In a real scenario, this would involve downloading files referenced in the manifest.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const remoteOpFiles: string[] = []; // e.g., ['ops_clientX_123.json', 'ops_clientY_456.json']
const newOps: Operation[] = []; // Populated from downloaded remoteOpFiles
const allRemoteOps: Operation[] = [];
for (const filename of remoteOpFileNames) {
try {
const fileContent = await syncProvider.downloadFile(OPS_DIR + filename);
const chunk = JSON.parse(fileContent.dataStr) as OperationLogEntry[];
// Filter already applied ops from this chunk before adding to allRemoteOps
const newOpsInChunk = chunk.filter((entry) => !appliedOpIds.has(entry.op.id));
allRemoteOps.push(...newOpsInChunk.map((entry) => entry.op));
} catch (e) {
PFLog.error(
`OperationLogSyncService: Failed to download or parse remote op file ${filename}`,
e,
);
// Continue with next file
}
}
if (newOps.length === 0) {
PFLog.normal('OperationLogSyncService: No new remote operations to download.');
if (allRemoteOps.length === 0) {
PFLog.normal(
'OperationLogSyncService: No new remote operations to download after filtering.',
);
return;
}
const { nonConflicting, conflicts } = await this.detectConflicts(
newOps,
allRemoteOps,
appliedFrontierByEntity,
);
@ -128,13 +154,12 @@ export class OperationLogSyncService {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const action = convertOpToAction(op);
// Dispatching action will be handled by a dedicated apply service in Phase 3/4
// TODO: Dispatching action will be handled by a dedicated apply service in Phase 3/4
// For now, just logging
PFLog.verbose(
`OperationLogSyncService: Dispatching non-conflicting remote op: ${op.id}`,
);
// this.store.dispatch(action); // Actual dispatch happens here in a dedicated service
// Mark applied
await this.opLogStore.markApplied(op.id);
}

View file

@ -50,4 +50,10 @@ export class SafFileAdapter implements FileAdapter {
// SAF works with a selected folder, so we just check if we have permission
return await SafService.checkPermission(uri);
}
// TODO: implement for operation log sync
async listFiles?(dirPath: string): Promise<string[]> {
PFLog.warn('SafFileAdapter: listFiles is not yet implemented for Android SAF.');
throw new Error('SafFileAdapter: listFiles is not yet implemented.');
}
}

View file

@ -40,6 +40,16 @@ export class ElectronFileAdapter implements FileAdapter {
}
}
async listFiles(dirPath: string): Promise<string[]> {
const result = await this.ea.fileSyncListFiles({
dirPath,
});
if (result instanceof Error) {
throw result;
}
return result;
}
// async checkDirExists(dirPath: string): Promise<boolean> {
// try {
// const result = await this.ea.checkDirExists({

View file

@ -3,4 +3,5 @@ export interface FileAdapter {
writeFile(filePath: string, dataStr: string): Promise<void>;
deleteFile(filePath: string): Promise<void>;
checkDirExists?(dirPath: string): Promise<boolean>;
listFiles?(dirPath: string): Promise<string[]>; // NEW
}

View file

@ -24,7 +24,7 @@ export abstract class LocalFileSyncBase
readonly isUploadForcePossible: boolean = false;
readonly maxConcurrentRequests = 10;
// since we cannot guarantee the order of files, we need to mush all our data into a single file
readonly isLimitedToSingleFileSync = true;
// removed as operation log requires multiple files
public privateCfg!: SyncProviderPrivateCfgStore<SyncProviderId.LocalFile>;
@ -38,6 +38,16 @@ export abstract class LocalFileSyncBase
protected abstract getFilePath(targetPath: string): Promise<string>;
async listFiles(dirPath: string): Promise<string[]> {
PFLog.normal(`${LocalFileSyncBase.LB}.${this.listFiles.name}()`, { dirPath });
if (!this.fileAdapter.listFiles) {
throw new Error('FileAdapter does not support listFiles');
}
// Assume getFilePath can correctly interpret dirPath as a directory
const fullPath = await this.getFilePath(dirPath);
return this.fileAdapter.listFiles(fullPath);
}
async getFileRev(targetPath: string, localRev: string): Promise<{ rev: string }> {
PFLog.normal(`${LocalFileSyncBase.LB}.${this.getFileRev.name}`, {
targetPath,