/* * This file is part of HexoEditor. * * Copyright (c) 2018 zhuzhuyule */ var shellServer = (function () { 'use strict' const Promise = require('bluebird'); const thread_kill = require('./thread_kill'); const exec = require('child_process').exec; const util = require('util'); const log = log4js.getLogger('hexo-shell.js') let _shellServer = false; class ShellServer { constructor() { this.shellProcess = null; this.isForce = false; this.oldbiu = null; this.drags = null; _shellServer = this; } processRunning() { return (this.shellProcess && this.shellProcess != null) } sendConsole(content, type, btnTip) { if (_shellServer.closeMsg) return; try { _shellServer.lastWindow.hexoeditorWindow.window.webContents.send('pop-message-shell', { subProcess: this.shellProcess, content: content, type: type, btnTip: btnTip, }); } catch (e) { content.error(e) } } execCmd(command) { let flagOK = false; clearTimeout(_shellServer.timeID); _shellServer.closeMsg = false; _shellServer.lastWindow = require('electron').BrowserWindow.getFocusedWindow(); _shellServer.isForce = false; log.info("path:", process.env.PATH) log.info('Begin execute:', `[${moeApp.hexo.config.__basedir}] [${command}]`); _shellServer.shellProcess = exec(command, {cwd: moeApp.hexo.config.__basedir}); _shellServer.sendConsole('' + __("Executing"), 'info', 'ban'); _shellServer.shellProcess.stderr.on('data', (data) => { log.error(data); }); _shellServer.shellProcess.stdout.on('data', (data) => { clearTimeout(_shellServer.timeID); log.debug(data); if (/INFO Hexo is running at https?:\/+/.test(data)) { flagOK = true; _shellServer.sendConsole('' + __('ServerStart'), 'info', 'stop'); // fix 这里会报异常 const externalParams = function() { const d = data.match(/INFO Hexo is running at (https?:\/+[^\/]+\/). Press Ctrl.C to stop./i); if (!d) { return null } if (d.length > 2) { return d[1] } return null }(); if (externalParams) { require('electron').shell.openExternal(externalParams) } } else { _shellServer.timeID = setTimeout(() => { if (!flagOK) { _shellServer.kill(_shellServer.shellProcess) flagOK = -1; } }, 10000) } }); _shellServer.shellProcess.on('close', (code, signal) => { log.info('End execute:', `[${moeApp.hexo.config.__basedir}] [${command}]`); if (flagOK === -1) _shellServer.sendConsole(__('Operation Execution Timeout'), 'danger', 'close'); else if (_shellServer.isForce) _shellServer.sendConsole(__('Operation Canceled'), 'success', 'check'); else if (code == 0) _shellServer.sendConsole(__('Operation Finished'), 'success', 'check'); _shellServer.shellProcess = null; }); _shellServer.shellProcess.on('error', err => { if (_shellServer.shellProcess) _shellServer.sendConsole(err, 'danger', 'close') log.error(err); }) } kill(subProcess) { _shellServer.isForce = true; _shellServer.closeMsg = (typeof subProcess === "boolean"); if (!subProcess) subProcess = _shellServer.shellProcess if (subProcess) thread_kill(subProcess.pid, function (err) { log.error(err); }); } checkPort(ip, port) { _shellServer.isForce = false; _shellServer.closeMsg = false; return new Promise(function (resolve, reject) { if (port > 65535 || port < 1) { return reject(new Error('Port number ' + port + ' is invalid. Try a number between 1 and 65535.')); } var server = require('net').createServer(); server.once('error', reject); server.once('listening', function () { server.close(); resolve(`${ip}:${port}`); }); server.listen(port, ip); }); } serverFail(err) { if (err.code === 'EADDRINUSE') { // 端口Ip地址占用 _shellServer.sendConsole(util.format(__('PortOccupied'), err.address, err.port), 'danger', 'close'); } } server() { this.checkPort(moeApp.hexo.config.server.ip, moeApp.hexo.config.server.port) .then(this.execCmd('hexo s'), this.serverFail); } clean() { Promise.resolve() .then(this.execCmd('hexo clean')); } general() { Promise.resolve() .then(this.execCmd('hexo g')); } deploy() { Promise.resolve() .then(this.execCmd('hexo d')); } generalAndDeploy() { Promise.resolve() .then(this.execCmd('hexo g -d')); } stopServerForce() { const port = moeApp.hexo.config.server.port; const ip = moeApp.hexo.config.server.ip; let command = ''; switch (process.platform) { case 'win32': command = 'netstat -nao | findstr '; break; case 'darwin': command = 'lsof -i:'; break; default: command = 'netstat -anp|grep '; break; } this.execCmd(command + port); let portList = []; this.shellProcess.stdout.on('data', (data) => { let reg; switch (process.platform) { case 'win32': reg = new RegExp(util.format('TCP\\s+%s:%s\\s+\\d+.\\d+.\\d+.\\d+:\\d+\\s+LISTENING\\s+(\\d+)', ip, port), 'i'); break; case 'darwin': reg = new RegExp('\\w+\\s+(\\d+)\\s+', 'i'); break; default: reg = new RegExp(util.format('tcp\\s+\\d+\\s+\\d*\\s+%s:%s\\s+\\d+.\\d+.\\d+.\\d+:[*\\d]+\\s+LISTEN\\s+(\\d+)', ip, port), 'i'); break; } if (reg.test(data)) { let pid = data.match(reg)[1] if (pid) portList.push(pid) } }); this.shellProcess.on('close', (code, signal) => { if (portList.length > 0) { for (let i = 0, len = portList.length; i < len; i++) { thread_kill(portList[i]) } } this.sendConsole(__('Operation Finished'), 'success', 'check'); this.shellProcess = null; }); } } return ShellServer; })(); module.exports = shellServer;