main.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // Modules to control application life and create native browser window
  2. const {app, BrowserWindow, dialog, ipcMain, screen, session} = require('electron');
  3. app.commandLine.appendSwitch("--disable-http-cache");
  4. const {Builder, By, Key, until} = require("selenium-webdriver");
  5. const chrome = require('selenium-webdriver/chrome');
  6. const {ServiceBuilder} = require('selenium-webdriver/chrome');
  7. const {rootCertificates} = require('tls');
  8. const {exit} = require('process');
  9. const path = require('path');
  10. const fs = require('fs');
  11. const {exec, spawn} = require('child_process');
  12. const iconPath = path.join(__dirname, 'favicon.ico');
  13. const task_server = require(path.join(__dirname, 'server.js'));
  14. const util = require('util');
  15. let config = fs.readFileSync(path.join(task_server.getDir(), `config.json`), 'utf8');
  16. config = JSON.parse(config);
  17. if(config.debug){
  18. let logPath = 'info.log'
  19. let logFile = fs.createWriteStream(logPath, { flags: 'a' })
  20. console.log = function() {
  21. logFile.write(util.format.apply(null, arguments) + '\n')
  22. process.stdout.write(util.format.apply(null, arguments) + '\n')
  23. }
  24. console.error = function() {
  25. logFile.write(util.format.apply(null, arguments) + '\n')
  26. process.stderr.write(util.format.apply(null, arguments) + '\n')
  27. }
  28. }
  29. let allWindowSockets = [];
  30. let allWindowScoketNames = [];
  31. task_server.start(config.webserver_port); //start local server
  32. let server_address = `${config.webserver_address}:${config.webserver_port}`;
  33. const websocket_port = 8084; //目前只支持8084端口,写死,因为扩展里面写死了
  34. console.log("server_address: " + server_address);
  35. let driverPath = "";
  36. let chromeBinaryPath = "";
  37. let execute_path = "";
  38. console.log(process.arch);
  39. exec(`wmic os get Caption`, function(error, stdout, stderr) {
  40. if (error) {
  41. console.error(`执行的错误: ${error}`);
  42. return;
  43. }
  44. if (stdout.includes('Windows 7')) {
  45. console.log('Windows 7');
  46. let sys_version = fs.readFileSync(path.join(__dirname, `sys_version.json`), 'utf8');
  47. sys_version = JSON.parse(sys_version);
  48. if (sys_version.arch === 'x64') {
  49. dialog.showMessageBoxSync({
  50. type: 'error',
  51. title: 'Error',
  52. message: 'Windows 7系统请下载使用x32版本的软件,不论Win 7系统为x64还是x32版本。\nFor Windows 7, please download and use the x32 version of the software, regardless of whether the Win 7 system is x64 or x32 version.',
  53. });
  54. }
  55. } else {
  56. console.log('Not Windows 7');
  57. }
  58. });
  59. if (process.platform === 'win32' && process.arch === 'ia32') {
  60. driverPath = path.join(__dirname, "chrome_win32/chromedriver_win32.exe");
  61. chromeBinaryPath = path.join(__dirname, "chrome_win32/chrome.exe");
  62. execute_path = path.join(__dirname, "chrome_win32/execute.bat");
  63. } else if (process.platform === 'win32' && process.arch === 'x64') {
  64. driverPath = path.join(__dirname, "chrome_win64/chromedriver_win64.exe");
  65. chromeBinaryPath = path.join(__dirname, "chrome_win64/chrome.exe");
  66. execute_path = path.join(__dirname, "chrome_win64/execute.bat");
  67. } else if (process.platform === 'darwin') {
  68. driverPath = path.join(__dirname, "chromedriver_mac64");
  69. chromeBinaryPath = path.join(__dirname, "chrome_mac64.app/Contents/MacOS/Google Chrome");
  70. execute_path = path.join(__dirname, "");
  71. } else if (process.platform === 'linux') {
  72. driverPath = path.join(__dirname, "chrome_linux64/chromedriver_linux64");
  73. chromeBinaryPath = path.join(__dirname, "chrome_linux64/chrome");
  74. execute_path = path.join(__dirname, "chrome_linux64/execute.sh");
  75. }
  76. console.log(driverPath, chromeBinaryPath, execute_path);
  77. let language = "en";
  78. let driver = null;
  79. let mainWindow = null;
  80. let flowchart_window = null;
  81. let current_handle = null;
  82. let old_handles = [];
  83. let handle_pairs = {};
  84. // var ffi = require('ffi-napi');
  85. // var libm = ffi.Library('libm', {
  86. // 'ceil': [ 'double', [ 'double' ] ]
  87. // });
  88. // libm.ceil(1.5); // 2
  89. // const {user32FindWindowEx,
  90. // winspoolGetDefaultPrinter,} = require('win32-api/fun');
  91. // async function testt(){
  92. // // 获取当前电脑当前用户默认打印机名
  93. // const printerName = await winspoolGetDefaultPrinter()
  94. // console.log(printerName);
  95. // }
  96. // testt();
  97. function createWindow() {
  98. // Create the browser window.
  99. mainWindow = new BrowserWindow({
  100. width: 520,
  101. height: 750,
  102. webPreferences: {
  103. preload: path.join(__dirname, 'src/js/preload.js')
  104. },
  105. icon: iconPath,
  106. // frame: false, //取消window自带的关闭最小化等
  107. resizable: false //禁止改变主窗口尺寸
  108. })
  109. // and load the index.html of the app.
  110. // mainWindow.loadFile('src/index.html');
  111. mainWindow.loadURL(server_address + '/index.html?user_data_folder=' + config.user_data_folder, { extraHeaders: 'pragma: no-cache\n' });
  112. // 隐藏菜单栏
  113. const {Menu} = require('electron');
  114. Menu.setApplicationMenu(null);
  115. mainWindow.on('close', function (e) {
  116. if (process.platform !== 'darwin') {
  117. app.quit();
  118. }
  119. });
  120. // mainWindow.webContents.openDevTools();
  121. // Open the DevTools.
  122. // mainWindow.webContents.openDevTools()
  123. }
  124. async function beginInvoke(msg, ws) {
  125. if (msg.type == 1) {
  126. if (msg.message.id != -1) {
  127. let url = "";
  128. if (language == "zh") {
  129. url = server_address + `/taskGrid/FlowChart_CN.html?id=${msg.message.id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address;
  130. } else if (language == "en") {
  131. url = server_address + `/taskGrid/FlowChart.html?id=${msg.message.id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address;
  132. }
  133. console.log(url);
  134. flowchart_window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
  135. }
  136. mainWindow.hide();
  137. // Prints the currently focused window bounds.
  138. // This method has to be called on macOS before changing the window's bounds, otherwise it will throw an error.
  139. // It will prompt an accessibility permission request dialog, if needed.
  140. if(process.platform != "linux" && process.platform != "darwin"){
  141. const {windowManager} = require("node-window-manager");
  142. const window = windowManager.getActiveWindow();
  143. console.log(window);
  144. windowManager.requestAccessibility();
  145. // Sets the active window's bounds.
  146. let size = screen.getPrimaryDisplay().workAreaSize
  147. let width = parseInt(size.width)
  148. let height = parseInt(size.height * 0.6)
  149. window.setBounds({x: 0, y: size.height * 0.4, height: height, width: width});
  150. }
  151. flowchart_window.show();
  152. // flowchart_window.openDevTools();
  153. } else if (msg.type == 2) {
  154. // 键盘输入事件
  155. // const robot = require("@jitsi/robotjs");
  156. let keyInfo = msg.message.keyboardStr;
  157. let handles = await driver.getAllWindowHandles();
  158. console.log("handles", handles);
  159. let exit = false;
  160. let content_handle = handle_pairs[msg.message.id];
  161. console.log(msg.message.id, content_handle);
  162. let order = [...handles.filter(handle => handle != current_handle && handle != content_handle), current_handle, content_handle]; //搜索顺序
  163. let len = order.length;
  164. while (true) {
  165. // console.log("handles");
  166. try{
  167. let iframe = msg.message.iframe;
  168. let enter = false;
  169. if (/<enter>/i.test(keyInfo)) {
  170. keyInfo = keyInfo.replace(/<enter>/gi, '');
  171. enter = true;
  172. }
  173. let h = order[len - 1];
  174. console.log("current_handle", current_handle);
  175. if(h != null && handles.includes(h)){
  176. await driver.switchTo().window(h);
  177. current_handle = h;
  178. console.log("switch to handle: ", h);
  179. }
  180. // await driver.executeScript("window.stop();");
  181. // console.log("executeScript");
  182. if(!iframe){
  183. let element = await driver.findElement(By.xpath(msg.message.xpath));
  184. console.log("Find Element at handle: ", current_handle);
  185. // 使用正则表达式匹配 '<enter>',不论大小写
  186. await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
  187. if(enter){
  188. await element.sendKeys(Key.ENTER);
  189. }
  190. console.log("send key");
  191. break;
  192. } else {
  193. let iframes = await driver.findElements(By.tagName('iframe'));
  194. // 遍历所有的 iframe 并点击里面的元素
  195. for(let i = 0; i < iframes.length; i++) {
  196. let iframe = iframes[i];
  197. // 切换到 iframe
  198. await driver.switchTo().frame(iframe);
  199. // 在 iframe 中查找并点击元素
  200. let element;
  201. try {
  202. element = await driver.findElement(By.xpath(msg.message.xpath));
  203. } catch (error) {
  204. console.log('No such element found in the iframe');
  205. }
  206. if (element) {
  207. await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
  208. if(enter){
  209. await element.sendKeys(Key.ENTER);
  210. }
  211. }
  212. // 完成操作后切回主文档
  213. await driver.switchTo().defaultContent();
  214. }
  215. break;
  216. }
  217. } catch (error) {
  218. console.log("len", len);
  219. len = len - 1;
  220. if (len == 0) {
  221. break;
  222. }
  223. }
  224. // .then(function (element) {
  225. // console.log("element", element, handles);
  226. // element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
  227. // exit = true;
  228. // }, function (error) {
  229. // console.log("error", error);
  230. // len = len - 1;
  231. // if (len == 0) {
  232. // exit = true;
  233. // }
  234. // }
  235. // );
  236. }
  237. // let handles = driver.getAllWindowHandles();
  238. // driver.switchTo().window(handles[handles.length - 1]);
  239. // driver.findElement(By.xpath(msg.message.xpath)).sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
  240. // robot.keyTap("a", "control");
  241. // robot.keyTap("backspace");
  242. // robot.typeString(keyInfo);
  243. // robot.keyTap("shift");
  244. // robot.keyTap("shift");
  245. } else if (msg.type == 3) {
  246. try {
  247. if (msg.from == 0) {
  248. socket_flowchart.send(msg.message.pipe); //直接把消息转接
  249. let message = JSON.parse(msg.message.pipe);
  250. let type = message.type;
  251. console.log("FROM Browser: ", message);
  252. console.log("Iframe:", message.iframe);
  253. if(type.indexOf("Click")>=0){
  254. // 鼠标点击事件
  255. let iframe = message.iframe;
  256. let handles = await driver.getAllWindowHandles();
  257. console.log("handles", handles);
  258. let exit = false;
  259. let content_handle = handle_pairs[message.id];
  260. console.log(message.id, content_handle);
  261. let order = [...handles.filter(handle => handle != current_handle && handle != content_handle), current_handle, content_handle]; //搜索顺序
  262. let len = order.length;
  263. while(true) {
  264. try{
  265. let h = order[len - 1];
  266. console.log("current_handle", current_handle);
  267. if(h != null && handles.includes(h)){
  268. await driver.switchTo().window(h); //执行失败会抛出异常
  269. current_handle = h;
  270. console.log("switch to handle: ", h);
  271. }
  272. //下面是找到窗口的情况下
  273. if(!iframe){
  274. let element = await driver.findElement(By.xpath(message.xpath));
  275. await element.click();
  276. break;
  277. } else {
  278. let iframes = await driver.findElements(By.tagName('iframe'));
  279. // 遍历所有的 iframe 并点击里面的元素
  280. for(let i = 0; i < iframes.length; i++) {
  281. let iframe = iframes[i];
  282. // 切换到 iframe
  283. await driver.switchTo().frame(iframe);
  284. // 在 iframe 中查找并点击元素
  285. let element;
  286. try {
  287. element = await driver.findElement(By.xpath(message.xpath));
  288. } catch (error) {
  289. console.log('No such element found in the iframe');
  290. }
  291. if (element) {
  292. await element.click();
  293. }
  294. // 完成操作后切回主文档
  295. await driver.switchTo().defaultContent();
  296. }
  297. break;
  298. }
  299. } catch (error) {
  300. console.log("len", len); //如果没有找到元素,就切换到下一个窗口
  301. len = len - 1;
  302. if (len == 0) {
  303. break;
  304. }
  305. }
  306. }
  307. }
  308. } else {
  309. socket_window.send(msg.message.pipe);
  310. for(let i in allWindowSockets){
  311. try{
  312. allWindowSockets[i].send(msg.message.pipe);
  313. } catch {
  314. console.log("Cannot send to socket with id: ", allWindowScoketNames[i]);
  315. }
  316. }
  317. console.log("FROM Flowchart: ", JSON.parse(msg.message.pipe));
  318. }
  319. } catch (e) {
  320. console.log(e);
  321. }
  322. } else if (msg.type == 5) {
  323. let child = require('child_process').execFile;
  324. // 参数顺序: 1. task id 2. server address 3. saved_file_name 4. "remote" or "local" 5. user_data_folder
  325. // var parameters = [msg.message.id, server_address];
  326. let parameters = [];
  327. console.log(msg.message)
  328. if (msg.message.user_data_folder == null || msg.message.user_data_folder == undefined || msg.message.user_data_folder == "") {
  329. parameters = ["--id", "[" + msg.message.id + "]", "--server_address", server_address, "--user_data", 0];
  330. } else {
  331. let user_data_folder_path = path.join(task_server.getDir(), msg.message.user_data_folder);
  332. parameters = ["--id", "[" + msg.message.id + "]", "--server_address", server_address, "--user_data", 1];
  333. config.user_data_folder = msg.message.user_data_folder;
  334. config.absolute_user_data_folder = user_data_folder_path;
  335. fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
  336. }
  337. if(msg.message.mysql_config_path != "-1"){
  338. config.mysql_config_path = msg.message.mysql_config_path;
  339. }
  340. fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
  341. // child('Chrome/easyspider_executestage.exe', parameters, function(err,stdout, stderr) {
  342. // console.log(stdout);
  343. // });
  344. let spawn = require("child_process").spawn;
  345. if (process.platform != "darwin" && msg.message.execute_type == 1 && msg.message.id != -1) {
  346. let child_process = spawn(execute_path, parameters);
  347. child_process.stdout.on('data', function (data) {
  348. console.log(data.toString());
  349. });
  350. }
  351. ws.send(JSON.stringify({"config_folder": task_server.getDir() + "/", "easyspider_location": task_server.getEasySpiderLocation()}));
  352. } else if (msg.type == 6) {
  353. try{
  354. flowchart_window.openDevTools();
  355. } catch {
  356. console.log("open devtools error");
  357. }
  358. } else if (msg.type == 7) {
  359. // 获得当前页面Cookies
  360. try{
  361. let cookies = await driver.manage().getCookies();
  362. console.log("Cookies: ", cookies);
  363. let cookiesText = cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('\n');
  364. socket_flowchart.send(JSON.stringify({"type": "GetCookies", "message": cookiesText}));
  365. } catch {
  366. console.log("Cannot get Cookies");
  367. }
  368. }
  369. }
  370. const WebSocket = require('ws');
  371. const {all} = require("express/lib/application");
  372. let socket_window = null;
  373. let socket_start = null;
  374. let socket_flowchart = null;
  375. let wss = new WebSocket.Server({port: websocket_port});
  376. wss.on('connection', function (ws) {
  377. ws.on('message', async function (message, isBinary) {
  378. let msg = JSON.parse(message.toString());
  379. console.log("\n\nGET A MESSAGE: ", msg);
  380. // console.log(msg, msg.type, msg.message);
  381. if (msg.type == 0) {
  382. if (msg.message.id == 0) {
  383. socket_window = ws;
  384. console.log("set socket_window")
  385. } else if (msg.message.id == 1) {
  386. socket_start = ws;
  387. console.log("set socket_start")
  388. } else if (msg.message.id == 2) {
  389. socket_flowchart = ws;
  390. console.log("set socket_flowchart");
  391. } else { //其他的ID是用来标识不同的浏览器标签页的
  392. await new Promise(resolve => setTimeout(resolve, 2300));
  393. let handles = await driver.getAllWindowHandles();
  394. if(arrayDifference(handles, old_handles).length > 0){
  395. old_handles = handles;
  396. current_handle = handles[handles.length - 1];
  397. console.log("New tab opened, change current_handle to: ", current_handle);
  398. }
  399. handle_pairs[msg.message.id] = current_handle;
  400. console.log("Set handle_pair for id: ", msg.message.id, " to ", current_handle, ", title is: ", msg.message.title);
  401. socket_flowchart.send(JSON.stringify({"type": "title", "data": {"title":msg.message.title}}));
  402. allWindowSockets.push(ws);
  403. allWindowScoketNames.push(msg.message.id);
  404. // console.log("handle_pairs: ", handle_pairs);
  405. }
  406. } else if (msg.type == 10) {
  407. let leave_handle = handle_pairs[msg.message.id];
  408. if (leave_handle!=null && leave_handle!=undefined && leave_handle!="")
  409. {
  410. await driver.switchTo().window(leave_handle);
  411. console.log("Switch to handle: ", leave_handle);
  412. current_handle = leave_handle;
  413. }
  414. }
  415. else {
  416. await beginInvoke(msg, ws);
  417. }
  418. });
  419. });
  420. console.log(process.platform);
  421. async function runBrowser(lang = "en", user_data_folder = '', mobile = false) {
  422. const serviceBuilder = new ServiceBuilder(driverPath);
  423. let options = new chrome.Options();
  424. options.addArguments('--disable-blink-features=AutomationControlled');
  425. language = lang;
  426. if (lang == "en") {
  427. options.addExtensions(path.join(__dirname, "EasySpider_en.crx"));
  428. } else if (lang == "zh") {
  429. options.addExtensions(path.join(__dirname, "EasySpider_zh.crx"));
  430. }
  431. options.addExtensions(path.join(__dirname, "XPathHelper.crx"));
  432. options.setChromeBinaryPath(chromeBinaryPath);
  433. if (user_data_folder != "") {
  434. let dir = path.join(task_server.getDir(), user_data_folder);
  435. console.log(dir);
  436. options.addArguments("--user-data-dir=" + dir);
  437. config.user_data_folder = user_data_folder;
  438. fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
  439. }
  440. if (mobile) {
  441. const mobileEmulation = {
  442. deviceName: 'iPhone XR'
  443. };
  444. options.addArguments(`--user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"`);
  445. options.setMobileEmulation(mobileEmulation);
  446. }
  447. driver = new Builder()
  448. .forBrowser('chrome')
  449. .setChromeOptions(options)
  450. .setChromeService(serviceBuilder)
  451. .build();
  452. await driver.manage().setTimeouts({implicit: 10000, pageLoad: 10000, script: 10000});
  453. await driver.executeScript("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})");
  454. // await driver.executeScript("localStorage.clear();"); //重置参数数量
  455. const cdpConnection = await driver.createCDPConnection("page");
  456. let stealth_path = path.join(__dirname, "stealth.min.js");
  457. let stealth = fs.readFileSync(stealth_path, 'utf8');
  458. await cdpConnection.execute('Page.addScriptToEvaluateOnNewDocument', {
  459. source: stealth,
  460. });
  461. try {
  462. if(mobile){
  463. await driver.get(server_address + "/taskGrid/taskList.html?wsport=" + websocket_port + "&backEndAddressServiceWrapper=" + server_address + "&mobile=1&lang=" + lang);
  464. } else {
  465. await driver.get(server_address + "/taskGrid/taskList.html?wsport=" + websocket_port + "&backEndAddressServiceWrapper=" + server_address + "&lang=" + lang);
  466. }
  467. old_handles = await driver.getAllWindowHandles();
  468. current_handle = old_handles[old_handles.length - 1];
  469. } finally {
  470. // await driver.quit(); // 退出浏览器
  471. }
  472. }
  473. function handleOpenBrowser(event, lang = "en", user_data_folder = "", mobile = false) {
  474. const webContents = event.sender;
  475. const win = BrowserWindow.fromWebContents(webContents);
  476. runBrowser(lang, user_data_folder, mobile);
  477. let size = screen.getPrimaryDisplay().workAreaSize;
  478. let width = parseInt(size.width);
  479. let height = parseInt(size.height * 0.6);
  480. flowchart_window = new BrowserWindow({
  481. x: 0,
  482. y: 0,
  483. width: width,
  484. height: height,
  485. icon: iconPath,
  486. });
  487. let url = "";
  488. let id = -1;
  489. if (lang == "en") {
  490. url = server_address + `/taskGrid/FlowChart.html?id=${id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address + "&mobile=" + mobile.toString();
  491. } else if (lang == "zh") {
  492. url = server_address + `/taskGrid/FlowChart_CN.html?id=${id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address+ "&mobile=" + mobile.toString();
  493. }
  494. // and load the index.html of the app.
  495. flowchart_window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
  496. if(process.platform != "darwin"){
  497. flowchart_window.hide();
  498. }
  499. flowchart_window.on('close', function (event) {
  500. mainWindow.show();
  501. driver.quit();
  502. });
  503. }
  504. function handleOpenInvoke(event, lang = "en") {
  505. const window = new BrowserWindow({icon: iconPath});
  506. let url = "";
  507. language = lang;
  508. if (lang == "en") {
  509. url = server_address + `/taskGrid/taskList.html?type=1&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address;
  510. } else if (lang == "zh") {
  511. url = server_address + `/taskGrid/taskList.html?type=1&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address + "&lang=zh";
  512. }
  513. // and load the index.html of the app.
  514. window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
  515. window.maximize();
  516. mainWindow.hide();
  517. window.on('close', function (event) {
  518. mainWindow.show();
  519. });
  520. }
  521. // This method will be called when Electron has finished
  522. // initialization and is ready to create browser windows.
  523. // Some APIs can only be used after this event occurs.
  524. app.whenReady().then(() => {
  525. session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
  526. details.requestHeaders['Accept-Language'] = 'zh'
  527. callback({ cancel: false, requestHeaders: details.requestHeaders })
  528. })
  529. ipcMain.on('start-design', handleOpenBrowser);
  530. ipcMain.on('start-invoke', handleOpenInvoke);
  531. createWindow();
  532. app.on('activate', function () {
  533. // On macOS it's common to re-create a window in the app when the
  534. // dock icon is clicked and there are no other windows open.
  535. if (BrowserWindow.getAllWindows().length === 0) {
  536. createWindow();
  537. }
  538. })
  539. })
  540. // Quit when all windows are closed, except on macOS. There, it's common
  541. // for applications and their menu bar to stay active until the user quits
  542. // explicitly with Cmd + Q.
  543. app.on('window-all-closed', function () {
  544. if (process.platform !== 'darwin') {
  545. app.quit();
  546. }
  547. })
  548. // In this file you can include the rest of your app's specific main process
  549. // code. You can also put them in separate files and require them here.
  550. function arrayDifference(arr1, arr2) {
  551. return arr1.filter(item => !arr2.includes(item));
  552. }