2025-08-25 07:25:23 +00:00
|
|
|
|
import { ipcMain,app,BrowserWindow } from 'electron';
|
2025-08-22 10:59:43 +00:00
|
|
|
|
import { getDeviceId, getWiredConnectionName,netmaskToCidr } from '../utils/utils';
|
|
|
|
|
|
const { exec } = require('child_process');
|
|
|
|
|
|
const { promisify } = require('util');
|
|
|
|
|
|
const execAsync = promisify(exec);
|
2025-07-30 01:07:36 +00:00
|
|
|
|
|
2025-08-25 07:25:23 +00:00
|
|
|
|
// 模拟grpc服务端
|
|
|
|
|
|
import { BTGrpcClient } from '../grpc/BTGrpcClient';
|
|
|
|
|
|
import { MockBTService } from '../grpc/MockBTService';
|
|
|
|
|
|
|
|
|
|
|
|
// 客户端和服务端 通信
|
|
|
|
|
|
const IS_TEST_MODE = true; // 设置为 false 时连接真实后端
|
|
|
|
|
|
const GRPC_SERVER_PORT = 50051;
|
|
|
|
|
|
// 先声明变量,但不立即初始化
|
|
|
|
|
|
let btGrpcClient: BTGrpcClient | null = null;
|
|
|
|
|
|
let mockServer: MockBTService | null = null;
|
|
|
|
|
|
let healthCheckInterval: NodeJS.Timeout | null = null; // 声明一个变量来存储定时器
|
|
|
|
|
|
|
2025-08-21 10:06:49 +00:00
|
|
|
|
const window = getBrowserWindowRuntime();
|
|
|
|
|
|
|
2025-08-25 07:25:23 +00:00
|
|
|
|
// 初始化 gRPC 客户端
|
|
|
|
|
|
async function initializeGrpc() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (IS_TEST_MODE) {
|
|
|
|
|
|
console.log('启动模拟 gRPC 服务器...');
|
|
|
|
|
|
mockServer = new MockBTService();
|
|
|
|
|
|
await mockServer.start(GRPC_SERVER_PORT);
|
|
|
|
|
|
|
|
|
|
|
|
// 给一点时间让服务器启动
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 BTGrpcClient 实例连接到gRPC服务
|
|
|
|
|
|
btGrpcClient = new BTGrpcClient();
|
|
|
|
|
|
|
|
|
|
|
|
// 注册进度回调函数,用于接收下载进度更新
|
|
|
|
|
|
btGrpcClient.registerProgressCallback('all', (progress) => {
|
|
|
|
|
|
const mainWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (mainWindow) {
|
|
|
|
|
|
mainWindow.webContents.send('grpc-progress-update', progress);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 测试连接
|
|
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const connected = await btGrpcClient!.testConnection();
|
|
|
|
|
|
console.log('gRPC 连接状态:', connected ? '已连接' : '未连接');
|
|
|
|
|
|
|
|
|
|
|
|
const mainWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (mainWindow) {
|
|
|
|
|
|
mainWindow.webContents.send('grpc-connection-status', {
|
|
|
|
|
|
connected,
|
|
|
|
|
|
isMock: IS_TEST_MODE
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('连接测试失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 2000);
|
|
|
|
|
|
|
|
|
|
|
|
// 启动健康检查
|
|
|
|
|
|
startHealthCheck();
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('gRPC 初始化失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 启动健康检查
|
|
|
|
|
|
function startHealthCheck() {
|
|
|
|
|
|
if (healthCheckInterval) {
|
|
|
|
|
|
clearInterval(healthCheckInterval);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
healthCheckInterval = setInterval(async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!btGrpcClient) return;
|
|
|
|
|
|
|
|
|
|
|
|
const isConnected = await btGrpcClient.testConnection();
|
|
|
|
|
|
const mainWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (mainWindow) {
|
|
|
|
|
|
mainWindow.webContents.send('grpc-connection-status', {
|
|
|
|
|
|
connected: isConnected,
|
|
|
|
|
|
state: btGrpcClient.getConnectionState(),
|
|
|
|
|
|
isMock: IS_TEST_MODE
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('健康检查失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 5000); // 每5秒检查一次
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 应用启动时初始化
|
|
|
|
|
|
app.whenReady().then(() => {
|
|
|
|
|
|
initializeGrpc();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 应用退出时清理
|
|
|
|
|
|
app.on('before-quit', async () => {
|
|
|
|
|
|
if (healthCheckInterval) {
|
|
|
|
|
|
clearInterval(healthCheckInterval);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mockServer) {
|
|
|
|
|
|
await mockServer.stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加 gRPC 相关的 IPC 处理程序
|
|
|
|
|
|
ipcMain.handle('grpc-start-download', async (event, config) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!btGrpcClient) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: 'gRPC客户端未初始化'
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('开始gRPC下载:', config);
|
|
|
|
|
|
// gRPC客户端向服务端发起 StartDownload 调用
|
|
|
|
|
|
const result = await btGrpcClient.startDownload({
|
|
|
|
|
|
torrent_url: config.torrentUrl,
|
|
|
|
|
|
item_name: config.itemName,
|
|
|
|
|
|
item_id: config.itemId
|
|
|
|
|
|
});
|
|
|
|
|
|
return { success: true, data: result };
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('gRPC下载失败:', error);
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: error.message || '未知错误',
|
|
|
|
|
|
details: error.details
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('grpc-stop-download', async (event, downloadId) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!btGrpcClient) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: 'gRPC客户端未初始化'
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const result = await btGrpcClient.stopDownload(downloadId);
|
|
|
|
|
|
return { success: true, data: result };
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: error.message || '未知错误'
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('grpc-check-connection', async () => {
|
|
|
|
|
|
if (!btGrpcClient) {
|
|
|
|
|
|
return { connected: false, error: 'gRPC客户端未初始化' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
connected: btGrpcClient.isConnected(),
|
|
|
|
|
|
state: btGrpcClient.getConnectionState()
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 重新连接 gRPC
|
|
|
|
|
|
ipcMain.handle('grpc-reconnect', async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (btGrpcClient) {
|
|
|
|
|
|
btGrpcClient.reconnect();
|
|
|
|
|
|
return { success: true, message: '正在重新连接' };
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await initializeGrpc();
|
|
|
|
|
|
return { success: true, message: '正在初始化连接' };
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
error: error.message || '重新连接失败'
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-21 10:06:49 +00:00
|
|
|
|
// 监听渲染进程发送的消息
|
2025-07-30 01:07:36 +00:00
|
|
|
|
ipcMain.handle('getPlatform', () => {
|
|
|
|
|
|
return `hi, i'm from ${process.platform}`;
|
|
|
|
|
|
});
|
2025-08-21 10:06:49 +00:00
|
|
|
|
|
|
|
|
|
|
// 窗口控制:最小化,退出全屏
|
|
|
|
|
|
ipcMain.on('close-app', () => {
|
|
|
|
|
|
app.quit();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ipcMain.on('minimize-app', () => {
|
|
|
|
|
|
window?.minimize();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ipcMain.on('exit-kiosk', () => {
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
window.setFullScreen(false);
|
|
|
|
|
|
}
|
2025-08-22 10:59:43 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('get-deviceid',async()=>{
|
|
|
|
|
|
const deviceId = await getDeviceId();
|
|
|
|
|
|
console.log(`Using device ID: ${deviceId}`);
|
|
|
|
|
|
// TODO:传给后端
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
/* IPC 处理应用有线网络配置 */
|
|
|
|
|
|
ipcMain.handle('apply-wired-config',async(event,config)=>{
|
|
|
|
|
|
// return {
|
|
|
|
|
|
// success: true,
|
|
|
|
|
|
// message: '网络配置已成功应用'
|
|
|
|
|
|
// };
|
|
|
|
|
|
try{
|
|
|
|
|
|
console.log('应用网络配置:', config);
|
|
|
|
|
|
// 获取有线连接名称
|
|
|
|
|
|
const connectionName = await getWiredConnectionName();
|
|
|
|
|
|
console.log('有线连接名称:', connectionName);
|
|
|
|
|
|
|
|
|
|
|
|
if(config.method==='static'){
|
|
|
|
|
|
// 使用nmcli配置静态IP,需要使用sudo权限,一次性设置所有参数
|
|
|
|
|
|
let modifyCmd = `echo "unis@123" | sudo -S nmcli connection modify "${connectionName}" ipv4.method manual ipv4.addresses "${config.ipv4}/${netmaskToCidr(config.subnetMask)}" ipv4.gateway "${config.ipv4Gateway}"`;
|
|
|
|
|
|
const dnsServers = [config.primaryDns, config.secondaryDns].filter(Boolean).join(',');
|
|
|
|
|
|
modifyCmd += ` ipv4.dns "${dnsServers}"`;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加 IPv6 配置(如果存在 ipv6Gateway)????ipv6和长度需要吗?ui只写了ipv6网关
|
|
|
|
|
|
// ipv6PrefixLength 是 IPv6 地址的前缀长度,类似于 IPv4 中的子网掩码。????
|
|
|
|
|
|
if (config.ipv6 && config.ipv6Gateway) {
|
|
|
|
|
|
modifyCmd += ` ipv6.method manual ipv6.addresses "${config.ipv6}/${config.ipv6PrefixLength || 64}" ipv6.gateway "${config.ipv6Gateway}"`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行配置命令
|
|
|
|
|
|
console.log('执行命令:', modifyCmd.replace('unis@123', '***'));
|
|
|
|
|
|
await execAsync(modifyCmd);
|
|
|
|
|
|
|
|
|
|
|
|
// 重新激活连接
|
|
|
|
|
|
await execAsync(`echo "unis@123" | sudo -S nmcli connection up "${connectionName}"`);
|
|
|
|
|
|
|
|
|
|
|
|
}else{
|
|
|
|
|
|
// DHCP配置,一次性设置所有参数
|
|
|
|
|
|
const modifyCmd = `echo "unis@123" | sudo -S nmcli connection modify "${connectionName}" ipv4.method auto ipv4.addresses "" ipv4.gateway "" ipv4.dns ""`;
|
|
|
|
|
|
|
|
|
|
|
|
// 执行配置命令
|
|
|
|
|
|
console.log('执行命令:', modifyCmd.replace('unis@123', '***'));
|
|
|
|
|
|
await execAsync(modifyCmd);
|
|
|
|
|
|
|
|
|
|
|
|
// 重新激活连接
|
|
|
|
|
|
await execAsync(`echo "unis@123" | sudo -S nmcli connection up "${connectionName}"`);
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '网络配置已成功应用'
|
|
|
|
|
|
};
|
|
|
|
|
|
}catch(error:unknown){
|
|
|
|
|
|
console.error('应用网络配置失败:', error);
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: `配置失败: ${error instanceof Error ? error.message : String(error || '未知错误')}`
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|