mirror of
https://gitee.com/dromara/electron-egg.git
synced 2026-05-14 19:52:10 +08:00
feat: rewrite controller service
This commit is contained in:
@@ -10,14 +10,27 @@ class CrossController {
|
||||
* View process service information
|
||||
*/
|
||||
info() {
|
||||
const pids = Cross.getPids();
|
||||
Log.info('cross pids:', pids);
|
||||
|
||||
let num = 1;
|
||||
pids.forEach(pid => {
|
||||
let entity = Cross.getProc(pid);
|
||||
Log.info(`server-${num} name:${entity.name}`);
|
||||
Log.info(`server-${num} config:`, entity.config);
|
||||
num++;
|
||||
})
|
||||
|
||||
return 'hello electron-egg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service url
|
||||
*/
|
||||
async getUrl(args) {
|
||||
|
||||
const { name } = args;
|
||||
const serverUrl = Cross.getUrl(name);
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,21 +38,51 @@ class CrossController {
|
||||
* By default (modifiable), killing the process will exit the electron application.
|
||||
*/
|
||||
async killServer(args) {
|
||||
const { type, name } = args;
|
||||
if (type == 'all') {
|
||||
Cross.killAll();
|
||||
} else {
|
||||
Cross.killByName(name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* create service
|
||||
*/
|
||||
async createServer(args) {
|
||||
const { program } = args;
|
||||
if (program == 'go') {
|
||||
Services.get('cross').createGoServer();
|
||||
} else if (program == 'java') {
|
||||
Services.get('cross').createJavaServer();
|
||||
} else if (program == 'python') {
|
||||
Services.get('cross').createPythonServer();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the api for the cross service
|
||||
*/
|
||||
async requestApi(args) {
|
||||
const { name, urlPath, params} = args;
|
||||
const hc = new HttpClient();
|
||||
const serverUrl = Cross.getUrl(name);
|
||||
console.log('Server Url:', serverUrl);
|
||||
|
||||
const apiHello = serverUrl + urlPath;
|
||||
const options = {
|
||||
method: 'GET',
|
||||
data: params || {},
|
||||
dataType: 'json',
|
||||
timeout: 1000,
|
||||
};
|
||||
const result = await hc.request(apiHello, options);
|
||||
|
||||
return result.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,65 @@
|
||||
'use strict';
|
||||
|
||||
const { dialog } = require('electron');
|
||||
const _ = require('lodash');
|
||||
const { getMainWindow } = require('ee-core/electron/window');
|
||||
|
||||
/**
|
||||
* 特效 - 功能demo
|
||||
* effect - demo
|
||||
* @class
|
||||
*/
|
||||
class EffectController {
|
||||
|
||||
/**
|
||||
* 选择文件
|
||||
* select file
|
||||
*/
|
||||
selectFile() {
|
||||
const filePaths = dialog.showOpenDialogSync({
|
||||
properties: ['openFile']
|
||||
});
|
||||
|
||||
if (_.isEmpty(filePaths)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return filePaths[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* login window
|
||||
*/
|
||||
loginWindow(args) {
|
||||
|
||||
const { width, height } = args;
|
||||
const win = getMainWindow();
|
||||
|
||||
const size = {
|
||||
width: width || 400,
|
||||
height: height || 300
|
||||
}
|
||||
win.setSize(size.width, size.height);
|
||||
win.setResizable(true);
|
||||
win.center();
|
||||
win.show();
|
||||
win.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* restore window
|
||||
*/
|
||||
restoreWindow(args) {
|
||||
const { width, height } = args;
|
||||
const win = getMainWindow();
|
||||
|
||||
}
|
||||
const size = {
|
||||
width: width || 980,
|
||||
height: height || 650
|
||||
}
|
||||
win.setSize(size.width, size.height);
|
||||
win.setResizable(true);
|
||||
win.center();
|
||||
win.show();
|
||||
win.focus();
|
||||
}
|
||||
}
|
||||
|
||||
EffectController.toString = () => '[class EffectController]';
|
||||
|
||||
@@ -1,17 +1,277 @@
|
||||
'use strict';
|
||||
|
||||
const dayjs = require('dayjs');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { exec } = require('child_process');
|
||||
const { app: electronApp, shell } = require('electron');
|
||||
const { getExtraResourcesDir } = require('ee-core/ps');
|
||||
const { logger } = require('ee-core/log');
|
||||
const { getConfig } = require('ee-core/config');
|
||||
|
||||
/**
|
||||
* example
|
||||
* framework - demo
|
||||
* @class
|
||||
*/
|
||||
class FrameworkController {
|
||||
|
||||
/**
|
||||
* test
|
||||
* 所有方法接收两个参数
|
||||
* @param args 前端传的参数
|
||||
* @param event - ipc通信时才有值。详情见:控制器文档
|
||||
*/
|
||||
async test () {
|
||||
return 'hello electron-egg';
|
||||
|
||||
/**
|
||||
* sqlite数据库操作
|
||||
*/
|
||||
async sqlitedbOperation(args) {
|
||||
const { action, info, delete_name, update_name, update_age, search_age, data_dir } = args;
|
||||
|
||||
const data = {
|
||||
action,
|
||||
result: null,
|
||||
all_list: [],
|
||||
code: 0
|
||||
};
|
||||
|
||||
try {
|
||||
// test
|
||||
Services.get('database.sqlitedb').getDataDir();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
data.code = -1;
|
||||
return data;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case 'add' :
|
||||
data.result = await Services.get('database.sqlitedb').addTestDataSqlite(info);;
|
||||
break;
|
||||
case 'del' :
|
||||
data.result = await Services.get('database.sqlitedb').delTestDataSqlite(delete_name);;
|
||||
break;
|
||||
case 'update' :
|
||||
data.result = await Services.get('database.sqlitedb').updateTestDataSqlite(update_name, update_age);
|
||||
break;
|
||||
case 'get' :
|
||||
data.result = await Services.get('database.sqlitedb').getTestDataSqlite(search_age);
|
||||
break;
|
||||
case 'getDataDir' :
|
||||
data.result = await Services.get('database.sqlitedb').getDataDir();
|
||||
break;
|
||||
case 'setDataDir' :
|
||||
data.result = await Services.get('database.sqlitedb').setCustomDataDir(data_dir);
|
||||
break;
|
||||
}
|
||||
|
||||
data.all_list = await Services.get('database.sqlitedb').getAllTestDataSqlite();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用其它程序(exe、bash等可执行程序)
|
||||
*
|
||||
*/
|
||||
openSoftware(softName) {
|
||||
if (!softName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let softwarePath = path.join(getExtraResourcesDir(), softName);
|
||||
logger.info('[openSoftware] softwarePath:', softwarePath);
|
||||
|
||||
// 检查程序是否存在
|
||||
if (!fs.existsSync(softwarePath)) {
|
||||
return false;
|
||||
}
|
||||
// 命令行字符串 并 执行, start 命令后面的路径要加双引号
|
||||
let cmdStr = `start "${softwarePath}"`;
|
||||
exec(cmdStr);
|
||||
|
||||
// 方法二
|
||||
// 推荐使用cross模块
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有新版本
|
||||
*/
|
||||
checkForUpdater() {
|
||||
Addon.get('autoUpdater').checkUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载新版本
|
||||
*/
|
||||
downloadApp() {
|
||||
Addon.get('autoUpdater').download();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测http服务是否开启
|
||||
*/
|
||||
async checkHttpServer() {
|
||||
const { httpServer } = getConfig;
|
||||
const url = httpServer.protocol + httpServer.host + ':' + httpServer.port;
|
||||
|
||||
const data = {
|
||||
enable: httpServer.enable,
|
||||
server: url
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* [todo] 一个http请求访问此方法
|
||||
*/
|
||||
async doHttpRequest() {
|
||||
const { CoreApp } = EE;
|
||||
// http方法
|
||||
const method = CoreApp.request.method;
|
||||
// http get 参数
|
||||
let params = CoreApp.request.query;
|
||||
params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
|
||||
// http post 参数
|
||||
const body = CoreApp.request.body;
|
||||
|
||||
const httpInfo = {
|
||||
method,
|
||||
params,
|
||||
body
|
||||
}
|
||||
Log.info('httpInfo:', httpInfo);
|
||||
|
||||
if (!body.id) {
|
||||
return false;
|
||||
}
|
||||
const dir = electronApp.getPath(body.id);
|
||||
shell.openPath(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个socket io请求访问此方法
|
||||
*/
|
||||
async doSocketRequest(args) {
|
||||
const { id } = args;
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
const dir = electronApp.getPath(id);
|
||||
shell.openPath(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步消息类型
|
||||
*/
|
||||
async ipcInvokeMsg(args, event) {
|
||||
let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
const data = args + ' - ' + timeNow;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步消息类型
|
||||
*/
|
||||
async ipcSendSyncMsg(args) {
|
||||
let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
const data = args + ' - ' + timeNow;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 双向异步通信
|
||||
*/
|
||||
async ipcSendMsg(args, event) {
|
||||
const { type, content } = args;
|
||||
const data = await Services.get('framework').bothWayMessage(type, content, event);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务
|
||||
*/
|
||||
someJob(args, event) {
|
||||
let jobId = args.id;
|
||||
let action = args.action;
|
||||
|
||||
let result;
|
||||
switch (action) {
|
||||
case 'create':
|
||||
result = Services.get('framework').doJob(jobId, action, event);
|
||||
break;
|
||||
case 'close':
|
||||
Services.get('framework').doJob(jobId, action, event);
|
||||
break;
|
||||
case 'pause':
|
||||
Services.get('framework').doJob(jobId, action, event);
|
||||
break;
|
||||
case 'resume':
|
||||
Services.get('framework').doJob(jobId, action, event);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
let data = {
|
||||
jobId,
|
||||
action,
|
||||
result
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建任务池
|
||||
*/
|
||||
async createPool(args, event) {
|
||||
let num = args.number;
|
||||
Services.get('framework').doCreatePool(num, event);
|
||||
|
||||
// test monitor
|
||||
Services.get('framework').monitorJob();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过进程池执行任务
|
||||
*/
|
||||
someJobByPool(args, event) {
|
||||
let jobId = args.id;
|
||||
let action = args.action;
|
||||
|
||||
let result;
|
||||
switch (action) {
|
||||
case 'run':
|
||||
result = Services.get('framework').doJobByPool(jobId, action, event);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
let data = {
|
||||
jobId,
|
||||
action,
|
||||
result
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试接口
|
||||
*/
|
||||
hello(args) {
|
||||
Log.info('hello ', args);
|
||||
}
|
||||
}
|
||||
|
||||
FrameworkController.toString = () => '[class FrameworkController]';
|
||||
|
||||
66
electron/controller/hardware.js
Normal file
66
electron/controller/hardware.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const { getBaseDir } = require('ee-core/ps');
|
||||
const { getMainWindow } = require('ee-core/electron/window');
|
||||
|
||||
/**
|
||||
* 硬件设备 - 功能demo
|
||||
* @class
|
||||
*/
|
||||
class HardwareController {
|
||||
|
||||
/**
|
||||
* 获取打印机列表
|
||||
*/
|
||||
async getPrinterList () {
|
||||
|
||||
//主线程获取打印机列表
|
||||
const win = getMainWindow();
|
||||
const list = await win.webContents.getPrintersAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
*/
|
||||
print (args, event) {
|
||||
const { view, deviceName } = args;
|
||||
let content = null;
|
||||
if (view.type == 'html') {
|
||||
content = path.join('file://', getBaseDir(), view.content)
|
||||
} else {
|
||||
content = view.content;
|
||||
}
|
||||
|
||||
let opt = {
|
||||
title: 'printer window',
|
||||
x: 10,
|
||||
y: 10,
|
||||
width: 980,
|
||||
height: 650
|
||||
}
|
||||
const name = 'window-printer';
|
||||
const printWindow = Addon.get('window').create(name, opt);
|
||||
|
||||
printWindow.loadURL(content);
|
||||
printWindow.webContents.once('did-finish-load', () => {
|
||||
// 页面完全加载完成后,开始打印
|
||||
printWindow.webContents.print({
|
||||
silent: false, // 显示打印对话框
|
||||
printBackground: true,
|
||||
deviceName,
|
||||
}, (success, failureReason) => {
|
||||
const channel = 'controller.hardware.printStatus';
|
||||
event.reply(`${channel}`, { success, failureReason });
|
||||
printWindow.close();
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
HardwareController.toString = () => '[class HardwareController]';
|
||||
module.exports = HardwareController;
|
||||
@@ -1,5 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const {
|
||||
app: electronApp, dialog, shell, Notification,
|
||||
powerMonitor, screen, nativeTheme
|
||||
} = require('electron');
|
||||
const { isProd, getBaseDir } = require('ee-core/ps');
|
||||
|
||||
/**
|
||||
* example
|
||||
* @class
|
||||
@@ -7,11 +15,325 @@
|
||||
class OsController {
|
||||
|
||||
/**
|
||||
* test
|
||||
* 所有方法接收两个参数
|
||||
* @param args 前端传的参数
|
||||
* @param event - ipc通信时才有值。详情见:控制器文档
|
||||
*/
|
||||
async test () {
|
||||
return 'hello electron-egg';
|
||||
|
||||
/**
|
||||
* 消息提示对话框
|
||||
*/
|
||||
messageShow() {
|
||||
dialog.showMessageBoxSync({
|
||||
type: 'info', // "none", "info", "error", "question" 或者 "warning"
|
||||
title: '自定义标题-message',
|
||||
message: '自定义消息内容',
|
||||
detail: '其它的额外信息'
|
||||
})
|
||||
|
||||
return '打开了消息框';
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息提示与确认对话框
|
||||
*/
|
||||
messageShowConfirm() {
|
||||
const res = dialog.showMessageBoxSync({
|
||||
type: 'info',
|
||||
title: '自定义标题-message',
|
||||
message: '自定义消息内容',
|
||||
detail: '其它的额外信息',
|
||||
cancelId: 1, // 用于取消对话框的按钮的索引
|
||||
defaultId: 0, // 设置默认选中的按钮
|
||||
buttons: ['确认', '取消'], // 按钮及索引
|
||||
})
|
||||
let data = (res === 0) ? '点击确认按钮' : '点击取消按钮';
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择目录
|
||||
*/
|
||||
selectFolder() {
|
||||
const filePaths = dialog.showOpenDialogSync({
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
});
|
||||
|
||||
if (_.isEmpty(filePaths)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return filePaths[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开目录
|
||||
*/
|
||||
openDirectory(args) {
|
||||
const { id } = args;
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
let dir = '';
|
||||
if (path.isAbsolute(id)) {
|
||||
dir = id;
|
||||
} else {
|
||||
dir = electronApp.getPath(id);
|
||||
}
|
||||
|
||||
shell.openPath(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择图片
|
||||
*/
|
||||
selectPic() {
|
||||
const filePaths = dialog.showOpenDialogSync({
|
||||
title: 'select pic',
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] },
|
||||
]
|
||||
});
|
||||
if (_.isEmpty(filePaths)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return filePaths[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载视图内容
|
||||
*/
|
||||
loadViewContent(args) {
|
||||
const { type, content } = args;
|
||||
let contentUrl = content;
|
||||
if (type == 'html') {
|
||||
contentUrl = path.join('file://', electronApp.getAppPath(), content);
|
||||
}
|
||||
|
||||
Services.get('os').createBrowserView(contentUrl);
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除视图内容
|
||||
*/
|
||||
removeViewContent() {
|
||||
Services.get('os').removeBrowserView();
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开新窗口
|
||||
*/
|
||||
createWindow(args) {
|
||||
const { type, content, windowName, windowTitle } = args;
|
||||
let contentUrl = null;
|
||||
if (type == 'html') {
|
||||
contentUrl = path.join('file://', electronApp.getAppPath(), content)
|
||||
} else if (type == 'web') {
|
||||
contentUrl = content;
|
||||
} else if (type == 'vue') {
|
||||
let addr = 'http://localhost:8080'
|
||||
if (isProd()) {
|
||||
const mainServer = Conf.getValue('mainServer');
|
||||
if (Conf.isFileProtocol(mainServer)) {
|
||||
addr = mainServer.protocol + path.join(Ps.getHomeDir(), mainServer.indexPath);
|
||||
} else {
|
||||
addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
|
||||
}
|
||||
}
|
||||
|
||||
contentUrl = addr + content;
|
||||
} else {
|
||||
// some
|
||||
}
|
||||
|
||||
console.log('contentUrl: ', contentUrl);
|
||||
let opt = {
|
||||
title: windowTitle
|
||||
}
|
||||
const win = Addon.get('window').create(windowName, opt);
|
||||
const winContentsId = win.webContents.id;
|
||||
|
||||
// load page
|
||||
win.loadURL(contentUrl);
|
||||
|
||||
return winContentsId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取窗口contents id
|
||||
*/
|
||||
getWCid(args) {
|
||||
// 主窗口的name默认是main,其它窗口name开发者自己定义
|
||||
const name = args;
|
||||
const id = Addon.get('window').getWCid(name);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建系统通知
|
||||
*/
|
||||
sendNotification(args, event) {
|
||||
const { title, subtitle, body, silent} = args;
|
||||
|
||||
if (!Notification.isSupported()) {
|
||||
return '当前系统不支持通知';
|
||||
}
|
||||
|
||||
let options = {};
|
||||
if (!_.isEmpty(title)) {
|
||||
options.title = title;
|
||||
}
|
||||
if (!_.isEmpty(subtitle)) {
|
||||
options.subtitle = subtitle;
|
||||
}
|
||||
if (!_.isEmpty(body)) {
|
||||
options.body = body;
|
||||
}
|
||||
if (!_.isEmpty(silent)) {
|
||||
options.silent = silent;
|
||||
}
|
||||
|
||||
Services.get('os').createNotification(options, event);
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 电源监控
|
||||
*/
|
||||
initPowerMonitor(args, event) {
|
||||
const channel = 'controller.os.initPowerMonitor';
|
||||
powerMonitor.on('on-ac', (e) => {
|
||||
let data = {
|
||||
type: 'on-ac',
|
||||
msg: '接入了电源'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
|
||||
powerMonitor.on('on-battery', (e) => {
|
||||
let data = {
|
||||
type: 'on-battery',
|
||||
msg: '使用电池中'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
|
||||
powerMonitor.on('lock-screen', (e) => {
|
||||
let data = {
|
||||
type: 'lock-screen',
|
||||
msg: '锁屏了'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
|
||||
powerMonitor.on('unlock-screen', (e) => {
|
||||
let data = {
|
||||
type: 'unlock-screen',
|
||||
msg: '解锁了'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取屏幕信息
|
||||
*/
|
||||
getScreen(args) {
|
||||
let data = [];
|
||||
let res = {};
|
||||
if (args == 0) {
|
||||
let res = screen.getCursorScreenPoint();
|
||||
data = [
|
||||
{
|
||||
title: '横坐标',
|
||||
desc: res.x
|
||||
},
|
||||
{
|
||||
title: '纵坐标',
|
||||
desc: res.y
|
||||
},
|
||||
]
|
||||
|
||||
return data;
|
||||
}
|
||||
if (args == 1) {
|
||||
res = screen.getPrimaryDisplay();
|
||||
}
|
||||
if (args == 2) {
|
||||
let resArr = screen.getAllDisplays();
|
||||
// 数组,只取一个吧
|
||||
res = resArr[0];
|
||||
}
|
||||
// Log.info('[electron] [ipc] [example] [getScreen] res:', res);
|
||||
data = [
|
||||
{
|
||||
title: '分辨率',
|
||||
desc: res.bounds.width + ' x ' + res.bounds.height
|
||||
},
|
||||
{
|
||||
title: '单色显示器',
|
||||
desc: res.monochrome ? '是' : '否'
|
||||
},
|
||||
{
|
||||
title: '色深',
|
||||
desc: res. colorDepth
|
||||
},
|
||||
{
|
||||
title: '色域',
|
||||
desc: res.colorSpace
|
||||
},
|
||||
{
|
||||
title: 'scaleFactor',
|
||||
desc: res.scaleFactor
|
||||
},
|
||||
{
|
||||
title: '加速器',
|
||||
desc: res.accelerometerSupport
|
||||
},
|
||||
{
|
||||
title: '触控',
|
||||
desc: res.touchSupport == 'unknown' ? '不支持' : '支持'
|
||||
},
|
||||
]
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统主题
|
||||
*/
|
||||
getTheme() {
|
||||
let theme = 'system';
|
||||
if (nativeTheme.shouldUseHighContrastColors) {
|
||||
theme = 'light';
|
||||
} else if (nativeTheme.shouldUseInvertedColorScheme) {
|
||||
theme = 'dark';
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统主题
|
||||
*/
|
||||
setTheme(args) {
|
||||
|
||||
// TODO 好像没有什么明显效果
|
||||
nativeTheme.themeSource = args;
|
||||
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
OsController.toString = () => '[class OsController]';
|
||||
|
||||
101
electron/service/cross.js
Normal file
101
electron/service/cross.js
Normal file
@@ -0,0 +1,101 @@
|
||||
'use strict';
|
||||
|
||||
const { logger } = require('ee-core/log');
|
||||
const { getExtraResourcesDir } = require('ee-core/ps');
|
||||
const path = require("path");
|
||||
const Is = require('ee-core/utils/is');
|
||||
|
||||
/**
|
||||
* cross
|
||||
* @class
|
||||
*/
|
||||
class CrossService {
|
||||
|
||||
/**
|
||||
* create go service
|
||||
* In the default configuration, services can be started with applications.
|
||||
* Developers can turn off the configuration and create it manually.
|
||||
*/
|
||||
async createGoServer() {
|
||||
// method 1: Use the default Settings
|
||||
//const entity = await Cross.run(serviceName);
|
||||
|
||||
// method 2: Use custom configuration
|
||||
const serviceName = "go";
|
||||
const opt = {
|
||||
name: 'goapp',
|
||||
cmd: path.join(getExtraResourcesDir(), 'goapp'),
|
||||
directory: getExtraResourcesDir(),
|
||||
args: ['--port=7073'],
|
||||
appExit: true,
|
||||
}
|
||||
const entity = await Cross.run(serviceName, opt);
|
||||
logger.info('server name:', entity.name);
|
||||
logger.info('server config:', entity.config);
|
||||
logger.info('server url:', entity.getUrl());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* create java server
|
||||
*/
|
||||
async createJavaServer() {
|
||||
const serviceName = "java";
|
||||
const jarPath = path.join(getExtraResourcesDir(), 'java-app.jar');
|
||||
const opt = {
|
||||
name: 'javaapp',
|
||||
cmd: path.join(getExtraResourcesDir(), 'jre1.8.0_201/bin/javaw.exe'),
|
||||
directory: getExtraResourcesDir(),
|
||||
args: ['-jar', '-server', '-Xms512M', '-Xmx512M', '-Xss512k', '-Dspring.profiles.active=prod', `-Dserver.port=18080`, `-Dlogging.file.path=${Ps.getLogDir()}`, `${jarPath}`],
|
||||
appExit: false,
|
||||
}
|
||||
if (Is.macOS()) {
|
||||
// Setup Java program
|
||||
opt.cmd = path.join(Ps.getExtraResourcesDir(), 'jre1.8.0_201.jre/Contents/Home/bin/java');
|
||||
}
|
||||
if (Is.linux()) {
|
||||
// Setup Java program
|
||||
}
|
||||
|
||||
const entity = await Cross.run(serviceName, opt);
|
||||
logger.info('server name:', entity.name);
|
||||
logger.info('server config:', entity.config);
|
||||
logger.info('server url:', Cross.getUrl(entity.name));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* create python service
|
||||
* In the default configuration, services can be started with applications.
|
||||
* Developers can turn off the configuration and create it manually.
|
||||
*/
|
||||
async createPythonServer() {
|
||||
// method 1: Use the default Settings
|
||||
//const entity = await Cross.run(serviceName);
|
||||
|
||||
// method 2: Use custom configuration
|
||||
const serviceName = "python";
|
||||
const opt = {
|
||||
name: 'pyapp',
|
||||
cmd: path.join(getExtraResourcesDir(), 'py', 'pyapp'),
|
||||
directory: path.join(getExtraResourcesDir(), 'py'),
|
||||
args: ['--port=7074'],
|
||||
windowsExtname: true,
|
||||
appExit: true,
|
||||
}
|
||||
const entity = await Cross.run(serviceName, opt);
|
||||
logger.info('server name:', entity.name);
|
||||
logger.info('server config:', entity.config);
|
||||
logger.info('server url:', entity.getUrl());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CrossService.toString = () => '[class CrossService]';
|
||||
module.exports = {
|
||||
CrossService,
|
||||
crossService: new CrossService()
|
||||
};
|
||||
163
electron/service/database/sqlitedb.js
Normal file
163
electron/service/database/sqlitedb.js
Normal file
@@ -0,0 +1,163 @@
|
||||
'use strict';
|
||||
|
||||
const Storage = require('ee-core/storage');
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* sqlite数据存储
|
||||
* @class
|
||||
*/
|
||||
class SqlitedbService {
|
||||
|
||||
constructor () {
|
||||
this.sqliteFile = 'sqlite-demo.db';
|
||||
let sqliteOptions = {
|
||||
driver: 'sqlite',
|
||||
default: {
|
||||
timeout: 6000,
|
||||
verbose: console.log // 打印sql语法
|
||||
}
|
||||
}
|
||||
this.demoSqliteDB = Storage.connection(this.sqliteFile, sqliteOptions);
|
||||
}
|
||||
|
||||
/*
|
||||
* 检查并创建表 (sqlite)
|
||||
*/
|
||||
async checkAndCreateTableSqlite(tableName = '') {
|
||||
if (_.isEmpty(tableName)) {
|
||||
throw new Error(`table name is required`);
|
||||
}
|
||||
// 检查表是否存在
|
||||
const userTable = this.demoSqliteDB.db.prepare('SELECT * FROM sqlite_master WHERE type=? AND name = ?');
|
||||
const result = userTable.get('table', tableName);
|
||||
//console.log('result:', result);
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建表
|
||||
const create_table_user =
|
||||
`CREATE TABLE ${tableName}
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name CHAR(50) NOT NULL,
|
||||
age INT
|
||||
);`
|
||||
this.demoSqliteDB.db.exec(create_table_user);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 增 Test data (sqlite)
|
||||
*/
|
||||
async addTestDataSqlite(data) {
|
||||
//console.log("add data:", data);
|
||||
|
||||
let table = 'user';
|
||||
await this.checkAndCreateTableSqlite(table);
|
||||
|
||||
const insert = this.demoSqliteDB.db.prepare(`INSERT INTO ${table} (name, age) VALUES (@name, @age)`);
|
||||
insert.run(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 删 Test data (sqlite)
|
||||
*/
|
||||
async delTestDataSqlite(name = '') {
|
||||
//console.log("delete name:", name);
|
||||
|
||||
let table = 'user';
|
||||
await this.checkAndCreateTableSqlite(table);
|
||||
|
||||
const delUser = this.demoSqliteDB.db.prepare(`DELETE FROM ${table} WHERE name = ?`);
|
||||
delUser.run(name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 改 Test data (sqlite)
|
||||
*/
|
||||
async updateTestDataSqlite(name= '', age = 0) {
|
||||
//console.log("update :", {name, age});
|
||||
|
||||
let table = 'user';
|
||||
await this.checkAndCreateTableSqlite(table);
|
||||
|
||||
const updateUser = this.demoSqliteDB.db.prepare(`UPDATE ${table} SET age = ? WHERE name = ?`);
|
||||
updateUser.run(age, name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 查 Test data (sqlite)
|
||||
*/
|
||||
async getTestDataSqlite(age = 0) {
|
||||
//console.log("select :", {age});
|
||||
|
||||
let table = 'user';
|
||||
await this.checkAndCreateTableSqlite(table);
|
||||
|
||||
const selectUser = this.demoSqliteDB.db.prepare(`SELECT * FROM ${table} WHERE age = @age`);
|
||||
const users = selectUser.all({age: age});
|
||||
//console.log("select users:", users);
|
||||
return users;
|
||||
}
|
||||
|
||||
/*
|
||||
* all Test data (sqlite)
|
||||
*/
|
||||
async getAllTestDataSqlite() {
|
||||
//console.log("select all user");
|
||||
|
||||
let table = 'user';
|
||||
await this.checkAndCreateTableSqlite(table);
|
||||
|
||||
const selectAllUser = this.demoSqliteDB.db.prepare(`SELECT * FROM ${table} `);
|
||||
const allUser = selectAllUser.all();
|
||||
//console.log("select allUser:", allUser);
|
||||
return allUser;
|
||||
}
|
||||
|
||||
/*
|
||||
* get data dir (sqlite)
|
||||
*/
|
||||
async getDataDir() {
|
||||
const dir = this.demoSqliteDB.getStorageDir();
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* set custom data dir (sqlite)
|
||||
*/
|
||||
async setCustomDataDir(dir) {
|
||||
if (_.isEmpty(dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the absolute path of the db file
|
||||
const dbFile = path.join(dir, this.sqliteFile);
|
||||
const sqliteOptions = {
|
||||
driver: 'sqlite',
|
||||
default: {
|
||||
timeout: 6000,
|
||||
verbose: console.log
|
||||
}
|
||||
}
|
||||
this.demoSqliteDB = Storage.connection(dbFile, sqliteOptions);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SqlitedbService.toString = () => '[class SqlitedbService]';
|
||||
module.exports = {
|
||||
SqlitedbService,
|
||||
sqlitedbService: new SqlitedbService()
|
||||
};
|
||||
30
electron/service/effect.js
Normal file
30
electron/service/effect.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
const { logger } = require('ee-core/log');
|
||||
|
||||
/**
|
||||
* effect
|
||||
* @class
|
||||
*/
|
||||
class EffectService {
|
||||
|
||||
/**
|
||||
* hello
|
||||
*/
|
||||
async hello(args) {
|
||||
let obj = {
|
||||
status:'ok',
|
||||
params: args
|
||||
}
|
||||
logger.info('EffectService obj:', obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EffectService.toString = () => '[class EffectService]';
|
||||
module.exports = {
|
||||
EffectService,
|
||||
effectService: new EffectService()
|
||||
};
|
||||
@@ -1,16 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const { Service } = require('ee-core');
|
||||
const { logger } = require('ee-core/log');
|
||||
|
||||
/**
|
||||
* 示例服务(service层为单例)
|
||||
* 示例服务
|
||||
* @class
|
||||
*/
|
||||
class ExampleService extends Service {
|
||||
|
||||
constructor(ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
class ExampleService {
|
||||
|
||||
/**
|
||||
* test
|
||||
@@ -21,9 +17,16 @@ class ExampleService extends Service {
|
||||
params: args
|
||||
}
|
||||
|
||||
logger.info('ExampleService obj:', obj);
|
||||
|
||||
//Services.get('framework').test('egg');
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
ExampleService.toString = () => '[class ExampleService]';
|
||||
module.exports = ExampleService;
|
||||
module.exports = {
|
||||
ExampleService,
|
||||
exampleService: new ExampleService()
|
||||
};
|
||||
164
electron/service/framework.js
Normal file
164
electron/service/framework.js
Normal file
@@ -0,0 +1,164 @@
|
||||
'use strict';
|
||||
|
||||
const { logger } = require('ee-core/log');
|
||||
const { ChildJob, ChildPoolJob } = require('ee-core/jobs');
|
||||
const Ps = require('ee-core/ps');
|
||||
|
||||
/**
|
||||
* framework
|
||||
* @class
|
||||
*/
|
||||
class FrameworkService {
|
||||
|
||||
constructor() {
|
||||
// 在构造函数中初始化一些变量
|
||||
this.myTimer = null;
|
||||
this.myJob = new ChildJob();
|
||||
this.myJobPool = new ChildPoolJob();
|
||||
this.taskForJob = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* test
|
||||
*/
|
||||
async test(args) {
|
||||
let obj = {
|
||||
status:'ok',
|
||||
params: args
|
||||
}
|
||||
logger.info('FrameworkService obj:', obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipc通信(双向)
|
||||
*/
|
||||
bothWayMessage(type, content, event) {
|
||||
// 前端ipc频道 channel
|
||||
const channel = 'controller.framework.ipcSendMsg';
|
||||
|
||||
if (type == 'start') {
|
||||
// 每隔1秒,向前端页面发送消息
|
||||
// 用定时器模拟
|
||||
this.myTimer = setInterval(function(e, c, msg) {
|
||||
let timeNow = Date.now();
|
||||
let data = msg + ':' + timeNow;
|
||||
e.reply(`${c}`, data)
|
||||
}, 1000, event, channel, content)
|
||||
|
||||
return '开始了'
|
||||
} else if (type == 'end') {
|
||||
clearInterval(this.myTimer);
|
||||
return '停止了'
|
||||
} else {
|
||||
return 'ohther'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*/
|
||||
doJob(jobId, action, event) {
|
||||
let res = {};
|
||||
let oneTask;
|
||||
const channel = 'controller.framework.timerJobProgress';
|
||||
if (action == 'create') {
|
||||
// 执行任务及监听进度
|
||||
let eventName = 'job-timer-progress-' + jobId;
|
||||
const timerTask = this.myJob.exec('./jobs/example/timer', {jobId});
|
||||
timerTask.emitter.on(eventName, (data) => {
|
||||
logger.info('[main-process] timerTask, from TimerJob data:', data);
|
||||
// 发送数据到渲染进程
|
||||
event.sender.send(`${channel}`, data)
|
||||
})
|
||||
|
||||
// 执行任务及监听进度 异步
|
||||
// myjob.execPromise('./jobs/example/timer', {jobId}).then(task => {
|
||||
// task.emitter.on(eventName, (data) => {
|
||||
// Log.info('[main-process] timerTask, from TimerJob data:', data);
|
||||
// // 发送数据到渲染进程
|
||||
// event.sender.send(`${channel}`, data)
|
||||
// })
|
||||
// });
|
||||
|
||||
res.pid = timerTask.pid;
|
||||
this.taskForJob[jobId] = timerTask;
|
||||
}
|
||||
if (action == 'close') {
|
||||
oneTask = this.taskForJob[jobId];
|
||||
oneTask.kill();
|
||||
event.sender.send(`${channel}`, {jobId, number:0, pid:0});
|
||||
}
|
||||
if (action == 'pause') {
|
||||
oneTask = this.taskForJob[jobId];
|
||||
oneTask.callFunc('./jobs/example/timer', 'pause', jobId);
|
||||
}
|
||||
if (action == 'resume') {
|
||||
oneTask = this.taskForJob[jobId];
|
||||
oneTask.callFunc('./jobs/example/timer', 'resume', jobId, oneTask.pid);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 创建pool
|
||||
*/
|
||||
doCreatePool(num, event) {
|
||||
const channel = 'controller.framework.createPoolNotice';
|
||||
this.myJobPool.create(num).then(pids => {
|
||||
event.reply(`${channel}`, pids);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过进程池执行任务
|
||||
*/
|
||||
doJobByPool(jobId, action, event) {
|
||||
let res = {};
|
||||
const channel = 'controller.framework.timerJobProgress';
|
||||
if (action == 'run') {
|
||||
// 异步-执行任务及监听进度
|
||||
this.myJobPool.runPromise('./jobs/example/timer', {jobId}).then(task => {
|
||||
|
||||
// 监听器名称唯一,否则会出现重复监听。
|
||||
// 任务完成时,需要移除监听器,防止内存泄漏
|
||||
let eventName = 'job-timer-progress-' + jobId;
|
||||
task.emitter.on(eventName, (data) => {
|
||||
logger.info('[main-process] [ChildPoolJob] timerTask, from TimerJob data:', data);
|
||||
|
||||
// 发送数据到渲染进程
|
||||
event.sender.send(`${channel}`, data)
|
||||
|
||||
// 如果收到任务完成的消息,移除监听器
|
||||
if (data.end) {
|
||||
task.emitter.removeAllListeners(eventName);
|
||||
}
|
||||
});
|
||||
|
||||
res.pid = task.pid;
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取正在运行的 job 进程
|
||||
*/
|
||||
monitorJob() {
|
||||
setInterval(() => {
|
||||
let jobPids = this.myJob.getPids();
|
||||
let jobPoolPids = this.myJobPool.getPids();
|
||||
logger.info(`[main-process] [monitorJob] jobPids: ${jobPids}, jobPoolPids: ${jobPoolPids}`);
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FrameworkService.toString = () => '[class FrameworkService]';
|
||||
module.exports = {
|
||||
FrameworkService,
|
||||
frameworkService: new FrameworkService()
|
||||
};
|
||||
28
electron/service/job/user.js
Normal file
28
electron/service/job/user.js
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
const { logger } = require('ee-core/log');
|
||||
|
||||
/**
|
||||
* job 中使用的 service 不要继承 const { Service } = require('ee-core')
|
||||
* 因为 Service 中会依赖 electron 的 api 导致错误
|
||||
* @class
|
||||
*/
|
||||
class UserService {
|
||||
|
||||
/**
|
||||
* hello
|
||||
*/
|
||||
async hello(args) {
|
||||
let obj = {
|
||||
status:'ok',
|
||||
params: args
|
||||
}
|
||||
logger.info('UserService obj:', obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UserService.toString = () => '[class UserService]';
|
||||
module.exports = UserService;
|
||||
88
electron/service/os.js
Normal file
88
electron/service/os.js
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
const { BrowserView, Notification } = require('electron');
|
||||
const { getMainWindow } = require('ee-core/electron/window');
|
||||
|
||||
/**
|
||||
* os
|
||||
* @class
|
||||
*/
|
||||
class OsService {
|
||||
|
||||
constructor() {
|
||||
this.myBrowserView = null;
|
||||
this.myNotification = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* createBrowserView
|
||||
*/
|
||||
createBrowserView(contentUrl) {
|
||||
|
||||
// electron 实验性功能,慎用
|
||||
const win = getMainWindow();
|
||||
this.myBrowserView = new BrowserView();
|
||||
win.setBrowserView(this.myBrowserView);
|
||||
this.myBrowserView.setBounds({
|
||||
x: 300,
|
||||
y: 170,
|
||||
width: 650,
|
||||
height: 400
|
||||
});
|
||||
this.myBrowserView.webContents.loadURL(contentUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* removeBrowserView
|
||||
*/
|
||||
removeBrowserView() {
|
||||
// one
|
||||
this.myBrowserView.webContents.loadURL('about:blank')
|
||||
|
||||
// two - electron 11 remove destroy()
|
||||
// this.myBrowserView.webContents.destroy();
|
||||
|
||||
// three
|
||||
// this.myBrowserView.webContents.forcefullyCrashRenderer()
|
||||
|
||||
// fore
|
||||
// this.myBrowserView.webContents.close
|
||||
}
|
||||
|
||||
/**
|
||||
* createNotification
|
||||
*/
|
||||
createNotification(options, event) {
|
||||
const channel = 'controller.os.sendNotification';
|
||||
this.myNotification = new Notification(options);
|
||||
|
||||
if (options.clickEvent) {
|
||||
this.myNotification.on('click', (e) => {
|
||||
let data = {
|
||||
type: 'click',
|
||||
msg: '您点击了通知消息'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
}
|
||||
|
||||
if (options.closeEvent) {
|
||||
this.myNotification.on('close', (e) => {
|
||||
let data = {
|
||||
type: 'close',
|
||||
msg: '您关闭了通知消息'
|
||||
}
|
||||
event.reply(`${channel}`, data)
|
||||
});
|
||||
}
|
||||
|
||||
this.myNotification.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OsService.toString = () => '[class OsService]';
|
||||
module.exports = {
|
||||
OsService,
|
||||
osService: new OsService()
|
||||
};
|
||||
Reference in New Issue
Block a user