import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import * as path from 'path'; import { RelayClient } from './relay-client'; import { LocalProxy } from './local-proxy'; import { ApiClient } from './api-client'; let mainWindow: BrowserWindow | null = null; let relayClient: RelayClient | null = null; let localProxy: LocalProxy | null = null; let apiClient: ApiClient | null = null; function createWindow() { mainWindow = new BrowserWindow({ width: 900, height: 650, minWidth: 800, minHeight: 600, title: 'FunConnect - Minecraft 联机客户端', frame: false, titleBarStyle: 'hidden', backgroundColor: '#1a1a2e', webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }); mainWindow.loadFile(path.join(__dirname, '../../renderer/index.html')); mainWindow.on('closed', () => { mainWindow = null; cleanup(); }); } function cleanup() { if (localProxy) { localProxy.stop(); localProxy = null; } if (relayClient) { relayClient.disconnect(); relayClient = null; } } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', () => { cleanup(); if (process.platform !== 'darwin') app.quit(); }); // ===== IPC Handlers ===== // Window controls ipcMain.handle('window:minimize', () => mainWindow?.minimize()); ipcMain.handle('window:maximize', () => { if (mainWindow?.isMaximized()) mainWindow.unmaximize(); else mainWindow?.maximize(); }); ipcMain.handle('window:close', () => mainWindow?.close()); // Server connection ipcMain.handle('server:connect', async (_event, serverUrl: string) => { try { apiClient = new ApiClient(serverUrl); const health = await apiClient.getHealth(); return { success: true, data: health }; } catch (err: any) { return { success: false, error: err.message }; } }); // Room operations ipcMain.handle('rooms:list', async () => { if (!apiClient) return { success: false, error: '未连接服务器' }; try { const data = await apiClient.getRooms(); return { success: true, data }; } catch (err: any) { return { success: false, error: err.message }; } }); ipcMain.handle('rooms:create', async (_event, roomData: any) => { if (!apiClient) return { success: false, error: '未连接服务器' }; try { const data = await apiClient.createRoom(roomData); return { success: true, data }; } catch (err: any) { return { success: false, error: err.response?.data?.error || err.message }; } }); ipcMain.handle('rooms:delete', async (_event, roomId: string) => { if (!apiClient) return { success: false, error: '未连接服务器' }; try { await apiClient.deleteRoom(roomId); return { success: true }; } catch (err: any) { return { success: false, error: err.message }; } }); // Join room - start local proxy and relay connection ipcMain.handle('rooms:join', async (_event, opts: { serverHost: string; serverPort: number; roomId: string; localPort: number }) => { try { cleanup(); relayClient = new RelayClient(opts.serverHost, opts.serverPort, opts.roomId); localProxy = new LocalProxy(opts.localPort, relayClient); await localProxy.start(); relayClient.on('connected', () => { mainWindow?.webContents.send('relay:status', { status: 'connected' }); }); relayClient.on('disconnected', () => { mainWindow?.webContents.send('relay:status', { status: 'disconnected' }); }); relayClient.on('error', (err: string) => { mainWindow?.webContents.send('relay:status', { status: 'error', error: err }); }); return { success: true, localPort: opts.localPort }; } catch (err: any) { return { success: false, error: err.message }; } }); // Host room - start relay and local proxy from local MC server ipcMain.handle('rooms:host', async (_event, opts: { serverUrl: string; roomName: string; localMcPort: number; gameVersion: string; gameEdition: string; maxPlayers: number; password?: string }) => { if (!apiClient) return { success: false, error: '未连接服务器' }; try { const result = await apiClient.createRoom({ name: opts.roomName, hostName: 'FunConnect', hostPort: opts.localMcPort, gameVersion: opts.gameVersion, gameEdition: opts.gameEdition, maxPlayers: opts.maxPlayers, password: opts.password, }); return { success: true, data: result }; } catch (err: any) { return { success: false, error: err.response?.data?.error || err.message }; } }); // Disconnect ipcMain.handle('relay:disconnect', () => { cleanup(); return { success: true }; }); // Stats ipcMain.handle('server:stats', async () => { if (!apiClient) return { success: false, error: '未连接服务器' }; try { const data = await apiClient.getStats(); return { success: true, data }; } catch (err: any) { return { success: false, error: err.message }; } });