servez 1.14.2 → 2.1.0
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/bin/servez +130 -141
- package/package.json +3 -3
- package/src/server-worker.js +10 -0
package/bin/servez
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { program } = require('commander');
|
|
6
|
+
const pkg = require('../package.json');
|
|
6
7
|
const colorSupport = require('color-support') || {};
|
|
7
8
|
const c = require('ansi-colors');
|
|
8
9
|
c.enabled = colorSupport.hasBasic;
|
|
@@ -19,153 +20,141 @@ const log = {
|
|
|
19
20
|
},
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const line = [];
|
|
30
|
-
for (let x = -2; x < size; ++x) {
|
|
31
|
-
line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
|
|
32
|
-
}
|
|
33
|
-
lines.push(line.join(''));
|
|
23
|
+
const fixedParseInt = v => parseInt(v);
|
|
24
|
+
const parseHeader = (v, oldV) => {
|
|
25
|
+
console.log('v:', `'${v}'`);
|
|
26
|
+
console.log('oldV:', `'${JSON.stringify(oldV)}'`);
|
|
27
|
+
const m = /^(.*?):(.*?)$/.exec(v);
|
|
28
|
+
if (!m) {
|
|
29
|
+
throw new Error('bad header argument: format is --header=<header>:<value>');
|
|
34
30
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const optionSpec = {
|
|
39
|
-
options: [
|
|
40
|
-
{ option: 'help', alias: 'h', type: 'Boolean', description: 'displays help' },
|
|
41
|
-
{ option: 'port', alias: 'p', type: 'Int', description: 'port', default: '8080' },
|
|
42
|
-
{ option: 'version', type: 'Boolean', description: 'print version' },
|
|
43
|
-
{ option: 'scan', type: 'Boolean', description: 'scan for open port', default: 'true', },
|
|
44
|
-
{ option: 'qr', type: 'Boolean', description: 'print QR Code for root url' },
|
|
45
|
-
{ option: 'dirs', type: 'Boolean', description: 'show directory listing', default: 'true', },
|
|
46
|
-
{ option: 'cors', type: 'Boolean', description: 'send CORS headers', default: 'true', },
|
|
47
|
-
{ option: 'local', type: 'Boolean', description: 'local machine only', default: 'false', },
|
|
48
|
-
{ option: 'index', type: 'Boolean', description: 'serve index.html for directories', default: 'true', },
|
|
49
|
-
{ option: 'extensions', type: '[String]', description: 'extensions to try if path does not exist', default: '["html"]', },
|
|
50
|
-
{ option: 'unity-hack', type: 'Boolean', description: 'ignore .gz and .br when computing content type', default: 'true', },
|
|
51
|
-
{ option: 'shared-array-buffers', type: 'Boolean', description: "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", default: 'false', },
|
|
52
|
-
{ option: 'header', type: 'Object', description: 'extra headers to include eg --header=Content-Language:de-DE', mergeRepeatedObjects: true},
|
|
53
|
-
{ option: 'gzip', type: 'Boolean', description: 'serve .gz files if they exist', default: 'false', },
|
|
54
|
-
{ option: 'brotli', type: 'Boolean', description: 'serve .br files if they exist', default: 'false', },
|
|
55
|
-
{ option: 'robots', type: 'Boolean', description: 'serve a robots.txt if one does not exist', default: 'true', },
|
|
56
|
-
{ option: 'hidden', type: 'Boolean', description: 'show hidden dotfiles', default: 'false', },
|
|
57
|
-
{ option: 'username', type: 'String', description: 'username for basic auth' },
|
|
58
|
-
{ option: 'password', type: 'String', description: 'password for basic auth' },
|
|
59
|
-
{ option: 'ssl', alias: 'S', type: 'Boolean', description: 'enable https (will use fake cert if not specified)', },
|
|
60
|
-
{ option: 'cert', alias: 'C', type: 'String', description: 'Path to ssl cert file', },
|
|
61
|
-
{ option: 'key', alias: 'K', type: 'String', description: 'Path to ssl key file', },
|
|
62
|
-
],
|
|
63
|
-
prepend: `Usage: servez [options] [path-to-serve]`,
|
|
64
|
-
helpStyle: {
|
|
65
|
-
typeSeparator: '=',
|
|
66
|
-
descriptionSeparator: ' : ',
|
|
67
|
-
initialIndent: 4,
|
|
68
|
-
},
|
|
31
|
+
const newV = {...oldV};
|
|
32
|
+
newV[m[1]] = m[2];
|
|
33
|
+
return newV;
|
|
69
34
|
};
|
|
70
|
-
/* eslint-enable object-curly-newline */
|
|
71
|
-
const optionator = makeOptions(optionSpec);
|
|
72
|
-
|
|
73
|
-
let args;
|
|
74
|
-
try {
|
|
75
|
-
args = optionator.parse(process.argv);
|
|
76
|
-
} catch (e) {
|
|
77
|
-
log.error(e);
|
|
78
|
-
printHelp();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function printHelp() {
|
|
82
|
-
log.info(optionator.generateHelp());
|
|
83
|
-
process.exit(1); // eslint-disable-line
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (args.help) {
|
|
87
|
-
printHelp();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (args.version) {
|
|
91
|
-
const pkg = require('../package.json');
|
|
92
|
-
log.info(pkg.version);
|
|
93
|
-
process.exit(0);
|
|
94
|
-
}
|
|
95
35
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
36
|
+
program
|
|
37
|
+
.name('servez')
|
|
38
|
+
.version(pkg.version)
|
|
39
|
+
.usage('[options] [path-to-serve]')
|
|
40
|
+
.argument('[path-to-serve]', 'path to serve')
|
|
41
|
+
.option('-p, --port <port>', 'port', fixedParseInt, 8080)
|
|
42
|
+
.option('-q, --quiet', 'do not show requests and missing file messages')
|
|
43
|
+
.option('--no-scan', 'do not scan for open port')
|
|
44
|
+
.option('--qr', 'print QR Code for root url')
|
|
45
|
+
.option('--no-dirs', 'do not show directory listing')
|
|
46
|
+
.option('--no-cors', 'do not send CORS headers')
|
|
47
|
+
.option('--local', 'local machine only')
|
|
48
|
+
.option('--no-index', 'do not serve index.html for directories')
|
|
49
|
+
.option('--extensions <extensions...>','extensions to try if path does not exist', ['html'])
|
|
50
|
+
.option('--no-unity-hack', 'do not ignore .gz and .br when computing content type')
|
|
51
|
+
.option('--shared-array-buffers', "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", false)
|
|
52
|
+
.option('--header <header>', 'extra headers to include eg --header=Content-Language:de-DE', parseHeader, {})
|
|
53
|
+
.option('--gzip', 'serve .gz files if they exist', false)
|
|
54
|
+
.option('--brotli', 'serve .br files if they exist', false)
|
|
55
|
+
.option('--no-robots', 'do not serve a robots.txt if one does not exist', true)
|
|
56
|
+
.option('--hidden', 'show hidden dotfiles', false)
|
|
57
|
+
.option('--username <username>', 'username for basic auth')
|
|
58
|
+
.option('--password <password>', 'password for basic auth')
|
|
59
|
+
.option('-S, --ssl', 'enable https (will use fake cert if not specified)', false)
|
|
60
|
+
.option('-C, --cert <cert>', 'Path to ssl cert file')
|
|
61
|
+
.option('-K, --key <key>', 'Path to ssl key file')
|
|
62
|
+
.action(main);
|
|
63
|
+
|
|
64
|
+
program.showHelpAfterError('(add --help for additional information)');
|
|
65
|
+
program.parse();
|
|
66
|
+
|
|
67
|
+
function main(pathToServe, args) {
|
|
68
|
+
args.headers = args.header;
|
|
69
|
+
delete args.header;
|
|
70
|
+
|
|
71
|
+
const fs = require('fs');
|
|
72
|
+
const path = require('path');
|
|
73
|
+
const {QrCode, Ecc} = require('../lib/qrcodegen');
|
|
74
|
+
const hosts = [];
|
|
75
|
+
|
|
76
|
+
function genQRCode(s) {
|
|
77
|
+
const qr = QrCode.encodeText(s, Ecc.MEDIUM);
|
|
78
|
+
const size = qr.size + 2;
|
|
79
|
+
|
|
80
|
+
const lines = [];
|
|
81
|
+
for (let y = -2; y < size; ++y) {
|
|
82
|
+
const line = [];
|
|
83
|
+
for (let x = -2; x < size; ++x) {
|
|
84
|
+
line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
|
|
85
|
+
}
|
|
86
|
+
lines.push(line.join(''));
|
|
87
|
+
}
|
|
88
|
+
return lines.join('\n');
|
|
117
89
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
process.stdin.destroy(); // this allows control-c to not print "Terminate Batch?"
|
|
121
|
-
process.title = `servez ${root.split(/\\|\//g).slice(-3).join(path.sep)}`;
|
|
122
90
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
},
|
|
130
|
-
host(args) {
|
|
131
|
-
const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
|
|
132
|
-
const [data] = args;
|
|
133
|
-
const {root} = data;
|
|
134
|
-
if (!localRE.test(root)) {
|
|
135
|
-
hosts.push(root);
|
|
91
|
+
const root = path.resolve(pathToServe || process.cwd());
|
|
92
|
+
try {
|
|
93
|
+
const stat = fs.statSync(root);
|
|
94
|
+
if (!stat.isDirectory()) {
|
|
95
|
+
log.error(`'${root}' is not a directory`);
|
|
96
|
+
process.exit(1); // eslint-disable-line
|
|
136
97
|
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
log.info('');
|
|
144
|
-
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
if (e.code === 'ENOENT') {
|
|
100
|
+
log.warn(c.bold.yellow(`!!!!!!!!!!!!!!!\n\n WARNING: '${root}' does not exist!\n\n!!!!!!!!!!!!!!!`));
|
|
101
|
+
} else {
|
|
102
|
+
log.error(e, e.stack);
|
|
103
|
+
process.exit(1); // eslint-disable-line
|
|
145
104
|
}
|
|
146
|
-
log.info('press CTRL-C to stop the server.');
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const {Worker} = require('worker_threads');
|
|
151
|
-
const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
|
|
152
|
-
workerData: {
|
|
153
|
-
root,
|
|
154
|
-
args,
|
|
155
|
-
useColors: colorSupport.hasBasic,
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
worker.on('message', (msg) => {
|
|
159
|
-
const cmd = msg.cmd;
|
|
160
|
-
const fn = commands[cmd];
|
|
161
|
-
if (!fn) {
|
|
162
|
-
throw new Error(`unknown cmd: ${cmd}`);
|
|
163
105
|
}
|
|
164
|
-
fn(msg.data);
|
|
165
|
-
});
|
|
166
106
|
|
|
167
|
-
process.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
107
|
+
process.stdin.destroy(); // this allows control-c to not print "Terminate Batch?"
|
|
108
|
+
process.title = `servez ${root.split(/\\|\//g).slice(-3).join(path.sep)}`;
|
|
109
|
+
|
|
110
|
+
const commands = {
|
|
111
|
+
log(args) {
|
|
112
|
+
console.log(...args);
|
|
113
|
+
},
|
|
114
|
+
error(args) {
|
|
115
|
+
console.error(c.red(args.join(' ')));
|
|
116
|
+
},
|
|
117
|
+
host(args) {
|
|
118
|
+
const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
|
|
119
|
+
const [data] = args;
|
|
120
|
+
const {root} = data;
|
|
121
|
+
if (!localRE.test(root)) {
|
|
122
|
+
hosts.push(root);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
start(data) {
|
|
126
|
+
if (args.qr) {
|
|
127
|
+
for (const host of hosts) {
|
|
128
|
+
log.info(`--------------\nQR code for: ${host}`);
|
|
129
|
+
log.info(genQRCode(host));
|
|
130
|
+
log.info('');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (args.verbose === undefined || args.verbose >= 1) {
|
|
134
|
+
log.info('press CTRL-C to stop the server.');
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const {Worker} = require('worker_threads');
|
|
140
|
+
const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
|
|
141
|
+
workerData: {
|
|
142
|
+
root,
|
|
143
|
+
args,
|
|
144
|
+
useColors: colorSupport.hasBasic,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
worker.on('message', (msg) => {
|
|
148
|
+
const cmd = msg.cmd;
|
|
149
|
+
const fn = commands[cmd];
|
|
150
|
+
if (!fn) {
|
|
151
|
+
throw new Error(`unknown cmd: ${cmd}`);
|
|
152
|
+
}
|
|
153
|
+
fn(msg.data);
|
|
154
|
+
});
|
|
171
155
|
|
|
156
|
+
process.on('SIGINT', function () {
|
|
157
|
+
console.log(c.red('servez stopped.'));
|
|
158
|
+
process.exit(0);
|
|
159
|
+
});
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "servez",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A simple command line server to replace http-server",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "node ./bin/servez"
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"ansi-colors": "^4.1.1",
|
|
27
27
|
"color-support": "^1.1.3",
|
|
28
|
-
"
|
|
29
|
-
"servez-lib": "^2.
|
|
28
|
+
"commander": "^11.0.0",
|
|
29
|
+
"servez-lib": "^2.8.0"
|
|
30
30
|
},
|
|
31
31
|
"bin": {
|
|
32
32
|
"servez": "./bin/servez"
|
package/src/server-worker.js
CHANGED
|
@@ -17,10 +17,20 @@ function sendCmd(cmd, data) {
|
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
console.log(JSON.stringify(args, null, 2));
|
|
21
|
+
|
|
20
22
|
c.enabled = useColors;
|
|
21
23
|
const logger = {
|
|
22
24
|
log: (...args) => sendCmd('log', args),
|
|
23
25
|
error: (...args) => sendCmd('error', args),
|
|
26
|
+
filter: (msgType) => {
|
|
27
|
+
switch (msgType) {
|
|
28
|
+
case Servez.MsgType.Info:
|
|
29
|
+
return args.quiet ? false : true;
|
|
30
|
+
default:
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
24
34
|
c,
|
|
25
35
|
};
|
|
26
36
|
|