feat(remote): 文件传输改用Electron IPC通道
- 主进程新增4个IPC handler处理远程文件操作 - 前端通过IPC调用而非浏览器fetch访问远程API - Remote服务新增3003端口专门处理文件传输 - 上传使用文件路径方案,下载使用保存对话框方案
This commit is contained in:
136
electron/main.ts
136
electron/main.ts
@@ -156,6 +156,142 @@ ipcMain.handle('clipboard-write-text', async (event, text: string) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('remote-fetch-drives', async (_event, serverHost: string, port: number, password?: string) => {
|
||||
try {
|
||||
let url = `http://${serverHost}:${port}/api/files/drives`;
|
||||
if (password) {
|
||||
url += `?password=${encodeURIComponent(password)}`;
|
||||
}
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch drives: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
const items = data.items || [];
|
||||
return {
|
||||
success: true,
|
||||
data: items.map((item: { name: string; isDirectory: boolean; size: number }) => ({
|
||||
name: item.name,
|
||||
path: item.name,
|
||||
type: item.isDirectory ? 'dir' : 'file',
|
||||
size: item.size,
|
||||
modified: '',
|
||||
}))
|
||||
};
|
||||
} catch (error: any) {
|
||||
log.error('Remote fetch drives failed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('remote-fetch-files', async (_event, serverHost: string, port: number, filePath: string, password?: string) => {
|
||||
try {
|
||||
let url = `http://${serverHost}:${port}/api/files/browse?path=${encodeURIComponent(filePath)}&allowSystem=true`;
|
||||
if (password) {
|
||||
url += `&password=${encodeURIComponent(password)}`;
|
||||
}
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch files: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
const items = data.items || [];
|
||||
return {
|
||||
success: true,
|
||||
data: items.map((item: { name: string; isDirectory: boolean; size: number; modified: Date }) => ({
|
||||
name: item.name,
|
||||
path: data.currentPath ? `${data.currentPath}/${item.name}` : item.name,
|
||||
type: item.isDirectory ? 'dir' : 'file',
|
||||
size: item.size,
|
||||
modified: item.modified?.toString(),
|
||||
}))
|
||||
};
|
||||
} catch (error: any) {
|
||||
log.error('Remote fetch files failed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('remote-upload-file', async (_event, serverHost: string, port: number, filePath: string, remotePath: string, password?: string) => {
|
||||
try {
|
||||
const win = electronState.getMainWindow();
|
||||
if (!win) {
|
||||
throw new Error('No window found');
|
||||
}
|
||||
|
||||
const fullPath = path.resolve(filePath);
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
throw new Error('File not found');
|
||||
}
|
||||
|
||||
const fileBuffer = fs.readFileSync(fullPath);
|
||||
const fileName = path.basename(fullPath);
|
||||
|
||||
let url = `http://${serverHost}:${port}/api/files/upload`;
|
||||
if (password) {
|
||||
url += `?password=${encodeURIComponent(password)}`;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
const blob = new Blob([fileBuffer]);
|
||||
formData.append('file', blob, fileName);
|
||||
if (remotePath) {
|
||||
formData.append('path', remotePath);
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Upload failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error: any) {
|
||||
log.error('Remote upload failed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('remote-download-file', async (_event, serverHost: string, port: number, fileName: string, remotePath: string, password?: string) => {
|
||||
try {
|
||||
const win = electronState.getMainWindow();
|
||||
if (!win) {
|
||||
throw new Error('No window found');
|
||||
}
|
||||
|
||||
let url = `http://${serverHost}:${port}/api/files/${encodeURIComponent(fileName)}`;
|
||||
if (password) {
|
||||
url += `?password=${encodeURIComponent(password)}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Download failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
const { filePath } = await dialog.showSaveDialog(win, {
|
||||
title: '保存文件',
|
||||
defaultPath: fileName,
|
||||
});
|
||||
|
||||
if (!filePath) {
|
||||
return { success: false, canceled: true };
|
||||
}
|
||||
|
||||
fs.writeFileSync(filePath, Buffer.from(buffer));
|
||||
|
||||
return { success: true, filePath };
|
||||
} catch (error: any) {
|
||||
log.error('Remote download failed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
async function startServer() {
|
||||
if (electronState.isDevelopment()) {
|
||||
log.info('In dev mode, assuming external servers are running.');
|
||||
|
||||
Reference in New Issue
Block a user