ee-core 2.4.0 → 2.5.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/window/index.js +1 -0
- package/ee/eeApp.js +64 -22
- package/electron/app/index.js +0 -7
- package/electron/window/index.js +8 -3
- package/html/boot.html +97 -0
- package/html/failure.html +28 -0
- package/package.json +1 -1
- package/ps/index.js +8 -0
- package/socket/httpServer.js +7 -2
- package/storage/jsondbStorage.js +68 -18
- package/utils/get-port/index.js +50 -11
- package/utils/helper.js +35 -0
package/addon/window/index.js
CHANGED
package/ee/eeApp.js
CHANGED
|
@@ -14,6 +14,8 @@ const Conf = require('../config');
|
|
|
14
14
|
const Ps = require('../ps');
|
|
15
15
|
const Socket = require('../socket');
|
|
16
16
|
const GetPort = require('../utils/get-port');
|
|
17
|
+
const UtilsHelper = require('../utils/helper');
|
|
18
|
+
const HttpClient = require('../httpclient');
|
|
17
19
|
|
|
18
20
|
class EeApp extends BaseApp {
|
|
19
21
|
constructor(options = {}) {
|
|
@@ -90,7 +92,7 @@ class EeApp extends BaseApp {
|
|
|
90
92
|
/**
|
|
91
93
|
* 应用类型 (远程、html、单页应用)
|
|
92
94
|
*/
|
|
93
|
-
selectAppType() {
|
|
95
|
+
async selectAppType() {
|
|
94
96
|
let type = '';
|
|
95
97
|
let url = '';
|
|
96
98
|
|
|
@@ -103,27 +105,65 @@ class EeApp extends BaseApp {
|
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
// 开发环境
|
|
109
|
+
if (Ps.isDev()) {
|
|
110
|
+
let modeInfo;
|
|
111
|
+
let url;
|
|
112
|
+
let load = 'url';
|
|
113
|
+
const configFile = './electron/config/bin.js';
|
|
114
|
+
|
|
115
|
+
const isBin = UtilsHelper.checkConfig(configFile);
|
|
116
|
+
if (isBin) {
|
|
117
|
+
const binConfig = UtilsHelper.loadConfig(configFile);
|
|
118
|
+
const { frontend } = binConfig.dev;
|
|
119
|
+
modeInfo = frontend;
|
|
120
|
+
} else {
|
|
121
|
+
// 兼容旧的 developmentMode
|
|
122
|
+
const developmentModeConfig = this.config.developmentMode;
|
|
123
|
+
const selectMode = developmentModeConfig.default;
|
|
124
|
+
modeInfo = developmentModeConfig.mode[selectMode];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
url = modeInfo.protocol + modeInfo.hostname + ':' + modeInfo.port;
|
|
128
|
+
if (Conf.isFileProtocol(modeInfo)) {
|
|
129
|
+
url = path.join(this.config.homeDir, modeInfo.directory, modeInfo.indexPath);
|
|
130
|
+
load = 'file';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 检查 UI serve是否启动,先加载一个boot page
|
|
134
|
+
if (load == 'url') {
|
|
135
|
+
const bootPage = path.join(__dirname, '..', 'html', 'boot.html');
|
|
136
|
+
this.mainWindow.loadFile(bootPage);
|
|
137
|
+
let count = 0;
|
|
138
|
+
let frontendReady = false;
|
|
139
|
+
const hc = new HttpClient();
|
|
140
|
+
while(!frontendReady && count < 30){
|
|
141
|
+
await UtilsHelper.sleep(1 * 1000);
|
|
142
|
+
try {
|
|
143
|
+
await hc.request(url, {
|
|
144
|
+
method: 'GET',
|
|
145
|
+
timeout: 1000,
|
|
146
|
+
});
|
|
147
|
+
frontendReady = true;
|
|
148
|
+
} catch(err) {
|
|
149
|
+
// console.log('The frontend service is starting');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
count++;
|
|
153
|
+
}
|
|
110
154
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
155
|
+
if (frontendReady == false) {
|
|
156
|
+
const bootFailurePage = path.join(__dirname, '..', 'html', 'failure.html');
|
|
157
|
+
this.mainWindow.loadFile(bootFailurePage);
|
|
158
|
+
Log.coreLogger.error(`[ee-core] Please check the ${url} !`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
115
161
|
}
|
|
116
|
-
|
|
162
|
+
|
|
163
|
+
this.loadMainUrl('spa', url, load);
|
|
117
164
|
return;
|
|
118
165
|
}
|
|
119
166
|
|
|
120
|
-
// 单页应用
|
|
121
|
-
// 开发环境
|
|
122
|
-
if (Ps.isDev()) {
|
|
123
|
-
url = modeInfo.protocol + modeInfo.hostname + ':' + modeInfo.port;
|
|
124
|
-
this.loadMainUrl('spa', url);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
167
|
// 生产环境
|
|
128
168
|
const mainServer = this.config.mainServer;
|
|
129
169
|
if (Conf.isFileProtocol(mainServer)) {
|
|
@@ -137,7 +177,7 @@ class EeApp extends BaseApp {
|
|
|
137
177
|
/**
|
|
138
178
|
* 加载本地前端资源
|
|
139
179
|
*/
|
|
140
|
-
loadLocalWeb(mode, staticDir
|
|
180
|
+
loadLocalWeb(mode, staticDir) {
|
|
141
181
|
if (!staticDir) {
|
|
142
182
|
staticDir = path.join(this.config.homeDir, 'public', 'dist')
|
|
143
183
|
}
|
|
@@ -147,9 +187,6 @@ class EeApp extends BaseApp {
|
|
|
147
187
|
|
|
148
188
|
const mainServer = this.config.mainServer;
|
|
149
189
|
let url = mainServer.protocol + mainServer.host + ':' + mainServer.port;
|
|
150
|
-
if (mode == 'html') {
|
|
151
|
-
url += '/' + hostInfo.indexPage;
|
|
152
|
-
}
|
|
153
190
|
|
|
154
191
|
const isHttps = mainServer.protocol == 'https://' ? true : false;
|
|
155
192
|
if (isHttps) {
|
|
@@ -170,7 +207,12 @@ class EeApp extends BaseApp {
|
|
|
170
207
|
this.loadMainUrl(mode, url);
|
|
171
208
|
});
|
|
172
209
|
} else {
|
|
173
|
-
|
|
210
|
+
// 使用 host port 避免绑定到0.0.0.0
|
|
211
|
+
const koaOpt = {
|
|
212
|
+
host: mainServer.host,
|
|
213
|
+
port: mainServer.port
|
|
214
|
+
}
|
|
215
|
+
koaApp.listen(koaOpt, () => {
|
|
174
216
|
this.loadMainUrl(mode, url);
|
|
175
217
|
});
|
|
176
218
|
}
|
package/electron/app/index.js
CHANGED
|
@@ -21,16 +21,9 @@ const CoreElectronApp = {
|
|
|
21
21
|
app.quit();
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
app.on('second-instance', (event) => {
|
|
26
|
-
Window.restoreMainWindow();
|
|
27
|
-
})
|
|
28
24
|
|
|
29
25
|
app.whenReady().then(() => {
|
|
30
26
|
CoreApp.createWindow();
|
|
31
|
-
app.on('activate', () => {
|
|
32
|
-
Window.restoreMainWindow();
|
|
33
|
-
})
|
|
34
27
|
})
|
|
35
28
|
|
|
36
29
|
app.on('window-all-closed', () => {
|
package/electron/window/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const is = require('is-type-of');
|
|
2
|
+
const { BrowserWindow, Menu } = require('electron');
|
|
2
3
|
const Conf = require('../../config');
|
|
3
4
|
const Ps = require('../../ps');
|
|
4
5
|
const EEMainWindow = Symbol('Ee#electron#mainWindow');
|
|
@@ -43,12 +44,16 @@ const Window = {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
// DevTools
|
|
46
|
-
if (config.openDevTools) {
|
|
47
|
+
if (is.object(config.openDevTools)) {
|
|
48
|
+
win.webContents.openDevTools(config.openDevTools);
|
|
49
|
+
} else if (config.openDevTools === true) {
|
|
47
50
|
win.webContents.openDevTools({
|
|
48
51
|
mode: 'undocked'
|
|
49
52
|
});
|
|
53
|
+
} else {
|
|
54
|
+
//
|
|
50
55
|
}
|
|
51
|
-
|
|
56
|
+
|
|
52
57
|
return win;
|
|
53
58
|
},
|
|
54
59
|
|
package/html/boot.html
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" />
|
|
7
|
+
<style>
|
|
8
|
+
#loadingPage {
|
|
9
|
+
background-color: #dedede;
|
|
10
|
+
font-size: 12px;
|
|
11
|
+
}
|
|
12
|
+
.base {
|
|
13
|
+
left: 45%;
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 40%;
|
|
16
|
+
}
|
|
17
|
+
.desc {
|
|
18
|
+
margin: 0, 0, 20px, 0;
|
|
19
|
+
}
|
|
20
|
+
.loading,
|
|
21
|
+
.loading > div {
|
|
22
|
+
position: relative;
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
}
|
|
25
|
+
.loading {
|
|
26
|
+
display: block;
|
|
27
|
+
font-size: 0;
|
|
28
|
+
color: #06b359;
|
|
29
|
+
}
|
|
30
|
+
.loading.la-dark {
|
|
31
|
+
color: #07C160;
|
|
32
|
+
}
|
|
33
|
+
.loading > div {
|
|
34
|
+
display: inline-block;
|
|
35
|
+
float: none;
|
|
36
|
+
background-color: currentColor;
|
|
37
|
+
border: 0 solid currentColor;
|
|
38
|
+
}
|
|
39
|
+
.loading {
|
|
40
|
+
width: 92px;
|
|
41
|
+
height: 92px;
|
|
42
|
+
}
|
|
43
|
+
.loading > div {
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: 50%;
|
|
46
|
+
left: 50%;
|
|
47
|
+
background: transparent;
|
|
48
|
+
border-style: solid;
|
|
49
|
+
border-width: 2px;
|
|
50
|
+
border-radius: 100%;
|
|
51
|
+
animation: ball-clip-rotate-multiple-rotate 1s ease-in-out infinite;
|
|
52
|
+
}
|
|
53
|
+
.loading > div:first-child {
|
|
54
|
+
position: absolute;
|
|
55
|
+
width: 92px;
|
|
56
|
+
height: 92px;
|
|
57
|
+
border-right-color: transparent;
|
|
58
|
+
border-left-color: transparent;
|
|
59
|
+
}
|
|
60
|
+
.loading > div:last-child {
|
|
61
|
+
width: 16px;
|
|
62
|
+
height: 16px;
|
|
63
|
+
border-top-color: transparent;
|
|
64
|
+
border-bottom-color: transparent;
|
|
65
|
+
animation-duration: 0.5s;
|
|
66
|
+
animation-direction: reverse;
|
|
67
|
+
}
|
|
68
|
+
@keyframes ball-clip-rotate-multiple-rotate {
|
|
69
|
+
0% {
|
|
70
|
+
transform: translate(-50%, -50%) rotate(0deg);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
50% {
|
|
74
|
+
transform: translate(-50%, -50%) rotate(180deg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
100% {
|
|
78
|
+
transform: translate(-50%, -50%) rotate(360deg);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
82
|
+
</head>
|
|
83
|
+
<body>
|
|
84
|
+
<div id="boot">
|
|
85
|
+
<div class='base'>
|
|
86
|
+
<!-- Booting the frontend service ... -->
|
|
87
|
+
<!-- <div class='desc'>
|
|
88
|
+
Booting frontend
|
|
89
|
+
</div> -->
|
|
90
|
+
<div class="loading">
|
|
91
|
+
<div></div>
|
|
92
|
+
<div></div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" />
|
|
7
|
+
<title>Booting failure</title>
|
|
8
|
+
<style>
|
|
9
|
+
#failure {
|
|
10
|
+
background-color: #dedede;
|
|
11
|
+
font-size: 14px;
|
|
12
|
+
}
|
|
13
|
+
.base {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 50%;
|
|
16
|
+
left: 50%;
|
|
17
|
+
transform: translate(-50%, -50%);
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="failure">
|
|
23
|
+
<div class='base'>
|
|
24
|
+
Booting failure, please check frontend serve is runing !
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
package/package.json
CHANGED
package/ps/index.js
CHANGED
|
@@ -181,6 +181,14 @@ exports.getElectronDir = function() {
|
|
|
181
181
|
return process.env.EE_BASE_DIR;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* 获取public目录
|
|
186
|
+
*/
|
|
187
|
+
exports.getPublicDir = function() {
|
|
188
|
+
const dir = path.join(process.env.EE_HOME, "public");
|
|
189
|
+
return dir;
|
|
190
|
+
}
|
|
191
|
+
|
|
184
192
|
/**
|
|
185
193
|
* 获取 额外资源目录
|
|
186
194
|
*/
|
package/socket/httpServer.js
CHANGED
|
@@ -65,13 +65,18 @@ class HttpServer {
|
|
|
65
65
|
.use(this.dispatch);
|
|
66
66
|
|
|
67
67
|
let msg = '[ee-core] [socket/http] server is: ' + url;
|
|
68
|
+
|
|
69
|
+
const listenOpt = {
|
|
70
|
+
host: httpServer.host,
|
|
71
|
+
port: httpServer.port
|
|
72
|
+
}
|
|
68
73
|
if (isHttps) {
|
|
69
|
-
https.createServer(sslOptions, koaApp.callback()).listen(
|
|
74
|
+
https.createServer(sslOptions, koaApp.callback()).listen(listenOpt, (err) => {
|
|
70
75
|
msg = err ? err : msg;
|
|
71
76
|
Log.coreLogger.info(msg);
|
|
72
77
|
});
|
|
73
78
|
} else {
|
|
74
|
-
koaApp.listen(
|
|
79
|
+
koaApp.listen(listenOpt, (e) => {
|
|
75
80
|
msg = e ? e : msg;
|
|
76
81
|
Log.coreLogger.info(msg);
|
|
77
82
|
});
|
package/storage/jsondbStorage.js
CHANGED
|
@@ -12,26 +12,22 @@ class JsondbStorage {
|
|
|
12
12
|
constructor (name, opt = {}) {
|
|
13
13
|
assert(name, `db name ${name} Cannot be empty`);
|
|
14
14
|
|
|
15
|
+
// 补全文件名
|
|
16
|
+
name = this._addExtname(name);
|
|
15
17
|
this.name = name;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
this.mode = this.getMode(name);
|
|
19
|
+
this.storageDir = this._createStorageDir();
|
|
20
|
+
this.fileName = this._formatFileName(name);
|
|
18
21
|
this.storageKey = Constants.storageKey;
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
if (!fs.existsSync(storageDir)) {
|
|
22
|
-
Helper.mkdir(storageDir);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this.db = this.table(name);
|
|
23
|
+
this.db = this.table();
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
/**
|
|
29
27
|
* 创建 table
|
|
30
28
|
*/
|
|
31
|
-
table
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const dbFile = this.getFilePath(name);
|
|
29
|
+
table() {
|
|
30
|
+
const dbFile = this.getFilePath();
|
|
35
31
|
const adapter = new FileSync(dbFile);
|
|
36
32
|
const db = Jsondb(adapter);
|
|
37
33
|
|
|
@@ -41,21 +37,75 @@ class JsondbStorage {
|
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
/**
|
|
44
|
-
*
|
|
40
|
+
* 补全扩展名
|
|
41
|
+
*/
|
|
42
|
+
_addExtname(name) {
|
|
43
|
+
if (path.extname(name) != '.json') {
|
|
44
|
+
name += ".json";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 创建storage目录
|
|
52
|
+
*/
|
|
53
|
+
_createStorageDir() {
|
|
54
|
+
let storageDir = Ps.getStorageDir();
|
|
55
|
+
|
|
56
|
+
if (this.mode == 'absolute') {
|
|
57
|
+
storageDir = path.dirname(this.name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(storageDir)) {
|
|
61
|
+
Helper.mkdir(storageDir);
|
|
62
|
+
Helper.chmodPath(storageDir, '777');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return storageDir;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 获取文件名
|
|
45
70
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
_formatFileName(name) {
|
|
72
|
+
let fileName = path.basename(name);
|
|
73
|
+
return fileName;
|
|
48
74
|
}
|
|
49
75
|
|
|
50
76
|
/**
|
|
51
77
|
* 获取文件绝对路径
|
|
52
78
|
*/
|
|
53
|
-
getFilePath
|
|
54
|
-
const
|
|
55
|
-
const dbFile = path.join(storageDir, this.getFileName(name));
|
|
79
|
+
getFilePath() {
|
|
80
|
+
const dbFile = path.join(this.storageDir, this.fileName);
|
|
56
81
|
return dbFile;
|
|
57
82
|
}
|
|
58
83
|
|
|
84
|
+
/**
|
|
85
|
+
* 获取file path 模式
|
|
86
|
+
*/
|
|
87
|
+
getMode(name) {
|
|
88
|
+
let mode = 'relative';
|
|
89
|
+
|
|
90
|
+
// 路径模式
|
|
91
|
+
name = name.replace(/[/\\]/g, '/');
|
|
92
|
+
if (name.indexOf('/') !== -1) {
|
|
93
|
+
const isAbsolute = path.isAbsolute(name);
|
|
94
|
+
if (isAbsolute) {
|
|
95
|
+
mode = 'absolute';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return mode;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 获取storage目录
|
|
104
|
+
*/
|
|
105
|
+
getStorageDir() {
|
|
106
|
+
return this.storageDir;
|
|
107
|
+
}
|
|
108
|
+
|
|
59
109
|
/**
|
|
60
110
|
* 为指定的 name 设置一个对应的值
|
|
61
111
|
*/
|
package/utils/get-port/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const net = require('net');
|
|
3
|
+
const os = require('os');
|
|
3
4
|
|
|
4
5
|
class Locked extends Error {
|
|
5
6
|
constructor(port) {
|
|
@@ -20,17 +21,53 @@ const releaseOldLockedPortsIntervalMs = 1000 * 15;
|
|
|
20
21
|
// Lazily create interval on first use
|
|
21
22
|
let interval;
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
const getLocalHosts = () => {
|
|
25
|
+
const interfaces = os.networkInterfaces();
|
|
26
|
+
|
|
27
|
+
// Add undefined value for createServer function to use default host,
|
|
28
|
+
// and default IPv4 host in case createServer defaults to IPv6.
|
|
29
|
+
const results = new Set([undefined, '0.0.0.0']);
|
|
30
|
+
|
|
31
|
+
for (const _interface of Object.values(interfaces)) {
|
|
32
|
+
for (const config of _interface) {
|
|
33
|
+
results.add(config.address);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return results;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const checkAvailablePort = options =>
|
|
41
|
+
new Promise((resolve, reject) => {
|
|
42
|
+
const server = net.createServer();
|
|
43
|
+
server.unref();
|
|
44
|
+
server.on('error', reject);
|
|
45
|
+
|
|
46
|
+
server.listen(options, () => {
|
|
47
|
+
const {port} = server.address();
|
|
48
|
+
server.close(() => {
|
|
49
|
+
resolve(port);
|
|
50
|
+
});
|
|
31
51
|
});
|
|
32
52
|
});
|
|
33
|
-
|
|
53
|
+
|
|
54
|
+
const getAvailablePort = async (options, hosts) => {
|
|
55
|
+
if (options.host || options.port === 0) {
|
|
56
|
+
return checkAvailablePort(options);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (const host of hosts) {
|
|
60
|
+
try {
|
|
61
|
+
await checkAvailablePort({port: options.port, host}); // eslint-disable-line no-await-in-loop
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (!['EADDRNOTAVAIL', 'EINVAL'].includes(error.code)) {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return options.port;
|
|
70
|
+
};
|
|
34
71
|
|
|
35
72
|
const portCheckSequence = function * (ports) {
|
|
36
73
|
if (ports) {
|
|
@@ -59,15 +96,17 @@ module.exports = async options => {
|
|
|
59
96
|
}
|
|
60
97
|
}
|
|
61
98
|
|
|
99
|
+
const hosts = getLocalHosts();
|
|
100
|
+
|
|
62
101
|
for (const port of portCheckSequence(ports)) {
|
|
63
102
|
try {
|
|
64
|
-
let availablePort = await getAvailablePort({...options, port}); // eslint-disable-line no-await-in-loop
|
|
103
|
+
let availablePort = await getAvailablePort({...options, port}, hosts); // eslint-disable-line no-await-in-loop
|
|
65
104
|
while (lockedPorts.old.has(availablePort) || lockedPorts.young.has(availablePort)) {
|
|
66
105
|
if (port !== 0) {
|
|
67
106
|
throw new Locked(port);
|
|
68
107
|
}
|
|
69
108
|
|
|
70
|
-
availablePort = await getAvailablePort({...options, port}); // eslint-disable-line no-await-in-loop
|
|
109
|
+
availablePort = await getAvailablePort({...options, port}, hosts); // eslint-disable-line no-await-in-loop
|
|
71
110
|
}
|
|
72
111
|
|
|
73
112
|
lockedPorts.young.add(availablePort);
|
package/utils/helper.js
CHANGED
|
@@ -3,6 +3,10 @@ const mkdirp = require('mkdirp');
|
|
|
3
3
|
const convert = require('koa-convert');
|
|
4
4
|
const is = require('is-type-of');
|
|
5
5
|
const co = require('./co');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
|
|
9
|
+
const _basePath = process.cwd();
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* fnDebounce
|
|
@@ -138,3 +142,34 @@ exports.validValue = function(value) {
|
|
|
138
142
|
value !== ''
|
|
139
143
|
);
|
|
140
144
|
}
|
|
145
|
+
|
|
146
|
+
exports.checkConfig = function(prop) {
|
|
147
|
+
const filepath = path.join(_basePath, prop);
|
|
148
|
+
if (fs.existsSync(filepath)) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
exports.loadConfig = function(prop) {
|
|
156
|
+
const configFile = prop;
|
|
157
|
+
const filepath = path.join(_basePath, configFile);
|
|
158
|
+
if (!fs.existsSync(filepath)) {
|
|
159
|
+
const errorTips = 'config file ' + chalk.blue(`${filepath}`) + ' does not exist !';
|
|
160
|
+
throw new Error(errorTips)
|
|
161
|
+
}
|
|
162
|
+
const obj = require(filepath);
|
|
163
|
+
if (!obj) return obj;
|
|
164
|
+
|
|
165
|
+
let ret = obj;
|
|
166
|
+
if (is.function(obj) && !is.class(obj)) {
|
|
167
|
+
ret = obj();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return ret || {};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
exports.sleep = function(ms) {
|
|
174
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
175
|
+
};
|