fix: improve screenshot service error handling and temp file management

- Use fileStorage.createTempFile for consistent temp file handling
- Add proper cleanup for temporary screenshot files
- Fix async cleanup method calls (void or await)
- Fix image load error handling in selection UI
- Remove unused os import

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
suyao 2025-12-15 03:25:18 +08:00
parent bca1a3f15a
commit 0534585fa9
No known key found for this signature in database
2 changed files with 26 additions and 20 deletions

View File

@ -33,6 +33,7 @@ export class ScreenshotService {
private selectionWindow: BrowserWindow | null = null private selectionWindow: BrowserWindow | null = null
private screenshotBuffer: Buffer | null = null private screenshotBuffer: Buffer | null = null
private screenshotData: string | null = null private screenshotData: string | null = null
private screenshotTempPath: string | null = null
private currentFileName: string | null = null private currentFileName: string | null = null
private selectionPromise: { private selectionPromise: {
resolve: (value: SelectionCaptureResult) => void resolve: (value: SelectionCaptureResult) => void
@ -59,7 +60,7 @@ export class ScreenshotService {
const buffer = await image.toPng() const buffer = await image.toPng()
const ext = '.png' const ext = '.png'
const tempFilePath = await fileStorage.createTempFile(undefined, fileName || `screenshot${ext}`) const tempFilePath = await fileStorage.createTempFile({} as any, fileName || `screenshot${ext}`)
await fs.promises.writeFile(tempFilePath, buffer) await fs.promises.writeFile(tempFilePath, buffer)
const stats = await fs.promises.stat(tempFilePath) const stats = await fs.promises.stat(tempFilePath)
@ -140,8 +141,8 @@ export class ScreenshotService {
}) })
// Clean up when closed // Clean up when closed
window.on('closed', () => { window.on('closed', async () => {
this.cleanupSelection() await this.cleanupSelection()
}) })
// Load the selection HTML // Load the selection HTML
@ -154,7 +155,7 @@ export class ScreenshotService {
return window return window
} }
private cleanupSelection() { private async cleanupSelection() {
if (this.selectionWindow && !this.selectionWindow.isDestroyed()) { if (this.selectionWindow && !this.selectionWindow.isDestroyed()) {
this.selectionWindow.destroy() this.selectionWindow.destroy()
} }
@ -163,6 +164,16 @@ export class ScreenshotService {
this.screenshotData = null this.screenshotData = null
this.currentFileName = null this.currentFileName = null
this.selectionPromise = null this.selectionPromise = null
// Clean up temporary file
if (this.screenshotTempPath) {
try {
await fs.promises.unlink(this.screenshotTempPath)
} catch (error) {
logger.warn('Failed to delete temporary screenshot file', error as Error)
}
this.screenshotTempPath = null
}
} }
public confirmSelection(selection: Rectangle): void { public confirmSelection(selection: Rectangle): void {
@ -178,7 +189,7 @@ export class ScreenshotService {
status: 'error', status: 'error',
message: 'Selection too small (minimum 10×10 pixels)' message: 'Selection too small (minimum 10×10 pixels)'
}) })
this.cleanupSelection() void this.cleanupSelection()
return return
} }
@ -197,7 +208,7 @@ export class ScreenshotService {
status: 'cancelled', status: 'cancelled',
message: 'User cancelled selection' message: 'User cancelled selection'
}) })
this.cleanupSelection() void this.cleanupSelection()
} }
private async processSelection(selection: Rectangle): Promise<void> { private async processSelection(selection: Rectangle): Promise<void> {
@ -245,7 +256,7 @@ export class ScreenshotService {
message: error instanceof Error ? error.message : 'Failed to process selection' message: error instanceof Error ? error.message : 'Failed to process selection'
}) })
} finally { } finally {
this.cleanupSelection() await this.cleanupSelection()
} }
} }
@ -286,12 +297,10 @@ export class ScreenshotService {
this.currentFileName = fileName this.currentFileName = fileName
// Write buffer to a temporary file and store the file URL for the renderer // Write buffer to a temporary file and store the file URL for the renderer
const os = await import('os'); const tempFilePath = await fileStorage.createTempFile({} as any, `screenshot-${uuidv4()}.png`)
const tempDir = os.tmpdir(); await fs.promises.writeFile(tempFilePath, buffer)
const tempFileName = `screenshot-${uuidv4()}.png`; this.screenshotTempPath = tempFilePath
const tempFilePath = path.join(tempDir, tempFileName); this.screenshotData = `file://${tempFilePath}`
await fs.promises.writeFile(tempFilePath, buffer);
this.screenshotData = `file://${tempFilePath}`;
// Create or show selection window // Create or show selection window
if (!this.selectionWindow || this.selectionWindow.isDestroyed()) { if (!this.selectionWindow || this.selectionWindow.isDestroyed()) {
@ -315,7 +324,7 @@ export class ScreenshotService {
}) })
} catch (error) { } catch (error) {
logger.error('Screenshot capture with selection failed', error as Error) logger.error('Screenshot capture with selection failed', error as Error)
this.cleanupSelection() await this.cleanupSelection()
// Check if it's a permission issue on macOS // Check if it's a permission issue on macOS
if (process.platform === 'darwin') { if (process.platform === 'darwin') {

View File

@ -64,12 +64,9 @@ const ScreenshotSelection = () => {
logger.info('Screenshot drawn on canvas') logger.info('Screenshot drawn on canvas')
} }
img.onerror = (e) => { img.onerror = (e) => {
logger.error('Failed to load screenshot image', { error: e, screenshotData }); logger.error('Failed to load screenshot image', { error: e })
// Optionally, notify the user or close the selection window gracefully // Close the selection window gracefully on image load error
// For example, close the window: window.api.screenshot.cancelSelection()
if (window.electron && window.electron.ipcRenderer) {
window.electron.ipcRenderer.send(IpcChannel.Screenshot_CloseSelectionWindow);
}
} }
img.src = screenshotData img.src = screenshotData
}, [screenshotData]) }, [screenshotData])