summaryrefslogtreecommitdiff
path: root/src/main/fileSyncBridge.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/fileSyncBridge.ts')
-rw-r--r--src/main/fileSyncBridge.ts32
1 files changed, 21 insertions, 11 deletions
diff --git a/src/main/fileSyncBridge.ts b/src/main/fileSyncBridge.ts
index ae22eb8..08bf69e 100644
--- a/src/main/fileSyncBridge.ts
+++ b/src/main/fileSyncBridge.ts
@@ -10,7 +10,7 @@ import { createHash } from 'crypto'
import * as chokidar from 'chokidar'
import { diff_match_patch } from 'diff-match-patch'
import { net } from 'electron'
-import type { BrowserWindow } from 'electron'
+import type { WebContents } from 'electron'
import type { OverleafSocket } from './overleafSocket'
import { OtClient } from './otClient'
import type { OtOp } from './otTypes'
@@ -87,7 +87,7 @@ export class FileSyncBridge {
private pathFileRefMap: Record<string, string> // relPath → fileRefId
private folderPathMap: Record<string, string> // folderId → relDirPath (no trailing slash)
private pathFolderMap: Record<string, string> // relDirPath (no trailing slash) → folderId
- private mainWindow: BrowserWindow
+ private target: WebContents // the owning tab's webContents
private projectId: string
private cookie: string
private csrfToken: string
@@ -103,7 +103,7 @@ export class FileSyncBridge {
docPathMap: Record<string, string>,
pathDocMap: Record<string, string>,
fileRefs: Array<{ id: string; path: string }>,
- mainWindow: BrowserWindow,
+ target: WebContents,
projectId: string,
cookie: string,
csrfToken: string,
@@ -114,7 +114,7 @@ export class FileSyncBridge {
this.tmpDir = tmpDir
this.docPathMap = docPathMap
this.pathDocMap = pathDocMap
- this.mainWindow = mainWindow
+ this.target = target
this.projectId = projectId
this.cookie = cookie
this.csrfToken = csrfToken
@@ -818,7 +818,7 @@ export class FileSyncBridge {
// lastKnownContent go stale or we'll re-detect the same "change" indefinitely.
this.lastKnownContent.set(relPath, newContent)
bridgeLog(`[FileSyncBridge] → sending sync:externalEdit to renderer for ${relPath}`)
- this.mainWindow.webContents.send('sync:externalEdit', { docId, content: newContent, baseContent: lastKnown ?? '' })
+ this.sendToWindow('sync:externalEdit', { docId, content: newContent, baseContent: lastKnown ?? '' })
} else {
// Doc NOT open in editor → bridge handles OT directly
const oldContent = lastKnown ?? ''
@@ -1168,7 +1168,7 @@ export class FileSyncBridge {
name: string,
parentFolderId?: string
): void {
- this.mainWindow.webContents.send('sync:entityCreated', {
+ this.sendToWindow('sync:entityCreated', {
kind,
entityId,
relPath,
@@ -1178,7 +1178,7 @@ export class FileSyncBridge {
}
private notifyEntityRemoved(kind: 'doc' | 'file' | 'folder', entityId: string, relPath: string): void {
- this.mainWindow.webContents.send('sync:entityRemoved', { kind, entityId, relPath })
+ this.sendToWindow('sync:entityRemoved', { kind, entityId, relPath })
}
private notifyEntityRenamed(
@@ -1188,7 +1188,7 @@ export class FileSyncBridge {
newPath: string,
newName: string
): void {
- this.mainWindow.webContents.send('sync:entityRenamed', {
+ this.sendToWindow('sync:entityRenamed', {
kind,
entityId,
oldPath,
@@ -1204,7 +1204,7 @@ export class FileSyncBridge {
newPath: string,
parentFolderId: string
): void {
- this.mainWindow.webContents.send('sync:entityMoved', {
+ this.sendToWindow('sync:entityMoved', {
kind,
entityId,
oldPath,
@@ -1584,8 +1584,18 @@ export class FileSyncBridge {
}
private notifySyncStatus(relPath: string, status: 'retrying' | 'synced' | 'failed', attempts?: number): void {
- if (this.mainWindow.isDestroyed() || this.mainWindow.webContents.isDestroyed()) return
- this.mainWindow.webContents.send('sync:fileStatus', { relPath, status, attempts })
+ this.sendToWindow('sync:fileStatus', { relPath, status, attempts })
+ }
+
+ /**
+ * Send to the owning tab, guarded — the bridge can outlive its webContents
+ * briefly (a debounced disk change firing during tab close), and an
+ * unguarded send to destroyed webContents throws inside an unawaited async
+ * path, which would take down the whole main process.
+ */
+ private sendToWindow(channel: string, payload: unknown): void {
+ if (this.target.isDestroyed()) return
+ this.target.send(channel, payload)
}
/** Create a text doc on Overleaf and sync its content */