2025-08-28 03:14:36 +00:00
|
|
|
|
import { ipcMain,app } from 'electron';
|
|
|
|
|
|
import { getDeviceId, getWiredConnectionName, netmaskToCidr,simulateUpdate,performRealUpdate } from '../utils/utils';
|
|
|
|
|
|
import { BrowserWindow } from 'electron';
|
|
|
|
|
|
import { autoUpdater } from 'electron-updater';
|
|
|
|
|
|
import request from '../utils/request';
|
|
|
|
|
|
|
2025-08-22 10:59:43 +00:00
|
|
|
|
const { exec } = require('child_process');
|
|
|
|
|
|
const { promisify } = require('util');
|
|
|
|
|
|
const execAsync = promisify(exec);
|
2025-07-30 01:07:36 +00:00
|
|
|
|
|
2025-08-21 10:06:49 +00:00
|
|
|
|
const window = getBrowserWindowRuntime();
|
|
|
|
|
|
|
2025-08-28 03:14:36 +00:00
|
|
|
|
let currentServerIp: string | undefined;
|
2025-08-25 07:25:23 +00:00
|
|
|
|
|
2025-08-28 12:18:57 +00:00
|
|
|
|
// 添加处理窗口调整
|
|
|
|
|
|
ipcMain.handle('adjust-window-for-normal', async (event) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
// 调整窗口大小和配置
|
|
|
|
|
|
window.setKiosk(false); // 退出全屏模式
|
|
|
|
|
|
window.setMinimumSize(1200, 800);
|
|
|
|
|
|
window.setSize(1200, 800);
|
|
|
|
|
|
window.setResizable(true);
|
|
|
|
|
|
window.setMaximizable(true);
|
|
|
|
|
|
window.setMinimizable(true);
|
|
|
|
|
|
// 保持无边框和隐藏标题栏的设置
|
|
|
|
|
|
window.setFullScreen(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { success: true };
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('调整窗口失败:', error);
|
|
|
|
|
|
return { success: false, };
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**拖动窗口 */
|
|
|
|
|
|
ipcMain.handle('drag-window', (event) => {
|
|
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
|
|
|
|
|
// 通知渲染进程开始拖拽
|
|
|
|
|
|
focusedWindow.webContents.send('start-drag');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
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
|
|
|
|
|
2025-08-28 12:18:57 +00:00
|
|
|
|
// 窗口控制:最小化,退出全屏,关闭,
|
|
|
|
|
|
// 获取窗口最大化状态
|
|
|
|
|
|
ipcMain.handle('get-window-maximized', (event) => {
|
|
|
|
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
|
|
|
|
return window?.isMaximized() || false;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-21 10:06:49 +00:00
|
|
|
|
ipcMain.on('close-app', () => {
|
|
|
|
|
|
app.quit();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-28 12:18:57 +00:00
|
|
|
|
// 最小化
|
2025-08-21 10:06:49 +00:00
|
|
|
|
ipcMain.on('minimize-app', () => {
|
2025-08-28 03:14:36 +00:00
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
|
|
|
|
|
focusedWindow.minimize();
|
|
|
|
|
|
}
|
|
|
|
|
|
// window?.minimize();
|
2025-08-21 10:06:49 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-28 12:18:57 +00:00
|
|
|
|
// 退出全屏
|
|
|
|
|
|
ipcMain.on('restore-window', () => {
|
2025-08-28 03:14:36 +00:00
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
2025-08-28 12:18:57 +00:00
|
|
|
|
focusedWindow.unmaximize();
|
2025-08-21 10:06:49 +00:00
|
|
|
|
}
|
2025-08-28 03:14:36 +00:00
|
|
|
|
// if (window) {
|
|
|
|
|
|
// window.setFullScreen(false);
|
|
|
|
|
|
// }
|
2025-08-22 10:59:43 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-28 12:18:57 +00:00
|
|
|
|
// 设置全屏
|
|
|
|
|
|
ipcMain.on('maximize-window', () => {
|
|
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
|
|
|
|
|
focusedWindow.maximize();
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 监听窗口状态变化并通知渲染进程
|
|
|
|
|
|
ipcMain.on('register-window-state-listeners', (event) => {
|
|
|
|
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
window.on('maximize', () => {
|
|
|
|
|
|
event.sender.send('window-maximized');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
window.on('unmaximize', () => {
|
|
|
|
|
|
event.sender.send('window-unmaximized');
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-22 10:59:43 +00:00
|
|
|
|
|
2025-08-28 03:14:36 +00:00
|
|
|
|
ipcMain.handle('get-device-id',async()=>{
|
2025-08-22 10:59:43 +00:00
|
|
|
|
const deviceId = await getDeviceId();
|
|
|
|
|
|
console.log(`Using device ID: ${deviceId}`);
|
|
|
|
|
|
// TODO:传给后端
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-08-28 03:14:36 +00:00
|
|
|
|
/* 1. 平台网络配置:IPC 处理应用有线网络配置 */
|
2025-08-22 10:59:43 +00:00
|
|
|
|
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) {
|
2025-08-28 03:14:36 +00:00
|
|
|
|
const ipv6PrefixLength = config.ipv6PrefixLength &&
|
|
|
|
|
|
config.ipv6PrefixLength >= 0 &&
|
|
|
|
|
|
config.ipv6PrefixLength <= 128 ?
|
|
|
|
|
|
config.ipv6PrefixLength : 64; // 默认使用64
|
|
|
|
|
|
modifyCmd += ` ipv6.method manual ipv6.addresses "${config.ipv6}/${ipv6PrefixLength}" ipv6.gateway "${config.ipv6Gateway}"`;
|
|
|
|
|
|
}else if (config.ipv6 || config.ipv6Gateway) {
|
|
|
|
|
|
console.warn('IPv6配置不完整:需要同时提供IPv6地址和网关');
|
2025-08-22 10:59:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行配置命令
|
|
|
|
|
|
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 || '未知错误')}`
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-08-28 03:14:36 +00:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
/**2. 服务器配置 */
|
|
|
|
|
|
ipcMain.handle('connect-server', async (event, { serverIp }) => {
|
|
|
|
|
|
console.log(`Connecting to server: ${serverIp}`);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 获取设备ID
|
|
|
|
|
|
const deviceId = await getDeviceId();
|
|
|
|
|
|
console.log(`Using device ID: ${deviceId}`);
|
|
|
|
|
|
|
|
|
|
|
|
// 构建新的API地址,使用POST请求
|
|
|
|
|
|
const apiUrl = `http://${serverIp}:8113/api/nex/v1/client/authentication`;
|
|
|
|
|
|
console.log(`Testing API endpoint: ${apiUrl}`);
|
|
|
|
|
|
|
|
|
|
|
|
// 调用Authentication接口进行连接验证(POST请求)
|
|
|
|
|
|
const response = await request(apiUrl, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
timeout: 10000, // 10秒超时
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
data: JSON.stringify({ device_id: deviceId })
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
console.log('API response received:', response);
|
|
|
|
|
|
|
|
|
|
|
|
// 解析响应数据
|
|
|
|
|
|
let responseData;
|
|
|
|
|
|
try {
|
|
|
|
|
|
responseData = JSON.parse((response as any).data);
|
|
|
|
|
|
} catch (parseError) {
|
|
|
|
|
|
console.error('Failed to parse authentication response:', parseError);
|
|
|
|
|
|
return { success: false, message: '服务器响应格式错误' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('Parsed authentication response:', responseData);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查认证结果 - 只有code等于200时才算成功
|
|
|
|
|
|
if (responseData.code === '200' || responseData.code === 200) {
|
|
|
|
|
|
// 认证成功,存储服务器IP
|
|
|
|
|
|
currentServerIp = serverIp;
|
|
|
|
|
|
console.log('Authentication successful, server IP stored:', serverIp);
|
|
|
|
|
|
return { success: true, message: `已连接到服务器 ${serverIp}`, serverIp: serverIp };
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 认证失败,返回服务器提供的错误信息
|
|
|
|
|
|
const errorMessage = responseData.message || responseData.msg || responseData.error || '服务器认证失败';
|
|
|
|
|
|
console.log('Authentication failed:', errorMessage);
|
|
|
|
|
|
return { success: false, message: errorMessage };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error:any) {
|
|
|
|
|
|
console.error('Server connection error details:', {
|
|
|
|
|
|
message: error.message,
|
|
|
|
|
|
code: error.code,
|
|
|
|
|
|
errno: error.errno,
|
|
|
|
|
|
syscall: error.syscall,
|
|
|
|
|
|
address: error.address,
|
|
|
|
|
|
port: error.port
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 根据具体错误提供更准确的提示
|
|
|
|
|
|
let errorMessage = '请输入正确服务器ip或者联系管理员';
|
|
|
|
|
|
|
|
|
|
|
|
if (error.message.includes('ECONNREFUSED')) {
|
|
|
|
|
|
errorMessage = `无法连接到服务器 ${serverIp}:8113,请检查服务器是否运行`;
|
|
|
|
|
|
} else if (error.message.includes('ENOTFOUND')) {
|
|
|
|
|
|
errorMessage = `无法解析服务器地址 ${serverIp},请检查IP地址是否正确`;
|
|
|
|
|
|
} else if (error.message.includes('请求超时')) {
|
|
|
|
|
|
errorMessage = `连接服务器 ${serverIp}:8113 超时,请检查网络连接`;
|
|
|
|
|
|
} else if (error.message.includes('ENETUNREACH')) {
|
|
|
|
|
|
errorMessage = `网络不可达,无法连接到服务器 ${serverIp}`;
|
|
|
|
|
|
} else if (error.message.includes('HTTP 404')) {
|
|
|
|
|
|
errorMessage = `服务器返回404错误,Authentication接口路径可能不正确`;
|
|
|
|
|
|
} else if (error.message.includes('HTTP')) {
|
|
|
|
|
|
errorMessage = `服务器返回错误: ${error.message}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: errorMessage
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
// 服务器IP获取
|
|
|
|
|
|
ipcMain.handle('get-current-server-ip', () => {
|
|
|
|
|
|
return currentServerIp;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**3. 侦测管理平台 */
|
|
|
|
|
|
// 下载并更新客户端
|
|
|
|
|
|
let updateDownloadedInfo: any = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 修改 download-and-update 处理器中的事件监听器
|
|
|
|
|
|
ipcMain.handle('download-and-update', async (event, url) => {
|
|
|
|
|
|
console.log('下载并更新客户端:', url);
|
|
|
|
|
|
|
|
|
|
|
|
// 重置更新状态
|
|
|
|
|
|
updateDownloadedInfo = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
|
|
|
// 开发环境下使用模拟更新
|
|
|
|
|
|
return simulateUpdate(event, url);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 生产环境下使用真实更新
|
|
|
|
|
|
// 清除之前的事件监听器,避免重复注册
|
|
|
|
|
|
autoUpdater.removeAllListeners('update-downloaded');
|
|
|
|
|
|
|
|
|
|
|
|
// 监听更新下载完成事件
|
|
|
|
|
|
autoUpdater.on('update-downloaded', (info) => {
|
|
|
|
|
|
console.log('更新已下载=====>', info);
|
|
|
|
|
|
updateDownloadedInfo = info;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return performRealUpdate(event, url);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 安装更新并重启应用
|
|
|
|
|
|
ipcMain.on('install-update-and-restart', () => {
|
|
|
|
|
|
console.log('安装更新并重启应用...');
|
|
|
|
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
|
|
|
// 开发环境下使用模拟更新
|
|
|
|
|
|
console.log('开发环境:模拟重启应用');
|
|
|
|
|
|
// 直接调用,添加小延迟
|
|
|
|
|
|
|
|
|
|
|
|
app.quit();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 生产环境下使用真实更新
|
|
|
|
|
|
if (!updateDownloadedInfo) {
|
|
|
|
|
|
console.warn('没有已完成下载的更新');
|
|
|
|
|
|
// 可以选择不执行重启或提示用户
|
|
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
|
|
|
|
|
focusedWindow.webContents.send('update-not-available', {
|
|
|
|
|
|
message: '没有已完成下载的更新,请先下载更新'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('生产环境:安装更新并重启');
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
autoUpdater.quitAndInstall(false, true);
|
|
|
|
|
|
} catch (installError) {
|
|
|
|
|
|
console.error('自动更新安装失败,降级到手动重启:', installError);
|
|
|
|
|
|
// app.relaunch();
|
|
|
|
|
|
// app.quit();
|
|
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
|
|
|
|
if (focusedWindow) {
|
|
|
|
|
|
focusedWindow.webContents.send('update-install-error', {
|
|
|
|
|
|
message: '更新安装失败: ' + (installError instanceof Error ? installError.message : String(installError))
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|