/** * SFTP IPC Handlers * 处理 SFTP 连接和文件操作相关 IPC */ import { ipcMain, IpcMainInvokeEvent } from 'electron' import type { SSHService } from '../services/ssh-service' // IPC channel names export const SFTP_CHANNELS = { CONNECT: 'sftp:connect', LIST_DIRECTORY: 'sftp:listDirectory', UPLOAD: 'sftp:upload', DOWNLOAD: 'sftp:download', RENAME: 'sftp:rename', DELETE: 'sftp:delete', MKDIR: 'sftp:mkdir', PROGRESS: 'sftp:progress', } as const export interface SFTPIPCOptions { sshService: SSHService mainWindowGetter: () => Electron.BrowserWindow | null } // ===== 彩色调试日志 ===== const DEBUG = true function logHeader(msg: string) { console.log(`%c${msg}`, 'background: #16a085; color: #fff; padding: 4px 8px; border-radius: 4px; font-weight: bold;') } function logInfo(label: string, value: any) { console.log(`%c${label}:%c ${value}`, 'background: #2c3e50; color: #fff; padding: 2px 6px; border-radius: 3px;', 'color: #1abc9c; font-weight: bold;') } function logSuccess(msg: string) { console.log(`%c✓ ${msg}`, 'color: #27ae60; font-weight: bold;') } function logError(msg: string) { console.log(`%c✗ ${msg}`, 'color: #e74c3c; font-weight: bold;') } export function registerSFTPIPCHandlers(options: SFTPIPCOptions): void { const { sshService, mainWindowGetter } = options // SFTP connect ipcMain.handle(SFTP_CHANNELS.CONNECT, async (_event: IpcMainInvokeEvent, connectionId: string) => { logHeader('📁 SFTP IPC CONNECT') logInfo('connectionId', connectionId) try { const sftp = await sshService.createSFTP(connectionId) logSuccess(`SFTP connected: ${sftp.id}`) return { success: true, sftpId: sftp.id } } catch (error: any) { logError(`SFTP connect failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP list directory ipcMain.handle(SFTP_CHANNELS.LIST_DIRECTORY, async (_event: IpcMainInvokeEvent, sftpId: string, dirPath: string) => { logHeader('📁 SFTP IPC LIST') logInfo('sftpId', sftpId) logInfo('dirPath', dirPath) try { const files = await sshService.sftpListDirectory(sftpId, dirPath) logSuccess(`Listed ${files.length} items`) return { success: true, files } } catch (error: any) { logError(`List failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP upload file ipcMain.handle(SFTP_CHANNELS.UPLOAD, async ( _event: IpcMainInvokeEvent, sftpId: string, localPath: string, remotePath: string ) => { logHeader('📤 SFTP IPC UPLOAD') logInfo('sftpId', sftpId) logInfo('localPath', localPath) logInfo('remotePath', remotePath) try { const mainWindow = mainWindowGetter() await sshService.sftpUpload(sftpId, localPath, remotePath, (transferred, total) => { mainWindow?.webContents.send(SFTP_CHANNELS.PROGRESS, sftpId, { transferred, total, percentage: Math.round((transferred / total) * 100), }) }) logSuccess('Upload complete') return { success: true } } catch (error: any) { logError(`Upload failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP download file ipcMain.handle(SFTP_CHANNELS.DOWNLOAD, async ( _event: IpcMainInvokeEvent, sftpId: string, remotePath: string, localPath: string ) => { logHeader('📥 SFTP IPC DOWNLOAD') logInfo('sftpId', sftpId) logInfo('remotePath', remotePath) logInfo('localPath', localPath) try { const mainWindow = mainWindowGetter() await sshService.sftpDownload(sftpId, remotePath, localPath, (transferred, total) => { mainWindow?.webContents.send(SFTP_CHANNELS.PROGRESS, sftpId, { transferred, total, percentage: Math.round((transferred / total) * 100), }) }) logSuccess('Download complete') return { success: true } } catch (error: any) { logError(`Download failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP rename ipcMain.handle(SFTP_CHANNELS.RENAME, async ( _event: IpcMainInvokeEvent, sftpId: string, oldPath: string, newPath: string ) => { logHeader('📁 SFTP IPC RENAME') logInfo('sftpId', sftpId) logInfo('oldPath', oldPath) logInfo('newPath', newPath) try { await sshService.sftpRename(sftpId, oldPath, newPath) logSuccess('Rename complete') return { success: true } } catch (error: any) { logError(`Rename failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP delete ipcMain.handle(SFTP_CHANNELS.DELETE, async ( _event: IpcMainInvokeEvent, sftpId: string, filePath: string, isDirectory: boolean ) => { logHeader('📁 SFTP IPC DELETE') logInfo('sftpId', sftpId) logInfo('filePath', filePath) logInfo('isDirectory', isDirectory) try { await sshService.sftpDelete(sftpId, filePath, isDirectory) logSuccess('Delete complete') return { success: true } } catch (error: any) { logError(`Delete failed: ${error.message}`) return { success: false, error: error.message } } }) // SFTP mkdir ipcMain.handle(SFTP_CHANNELS.MKDIR, async ( _event: IpcMainInvokeEvent, sftpId: string, dirPath: string ) => { logHeader('📁 SFTP IPC MKDIR') logInfo('sftpId', sftpId) logInfo('dirPath', dirPath) try { await sshService.sftpMkdir(sftpId, dirPath) logSuccess('Mkdir complete') return { success: true } } catch (error: any) { logError(`Mkdir failed: ${error.message}`) return { success: false, error: error.message } } }) }