service.js 10.6 KB
Newer Older
H
Hao Sun 已提交
1
import path from 'path';
aaronchen2k2k's avatar
aaronchen2k2k 已提交
2
import cp, {spawn} from 'child_process';
H
Hao Sun 已提交
3
import os from 'os';
4 5
import {app} from 'electron';
import express from 'express';
aaronchen2k2k's avatar
aaronchen2k2k 已提交
6
import {logInfo, logErr} from './log';
H
Hao Sun 已提交
7

8
const psTree = require('ps-tree');
H
Hao Sun 已提交
9
const DEBUG = process.env.NODE_ENV === 'development';
aaronchen2k2k's avatar
aaronchen2k2k 已提交
10
const isWin = /^win/.test(process.platform);
aaronchen2k2k's avatar
aaronchen2k2k 已提交
11
const isMac = /^darwin/.test(process.platform);
aaronchen2k2k's avatar
aaronchen2k2k 已提交
12
const uuid = 'ZTF@1CF17A46-B136-4AEB-96B4-F21C8200EF5A~'
H
Hao Sun 已提交
13
let _ztfServerProcess;
14
let _ztfSubProcessIds = [];
H
Hao Sun 已提交
15 16

export function startZtfServer() {
17
    if (process.env.SKIP_SERVER) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
18
        logInfo(`>> Skip to start ZTF Server by env "SKIP_SERVER=${process.env.SKIP_SERVER}".`);
19 20
        return Promise.resolve();
    }
H
Hao Sun 已提交
21 22 23 24
    if (_ztfServerProcess) {
        return Promise.resolve(_ztfServerProcess);
    }

25
    let {SERVER_EXE_PATH: serverExePath} = process.env;
H
Hao Sun 已提交
26
    if (!serverExePath && !DEBUG) {
H
Hao Sun 已提交
27 28
        const platform = os.platform(); // 'darwin', 'linux', 'win32'
        const exePath = `bin/${platform}/ztf${platform === 'win32' ? '.exe' : ''}`;
29
        serverExePath = path.join(process.resourcesPath, exePath);
H
Hao Sun 已提交
30
    }
31 32 33 34
    if (serverExePath) {
        if (!path.isAbsolute(serverExePath)) {
            serverExePath = path.resolve(app.getAppPath(), serverExePath);
        }
H
Hao Sun 已提交
35
        return new Promise((resolve, reject) => {
36
            const cwd = process.env.SERVER_CWD_PATH || path.dirname(serverExePath);
aaronchen2k2k's avatar
aaronchen2k2k 已提交
37
            logInfo(`>> Starting ZTF Server from exe path with command "${serverExePath} -P 8085" in "${cwd}"...`);
aaronchen2k2k's avatar
aaronchen2k2k 已提交
38
            const cmd = spawn(serverExePath, ['-p', '8085', "-uuid", uuid], {
39
                cwd,
H
Hao Sun 已提交
40 41
                shell: true,
            });
H
Hao Sun 已提交
42
            cmd.on('close', (code) => {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
43
                logInfo(`>> ZTF server closed with code ${code}`);
H
Hao Sun 已提交
44
                _ztfServerProcess = null;
aaronchen2k2k's avatar
aaronchen2k2k 已提交
45
                cmd.kill()
H
Hao Sun 已提交
46 47 48 49 50 51
            });
            cmd.stdout.on('data', data => {
                const dataString = String(data);
                const lines = dataString.split('\n');
                for (let i = 0; i < lines.length; i++) {
                    const line = lines[i];
H
Hao Sun 已提交
52
                    if (DEBUG) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
53
                        logInfo('\t' + line);
H
Hao Sun 已提交
54
                    }
H
Hao Sun 已提交
55 56
                    if (line.includes('Now listening on: http')) {
                        resolve(line.split('Now listening on:')[1].trim());
H
Hao Sun 已提交
57 58 59
                        if (!DEBUG) {
                            break;
                        }
H
Hao Sun 已提交
60 61
                    } else if (line.includes('启动HTTP服务于')) {
                        resolve(line.split(/启动HTTP服务于|,/)[1].trim());
H
Hao Sun 已提交
62 63 64
                        if (!DEBUG) {
                            break;
                        }
H
Hao Sun 已提交
65 66
                    } else if (line.startsWith('[ERRO]')) {
                        reject(new Error(`Start ztf server failed with error: ${line.substring('[ERRO]'.length)}`));
H
Hao Sun 已提交
67 68 69
                        if (!DEBUG) {
                            break;
                        }
H
Hao Sun 已提交
70 71
                    }
                }
H
Hao Sun 已提交
72
            });
H
Hao Sun 已提交
73 74 75 76 77
            cmd.on('error', spawnError => {
                console.error('>>> Start ztf server failed with error', spawnError);
                reject(spawnError)
            });
            _ztfServerProcess = cmd;
aaronchen2k2k's avatar
aaronchen2k2k 已提交
78
            logInfo(`>> _ztfServerProcess = ${_ztfServerProcess.pid}`)
79 80 81 82 83 84 85 86 87

            psTree(_ztfServerProcess.pid, function (err, children) {
                _ztfSubProcessIds = [_ztfServerProcess.pid].concat(
                    children.map(function (p) {
                        return p.PID;
                    })
                );
                logInfo(`>> _ztfSubProcessIds = ${_ztfSubProcessIds}`)
            });
H
Hao Sun 已提交
88 89 90 91
        });
    }

    return new Promise((resolve, reject) => {
92
        const cwd = process.env.SERVER_CWD_PATH || path.resolve(app.getAppPath(), '../');
aaronchen2k2k's avatar
aaronchen2k2k 已提交
93
        logInfo(`>> Starting ZTF development server from source with command "go run cmd/server/main.go -P 8085" in "${cwd}"`);
H
Hao Sun 已提交
94
        const cmd = spawn('go', ['run', 'main.go', '-P', '8085'], {
95
            cwd,
H
Hao Sun 已提交
96 97
            shell: true,
        });
H
Hao Sun 已提交
98
        cmd.on('close', (code) => {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
99
            logInfo(`>> ZTF server closed with code ${code}`);
H
Hao Sun 已提交
100 101 102 103
            _ztfServerProcess = null;
        });
        cmd.stdout.on('data', data => {
            const dataString = String(data);
104 105 106
            const lines = dataString.split('\n');
            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
H
Hao Sun 已提交
107
                if (DEBUG) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
108
                    logInfo('\t' + line);
H
Hao Sun 已提交
109
                }
110 111
                if (line.includes('Now listening on: http')) {
                    resolve(line.split('Now listening on:')[1].trim());
H
Hao Sun 已提交
112 113 114
                    if (!DEBUG) {
                        break;
                    }
115 116
                } else if (line.startsWith('[ERRO]')) {
                    reject(new Error(`Start ztf server failed with error: ${line.substring('[ERRO]'.length)}`));
H
Hao Sun 已提交
117 118 119
                    if (!DEBUG) {
                        break;
                    }
120
                }
H
Hao Sun 已提交
121 122 123 124 125 126 127 128 129 130
            }
        });
        cmd.on('error', spawnError => {
            console.error('>>> Start ztf server failed with error', spawnError);
            reject(spawnError)
        });
        _ztfServerProcess = cmd;
    });
}

