mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 23:59:45 +08:00
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:
parent
bca1a3f15a
commit
0534585fa9
@ -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') {
|
||||||
|
|||||||
@ -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])
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user