init
This commit is contained in:
177
electron/service/os/auto_updater.ts
Normal file
177
electron/service/os/auto_updater.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import { app as electronApp } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import { is } from 'ee-core/utils';
|
||||
import { logger } from 'ee-core/log';
|
||||
import { getMainWindow, setCloseAndQuit } from 'ee-core/electron';
|
||||
|
||||
/**
|
||||
* AutoUpdaterService class for automatic updates
|
||||
*/
|
||||
class AutoUpdaterService {
|
||||
private config: {
|
||||
windows: boolean;
|
||||
macOS: boolean;
|
||||
linux: boolean;
|
||||
options: any;
|
||||
};
|
||||
constructor() {
|
||||
this.config = {
|
||||
windows: false,
|
||||
macOS: false,
|
||||
linux: false,
|
||||
options: {
|
||||
provider: 'generic',
|
||||
url: 'http://kodo.qiniu.com/'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure the auto updater
|
||||
*/
|
||||
create(): void {
|
||||
logger.info('[autoUpdater] load');
|
||||
const cfg = this.config;
|
||||
if ((is.windows() && cfg.windows) ||
|
||||
(is.macOS() && cfg.macOS) ||
|
||||
(is.linux() && cfg.linux)) {
|
||||
// continue
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = {
|
||||
error: -1,
|
||||
available: 1,
|
||||
noAvailable: 2,
|
||||
downloading: 3,
|
||||
downloaded: 4,
|
||||
};
|
||||
|
||||
const version = electronApp.getVersion();
|
||||
logger.info('[autoUpdater] current version: ', version);
|
||||
|
||||
// Set the download server address
|
||||
let server = cfg.options.url;
|
||||
const lastChar = server.substring(server.length - 1);
|
||||
server = lastChar === '/' ? server : server + "/";
|
||||
cfg.options.url = server;
|
||||
|
||||
try {
|
||||
autoUpdater.setFeedURL(cfg.options);
|
||||
} catch (error) {
|
||||
logger.error('[autoUpdater] setFeedURL error : ', error);
|
||||
}
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
// sendStatusToWindow('正在检查更新...');
|
||||
});
|
||||
autoUpdater.on('update-available', () => {
|
||||
const data = {
|
||||
status: status.available,
|
||||
desc: '有可用更新',
|
||||
};
|
||||
this.sendStatusToWindow(data);
|
||||
});
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
const data = {
|
||||
status: status.noAvailable,
|
||||
desc: '没有可用更新',
|
||||
};
|
||||
this.sendStatusToWindow(data);
|
||||
});
|
||||
autoUpdater.on('error', (err) => {
|
||||
const data = {
|
||||
status: status.error,
|
||||
desc: err,
|
||||
};
|
||||
this.sendStatusToWindow(data);
|
||||
});
|
||||
autoUpdater.on('download-progress', (progressObj) => {
|
||||
const percentNumber = progressObj.percent;
|
||||
const totalSize = this.bytesChange(progressObj.total);
|
||||
const transferredSize = this.bytesChange(progressObj.transferred);
|
||||
let text = '已下载 ' + percentNumber + '%';
|
||||
text = text + ' (' + transferredSize + "/" + totalSize + ')';
|
||||
|
||||
const data = {
|
||||
status: status.downloading,
|
||||
desc: text,
|
||||
percentNumber,
|
||||
totalSize,
|
||||
transferredSize,
|
||||
};
|
||||
logger.info('[addon:autoUpdater] progress: ', text);
|
||||
this.sendStatusToWindow(data);
|
||||
});
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
const data = {
|
||||
status: status.downloaded,
|
||||
desc: '下载完成',
|
||||
};
|
||||
this.sendStatusToWindow(data);
|
||||
|
||||
// Allow the window to close
|
||||
setCloseAndQuit(true);
|
||||
|
||||
// Install updates and exit the application
|
||||
autoUpdater.quitAndInstall();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates
|
||||
*/
|
||||
checkUpdate(): void {
|
||||
autoUpdater.checkForUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Download updates
|
||||
*/
|
||||
download(): void {
|
||||
autoUpdater.downloadUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send status to the frontend
|
||||
*/
|
||||
sendStatusToWindow(content: any = {}): void {
|
||||
const textJson = JSON.stringify(content);
|
||||
const channel = 'custom/app/updater';
|
||||
const win = getMainWindow();
|
||||
win.webContents.send(channel, textJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bytes to a more readable format
|
||||
*/
|
||||
bytesChange(limit: number): string {
|
||||
let size = "";
|
||||
if (limit < 0.1 * 1024) {
|
||||
size = limit.toFixed(2) + "B";
|
||||
} else if (limit < 0.1 * 1024 * 1024) {
|
||||
size = (limit / 1024).toFixed(2) + "KB";
|
||||
} else if (limit < 0.1 * 1024 * 1024 * 1024) {
|
||||
size = (limit / (1024 * 1024)).toFixed(2) + "MB";
|
||||
} else {
|
||||
size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB";
|
||||
}
|
||||
|
||||
let sizeStr = size + "";
|
||||
let index = sizeStr.indexOf(".");
|
||||
let dou = sizeStr.substring(index + 1, index + 3);
|
||||
if (dou === "00") {
|
||||
return sizeStr.substring(0, index) + sizeStr.substring(index + 3, index + 5);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
AutoUpdaterService.toString = () => '[class AutoUpdaterService]';
|
||||
const autoUpdaterService = new AutoUpdaterService();
|
||||
|
||||
export {
|
||||
AutoUpdaterService,
|
||||
autoUpdaterService
|
||||
};
|
||||
15
electron/service/os/icon.js
Normal file
15
electron/service/os/icon.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const {getMainWindow} = require("ee-core/electron");
|
||||
|
||||
|
||||
class IconService {
|
||||
|
||||
|
||||
|
||||
update(iconPath) {
|
||||
const win = getMainWindow();
|
||||
win.setIcon(iconPath);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
iconService: new IconService()
|
||||
};
|
||||
31
electron/service/os/security.ts
Normal file
31
electron/service/os/security.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { logger } from 'ee-core/log';
|
||||
import { app as electronApp } from 'electron';
|
||||
|
||||
/**
|
||||
* SecurityService class for handling security-related operations
|
||||
*/
|
||||
class SecurityService {
|
||||
/**
|
||||
* Create and configure the security service
|
||||
*/
|
||||
create(): void {
|
||||
logger.info('[security] load');
|
||||
const runWithDebug = process.argv.find((e) => {
|
||||
const isHasDebug = e.includes('--inspect') || e.includes('--inspect-brk') || e.includes('--remote-debugging-port');
|
||||
return isHasDebug;
|
||||
});
|
||||
|
||||
// Do not allow remote debugging
|
||||
if (runWithDebug) {
|
||||
logger.error('[error] Remote debugging is not allowed, runWithDebug:', runWithDebug);
|
||||
electronApp.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
SecurityService.toString = () => '[class SecurityService]';
|
||||
const securityService = new SecurityService();
|
||||
|
||||
export {
|
||||
SecurityService,
|
||||
securityService
|
||||
};
|
||||
81
electron/service/os/tray.ts
Normal file
81
electron/service/os/tray.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Tray, Menu } from 'electron';
|
||||
import path from 'path';
|
||||
import { isDev, getBaseDir } from 'ee-core/ps';
|
||||
import { logger } from 'ee-core/log';
|
||||
import { app as electronApp } from 'electron';
|
||||
import { getMainWindow, getCloseAndQuit, setCloseAndQuit } from 'ee-core/electron';
|
||||
|
||||
/**
|
||||
* 托盘
|
||||
* @class
|
||||
*/
|
||||
class TrayService {
|
||||
tray: Tray | null;
|
||||
config: {
|
||||
title: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.tray = null;
|
||||
this.config = {
|
||||
title: 'electron-egg',
|
||||
icon: '/public/images/tray.png',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tray icon
|
||||
*/
|
||||
create () {
|
||||
logger.info('[tray] load');
|
||||
|
||||
const cfg = this.config;
|
||||
const mainWindow = getMainWindow();
|
||||
|
||||
// tray icon
|
||||
const iconPath = path.join(getBaseDir(), cfg.icon);
|
||||
|
||||
// Tray menu items
|
||||
const trayMenuTemplate = [
|
||||
{
|
||||
label: '显示',
|
||||
click: function () {
|
||||
mainWindow.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '退出',
|
||||
click: function () {
|
||||
electronApp.quit();
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// Set a flag to minimize to tray instead of closing
|
||||
setCloseAndQuit(false);
|
||||
mainWindow.on('close', (event: any) => {
|
||||
if (getCloseAndQuit()) {
|
||||
return;
|
||||
}
|
||||
mainWindow.hide();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Initialize the tray
|
||||
this.tray = new Tray(iconPath);
|
||||
this.tray.setToolTip(cfg.title);
|
||||
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);
|
||||
this.tray.setContextMenu(contextMenu);
|
||||
// Show the main window when the tray icon is clicked
|
||||
this.tray.on('click', () => {
|
||||
mainWindow.show()
|
||||
})
|
||||
}
|
||||
}
|
||||
TrayService.toString = () => '[class TrayService]';
|
||||
const trayService = new TrayService();
|
||||
|
||||
export {
|
||||
trayService
|
||||
}
|
||||
131
electron/service/os/window.ts
Normal file
131
electron/service/os/window.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import path from 'path';
|
||||
import { BrowserWindow, Notification } from 'electron';
|
||||
import { getMainWindow } from 'ee-core/electron';
|
||||
import { isProd, getBaseDir } from 'ee-core/ps';
|
||||
import { getConfig } from 'ee-core/config';
|
||||
import { isFileProtocol } from 'ee-core/utils';
|
||||
import { logger } from 'ee-core/log';
|
||||
|
||||
/**
|
||||
* Window
|
||||
* @class
|
||||
*/
|
||||
class WindowService {
|
||||
myNotification: Notification | null;
|
||||
windows: { [key: string]: BrowserWindow };
|
||||
|
||||
constructor() {
|
||||
this.myNotification = null;
|
||||
this.windows = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new window
|
||||
*/
|
||||
createWindow(args: { type: string; content: string; windowName: string; windowTitle: string }): number {
|
||||
const { type, content, windowName, windowTitle } = args;
|
||||
let contentUrl: string = '';
|
||||
if (type == 'html') {
|
||||
contentUrl = path.join('file://', getBaseDir(), content)
|
||||
} else if (type == 'web') {
|
||||
contentUrl = content;
|
||||
} else if (type == 'vue') {
|
||||
let addr = 'http://localhost:8080'
|
||||
if (isProd()) {
|
||||
const { mainServer } = getConfig();
|
||||
if (mainServer && mainServer.protocol && isFileProtocol(mainServer.protocol)) {
|
||||
addr = mainServer.protocol + path.join(getBaseDir(), mainServer.indexPath);
|
||||
}
|
||||
}
|
||||
|
||||
contentUrl = addr + content;
|
||||
}
|
||||
|
||||
logger.info('[createWindow] url: ', contentUrl);
|
||||
const opt = {
|
||||
title: windowTitle,
|
||||
x: 10,
|
||||
y: 10,
|
||||
width: 980,
|
||||
height: 650,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true,
|
||||
},
|
||||
}
|
||||
const win = new BrowserWindow(opt);
|
||||
const winContentsId = win.webContents.id;
|
||||
win.loadURL(contentUrl);
|
||||
win.webContents.openDevTools();
|
||||
this.windows[windowName] = win;
|
||||
|
||||
return winContentsId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get window contents id
|
||||
*/
|
||||
getWCid(args: { windowName: string }): number {
|
||||
const { windowName } = args;
|
||||
let win: BrowserWindow;
|
||||
if (windowName == 'main') {
|
||||
win = getMainWindow();
|
||||
} else {
|
||||
win = this.windows[windowName];
|
||||
}
|
||||
|
||||
return win.webContents.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Realize communication between two windows through the transfer of the main process
|
||||
*/
|
||||
communicate(args: { receiver: string; content: any }): void {
|
||||
const { receiver, content } = args;
|
||||
if (receiver == 'main') {
|
||||
const win = getMainWindow();
|
||||
win.webContents.send('controller/os/window2ToWindow1', content);
|
||||
} else if (receiver == 'window2') {
|
||||
const win = this.windows[receiver];
|
||||
win.webContents.send('controller/os/window1ToWindow2', content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* createNotification
|
||||
*/
|
||||
createNotification(options: any, event: any): void {
|
||||
const channel = 'controller/os/sendNotification';
|
||||
this.myNotification = new Notification(options);
|
||||
|
||||
if (options.clickEvent) {
|
||||
this.myNotification.on('click', () => {
|
||||
let data = {
|
||||
type: 'click',
|
||||
msg: '您点击了通知消息'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
}
|
||||
|
||||
if (options.closeEvent) {
|
||||
this.myNotification.on('close', () => {
|
||||
let data = {
|
||||
type: 'close',
|
||||
msg: '您关闭了通知消息'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
}
|
||||
|
||||
this.myNotification.show();
|
||||
}
|
||||
|
||||
}
|
||||
WindowService.toString = () => '[class WindowService]';
|
||||
const windowService = new WindowService();
|
||||
|
||||
export {
|
||||
WindowService,
|
||||
windowService
|
||||
}
|
||||
Reference in New Issue
Block a user