131
let _uiServerApp;
H
Hao Sun 已提交
132 133

export function getUIServerUrl() {
134 135
    if (_uiServerApp) {
        return Promise.resolve();
H
Hao Sun 已提交
136 137
    }

138
    let {UI_SERVER_URL: uiServerUrl} = process.env;
H
Hao Sun 已提交
139
    if (!uiServerUrl && !DEBUG) {
H
Hao Sun 已提交
140 141 142
        uiServerUrl = path.resolve(process.resourcesPath, 'ui');
    }

143 144 145 146 147 148 149 150 151
    if (uiServerUrl) {
        if (/^https?:\/\//.test(uiServerUrl)) {
            return Promise.resolve(uiServerUrl);
        }
        return new Promise((resolve, reject) => {
            if (!path.isAbsolute(uiServerUrl)) {
                uiServerUrl = path.resolve(app.getAppPath(), uiServerUrl);
            }

H
Hao Sun 已提交
152
            const port = process.env.UI_SERVER_PORT || 8000;
aaronchen2k2k's avatar
aaronchen2k2k 已提交
153
            logInfo(`>> Starting UI serer at ${uiServerUrl} with port ${port}`);
154 155 156

            const uiServer = express();
            uiServer.use(express.static(uiServerUrl));
H
Hao Sun 已提交
157
            const server = uiServer.listen(port, serverError => {
158 159 160 161 162
                if (serverError) {
                    console.error('>>> Start ui server failed with error', serverError);
                    _uiServerApp = null;
                    reject(serverError);
                } else {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
163
                    logInfo(`>> UI server started successfully on http://localhost:${port}.`);
H
Hao Sun 已提交
164
                    resolve(`http://localhost:${port}`);
165
                }
H
Hao Sun 已提交
166
            });
167 168 169 170 171
            server.on('close', () => {
                _uiServerApp = null;
            });
            _uiServerApp = uiServer;
        })
H
Hao Sun 已提交
172 173 174
    }

    return new Promise((resolve, reject) => {
H
Hao Sun 已提交
175
        const cwd = path.resolve(app.getAppPath(), '../ui');
aaronchen2k2k's avatar
aaronchen2k2k 已提交
176
        logInfo(`>> Starting UI development server with command "npm run serve" in "${cwd}"...`);
177

H
Hao Sun 已提交
178 179
        let resolved = false;
        const cmd = spawn('npm', ['run', 'serve'], {
H
Hao Sun 已提交
180
            cwd,
H
Hao Sun 已提交
181 182
            shell: true,
        });
H
Hao Sun 已提交
183
        cmd.on('close', (code) => {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
184
            logInfo(`>> ZTF server closed with code ${code}`);
185
            _uiServerApp = null;
H
Hao Sun 已提交
186 187 188 189 190 191 192 193 194
        });
        cmd.stdout.on('data', data => {
            if (resolved) {
                return;
            }
            const dataString = String(data);
            const lines = dataString.split('\n');
            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
H
Hao Sun 已提交
195
                if (DEBUG) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
196
                    logInfo('\t' + line);
H
Hao Sun 已提交
197
                }
H
Hao Sun 已提交
198
                if (line.includes('App running at:')) {
199
                    const nextLine = lines[i + 1] || lines[i + 2];
H
Hao Sun 已提交
200
                    if (DEBUG) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
201
                        logInfo('\t' + nextLine);
H
Hao Sun 已提交
202
                    }
H
Hao Sun 已提交
203
                    if (!nextLine) {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
204
                        console.error('\t' + `Cannot grabing running address after line "${line}".`);
H
Hao Sun 已提交
205
                        throw new Error(`Cannot grabing running address after line "${line}".`);
H
Hao Sun 已提交
206
                    }
H
Hao Sun 已提交
207
                    const url = nextLine.split('Local:   ')[1];
208 209 210 211
                    if (url) {
                        resolved = true;
                        resolve(url);
                    }
H
Hao Sun 已提交
212 213 214
                    if (!DEBUG) {
                        break;
                    }
H
Hao Sun 已提交
215 216 217 218 219 220 221
                }
            }
        });
        cmd.on('error', spawnError => {
            console.error('>>> Get ui server url failed with error', spawnError);
            reject(spawnError)
        });
