-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
170 lines (142 loc) · 4.87 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
const cluster = require('cluster');
const fs = require('fs');
const isMaster = cluster.isMaster;
const colors = require('colors');
const names = require('human-names');
const moment = require('moment');
const Koa = require('koa');
let processName = 'Master';
let powerLog;
let powerPath;
let powerStream;
// equally space text in a width
let space = (text, width) => {
if (text.length < width)
return ' '.repeat(width - text.length) + text;
else
return text;
};
// set text color to italy's flag
let italy = str => {
let out = '';
let cur = 0;
for (let i = 0; i < str.length; i++) {
let char = str.charAt(i);
if (char !== ' ')
switch (cur) {
case 0:
out += char.green;
cur++;
break;
case 1:
out += char.white;
cur++;
break;
case 2:
out += char.red;
cur = 0;
break;
}
else
out += char;
}
return out;
};
// set italy's color to string prototype
Object.defineProperty(String.prototype, 'italy', {
get: function () {
return italy(this);
}
});
let name = text => {
processName = text;
};
let log = args => {
let out = `[${moment().format('YY-MM-DD H:mm:ss:SSS')}] `.cyan + space(processName, 10).cyan + ` | ${args}\n`;
if (powerLog) {
let powerOut = out.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
powerStream.write(powerOut);
}
return process.stdout.write(out);
};
let load = (worker, options) => {
let config = options || {};
!config.appName && (config.appName = 'Koa Power App');
!config.numWorkers && (config.numWorkers = 2);
!config.mid && (config.mid = []);
!config.enableLog && (config.enableLog = false);
!config.afterFork && (config.afterFork = () => {});
let appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
!config.logFileName && (config.logFileName = appDirectory + '/power.log');
powerLog = config.enableLog;
powerPath = config.logFileName;
let shouldLineBreak = false;
powerLog && fs.existsSync(powerPath) && (shouldLineBreak = true);
powerLog && (powerStream = fs.createWriteStream(powerPath, {flags: 'a'}));
let numWorkers = config.numWorkers;
let mid = config.mid;
// set locale
moment.locale(config.locale || 'en');
if (isMaster) {
powerLog && shouldLineBreak && powerStream.write('\n');
let workers = {};
let workerNames = [];
// output app name
let out = `${config.appName}`.italy;
if (config.appNameColor && colors[config.appNameColor]) {
out = `${config.appName}`[config.appNameColor];
}
log(out);
// fork new worker
const fork = () => {
cluster.fork();
config.afterFork();
};
// forking workers
log(`Forking ${numWorkers} worker` + (numWorkers !== 1 ? 's' : ''));
[...Array(numWorkers)].map(() => fork());
// wait for worker to be online and give it a name
cluster.on('online', (worker) => {
while (!workers[worker.process.pid]) {
let maybeName = names.allRandom();
maybeName.length < 10 && !workerNames.includes(maybeName) && (workers[worker.process.pid] = maybeName);
}
workerNames.push(workers[worker.process.pid]);
worker.send({name:workers[worker.process.pid]});
log(`Worker ${workers[worker.process.pid]} is online`.green)
});
cluster.on('exit', (worker, exitCode) => {
log(`Worker ${worker.process.id} exited with code ${exitCode}`);
log(`Starting a new worker`);
fork();
})
} else {
// get process name from master
process.on('message', (msg) => {
if (msg.name) {
name(msg.name);
}
});
// init koa app
const app = new Koa();
// additional prepended middleware
mid.forEach(middleware => app.use(middleware));
// logger
app.use(async (ctx, next) => {
log(`${ctx.method} ${ctx.url} - BEGIN`.cyan);
await next();
const rt = ctx.response.get('X-Response-Time');
log(`${ctx.method} ${ctx.url} - END`.cyan + ` ~ ${rt}`);
});
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// call worker
worker(app);
}
};
module.exports = {load, log, italy, space, name};