diff --git a/src/locales/en.json b/src/locales/en.json index 31772db..d225959 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -46,6 +46,7 @@ "notice.sopExportExists": "{path} already exists. The path now points to it.", "notice.savedTo": "Saved to {folder}\nWant a different location? Settings → Vault Autopilot → Storage locations", "notice.portInUse": "Vault Autopilot: port {port} is already in use. Quit the program using it, or set the same new port in both the plugin settings and the extension settings.", + "notice.serverError": "Vault Autopilot: the local server on port {port} stopped. Toggle it off and on in settings to retry.", "notice.sectionExists": "\"{section}\" already exists — not overwritten. To redo it, delete that section first, then clip again.", "error.screenshotFolderNotConfigured": "Screenshots folder not configured: set it in Settings → Vault Autopilot → Storage locations → Screenshots folder.", "error.videoFolderNotConfigured": "Video notes folder or cover images folder not configured: set them in Settings → Vault Autopilot → Storage locations.", diff --git a/src/locales/zh.json b/src/locales/zh.json index 119da16..f738147 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -46,6 +46,7 @@ "notice.sopExportExists": "{path} 已存在,路径已指向它。", "notice.savedTo": "已存到 {folder}\n想换位置?设置 → Vault Autopilot → 存储位置", "notice.portInUse": "Vault Autopilot:端口 {port} 被占用。请关闭占用它的程序;或在插件设置和扩展设置两处改成同一个新端口。", + "notice.serverError": "Vault Autopilot:端口 {port} 上的本地服务已停止。请在设置里关闭再打开重试。", "notice.sectionExists": "「{section}」已存在,未覆盖。想重做请先删掉该小节再点。", "error.screenshotFolderNotConfigured": "截图文件夹未配置:请在 设置 → Vault Autopilot → 存储位置 → 截图文件夹 填写。", "error.videoFolderNotConfigured": "视频笔记文件夹或封面图片文件夹未配置:请在 设置 → Vault Autopilot → 存储位置 填写。", diff --git a/src/main.ts b/src/main.ts index 0f53b33..376833a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -64,9 +64,13 @@ export default class VaultAutopilotPlugin extends Plugin { } restartServer(): void { - this.server?.close(); + const start = () => { if (this.settings.httpServer.enabled) this.startServer(); }; + const old = this.server; this.server = null; - if (this.settings.httpServer.enabled) this.startServer(); + // Rebind only after the old socket has fully closed; starting on the same + // tick races the close and hits EADDRINUSE on the same port. + if (old) old.close(() => start()); + else start(); } private async ensureFolder(folderPath: string): Promise { @@ -179,9 +183,13 @@ export default class VaultAutopilotPlugin extends Plugin { this.manifest.version, ); this.server.on('error', (err: NodeJS.ErrnoException) => { - if (err.code === 'EADDRINUSE') { - new Notice(t('notice.portInUse', { port }), 10000); - } + // A failed listen leaves a dead server; drop the reference so /ping and + // clips report honestly and the next toggle/restart can rebind. + this.server = null; + new Notice( + err.code === 'EADDRINUSE' ? t('notice.portInUse', { port }) : t('notice.serverError', { port }), + 10000, + ); }); } }