222
        _uiServerApp = cmd;
H
Hao Sun 已提交
223 224
    });
}
aaronchen2k2k's avatar
aaronchen2k2k 已提交
225

aaronchen2k2k's avatar
aaronchen2k2k 已提交
226
export function killZtfServer() {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
227 228 229 230 231 232
    let cmd = ''
    if (!isWin) {
        logInfo(`>> no windows`);

        cmd = `ps -ef | grep ${uuid} | grep -v "\-\-%s" | grep -v "grep" | awk '{print $2}' | xargs kill -9`
        logInfo(`kill cmd : ${cmd}`);
aaronchen2k2k's avatar
aaronchen2k2k 已提交
233
        const cp = require('child_process');
aaronchen2k2k's avatar
aaronchen2k2k 已提交
234 235 236
        cp.exec(cmd, function (error, stdout, stderr) {
            logInfo(`stdout: ${stdout}; stderr: ${stderr}; error: ${error}`);
        });
aaronchen2k2k's avatar
aaronchen2k2k 已提交
237
    } else {
aaronchen2k2k's avatar
aaronchen2k2k 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
        logInfo(`>> is windows`);
			
        const cmd = 'WMIC path win32_process  where "Commandline like \'%%' + uuid + '%%\'" get Processid,Caption';
        const cp = require('child_process');
        cp.exec(cmd, function (error, stdout, stderr) {
            // console.log('stdout: ' + stdout + '; stderr: ' + stderr + '; error: ' + error + '.');
            const lines = stdout.split('\n')
            lines.forEach(function(line){
                line = line.trim()
                console.log('<' + line + '>')
                const columns = line.split(/\s/)

                if (columns.length > 2) {
                    const pid = columns[2].trim()
                    console.log(`pid=${pid}`);

                    const cpKill = require('child_process');
                    cpKill.exec(`taskkill /F /pid ${pid}`, function (error, stdout, stderr) {
                        console.log('stdout: ' + stdout + '; stderr: ' + stderr + '; error: ' + error + '.');
                    });
                }
            });
aaronchen2k2k's avatar
aaronchen2k2k 已提交
260
        });
261
    }
aaronchen2k2k's avatar
aaronchen2k2k 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

    // if (isWin) {
    //     logInfo(`>> isWin`);
    //     const cp = require('child_process');
    //     cp.exec('taskkill /PID ' + _ztfServerProcess.pid + ' /T /F',
    //         function (error, stdout, stderr) {
    //             // logInfo('stdout: ' + stdout + '; stderr: ' + stderr + '; error: ' + error + '.');
    //         });
    // } else if (isMac) {
    //     logInfo(`>> isMac`);
    //     if (_ztfServerProcess) _ztfServerProcess.kill();
    // } else {
    //     logInfo(`>> isLinux`);
    //     _ztfSubProcessIds.forEach(function (tpid) {
    //         logInfo(`>> kill ${tpid}`)
    //         try {
    //             process.kill(tpid, 'SIGKILL')
    //         } catch (ex) {
    //             logErr(`>> ` + ex)
    //         }
    //     });
    // }
284 285 286
}