example.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. 'use strict';
  2. const _ = require('lodash');
  3. const path = require('path');
  4. const fs = require('fs');
  5. const { exec } = require('child_process');
  6. const { Controller } = require('ee-core');
  7. const {
  8. app: electronApp,
  9. dialog, shell, BrowserView, Notification,
  10. powerMonitor, screen, nativeTheme
  11. } = require('electron');
  12. const dayjs = require('dayjs');
  13. const Ps = require('ee-core/ps');
  14. const Log = require('ee-core/log');
  15. const Utils = require('ee-core/utils');
  16. let myTimer = null;
  17. let browserViewObj = null;
  18. let notificationObj = null;
  19. /**
  20. * 示例控制器
  21. * @class
  22. */
  23. class ExampleController extends Controller {
  24. constructor(ctx) {
  25. super(ctx);
  26. }
  27. /**
  28. * 所有方法接收两个参数
  29. * @param args 前端传的参数
  30. * @param event - ipc通信时才有值。详情见:控制器文档
  31. */
  32. /**
  33. * test
  34. */
  35. async test () {
  36. const result = await this.service.example.test('electron');
  37. // let tmpDir = Ps.getLogDir();
  38. // Log.info('tmpDir:', tmpDir);
  39. let mid = await Utils.machineIdSync(true);
  40. Log.info('mid 11111111:', mid);
  41. Utils.machineId().then((id) => {
  42. Log.info('mid 222222222:', id);
  43. });
  44. return result;
  45. }
  46. /**
  47. * json数据库操作
  48. */
  49. async dbOperation(args) {
  50. const { service } = this;
  51. const paramsObj = args;
  52. //Log.info('eeeee paramsObj:', paramsObj);
  53. const data = {
  54. action: paramsObj.action,
  55. result: null,
  56. all_list: []
  57. };
  58. switch (paramsObj.action) {
  59. case 'add' :
  60. data.result = await service.storage.addTestData(paramsObj.info);;
  61. break;
  62. case 'del' :
  63. data.result = await service.storage.delTestData(paramsObj.delete_name);;
  64. break;
  65. case 'update' :
  66. data.result = await service.storage.updateTestData(paramsObj.update_name, paramsObj.update_age);
  67. break;
  68. case 'get' :
  69. data.result = await service.storage.getTestData(paramsObj.search_age);
  70. break;
  71. }
  72. data.all_list = await service.storage.getAllTestData();
  73. return data;
  74. }
  75. /**
  76. * sqlite数据库操作
  77. */
  78. async sqlitedbOperation(args) {
  79. const { service } = this;
  80. const paramsObj = args;
  81. //Log.info('eeeee paramsObj:', paramsObj);
  82. const data = {
  83. action: paramsObj.action,
  84. result: null,
  85. all_list: []
  86. };
  87. switch (paramsObj.action) {
  88. case 'add' :
  89. data.result = await service.storage.addTestDataSqlite(paramsObj.info);;
  90. break;
  91. case 'del' :
  92. data.result = await service.storage.delTestDataSqlite(paramsObj.delete_name);;
  93. break;
  94. case 'update' :
  95. data.result = await service.storage.updateTestDataSqlite(paramsObj.update_name, paramsObj.update_age);
  96. break;
  97. case 'get' :
  98. data.result = await service.storage.getTestDataSqlite(paramsObj.search_age);
  99. break;
  100. case 'getDataDir' :
  101. data.result = await service.storage.getDataDir();
  102. break;
  103. case 'setDataDir' :
  104. data.result = await service.storage.setCustomDataDir(paramsObj.data_dir);
  105. break;
  106. }
  107. data.all_list = await service.storage.getAllTestDataSqlite();
  108. return data;
  109. }
  110. /**
  111. * 消息提示对话框
  112. */
  113. messageShow () {
  114. dialog.showMessageBoxSync({
  115. type: 'info', // "none", "info", "error", "question" 或者 "warning"
  116. title: '自定义标题-message',
  117. message: '自定义消息内容',
  118. detail: '其它的额外信息'
  119. })
  120. return '打开了消息框';
  121. }
  122. /**
  123. * 消息提示与确认对话框
  124. */
  125. messageShowConfirm () {
  126. const res = dialog.showMessageBoxSync({
  127. type: 'info',
  128. title: '自定义标题-message',
  129. message: '自定义消息内容',
  130. detail: '其它的额外信息',
  131. cancelId: 1, // 用于取消对话框的按钮的索引
  132. defaultId: 0, // 设置默认选中的按钮
  133. buttons: ['确认', '取消'], // 按钮及索引
  134. })
  135. let data = (res === 0) ? '点击确认按钮' : '点击取消按钮';
  136. return data;
  137. }
  138. /**
  139. * 选择目录
  140. */
  141. selectFolder () {
  142. const filePaths = dialog.showOpenDialogSync({
  143. properties: ['openDirectory', 'createDirectory']
  144. });
  145. if (_.isEmpty(filePaths)) {
  146. return null
  147. }
  148. return filePaths[0];
  149. }
  150. /**
  151. * 打开目录
  152. */
  153. openDirectory (args) {
  154. if (!args.id) {
  155. return false;
  156. }
  157. let dir = '';
  158. if (path.isAbsolute(args.id)) {
  159. dir = args.id;
  160. } else {
  161. dir = electronApp.getPath(args.id);
  162. }
  163. shell.openPath(dir);
  164. return true;
  165. }
  166. /**
  167. * 加载视图内容
  168. */
  169. loadViewContent (args) {
  170. let content = null;
  171. if (args.type == 'html') {
  172. content = path.join('file://', electronApp.getAppPath(), args.content)
  173. } else {
  174. content = args.content;
  175. }
  176. // electron实验性功能,慎用
  177. browserViewObj = new BrowserView();
  178. this.app.electron.mainWindow.setBrowserView(browserViewObj)
  179. browserViewObj.setBounds({
  180. x: 300,
  181. y: 170,
  182. width: 650,
  183. height: 400
  184. });
  185. browserViewObj.webContents.loadURL(content);
  186. return true
  187. }
  188. /**
  189. * 移除视图内容
  190. */
  191. removeViewContent () {
  192. // removeBrowserView移除视图后,进程依然存在,估计是electron bug
  193. this.app.electron.mainWindow.removeBrowserView(browserViewObj);
  194. return true
  195. }
  196. /**
  197. * 打开新窗口
  198. */
  199. createWindow (args) {
  200. let content = null;
  201. if (args.type == 'html') {
  202. content = path.join('file://', electronApp.getAppPath(), args.content)
  203. } else if (args.type == 'web') {
  204. content = args.content;
  205. } else if (args.type == 'vue') {
  206. let addr = 'http://localhost:8080'
  207. if (this.config.env == 'prod') {
  208. const mainServer = this.app.config.mainServer;
  209. addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
  210. }
  211. content = addr + args.content;
  212. } else {
  213. // some
  214. }
  215. const addonWindow = this.app.addon.window;
  216. let opt = {
  217. title: args.windowName || 'new window'
  218. }
  219. const name = args.windowName || 'window-1';
  220. const win = addonWindow.create(name, opt);
  221. const winContentsId = win.webContents.id;
  222. // load page
  223. win.loadURL(content);
  224. return winContentsId
  225. }
  226. /**
  227. * 获取窗口contents id
  228. */
  229. getWCid (args) {
  230. const addonWindow = this.app.addon.window;
  231. // 主窗口的name默认是main,其它窗口name开发者自己定义
  232. const name = args;
  233. const id = addonWindow.getWCid(name);
  234. return id;
  235. }
  236. /**
  237. * 加载扩展程序
  238. */
  239. // async loadExtension (args) {
  240. // const crxFile = args[0];
  241. // if (_.isEmpty(crxFile)) {
  242. // return false;
  243. // }
  244. // const extensionId = path.basename(crxFile, '.crx');
  245. // const chromeExtensionDir = chromeExtension.getDirectory();
  246. // const extensionDir = path.join(chromeExtensionDir, extensionId);
  247. // Log.info("[api] [example] [loadExtension] extension id:", extensionId);
  248. // unzip(crxFile, extensionDir).then(() => {
  249. // Log.info("[api] [example] [loadExtension] unzip success!");
  250. // chromeExtension.load(extensionId);
  251. // });
  252. // return true;
  253. // }
  254. /**
  255. * 创建系统通知
  256. */
  257. sendNotification (arg, event) {
  258. const channel = 'controller.example.sendNotification';
  259. if (!Notification.isSupported()) {
  260. return '当前系统不支持通知';
  261. }
  262. let options = {};
  263. if (!_.isEmpty(arg.title)) {
  264. options.title = arg.title;
  265. }
  266. if (!_.isEmpty(arg.subtitle)) {
  267. options.subtitle = arg.subtitle;
  268. }
  269. if (!_.isEmpty(arg.body)) {
  270. options.body = arg.body;
  271. }
  272. if (!_.isEmpty(arg.silent)) {
  273. options.silent = arg.silent;
  274. }
  275. notificationObj = new Notification(options);
  276. if (arg.clickEvent) {
  277. notificationObj.on('click', (e) => {
  278. let data = {
  279. type: 'click',
  280. msg: '您点击了通知消息'
  281. }
  282. event.reply(`${channel}`, data)
  283. });
  284. }
  285. if (arg.closeEvent) {
  286. notificationObj.on('close', (e) => {
  287. let data = {
  288. type: 'close',
  289. msg: '您关闭了通知消息'
  290. }
  291. event.reply(`${channel}`, data)
  292. });
  293. }
  294. notificationObj.show();
  295. return true
  296. }
  297. /**
  298. * 电源监控
  299. */
  300. initPowerMonitor (arg, event) {
  301. const channel = 'controller.example.initPowerMonitor';
  302. powerMonitor.on('on-ac', (e) => {
  303. let data = {
  304. type: 'on-ac',
  305. msg: '接入了电源'
  306. }
  307. event.reply(`${channel}`, data)
  308. });
  309. powerMonitor.on('on-battery', (e) => {
  310. let data = {
  311. type: 'on-battery',
  312. msg: '使用电池中'
  313. }
  314. event.reply(`${channel}`, data)
  315. });
  316. powerMonitor.on('lock-screen', (e) => {
  317. let data = {
  318. type: 'lock-screen',
  319. msg: '锁屏了'
  320. }
  321. event.reply(`${channel}`, data)
  322. });
  323. powerMonitor.on('unlock-screen', (e) => {
  324. let data = {
  325. type: 'unlock-screen',
  326. msg: '解锁了'
  327. }
  328. event.reply(`${channel}`, data)
  329. });
  330. return true
  331. }
  332. /**
  333. * 获取屏幕信息
  334. */
  335. getScreen (arg) {
  336. let data = [];
  337. let res = {};
  338. if (arg == 0) {
  339. let res = screen.getCursorScreenPoint();
  340. data = [
  341. {
  342. title: '横坐标',
  343. desc: res.x
  344. },
  345. {
  346. title: '纵坐标',
  347. desc: res.y
  348. },
  349. ]
  350. return data;
  351. }
  352. if (arg == 1) {
  353. res = screen.getPrimaryDisplay();
  354. }
  355. if (arg == 2) {
  356. let resArr = screen.getAllDisplays();
  357. // 数组,只取一个吧
  358. res = resArr[0];
  359. }
  360. // Log.info('[electron] [ipc] [example] [getScreen] res:', res);
  361. data = [
  362. {
  363. title: '分辨率',
  364. desc: res.bounds.width + ' x ' + res.bounds.height
  365. },
  366. {
  367. title: '单色显示器',
  368. desc: res.monochrome ? '是' : '否'
  369. },
  370. {
  371. title: '色深',
  372. desc: res. colorDepth
  373. },
  374. {
  375. title: '色域',
  376. desc: res.colorSpace
  377. },
  378. {
  379. title: 'scaleFactor',
  380. desc: res.scaleFactor
  381. },
  382. {
  383. title: '加速器',
  384. desc: res.accelerometerSupport
  385. },
  386. {
  387. title: '触控',
  388. desc: res.touchSupport == 'unknown' ? '不支持' : '支持'
  389. },
  390. ]
  391. return data;
  392. }
  393. /**
  394. * 调用其它程序(exe、bash等可执行程序)
  395. */
  396. openSoftware (softName) {
  397. if (!softName) {
  398. return false;
  399. }
  400. let softwarePath = path.join(Ps.getExtraResourcesDir(), softName);
  401. Log.info('[openSoftware] softwarePath:', softwarePath);
  402. // 检查程序是否存在
  403. if (!fs.existsSync(softwarePath)) {
  404. return false;
  405. }
  406. // 命令行字符串 并 执行
  407. let cmdStr = 'start ' + softwarePath;
  408. exec(cmdStr);
  409. return true;
  410. }
  411. /**
  412. * 获取系统主题
  413. */
  414. getTheme () {
  415. let theme = 'system';
  416. if (nativeTheme.shouldUseHighContrastColors) {
  417. theme = 'light';
  418. } else if (nativeTheme.shouldUseInvertedColorScheme) {
  419. theme = 'dark';
  420. }
  421. return theme;
  422. }
  423. /**
  424. * 设置系统主题
  425. */
  426. setTheme (args) {
  427. // TODO 好像没有什么明显效果
  428. nativeTheme.themeSource = args;
  429. return args;
  430. }
  431. /**
  432. * 检查是否有新版本
  433. */
  434. checkForUpdater () {
  435. const autoUpdaterAddon = this.app.addon.autoUpdater;
  436. autoUpdaterAddon.checkUpdate();
  437. return;
  438. }
  439. /**
  440. * 下载新版本
  441. */
  442. downloadApp () {
  443. const autoUpdaterAddon = this.app.addon.autoUpdater;
  444. autoUpdaterAddon.download();
  445. return;
  446. }
  447. /**
  448. * 检测http服务是否开启
  449. */
  450. async checkHttpServer () {
  451. const httpServerConfig = this.app.config.httpServer;
  452. const url = httpServerConfig.protocol + httpServerConfig.host + ':' + httpServerConfig.port;
  453. const data = {
  454. enable: httpServerConfig.enable,
  455. server: url
  456. }
  457. return data;
  458. }
  459. /**
  460. * 一个http请求访问此方法
  461. */
  462. async doHttpRequest () {
  463. // http方法
  464. const method = this.app.request.method;
  465. // http get 参数
  466. let params = this.app.request.query;
  467. params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
  468. // http post 参数
  469. const body = this.app.request.body;
  470. const httpInfo = {
  471. method,
  472. params,
  473. body
  474. }
  475. Log.info('httpInfo:', httpInfo);
  476. if (!body.id) {
  477. return false;
  478. }
  479. const dir = electronApp.getPath(body.id);
  480. shell.openPath(dir);
  481. return true;
  482. }
  483. /**
  484. * 一个socket io请求访问此方法
  485. */
  486. async doSocketRequest (args) {
  487. if (!args.id) {
  488. return false;
  489. }
  490. const dir = electronApp.getPath(args.id);
  491. shell.openPath(dir);
  492. return true;
  493. }
  494. /**
  495. * 异步消息类型
  496. * @param args 前端传的参数
  497. * @param event - IpcMainInvokeEvent 文档:https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-invoke-event
  498. */
  499. async ipcInvokeMsg (args, event) {
  500. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  501. const data = args + ' - ' + timeNow;
  502. return data;
  503. }
  504. /**
  505. * 同步消息类型
  506. * @param args 前端传的参数
  507. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  508. */
  509. async ipcSendSyncMsg (args) {
  510. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  511. const data = args + ' - ' + timeNow;
  512. return data;
  513. }
  514. /**
  515. * 双向异步通信
  516. * @param args 前端传的参数
  517. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  518. */
  519. ipcSendMsg (args, event) {
  520. // 前端ipc频道 channel
  521. const channel = 'controller.example.ipcSendMsg';
  522. if (args.type == 'start') {
  523. // 每隔1秒,向前端页面发送消息
  524. // 用定时器模拟
  525. myTimer = setInterval(function(e, c, msg) {
  526. let timeNow = Date.now();
  527. let data = msg + ':' + timeNow;
  528. e.reply(`${c}`, data)
  529. }, 1000, event, channel, args.content)
  530. return '开始了'
  531. } else if (args.type == 'end') {
  532. clearInterval(myTimer);
  533. return '停止了'
  534. } else {
  535. return 'ohther'
  536. }
  537. }
  538. /**
  539. * 上传文件
  540. */
  541. async uploadFile() {
  542. let tmpDir = Ps.getLogDir();
  543. const files = this.app.request.files;
  544. let file = files.file;
  545. let tmpFilePath = path.join(tmpDir, file.originalFilename);
  546. try {
  547. let tmpFile = fs.readFileSync(file.filepath);
  548. fs.writeFileSync(tmpFilePath, tmpFile);
  549. } finally {
  550. await fs.unlink(file.filepath, function(){});
  551. }
  552. const fileStream = fs.createReadStream(tmpFilePath);
  553. const uploadRes = await this.service.example.uploadFileToSMMS(fileStream);
  554. return uploadRes;
  555. }
  556. /**
  557. * 启动java项目
  558. */
  559. async startJavaServer () {
  560. let data = {
  561. code: 0,
  562. msg: '',
  563. server: ''
  564. }
  565. const javaCfg = this.app.config.addons.javaServer || {};
  566. if (!javaCfg.enable) {
  567. data.code = -1;
  568. data.msg = 'addon not enabled!';
  569. return data;
  570. }
  571. const javaServerAddon = this.app.addon.javaServer;
  572. await javaServerAddon.createServer();
  573. data.server = 'http://localhost:' + javaCfg.port;
  574. return data;
  575. }
  576. /**
  577. * 关闭java项目
  578. */
  579. async closeJavaServer () {
  580. let data = {
  581. code: 0,
  582. msg: '',
  583. }
  584. const javaCfg = this.app.config.addons.javaServer || {};
  585. if (!javaCfg.enable) {
  586. data.code = -1;
  587. data.msg = 'addon not enabled!';
  588. return data;
  589. }
  590. const javaServerAddon = this.app.addon.javaServer;
  591. await javaServerAddon.kill();
  592. return data;
  593. }
  594. /**
  595. * 任务
  596. */
  597. someJob (args, event) {
  598. let jobId = args.id;
  599. let action = args.action;
  600. let result;
  601. switch (action) {
  602. case 'create':
  603. result = this.service.example.doJob(jobId, action, event);
  604. break;
  605. case 'close':
  606. this.service.example.doJob(jobId, action, event);
  607. break;
  608. default:
  609. }
  610. let data = {
  611. jobId,
  612. action,
  613. result
  614. }
  615. return data;
  616. }
  617. /**
  618. * 创建任务池
  619. */
  620. async createPool (args, event) {
  621. let num = args.number;
  622. this.service.example.doCreatePool(num, event);
  623. // test monitor
  624. this.service.example.monitorJob();
  625. return;
  626. }
  627. /**
  628. * 通过进程池执行任务
  629. */
  630. someJobByPool (args, event) {
  631. let jobId = args.id;
  632. let action = args.action;
  633. let result;
  634. switch (action) {
  635. case 'run':
  636. result = this.service.example.doJobByPool(jobId, action, event);
  637. break;
  638. default:
  639. }
  640. let data = {
  641. jobId,
  642. action,
  643. result
  644. }
  645. return data;
  646. }
  647. /**
  648. * 测试接口
  649. */
  650. hello (args) {
  651. Log.info('hello ', args);
  652. }
  653. }
  654. ExampleController.toString = () => '[class ExampleController]';
  655. module.exports = ExampleController;