xshell 0.0.10 → 0.0.14
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/extension.js +11 -11
- package/extension.js.map +1 -1
- package/file.d.ts +34 -13
- package/file.js +28 -19
- package/file.js.map +1 -1
- package/net.d.ts +28 -19
- package/net.js +66 -56
- package/net.js.map +1 -1
- package/package.json +15 -19
- package/process.d.ts +14 -14
- package/process.js +56 -62
- package/process.js.map +1 -1
- package/prototype.d.ts +31 -20
- package/prototype.js +115 -96
- package/prototype.js.map +1 -1
- package/repl.d.ts +2 -5
- package/repl.js +72 -58
- package/repl.js.map +1 -1
- package/server.d.ts +26 -9
- package/server.js +224 -100
- package/server.js.map +1 -1
- package/tsconfig.json +6 -6
- package/ufs.d.ts +21 -0
- package/ufs.js +153 -0
- package/ufs.js.map +1 -0
- package/utils.d.ts +17 -10
- package/utils.js +84 -41
- package/utils.js.map +1 -1
package/server.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.server =
|
|
3
|
+
exports.server = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const http_1 = require("http");
|
|
6
6
|
const zlib_1 = (0, tslib_1.__importDefault)(require("zlib"));
|
|
7
|
-
|
|
7
|
+
const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
// --- 3rd party
|
|
10
|
+
const upath_1 = (0, tslib_1.__importDefault)(require("upath"));
|
|
8
11
|
const invoke_1 = (0, tslib_1.__importDefault)(require("lodash/invoke"));
|
|
9
12
|
const qs_1 = (0, tslib_1.__importDefault)(require("qs"));
|
|
10
|
-
|
|
13
|
+
const resolve_path_1 = (0, tslib_1.__importDefault)(require("resolve-path"));
|
|
14
|
+
// --- koa & koa middleware
|
|
11
15
|
const koa_1 = (0, tslib_1.__importDefault)(require("koa"));
|
|
12
16
|
const cors_1 = (0, tslib_1.__importDefault)(require("@koa/cors"));
|
|
13
17
|
const koa_compress_1 = (0, tslib_1.__importDefault)(require("koa-compress"));
|
|
14
18
|
const koa_useragent_1 = require("koa-useragent");
|
|
15
19
|
const utils_1 = require("./utils");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
exports.ROUTER_IP = '192.168.1.1';
|
|
19
|
-
exports.PHONE_IP = '192.168.1.113';
|
|
20
|
-
exports.KNOWN_IPS = new Set([...exports.LOCALHOST_IPS, exports.ROUTER_IP, exports.PHONE_IP]);
|
|
21
|
-
// ------------ MyServer
|
|
20
|
+
const file_1 = require("./file");
|
|
21
|
+
// ------------ my server
|
|
22
22
|
exports.server = {
|
|
23
23
|
app: null,
|
|
24
24
|
handler: null,
|
|
25
25
|
server_80: null,
|
|
26
26
|
/** start http server and listen */
|
|
27
27
|
async start() {
|
|
28
|
+
// --- init koa app
|
|
28
29
|
let app = new koa_1.default();
|
|
29
30
|
app.on('error', (error, ctx) => {
|
|
30
31
|
console.error(error);
|
|
@@ -36,7 +37,7 @@ exports.server = {
|
|
|
36
37
|
// https://nodejs.org/api/zlib.html#zlib_class_brotlioptions
|
|
37
38
|
params: {
|
|
38
39
|
[zlib_1.default.constants.BROTLI_PARAM_MODE]: zlib_1.default.constants.BROTLI_MODE_TEXT,
|
|
39
|
-
[zlib_1.default.constants.BROTLI_PARAM_QUALITY]: 6 // default 11 (maximized compression), may lead to news/get generated
|
|
40
|
+
[zlib_1.default.constants.BROTLI_PARAM_QUALITY]: 6 // default 11 (maximized compression), may lead to news/get generated 14mb json taking 24s
|
|
40
41
|
},
|
|
41
42
|
},
|
|
42
43
|
threshold: 512
|
|
@@ -45,76 +46,95 @@ exports.server = {
|
|
|
45
46
|
app.use(koa_useragent_1.userAgent);
|
|
46
47
|
app.use(this.router.bind(this));
|
|
47
48
|
this.app = app;
|
|
48
|
-
await this.listen();
|
|
49
|
-
},
|
|
50
|
-
async listen() {
|
|
51
49
|
this.handler = this.app.callback();
|
|
52
50
|
this.server_80 = (0, http_1.createServer)(this.handler);
|
|
53
|
-
await Promise
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
await new Promise(resolve => {
|
|
52
|
+
this.server_80.listen(8421, resolve);
|
|
53
|
+
});
|
|
56
54
|
},
|
|
57
55
|
stop() {
|
|
58
56
|
this.server_80.close();
|
|
59
57
|
},
|
|
60
58
|
async entry(ctx, next) {
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
let { response } = ctx;
|
|
60
|
+
await this.parse(ctx);
|
|
61
|
+
// ------------ next
|
|
62
|
+
try {
|
|
63
|
+
await next();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.status !== 404)
|
|
67
|
+
console.error(error);
|
|
68
|
+
response.status = error.status || 500;
|
|
69
|
+
response.body = (0, utils_1.inspect)(error, { colors: false });
|
|
70
|
+
response.type = 'text/plain';
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
parse req.body to request.body
|
|
75
|
+
process request.ip
|
|
76
|
+
*/
|
|
77
|
+
async parse(ctx) {
|
|
78
|
+
const { request, req, req: { tunnel }, } = ctx;
|
|
63
79
|
if (!tunnel) {
|
|
64
80
|
const buf = await (0, utils_1.stream_to_buffer)(req);
|
|
65
81
|
if (buf.length)
|
|
66
82
|
req.body = buf;
|
|
67
83
|
}
|
|
68
|
-
//
|
|
69
|
-
if (req.body)
|
|
70
|
-
if (ctx.is('application/json') || ctx.is('text/plain'))
|
|
71
|
-
request.body = JSON.parse(req.body.toString());
|
|
72
|
-
else if (ctx.is('application/x-www-form-urlencoded'))
|
|
73
|
-
request.body = qs_1.default.parse(req.body.toString());
|
|
74
|
-
else if (ctx.is('multipart/form-data')) {
|
|
75
|
-
throw new Error('multipart/form-data is not supported');
|
|
76
|
-
}
|
|
77
|
-
else
|
|
78
|
-
request.body = req.body;
|
|
79
|
-
// ------------ parse request.ip
|
|
84
|
+
// --- parse request.ip
|
|
80
85
|
request.ip = (request.headers['x-real-ip'] || request.ip).replace(/^::ffff:/, '');
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
// --- parse body
|
|
87
|
+
if (!req.body)
|
|
88
|
+
return;
|
|
89
|
+
if (ctx.is('application/json') || ctx.is('text/plain'))
|
|
90
|
+
request.body = JSON.parse(req.body.toString());
|
|
91
|
+
else if (ctx.is('application/x-www-form-urlencoded'))
|
|
92
|
+
request.body = qs_1.default.parse(req.body.toString());
|
|
93
|
+
else if (ctx.is('multipart/form-data')) {
|
|
94
|
+
throw new Error('multipart/form-data is not supported');
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
request.body = req.body;
|
|
84
98
|
},
|
|
85
99
|
async router(ctx, next) {
|
|
86
|
-
|
|
87
|
-
request
|
|
88
|
-
request._path = decodeURIComponent(request.path);
|
|
100
|
+
var _a;
|
|
101
|
+
let { request } = ctx;
|
|
102
|
+
const _path = request._path = decodeURIComponent(request.path);
|
|
89
103
|
Object.defineProperty(request, 'path', {
|
|
90
|
-
value:
|
|
104
|
+
value: _path,
|
|
91
105
|
configurable: true,
|
|
92
106
|
enumerable: true,
|
|
93
107
|
writable: true
|
|
94
108
|
});
|
|
95
109
|
const { path } = request;
|
|
96
|
-
// ------------
|
|
110
|
+
// ------------ /repl/rpc
|
|
97
111
|
if (path === '/api/rpc') {
|
|
98
112
|
await this.rpc(ctx);
|
|
99
113
|
return;
|
|
100
114
|
}
|
|
101
115
|
// ------------ log
|
|
102
116
|
this.logger(ctx);
|
|
117
|
+
// ------------ repl_router hook
|
|
118
|
+
if (await ((_a = global.repl_router) === null || _a === void 0 ? void 0 : _a.call(global, ctx)))
|
|
119
|
+
return;
|
|
103
120
|
await (next === null || next === void 0 ? void 0 : next());
|
|
104
121
|
},
|
|
105
|
-
/** args are array http://
|
|
122
|
+
/** args are array http://localhost/repl/rpc?func=to_json&args=aaa&args=bbb
|
|
106
123
|
should use POST when arg is number, otherwise type will be string
|
|
107
124
|
queries:
|
|
108
125
|
- func: function name
|
|
109
126
|
- args?: `[]` args array
|
|
110
|
-
- async?: `false` don't wait
|
|
111
127
|
- ignore?: `false` don't serialize result into response
|
|
128
|
+
- async?: `false` don't wait
|
|
112
129
|
*/
|
|
113
130
|
async rpc(ctx) {
|
|
114
131
|
const { request: { query, body }, response } = ctx;
|
|
115
132
|
let { func, args = [], ignore = false, async: _async = false } = { ...query, ...body };
|
|
116
|
-
if (!func)
|
|
117
|
-
|
|
133
|
+
if (!func) {
|
|
134
|
+
let error = new Error('rpc no func');
|
|
135
|
+
error.status = 400;
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
118
138
|
if (!Array.isArray(args))
|
|
119
139
|
args = [args];
|
|
120
140
|
// ?async=1 or ?async=0 or ?async=false
|
|
@@ -136,84 +156,188 @@ exports.server = {
|
|
|
136
156
|
response.body = JSON.stringify(result) || '';
|
|
137
157
|
}
|
|
138
158
|
catch (error) {
|
|
139
|
-
|
|
140
|
-
response.body = error;
|
|
159
|
+
error.status = 500;
|
|
141
160
|
throw error;
|
|
142
161
|
}
|
|
143
162
|
},
|
|
144
163
|
logger(ctx) {
|
|
145
164
|
const { request } = ctx;
|
|
146
|
-
const { query, body, path,
|
|
147
|
-
|
|
165
|
+
const { query, body, path, _path, protocol, host, req: { httpVersion: http_version }, ip, } = request;
|
|
166
|
+
let { method } = request;
|
|
148
167
|
const ua = ctx.userAgent;
|
|
149
168
|
let s = '';
|
|
150
169
|
// --- time
|
|
151
|
-
s += new Date().to_time_str()
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
else if (ip === exports.ROUTER_IP)
|
|
158
|
-
t = 'Router'.grey;
|
|
159
|
-
else if (ip === exports.PHONE_IP)
|
|
160
|
-
t = 'Phone';
|
|
161
|
-
else
|
|
162
|
-
t = ip;
|
|
163
|
-
else
|
|
164
|
-
t = ip;
|
|
165
|
-
s += t.pad(50) + ' ';
|
|
166
|
-
// --- UA
|
|
167
|
-
t = '';
|
|
168
|
-
if (!known) {
|
|
170
|
+
s += `${new Date().to_time_str()} `;
|
|
171
|
+
// --- ip
|
|
172
|
+
s += (ip || '').pad(40) + ' ';
|
|
173
|
+
// --- ua
|
|
174
|
+
s += (() => {
|
|
175
|
+
let t = '';
|
|
169
176
|
if (ua.isMobile)
|
|
170
|
-
t += '
|
|
171
|
-
if (ua.isBot)
|
|
172
|
-
t += ' Robot'.blue;
|
|
177
|
+
t += 'mobile';
|
|
173
178
|
if (ua.isDesktop)
|
|
174
|
-
t += '
|
|
179
|
+
t += 'desktop';
|
|
180
|
+
if (ua.isBot)
|
|
181
|
+
t += `${t ? ' ' : ''}${'robot'.blue}`;
|
|
175
182
|
if (ua.platform !== 'unknown' && !ua.os.startsWith('Windows'))
|
|
176
|
-
t += '/' + ua.platform;
|
|
183
|
+
t += '/' + ua.platform.toLowerCase().replace('apple mac', 'mac');
|
|
177
184
|
if (ua.os !== 'unknown' && ua.platform !== 'Android')
|
|
178
|
-
t += '/' + ua.os;
|
|
185
|
+
t += '/' + ua.os.toLowerCase();
|
|
179
186
|
if (ua.browser !== 'unknown')
|
|
180
|
-
t += '/' + ua.browser;
|
|
187
|
+
t += '/' + ua.browser.toLowerCase();
|
|
188
|
+
if (ua.isWechat)
|
|
189
|
+
t += '/weixin';
|
|
181
190
|
if (ua.version !== 'unknown')
|
|
182
|
-
t += '/' + ua.version;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// ---
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
s += '
|
|
191
|
-
// ---
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
t =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if ((s + t).width > global.WIDTH)
|
|
209
|
-
s += '\n';
|
|
191
|
+
t += '/' + ua.version.split('.').slice(0, 2).join('.');
|
|
192
|
+
return t;
|
|
193
|
+
})().pad(40) + ' ';
|
|
194
|
+
// --- https/2.0
|
|
195
|
+
// if (req.tunnel) `tunnel/${http_version}`.pad(10).cyan
|
|
196
|
+
s += `${`${protocol.pad(5)}/${http_version}`.pad(10)} `;
|
|
197
|
+
// --- method
|
|
198
|
+
method = method.toLowerCase();
|
|
199
|
+
s += method === 'get' ? method.pad(10) : method.pad(10).yellow;
|
|
200
|
+
// --- host
|
|
201
|
+
s += `${host.pad(20)} `;
|
|
202
|
+
// --- path
|
|
203
|
+
s += (() => {
|
|
204
|
+
if (path.toLowerCase() !== _path.toLowerCase())
|
|
205
|
+
return `${_path.blue} → ${path}`;
|
|
206
|
+
if (!path.includes('.'))
|
|
207
|
+
return path.yellow;
|
|
208
|
+
return path;
|
|
209
|
+
})();
|
|
210
|
+
// --- query
|
|
211
|
+
if (Object.keys(query).length) {
|
|
212
|
+
let t = (0, utils_1.inspect)(query, { compact: true })
|
|
213
|
+
.replace('[Object: null prototype] ', '');
|
|
214
|
+
if (t.endsWith('\n'))
|
|
215
|
+
t = t.slice(0, -1);
|
|
216
|
+
s += (s + t).width > utils_1.output_width ? '\n' : ' ';
|
|
210
217
|
s += t;
|
|
211
218
|
}
|
|
212
|
-
// ---
|
|
219
|
+
// --- body
|
|
213
220
|
if (body && Object.keys(body).length)
|
|
214
221
|
s += '\n' + (0, utils_1.inspect)(body).replace('[Object: null prototype] ', '');
|
|
222
|
+
// --- print log
|
|
215
223
|
console.log(s);
|
|
216
224
|
},
|
|
225
|
+
async try_send(ctx, fp, { fs = file_1.ufs, root }) {
|
|
226
|
+
const { request: { _path, path, method }, response, } = ctx;
|
|
227
|
+
if (!(typeof response.body === 'undefined') || response.status !== 404)
|
|
228
|
+
return true;
|
|
229
|
+
if (method !== 'HEAD' && method !== 'GET')
|
|
230
|
+
return false;
|
|
231
|
+
function log_404() {
|
|
232
|
+
let s = `${' '.repeat(13)} ${method.toLowerCase()} 404: ${path}`;
|
|
233
|
+
if (_path !== path)
|
|
234
|
+
s += ` ${_path.bracket()}`;
|
|
235
|
+
console.log(s.red);
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
await this.fsend(ctx, fp, { fs, root });
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error.status !== 404)
|
|
243
|
+
throw error;
|
|
244
|
+
log_404();
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
/** send file at `path` with the given `options` to the koa `ctx`. */
|
|
249
|
+
async fsend(ctx, path, { fs = fs_1.default, root, absolute } = {}) {
|
|
250
|
+
const { request, response, req } = ctx;
|
|
251
|
+
if (!absolute && !root)
|
|
252
|
+
throw new Error('fsend with `!absolute && !root`');
|
|
253
|
+
if (absolute)
|
|
254
|
+
path = upath_1.default.resolve(path);
|
|
255
|
+
else {
|
|
256
|
+
if (path.startsWith(root))
|
|
257
|
+
path = path.slice(root.length);
|
|
258
|
+
if (path.startsWith('/'))
|
|
259
|
+
path = path.slice(1);
|
|
260
|
+
try {
|
|
261
|
+
path = upath_1.default.normalize((0, resolve_path_1.default)(root, path));
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
error.message += `, path = ${path}`;
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// stat
|
|
269
|
+
let stats;
|
|
270
|
+
try {
|
|
271
|
+
stats = await (0, util_1.promisify)(fs.stat)(path);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
if (['ENOENT', 'ENAMETOOLONG', 'ENOTDIR'].includes(error.code)) {
|
|
275
|
+
error.status = 404;
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
error.status = 500;
|
|
279
|
+
error.message = `fs.stat 出错: ${error.message}`;
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
if (stats.size >= 100 * 2 ** 20) {
|
|
283
|
+
let error = new Error('body.length >= 100 mb');
|
|
284
|
+
error.status = 500;
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
if (!req.tunnel) {
|
|
288
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges
|
|
289
|
+
// advertise server support of partial requests
|
|
290
|
+
response.set('accept-ranges', 'bytes');
|
|
291
|
+
}
|
|
292
|
+
if (!response.get('cache-control'))
|
|
293
|
+
response.set('cache-control', 'max-age=0, must-revalidate');
|
|
294
|
+
if (!response.get('last-modified'))
|
|
295
|
+
response.set('last-modified', stats.mtime ? stats.mtime.toUTCString() : new Date().toUTCString());
|
|
296
|
+
const fext = path.fext;
|
|
297
|
+
if (!response.type)
|
|
298
|
+
response.type = fext;
|
|
299
|
+
if (fext === '.pdf')
|
|
300
|
+
response.set('content-disposition', `attachment; filename="${encodeURIComponent(path.fname)}"`);
|
|
301
|
+
if (request.fresh) {
|
|
302
|
+
response.status = 304;
|
|
303
|
+
// 以上会自动设置 response.body = null
|
|
304
|
+
return path;
|
|
305
|
+
}
|
|
306
|
+
if (request.headers.range) {
|
|
307
|
+
if (req.tunnel) {
|
|
308
|
+
response.status = 400;
|
|
309
|
+
response.body = '';
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const range_header = request.headers.range;
|
|
314
|
+
const range_value = /=(.*)$/.exec(range_header)[1];
|
|
315
|
+
const range = /^[\w]*?(\d*)-(\d*)$/.exec(range_value);
|
|
316
|
+
let start = range[1] ? parseInt(range[1]) : undefined;
|
|
317
|
+
let end = range[2] ? parseInt(range[2]) : stats.size - 1;
|
|
318
|
+
if (typeof start == 'undefined') {
|
|
319
|
+
start = (stats.size - end);
|
|
320
|
+
end = (stats.size - 1);
|
|
321
|
+
}
|
|
322
|
+
const chunksize = (end - start + 1);
|
|
323
|
+
response.status = 206;
|
|
324
|
+
response.set('content-length', String(chunksize));
|
|
325
|
+
response.set('content-range', `bytes ${start}-${end}/${stats.size}`);
|
|
326
|
+
response.body = fs.createReadStream(path, { start, end });
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
response.status = 416;
|
|
330
|
+
response.set('content-length', String(stats.size));
|
|
331
|
+
response.set('content-range', `bytes */${stats.size}`);
|
|
332
|
+
response.body = fs.createReadStream(path);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
response.set('content-length', String(stats.size));
|
|
337
|
+
response.body = fs.createReadStream(path);
|
|
338
|
+
}
|
|
339
|
+
return path;
|
|
340
|
+
}
|
|
217
341
|
};
|
|
218
342
|
exports.default = exports.server;
|
|
219
343
|
//# sourceMappingURL=server.js.map
|
package/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer as create_server } from 'http'\nimport type { Server as HttpServer, IncomingHttpHeaders } from 'http'\n\nimport zlib from 'zlib'\n\n// --- 3-rd party\nimport invoke from 'lodash/invoke'\nimport qs from 'qs'\n\n\n// --- Koa & Koa Middleware\nimport Koa from 'koa'\nimport type { Context, Next } from 'koa'\n\nimport KoaCors from '@koa/cors'\nimport KoaCompress from 'koa-compress'\nimport { userAgent as KoaUserAgent } from 'koa-useragent'\n\n\ndeclare module 'koa' {\n interface Request {\n _path: string\n body: any\n }\n \n interface Context {\n compress: boolean\n }\n}\n\n// --- My Lib\nimport { request as _request } from './net'\nimport { stream_to_buffer, inspect } from './utils'\n\n\ndeclare module 'http' {\n interface IncomingMessage {\n tunnel?: boolean\n id?: string\n body?: Buffer\n }\n \n interface ServerResponse {\n body?: Buffer\n }\n}\n\ninterface Message {\n id: string\n headers: IncomingHttpHeaders\n body: {\n buffer: Buffer\n }\n}\n\n// ------------ CONSTs\nexport const LOCALHOST_IPS = new Set(['127.0.0.1', '::ffff:127.0.0.1', '::1'])\nexport const ROUTER_IP = '192.168.1.1'\nexport const PHONE_IP = '192.168.1.113'\nexport const KNOWN_IPS = new Set([...LOCALHOST_IPS, ROUTER_IP, PHONE_IP])\n\n\n// ------------ MyServer\nexport const server = {\n app: null as Koa,\n \n handler: null as ReturnType<Koa['callback']>,\n \n server_80: null as HttpServer,\n \n \n /** start http server and listen */\n async start () {\n let app = new Koa()\n app.on('error', (error, ctx) => {\n console.error(error)\n console.log(ctx)\n })\n \n app.use(this.entry.bind(this))\n \n app.use(KoaCompress({\n br: {\n // https://nodejs.org/api/zlib.html#zlib_class_brotlioptions\n params: {\n [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,\n [zlib.constants.BROTLI_PARAM_QUALITY]: 6 // default 11 (maximized compression), may lead to news/get generated 14MB JSON taking 24s\n },\n },\n threshold: 512\n }))\n \n app.use(KoaCors({ credentials: true }))\n app.use(KoaUserAgent)\n \n app.use(this.router.bind(this))\n \n this.app = app\n \n await this.listen()\n },\n \n \n async listen () {\n this.handler = this.app.callback()\n this.server_80 = create_server(this.handler)\n \n await Promise.all([\n new Promise<void>( resolve => { this.server_80.listen(8421, resolve) }),\n ])\n },\n \n \n stop () {\n this.server_80.close()\n },\n \n \n async entry (ctx: Context, next: Next) {\n const { req: { tunnel, id }, res } = ctx\n let { req, request } = ctx\n \n if (!tunnel) {\n const buf = await stream_to_buffer(req)\n if (buf.length)\n req.body = buf\n }\n \n // ------------ parse req.body to request.body\n if (req.body)\n if (ctx.is('application/json') || ctx.is('text/plain'))\n request.body = JSON.parse(req.body.toString())\n else if (ctx.is('application/x-www-form-urlencoded'))\n request.body = qs.parse(req.body.toString())\n else if (ctx.is('multipart/form-data')) {\n throw new Error('multipart/form-data is not supported')\n } else\n request.body = req.body\n \n \n // ------------ parse request.ip\n request.ip = (request.headers['x-real-ip'] as string || request.ip).replace(/^::ffff:/, '')\n \n \n // ------------ next\n await next()\n // ------------ post processing\n },\n \n \n \n async router (ctx: Context, next: Next) {\n let { request, response } = ctx\n request.path\n request._path = decodeURIComponent(request.path)\n Object.defineProperty(request, 'path', {\n value: request._path,\n configurable: true,\n enumerable: true,\n writable: true\n })\n \n const { path } = request\n \n // ------------ RPC\n if (path === '/api/rpc') {\n await this.rpc(ctx)\n return\n }\n \n \n // ------------ log\n this.logger(ctx)\n \n await next?.()\n },\n \n \n /** args are array http://127.0.0.1/repl/rpc?func=to_json&args=aaa&args=bbb \n should use POST when arg is number, otherwise type will be string \n queries:\n - func: function name\n - args?: `[]` args array\n - async?: `false` don't wait\n - ignore?: `false` don't serialize result into response\n */\n async rpc (ctx: Context) {\n const { request: { query, body }, response } = ctx\n \n let { func, args = [], ignore = false, async: _async = false }: { func: string, args: any[] | string, ignore: boolean | string, async: boolean | string } = { ...query, ...body }\n \n if (!func) throw new Error('rpc no func')\n \n if (!Array.isArray(args))\n args = [args]\n \n // ?async=1 or ?async=0 or ?async=false\n if (typeof ignore === 'string')\n ignore = ignore.to_bool()\n \n if (typeof _async === 'string')\n _async = _async.to_bool()\n \n try {\n const presult = invoke(global, func, ...args)\n \n if (_async) {\n response.body = ''\n return\n }\n \n const result = await presult\n \n if (ignore) {\n response.body = ''\n return\n }\n \n response.body = JSON.stringify(result) || ''\n } catch (error) {\n response.status = 500\n response.body = error\n throw error\n }\n },\n \n \n logger (ctx: Context) {\n const { request } = ctx\n const { query, body, path, method, req: { httpVersion, tunnel }, ip } = request\n \n const known = KNOWN_IPS.has(ip)\n const ua = ctx.userAgent\n \n let s = ''\n \n // --- time\n s += new Date().to_time_str() + ' '\n \n \n let t: string\n // --- IP 50\n if (known)\n if (LOCALHOST_IPS.has(ip))\n t = ''\n else if (ip === ROUTER_IP)\n t = 'Router'.grey\n else if (ip === PHONE_IP)\n t = 'Phone'\n else\n t = ip\n else\n t = ip\n \n s += t.pad(50) + ' '\n \n \n // --- UA\n t = ''\n if (!known) {\n if (ua.isMobile)\n t += ' Mobile'.magenta\n if (ua.isBot)\n t += ' Robot'.blue\n if (ua.isDesktop)\n t += ' Desktop'\n if (ua.platform !== 'unknown' && !ua.os.startsWith('Windows'))\n t += '/' + ua.platform\n if (ua.os !== 'unknown' && ua.platform !== 'Android')\n t += '/' + ua.os\n if (ua.browser !== 'unknown')\n t += '/' + ua.browser\n if (ua.version !== 'unknown')\n t += '/' + ua.version\n }\n s += t.pad(50) + ' '\n \n \n // --- Tunnel/HTTP version\n s += tunnel ? \n ('Tunnel/' + httpVersion).pad(10).cyan\n :\n ('HTTP/' + httpVersion).pad(10)\n \n s += ' '\n \n \n // --- Method 8\n if (method === 'GET')\n t = method\n else\n t = method.red\n \n s += t.pad(8)\n \n \n // --- Path 60\n if (path.toLowerCase() !== request._path.toLowerCase())\n t = request._path.blue + ' → ' + path\n else\n if (!path.includes('.'))\n t = path.yellow\n else\n t = path\n \n s += t.pad(60) + ' '\n \n \n // --- Query\n if (query && Object.keys(query).length) {\n t = ` ${inspect(query, { compact: true }).replace('[Object: null prototype] ', '')}`\n if ((s + t).width > global.WIDTH)\n s += '\\n'\n s += t\n }\n \n \n // --- Body\n if (body && Object.keys(body).length)\n s += '\\n' + inspect(body).replace('[Object: null prototype] ', '')\n \n \n console.log(s)\n },\n}\n\n\nexport default server\n\nexport type Server = typeof server\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["server.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createServer as http_create_server,\n type Server as HttpServer,\n} from 'http'\n\nimport zlib from 'zlib'\nimport { default as nodefs, type Stats } from 'fs'\nimport { promisify } from 'util'\n\n// --- 3rd party\nimport upath from 'upath'\nimport invoke from 'lodash/invoke'\nimport qs from 'qs'\nimport resolve_safely from 'resolve-path'\n\n\n// --- koa & koa middleware\nimport Koa from 'koa'\nimport type { Context, Next } from 'koa'\n\nimport KoaCors from '@koa/cors'\nimport KoaCompress from 'koa-compress'\nimport {\n userAgent as KoaUserAgent,\n type UserAgentContext\n} from 'koa-useragent'\n\n\ndeclare module 'koa' {\n interface Request {\n _path: string\n body: any\n }\n \n interface Context {\n compress: boolean\n userAgent: UserAgentContext['userAgent'] & { isWechat: boolean }\n }\n}\n\n// --- my libs\nimport { request as _request } from './net'\nimport { stream_to_buffer, inspect, output_width } from './utils'\nimport { ufs, type UFS } from './file'\n\n\ndeclare module 'http' {\n interface IncomingMessage {\n tunnel?: boolean\n id?: string\n body?: Buffer\n }\n \n interface ServerResponse {\n body?: Buffer\n }\n}\n\n// ------------ my server\nexport const server = {\n app: null as Koa,\n \n handler: null as ReturnType<Koa['callback']>,\n \n server_80: null as HttpServer,\n \n \n /** start http server and listen */\n async start () {\n // --- init koa app\n let app = new Koa()\n \n app.on('error', (error, ctx) => {\n console.error(error)\n console.log(ctx)\n })\n \n app.use(\n this.entry.bind(this)\n )\n \n app.use(KoaCompress({\n br: {\n // https://nodejs.org/api/zlib.html#zlib_class_brotlioptions\n params: {\n [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,\n [zlib.constants.BROTLI_PARAM_QUALITY]: 6 // default 11 (maximized compression), may lead to news/get generated 14mb json taking 24s\n },\n },\n threshold: 512\n }))\n \n app.use(\n KoaCors({ credentials: true })\n )\n app.use(KoaUserAgent)\n \n app.use(this.router.bind(this))\n \n this.app = app\n \n this.handler = this.app.callback()\n \n this.server_80 = http_create_server(this.handler)\n \n await new Promise<void>(resolve => {\n this.server_80.listen(8421, resolve)\n })\n },\n \n \n stop () {\n this.server_80.close()\n },\n \n \n async entry (ctx: Context, next: Next) {\n let { response } = ctx\n \n await this.parse(ctx)\n \n // ------------ next\n try {\n await next()\n } catch (error) {\n if (error.status !== 404)\n console.error(error)\n response.status = error.status || 500\n response.body = inspect(error, { colors: false })\n response.type = 'text/plain'\n }\n },\n \n \n /** \n parse req.body to request.body \n process request.ip\n */\n async parse (ctx: Context) {\n const {\n request,\n req,\n req: { tunnel },\n } = ctx\n \n if (!tunnel) {\n const buf = await stream_to_buffer(req)\n if (buf.length)\n req.body = buf\n }\n \n // --- parse request.ip\n request.ip = (request.headers['x-real-ip'] as string || request.ip).replace(/^::ffff:/, '')\n \n \n // --- parse body\n if (!req.body) return\n \n if (ctx.is('application/json') || ctx.is('text/plain'))\n request.body = JSON.parse(req.body.toString())\n else if (ctx.is('application/x-www-form-urlencoded'))\n request.body = qs.parse(req.body.toString())\n else if (ctx.is('multipart/form-data')) {\n throw new Error('multipart/form-data is not supported')\n } else\n request.body = req.body\n },\n \n \n async router (ctx: Context, next: Next) {\n let { request } = ctx\n const _path = request._path = decodeURIComponent(request.path)\n Object.defineProperty(request, 'path', {\n value: _path,\n configurable: true,\n enumerable: true,\n writable: true\n })\n \n const { path } = request\n \n // ------------ /repl/rpc\n if (path === '/api/rpc') {\n await this.rpc(ctx)\n return\n }\n \n \n // ------------ log\n this.logger(ctx)\n \n // ------------ repl_router hook\n if (await global.repl_router?.(ctx))\n return\n \n await next?.()\n },\n \n \n /** args are array http://localhost/repl/rpc?func=to_json&args=aaa&args=bbb \n should use POST when arg is number, otherwise type will be string \n queries:\n - func: function name\n - args?: `[]` args array\n - ignore?: `false` don't serialize result into response\n - async?: `false` don't wait\n */\n async rpc (ctx: Context) {\n const { request: { query, body }, response } = ctx\n \n let { func, args = [], ignore = false, async: _async = false }: { func: string, args: any[] | string, ignore: boolean | string, async: boolean | string } = { ...query, ...body }\n \n if (!func) {\n let error = new Error('rpc no func')\n ;(error as any).status = 400\n throw error\n }\n \n if (!Array.isArray(args))\n args = [args]\n \n // ?async=1 or ?async=0 or ?async=false\n if (typeof ignore === 'string')\n ignore = ignore.to_bool()\n \n if (typeof _async === 'string')\n _async = _async.to_bool()\n \n try {\n const presult = invoke(global, func, ...args)\n \n if (_async) {\n response.body = ''\n return\n }\n \n const result = await presult\n \n if (ignore) {\n response.body = ''\n return\n }\n \n response.body = JSON.stringify(result) || ''\n } catch (error) {\n error.status = 500\n throw error\n }\n },\n \n \n logger (ctx: Context) {\n const { request } = ctx\n const {\n query, \n body, \n path, _path, \n protocol,\n host,\n req: { httpVersion: http_version },\n ip,\n } = request\n \n let { method } = request\n \n const ua = ctx.userAgent\n \n \n let s = ''\n \n // --- time\n s += `${new Date().to_time_str()} `\n \n \n // --- ip\n s += (ip || '').pad(40) + ' '\n \n \n // --- ua\n s += (() => {\n let t = ''\n if (ua.isMobile)\n t += 'mobile'\n if (ua.isDesktop)\n t += 'desktop'\n if (ua.isBot)\n t += `${ t ? ' ' : '' }${'robot'.blue}`\n if (ua.platform !== 'unknown' && !ua.os.startsWith('Windows'))\n t += '/' + ua.platform.toLowerCase().replace('apple mac', 'mac')\n if (ua.os !== 'unknown' && ua.platform !== 'Android')\n t += '/' + ua.os.toLowerCase()\n if (ua.browser !== 'unknown')\n t += '/' + ua.browser.toLowerCase()\n if (ua.isWechat)\n t += '/weixin'\n if (ua.version !== 'unknown')\n t += '/' + ua.version.split('.').slice(0, 2).join('.')\n return t\n })().pad(40) + ' '\n \n \n // --- https/2.0\n // if (req.tunnel) `tunnel/${http_version}`.pad(10).cyan\n s += `${`${protocol.pad(5)}/${http_version}`.pad(10)} `\n \n \n // --- method\n method = method.toLowerCase()\n s += method === 'get' ? method.pad(10) : method.pad(10).yellow\n \n \n // --- host\n s += `${host.pad(20)} `\n \n \n // --- path\n s += (() => {\n if (path.toLowerCase() !== _path.toLowerCase())\n return `${_path.blue} → ${path}`\n if (!path.includes('.'))\n return path.yellow\n return path\n })()\n \n \n // --- query\n if (Object.keys(query).length) {\n let t = inspect(query, { compact: true })\n .replace('[Object: null prototype] ', '')\n \n if (t.endsWith('\\n'))\n t = t.slice(0, -1)\n \n s += (s + t).width > output_width ? '\\n' : ' '\n \n s += t\n }\n \n \n // --- body\n if (body && Object.keys(body).length)\n s += '\\n' + inspect(body).replace('[Object: null prototype] ', '')\n \n \n // --- print log\n console.log(s)\n },\n \n \n async try_send (\n ctx: Context, \n fp: string,\n {\n fs = ufs, \n root\n }: {\n fs?: (typeof nodefs) | UFS\n root: string\n }) {\n const {\n request: { _path, path, method },\n response,\n } = ctx\n \n if (!(typeof response.body === 'undefined') || response.status !== 404) return true\n \n if (method !== 'HEAD' && method !== 'GET') return false\n \n function log_404 () {\n let s = `${' '.repeat(13)} ${method.toLowerCase()} 404: ${path}`\n if (_path !== path)\n s += ` ${_path.bracket()}`\n console.log(s.red)\n }\n \n try {\n await this.fsend(ctx, fp, { fs, root })\n return true\n } catch (error) {\n if (error.status !== 404) throw error\n log_404()\n return false\n }\n },\n \n \n /** send file at `path` with the given `options` to the koa `ctx`. */\n async fsend (\n ctx: Context,\n path: string,\n {\n fs = nodefs,\n root,\n absolute\n }: {\n /** `fs` */\n fs?: (typeof nodefs) | UFS\n \n root?: string\n \n /** `false` */\n absolute?: boolean\n \n } = { } as any\n ) {\n const { request, response, req } = ctx\n \n if (!absolute && !root)\n throw new Error('fsend with `!absolute && !root`')\n \n if (absolute)\n path = upath.resolve(path)\n else {\n if (path.startsWith(root))\n path = path.slice(root.length)\n \n if (path.startsWith('/'))\n path = path.slice(1)\n \n try {\n path = upath.normalize(\n resolve_safely(root, path)\n )\n } catch (error) {\n error.message += `, path = ${path}`\n throw error\n }\n }\n \n \n // stat\n let stats: Stats\n try {\n stats = await promisify(fs.stat)(path)\n } catch (error) {\n if (['ENOENT', 'ENAMETOOLONG', 'ENOTDIR'].includes(error.code)) {\n error.status = 404\n throw error\n }\n \n error.status = 500\n error.message = `fs.stat 出错: ${error.message}`\n throw error\n }\n \n \n if (stats.size >= 100 * 2**20) {\n let error = new Error('body.length >= 100 mb')\n ;(error as any).status = 500\n throw error\n }\n \n \n if (!req.tunnel) {\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges\n // advertise server support of partial requests\n response.set('accept-ranges', 'bytes')\n }\n \n if (!response.get('cache-control'))\n response.set('cache-control', 'max-age=0, must-revalidate')\n \n if (!response.get('last-modified'))\n response.set('last-modified', stats.mtime ? stats.mtime.toUTCString() : new Date().toUTCString())\n \n const fext = path.fext\n \n if (!response.type)\n response.type = fext\n \n if (fext === '.pdf')\n response.set('content-disposition', `attachment; filename=\"${encodeURIComponent(path.fname)}\"`)\n \n if (request.fresh) {\n response.status = 304\n // 以上会自动设置 response.body = null\n return path\n }\n \n if (request.headers.range) {\n if (req.tunnel) {\n response.status = 400\n response.body = ''\n return\n }\n \n try {\n const range_header = request.headers.range\n const range_value = /=(.*)$/.exec(range_header)[1]\n const range = /^[\\w]*?(\\d*)-(\\d*)$/.exec(range_value)\n \n let start = range[1] ? parseInt(range[1]) : undefined\n let end = range[2] ? parseInt(range[2]) : stats.size - 1\n \n if (typeof start == 'undefined') {\n start = (stats.size - end)\n end = (stats.size - 1)\n }\n \n const chunksize = (end - start + 1)\n \n response.status = 206\n response.set('content-length', String(chunksize))\n response.set('content-range', `bytes ${start}-${end}/${stats.size}`)\n response.body = fs.createReadStream(path, { start, end })\n } catch (err) {\n response.status = 416\n response.set('content-length', String(stats.size))\n response.set('content-range', `bytes */${stats.size}`)\n response.body = fs.createReadStream(path)\n }\n } else {\n response.set('content-length', String(stats.size))\n response.body = fs.createReadStream(path)\n }\n \n return path\n }\n}\n\n\nexport default server\n\nexport type Server = typeof server\n"]}
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
// ---
|
|
3
|
+
// --- module
|
|
4
4
|
"module": "CommonJS", // none, CommonJS, amd, system, umd, es6, es2015, ESNext
|
|
5
5
|
"moduleResolution": "Node",
|
|
6
6
|
"allowSyntheticDefaultImports": true,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"resolveJsonModule": true,
|
|
9
9
|
"isolatedModules": true,
|
|
10
10
|
|
|
11
|
-
// ---
|
|
11
|
+
// --- build
|
|
12
12
|
"target": "ES2019",
|
|
13
13
|
"allowJs": false,
|
|
14
14
|
"checkJs": false,
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"tsBuildInfoFile": "./node_modules/.tsbuildinfo",
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
// ---
|
|
24
|
+
// --- emit
|
|
25
25
|
"declaration": true,
|
|
26
26
|
"emitDeclarationOnly": false,
|
|
27
27
|
"noEmitOnError": false,
|
|
28
28
|
"listEmittedFiles": true,
|
|
29
29
|
|
|
30
|
-
// ---
|
|
30
|
+
// --- source maps
|
|
31
31
|
"sourceMap": true,
|
|
32
32
|
"inlineSourceMap": false,
|
|
33
33
|
"inlineSources": true,
|
|
34
34
|
|
|
35
|
-
// ---
|
|
35
|
+
// --- features
|
|
36
36
|
"experimentalDecorators": true,
|
|
37
37
|
"emitDecoratorMetadata": true,
|
|
38
38
|
"preserveSymlinks": true,
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"forceConsistentCasingInFileNames": true,
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
// ---
|
|
45
|
+
// --- type checking
|
|
46
46
|
"strict": false,
|
|
47
47
|
"alwaysStrict": false,
|
|
48
48
|
"noImplicitAny": false,
|
package/ufs.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type fs from 'fs';
|
|
3
|
+
import './prototype.js';
|
|
4
|
+
declare type FS = typeof fs;
|
|
5
|
+
export interface UFS extends FS {
|
|
6
|
+
}
|
|
7
|
+
export declare class UFS {
|
|
8
|
+
fss: FS[];
|
|
9
|
+
constructor(fss: any[]);
|
|
10
|
+
use(fs: any): this;
|
|
11
|
+
existsSync(path: string): boolean;
|
|
12
|
+
readdir(...args: any[]): any;
|
|
13
|
+
readdirSync(...args: any[]): unknown[];
|
|
14
|
+
createReadStream(path: string, options?: any): any;
|
|
15
|
+
createWriteStream(path: string, options?: any): any;
|
|
16
|
+
static sync_method_wrapper(this: UFS, method: string, ...args: any[]): any;
|
|
17
|
+
static async_method_wrapper(this: UFS, method: string, ...args: any[]): any;
|
|
18
|
+
}
|
|
19
|
+
export declare let ufs: UFS;
|
|
20
|
+
export declare function set_ufs(_ufs: UFS): void;
|
|
21
|
+
export default UFS;
|