120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
import { ipcMain } from "electron";
|
|
import type {
|
|
ArtifactStoreLoadResult,
|
|
ArtifactStoreRemoveResult,
|
|
ArtifactStoreRepositoryPort,
|
|
ArtifactStoreSaveResult,
|
|
ReviewSampleListResult,
|
|
ReviewSamplePayload,
|
|
ReviewSamplesRepositoryPort,
|
|
} from "../repositories/contracts.js";
|
|
import type {
|
|
GoodDatabase,
|
|
LoadScannerLearningRulesResult,
|
|
SaveScannerLearningRulesResult,
|
|
ScannerLearningRulePayload,
|
|
SaveResultWithPath,
|
|
GoodImportFileResult,
|
|
} from "../../src/types/global.js";
|
|
import type { StoredArtifactRecord } from "../../src/types/storage.js";
|
|
|
|
type ArtifactStoreAccessor = () => ArtifactStoreRepositoryPort;
|
|
type ReviewSamplesAccessor = () => ReviewSamplesRepositoryPort;
|
|
|
|
interface PersistenceDependencies {
|
|
getArtifactStoreRepository: ArtifactStoreAccessor;
|
|
getReviewSamplesRepository: ReviewSamplesAccessor;
|
|
artifactStorePath: () => string;
|
|
reviewSamplesPath: () => string;
|
|
loadReviewSamples: (limit?: number) => Promise<ReviewSampleListResult>;
|
|
loadScannerLearningRules: () => Promise<LoadScannerLearningRulesResult>;
|
|
writeScannerLearningRules: (rules: ScannerLearningRulePayload) => Promise<SaveScannerLearningRulesResult>;
|
|
exportGood: (payload: GoodDatabase) => Promise<SaveResultWithPath>;
|
|
importGoodFile: () => Promise<GoodImportFileResult>;
|
|
}
|
|
|
|
export function registerPersistenceHandlers({
|
|
getArtifactStoreRepository,
|
|
getReviewSamplesRepository,
|
|
artifactStorePath,
|
|
reviewSamplesPath,
|
|
loadReviewSamples,
|
|
loadScannerLearningRules,
|
|
writeScannerLearningRules,
|
|
exportGood,
|
|
importGoodFile,
|
|
}: PersistenceDependencies) {
|
|
ipcMain.handle("review:saveSample", async (_event, sample: ReviewSamplePayload) => {
|
|
try {
|
|
return await getReviewSamplesRepository().append(sample);
|
|
} catch {
|
|
const filePath = reviewSamplesPath();
|
|
return { ok: false, path: filePath };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("review:loadSamples", async (_event, limit = 50) => {
|
|
return loadReviewSamples(Number(limit) || 50);
|
|
});
|
|
|
|
ipcMain.handle("scanner:loadLearningRules", async () => {
|
|
return loadScannerLearningRules();
|
|
});
|
|
|
|
ipcMain.handle("scanner:saveLearningRules", async (_event, rules: ScannerLearningRulePayload) => {
|
|
return writeScannerLearningRules(rules);
|
|
});
|
|
|
|
ipcMain.handle("artifacts:load", async () => {
|
|
try {
|
|
return (await getArtifactStoreRepository().loadAll()) as ArtifactStoreLoadResult;
|
|
} catch {
|
|
return { ok: false, artifacts: [], total: 0, path: artifactStorePath() };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("artifacts:saveMany", async (_event, records: StoredArtifactRecord[]) => {
|
|
try {
|
|
const safeRecords = Array.isArray(records) ? records : [];
|
|
return (await getArtifactStoreRepository().saveMany(safeRecords)) as ArtifactStoreSaveResult;
|
|
} catch {
|
|
return { ok: false, added: 0, updated: 0, total: 0, path: artifactStorePath() };
|
|
}
|
|
});
|
|
|
|
// Intentionally accepts one exact local Store id only. Native result/crop
|
|
// tombstones use their separate scanner workflow, and this handler never
|
|
// invokes the input helper or sends any action to Genshin.
|
|
ipcMain.handle("artifacts:removeOne", async (_event, id: unknown): Promise<ArtifactStoreRemoveResult> => {
|
|
const artifactId = typeof id === "string" ? id.trim() : "";
|
|
if (!artifactId) {
|
|
return {
|
|
ok: false,
|
|
removed: 0,
|
|
total: 0,
|
|
path: artifactStorePath(),
|
|
error: "A local artifact Store id is required.",
|
|
};
|
|
}
|
|
try {
|
|
return (await getArtifactStoreRepository().removeByIds([artifactId])) as ArtifactStoreRemoveResult;
|
|
} catch {
|
|
return {
|
|
ok: false,
|
|
removed: 0,
|
|
total: 0,
|
|
path: artifactStorePath(),
|
|
error: "The local artifact Store record could not be removed.",
|
|
};
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("good:export", async (_event, payload: GoodDatabase) => {
|
|
return exportGood(payload);
|
|
});
|
|
|
|
ipcMain.handle("good:importFile", async () => {
|
|
return importGoodFile();
|
|
});
|
|
}
|