mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 00:36:31 +02:00
feat: add renderer readiness signaling and update IPC channels for folder sync
This commit is contained in:
parent
1ef0d913e7
commit
5d6e3ffb7b
4 changed files with 48 additions and 20 deletions
|
|
@ -16,4 +16,5 @@ export const IPC_CHANNELS = {
|
|||
FOLDER_SYNC_WATCHER_READY: 'folder-sync:watcher-ready',
|
||||
FOLDER_SYNC_PAUSE: 'folder-sync:pause',
|
||||
FOLDER_SYNC_RESUME: 'folder-sync:resume',
|
||||
FOLDER_SYNC_RENDERER_READY: 'folder-sync:renderer-ready',
|
||||
} as const;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
getWatcherStatus,
|
||||
pauseWatcher,
|
||||
resumeWatcher,
|
||||
markRendererReady,
|
||||
} from '../modules/folder-watcher';
|
||||
|
||||
export function registerIpcHandlers(): void {
|
||||
|
|
@ -44,4 +45,8 @@ export function registerIpcHandlers(): void {
|
|||
ipcMain.handle(IPC_CHANNELS.FOLDER_SYNC_PAUSE, () => pauseWatcher());
|
||||
|
||||
ipcMain.handle(IPC_CHANNELS.FOLDER_SYNC_RESUME, () => resumeWatcher());
|
||||
|
||||
ipcMain.handle(IPC_CHANNELS.FOLDER_SYNC_RENDERER_READY, () => {
|
||||
markRendererReady();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export interface WatchedFolderConfig {
|
|||
name: string;
|
||||
excludePatterns: string[];
|
||||
fileExtensions: string[] | null;
|
||||
connectorId: number;
|
||||
rootFolderId: number | null;
|
||||
searchSpaceId: number;
|
||||
active: boolean;
|
||||
}
|
||||
|
|
@ -34,6 +34,25 @@ let watchers: Map<string, WatcherEntry> = new Map();
|
|||
*/
|
||||
const mtimeMaps: Map<string, MtimeMap> = new Map();
|
||||
|
||||
let rendererReady = false;
|
||||
const pendingEvents: any[] = [];
|
||||
|
||||
export function markRendererReady() {
|
||||
rendererReady = true;
|
||||
for (const event of pendingEvents) {
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, event);
|
||||
}
|
||||
pendingEvents.length = 0;
|
||||
}
|
||||
|
||||
function sendFileChangedEvent(data: any) {
|
||||
if (rendererReady) {
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, data);
|
||||
} else {
|
||||
pendingEvents.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
async function getStore() {
|
||||
if (!store) {
|
||||
const { default: Store } = await import('electron-store');
|
||||
|
|
@ -83,7 +102,6 @@ function walkFolderMtimes(config: WatchedFolderConfig): MtimeMap {
|
|||
for (const entry of entries) {
|
||||
const name = entry.name;
|
||||
|
||||
// Skip dotfiles/dotdirs and excluded names
|
||||
if (name.startsWith('.') || excludes.has(name)) continue;
|
||||
|
||||
const full = path.join(dir, name);
|
||||
|
|
@ -131,7 +149,6 @@ async function startWatcher(config: WatchedFolderConfig) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Load persisted mtime map into memory before starting the watcher
|
||||
const ms = await getMtimeStore();
|
||||
const storedMap: MtimeMap = ms.get(config.path) ?? {};
|
||||
mtimeMaps.set(config.path, { ...storedMap });
|
||||
|
|
@ -156,45 +173,49 @@ async function startWatcher(config: WatchedFolderConfig) {
|
|||
watcher.on('ready', () => {
|
||||
ready = true;
|
||||
|
||||
// Detect offline changes by diffing current filesystem against stored mtime map
|
||||
const currentMap = walkFolderMtimes(config);
|
||||
const storedSnapshot = loadMtimeMap(config.path);
|
||||
const now = Date.now();
|
||||
|
||||
// Track which files are unchanged so we can selectively update the mtime map
|
||||
const unchangedMap: MtimeMap = {};
|
||||
|
||||
for (const [rel, currentMtime] of Object.entries(currentMap)) {
|
||||
const storedMtime = storedSnapshot[rel];
|
||||
if (storedMtime === undefined) {
|
||||
// New file added while app was closed
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, {
|
||||
connectorId: config.connectorId,
|
||||
sendFileChangedEvent({
|
||||
rootFolderId: config.rootFolderId,
|
||||
searchSpaceId: config.searchSpaceId,
|
||||
folderPath: config.path,
|
||||
folderName: config.name,
|
||||
relativePath: rel,
|
||||
fullPath: path.join(config.path, rel),
|
||||
action: 'add',
|
||||
timestamp: now,
|
||||
});
|
||||
} else if (Math.abs(currentMtime - storedMtime) >= MTIME_TOLERANCE_S * 1000) {
|
||||
// File modified while app was closed
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, {
|
||||
connectorId: config.connectorId,
|
||||
sendFileChangedEvent({
|
||||
rootFolderId: config.rootFolderId,
|
||||
searchSpaceId: config.searchSpaceId,
|
||||
folderPath: config.path,
|
||||
folderName: config.name,
|
||||
relativePath: rel,
|
||||
fullPath: path.join(config.path, rel),
|
||||
action: 'change',
|
||||
timestamp: now,
|
||||
});
|
||||
} else {
|
||||
unchangedMap[rel] = currentMtime;
|
||||
}
|
||||
}
|
||||
|
||||
for (const rel of Object.keys(storedSnapshot)) {
|
||||
if (!(rel in currentMap)) {
|
||||
// File deleted while app was closed
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, {
|
||||
connectorId: config.connectorId,
|
||||
sendFileChangedEvent({
|
||||
rootFolderId: config.rootFolderId,
|
||||
searchSpaceId: config.searchSpaceId,
|
||||
folderPath: config.path,
|
||||
folderName: config.name,
|
||||
relativePath: rel,
|
||||
fullPath: path.join(config.path, rel),
|
||||
action: 'unlink',
|
||||
|
|
@ -203,12 +224,13 @@ async function startWatcher(config: WatchedFolderConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
// Replace stored map with current filesystem state
|
||||
mtimeMaps.set(config.path, currentMap);
|
||||
// Only update the mtime map for unchanged files; changed files keep their
|
||||
// stored mtime so they'll be re-detected if the app crashes before indexing.
|
||||
mtimeMaps.set(config.path, unchangedMap);
|
||||
persistMtimeMap(config.path);
|
||||
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_WATCHER_READY, {
|
||||
connectorId: config.connectorId,
|
||||
rootFolderId: config.rootFolderId,
|
||||
folderPath: config.path,
|
||||
});
|
||||
});
|
||||
|
|
@ -226,7 +248,6 @@ async function startWatcher(config: WatchedFolderConfig) {
|
|||
if (!config.fileExtensions.includes(ext)) return;
|
||||
}
|
||||
|
||||
// Keep mtime map in sync with live changes
|
||||
const map = mtimeMaps.get(config.path);
|
||||
if (map) {
|
||||
if (action === 'unlink') {
|
||||
|
|
@ -241,10 +262,11 @@ async function startWatcher(config: WatchedFolderConfig) {
|
|||
persistMtimeMap(config.path);
|
||||
}
|
||||
|
||||
sendToRenderer(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, {
|
||||
connectorId: config.connectorId,
|
||||
sendFileChangedEvent({
|
||||
rootFolderId: config.rootFolderId,
|
||||
searchSpaceId: config.searchSpaceId,
|
||||
folderPath: config.path,
|
||||
folderName: config.name,
|
||||
relativePath,
|
||||
fullPath: filePath,
|
||||
action,
|
||||
|
|
@ -311,7 +333,6 @@ export async function removeWatchedFolder(
|
|||
|
||||
stopWatcher(folderPath);
|
||||
|
||||
// Clean up persisted mtime map for this folder
|
||||
mtimeMaps.delete(folderPath);
|
||||
const ms = await getMtimeStore();
|
||||
ms.delete(folderPath);
|
||||
|
|
|
|||
|
|
@ -44,4 +44,5 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
},
|
||||
pauseWatcher: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_PAUSE),
|
||||
resumeWatcher: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_RESUME),
|
||||
signalRendererReady: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_RENDERER_READY),
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue