@maiyunnet/kebab 2.0.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/.VSCodeCounter/2025-02-14_14-46-44/details.md +82 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff-details.md +15 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.csv +2 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.md +19 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.txt +22 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.csv +69 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.json +1 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.md +48 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.txt +118 -0
- package/.vscode/tasks.json +15 -0
- package/LICENSE +201 -0
- package/README.md +201 -0
- package/bin/kebab.js +2 -0
- package/eslint.config.js +22 -0
- package/index.js +19 -0
- package/index.ts +33 -0
- package/lib/buffer.js +108 -0
- package/lib/buffer.ts +152 -0
- package/lib/captcha/zcool-addict-italic.ttf +0 -0
- package/lib/captcha.js +71 -0
- package/lib/captcha.ts +63 -0
- package/lib/consistent.js +171 -0
- package/lib/consistent.ts +219 -0
- package/lib/core.js +663 -0
- package/lib/core.ts +880 -0
- package/lib/crypto.js +256 -0
- package/lib/crypto.ts +384 -0
- package/lib/db.js +521 -0
- package/lib/db.ts +719 -0
- package/lib/dns.js +321 -0
- package/lib/dns.ts +405 -0
- package/lib/fs.js +405 -0
- package/lib/fs.ts +527 -0
- package/lib/jwt.js +223 -0
- package/lib/jwt.ts +276 -0
- package/lib/kv.js +1004 -0
- package/lib/kv.ts +1489 -0
- package/lib/lan.js +99 -0
- package/lib/lan.ts +87 -0
- package/lib/net/cacert.pem +3480 -0
- package/lib/net/formdata.js +137 -0
- package/lib/net/formdata.ts +166 -0
- package/lib/net/request.js +102 -0
- package/lib/net/request.ts +150 -0
- package/lib/net/response.js +28 -0
- package/lib/net/response.ts +59 -0
- package/lib/net.js +462 -0
- package/lib/net.ts +662 -0
- package/lib/s3.js +180 -0
- package/lib/s3.ts +235 -0
- package/lib/scan.js +276 -0
- package/lib/scan.ts +364 -0
- package/lib/session.js +177 -0
- package/lib/session.ts +230 -0
- package/lib/sql.js +818 -0
- package/lib/sql.ts +1151 -0
- package/lib/ssh/sftp.js +373 -0
- package/lib/ssh/sftp.ts +508 -0
- package/lib/ssh/shell.js +109 -0
- package/lib/ssh/shell.ts +123 -0
- package/lib/ssh.js +171 -0
- package/lib/ssh.ts +191 -0
- package/lib/text/tld.json +1 -0
- package/lib/text.js +452 -0
- package/lib/text.ts +607 -0
- package/lib/time.js +216 -0
- package/lib/time.ts +254 -0
- package/lib/ws.js +373 -0
- package/lib/ws.ts +523 -0
- package/lib/zip.js +381 -0
- package/lib/zip.ts +447 -0
- package/lib/zlib.js +289 -0
- package/lib/zlib.ts +350 -0
- package/main.js +51 -0
- package/main.ts +27 -0
- package/package.json +37 -0
- package/sys/child.js +585 -0
- package/sys/child.ts +678 -0
- package/sys/cmd.js +226 -0
- package/sys/cmd.ts +225 -0
- package/sys/ctr.js +608 -0
- package/sys/ctr.ts +904 -0
- package/sys/master.js +314 -0
- package/sys/master.ts +355 -0
- package/sys/mod.js +1273 -0
- package/sys/mod.ts +1871 -0
- package/sys/route.js +922 -0
- package/sys/route.ts +1113 -0
- package/types/index.d.ts +283 -0
- package/www/example/ctr/main.js +42 -0
- package/www/example/ctr/main.ts +9 -0
- package/www/example/ctr/middle.js +57 -0
- package/www/example/ctr/middle.ts +26 -0
- package/www/example/ctr/test.js +2818 -0
- package/www/example/ctr/test.ts +3218 -0
- package/www/example/data/locale/en.test.json +8 -0
- package/www/example/data/locale/index.html +1 -0
- package/www/example/data/locale/ja.test.json +8 -0
- package/www/example/data/locale/sc.test.json +8 -0
- package/www/example/data/locale/tc.test.json +8 -0
- package/www/example/data/test.zip +0 -0
- package/www/example/kebab.json +24 -0
- package/www/example/mod/test.js +49 -0
- package/www/example/mod/test.ts +47 -0
- package/www/example/mod/testdata.js +11 -0
- package/www/example/mod/testdata.ts +30 -0
- package/www/example/route.json +6 -0
- package/www/example/view/test.ejs +11 -0
- package/www/example/ws/mproxy.js +49 -0
- package/www/example/ws/mproxy.ts +16 -0
- package/www/example/ws/rproxy.js +47 -0
- package/www/example/ws/rproxy.ts +14 -0
- package/www/example/ws/test.js +68 -0
- package/www/example/ws/test.ts +36 -0
package/lib/ws.ts
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* Date: 2019-6-2 20:42
|
|
4
|
+
* Last: 2020-4-9 22:33:11, 2022-09-13 13:32:01, 2022-12-30 19:13:07, 2024-2-6 23:53:45, 2024-12-23 01:33:16, 2025-1-28 21:05:51
|
|
5
|
+
*/
|
|
6
|
+
import * as http from 'http';
|
|
7
|
+
import * as net from 'net';
|
|
8
|
+
import * as types from '~/types';
|
|
9
|
+
// --- 第三方 ---
|
|
10
|
+
import * as liws from '@litert/websocket';
|
|
11
|
+
// --- 库 ---
|
|
12
|
+
import * as lText from '~/lib/text';
|
|
13
|
+
import * as lNet from '~/lib/net';
|
|
14
|
+
import * as sCtr from '~/sys/ctr';
|
|
15
|
+
|
|
16
|
+
/** --- 一般用 SIMPLE --- */
|
|
17
|
+
export enum EFrameReceiveMode {
|
|
18
|
+
STANDARD,
|
|
19
|
+
LITE,
|
|
20
|
+
SIMPLE
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** --- OPCODE --- */
|
|
24
|
+
export enum EOpcode {
|
|
25
|
+
CONTINUATION = 0x0,
|
|
26
|
+
TEXT = 0x1,
|
|
27
|
+
BINARY = 0x2,
|
|
28
|
+
CLOSE = 0x8,
|
|
29
|
+
PING = 0x9,
|
|
30
|
+
PONG = 0xA
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** --- 请求的传入参数选项 --- */
|
|
34
|
+
export interface IConnectOptions {
|
|
35
|
+
/** --- 秒数 --- */
|
|
36
|
+
'timeout'?: number;
|
|
37
|
+
'hosts'?: Record<string, string>;
|
|
38
|
+
'local'?: string;
|
|
39
|
+
'headers'?: types.THttpHeaders;
|
|
40
|
+
/** --- cookie 托管对象 --- */
|
|
41
|
+
'cookie'?: Record<string, types.ICookie>;
|
|
42
|
+
/** --- 小帧模式,默认 false --- */
|
|
43
|
+
'mode'?: EFrameReceiveMode;
|
|
44
|
+
/** --- 加密模式,默认 true --- */
|
|
45
|
+
'masking'?: boolean;
|
|
46
|
+
/** --- 正向 mproxy 代理,url 如 wss://xxx/abc --- */
|
|
47
|
+
'mproxy'?: {
|
|
48
|
+
'url': string;
|
|
49
|
+
'auth': string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** --- 正向代理请求的传入参数选项 --- */
|
|
54
|
+
export interface IMproxyOptions {
|
|
55
|
+
/** --- 秒数 --- */
|
|
56
|
+
'timeout'?: number;
|
|
57
|
+
'hosts'?: Record<string, string>;
|
|
58
|
+
'local'?: string;
|
|
59
|
+
'headers'?: types.THttpHeaders;
|
|
60
|
+
/** --- 小帧模式,默认 false --- */
|
|
61
|
+
'mode'?: EFrameReceiveMode;
|
|
62
|
+
/** --- 加密模式,默认 true --- */
|
|
63
|
+
'masking'?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** --- 反向代理请求的传入参数选项 --- */
|
|
67
|
+
export interface IRproxyOptions {
|
|
68
|
+
/** --- 秒数 --- */
|
|
69
|
+
'timeout'?: number;
|
|
70
|
+
'hosts'?: Record<string, string>;
|
|
71
|
+
'local'?: string;
|
|
72
|
+
'headers'?: types.THttpHeaders;
|
|
73
|
+
/** --- 小帧模式,默认 false --- */
|
|
74
|
+
'mode'?: EFrameReceiveMode;
|
|
75
|
+
/** --- 加密模式,默认 true --- */
|
|
76
|
+
'masking'?: boolean;
|
|
77
|
+
/** --- 正向 mproxy 代理,url 如 wss://xxx/abc --- */
|
|
78
|
+
'mproxy'?: {
|
|
79
|
+
'url': string;
|
|
80
|
+
'auth': string;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const liwsServer = liws.createServer();
|
|
85
|
+
|
|
86
|
+
export class Socket {
|
|
87
|
+
|
|
88
|
+
/** --- 当前的 ws 对象 --- */
|
|
89
|
+
private _ws!: liws.IWebSocket | liws.IClient;
|
|
90
|
+
|
|
91
|
+
public constructor(request?: http.IncomingMessage, socket?: net.Socket, options: {
|
|
92
|
+
'headers'?: http.OutgoingHttpHeaders;
|
|
93
|
+
'timeout'?: number;
|
|
94
|
+
} = {}) {
|
|
95
|
+
if (!request || !socket) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// --- 一定是 server 模式 ---
|
|
99
|
+
this._ws = liwsServer.accept({
|
|
100
|
+
'request': request,
|
|
101
|
+
'socket': socket,
|
|
102
|
+
'headers': options.headers,
|
|
103
|
+
'timeout': options.timeout
|
|
104
|
+
});
|
|
105
|
+
this._bindEvent();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* --- 以客户端形式发起链接 ---
|
|
110
|
+
* @param u 以 ws, wss 开头的地址
|
|
111
|
+
* @param opt 参数
|
|
112
|
+
*/
|
|
113
|
+
public async connect(u: string, opt: IConnectOptions = {}): Promise<this | null> {
|
|
114
|
+
const uri = lText.parseUrl(u);
|
|
115
|
+
if (!uri.hostname) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
/** --- 正向代理的地址 --- */
|
|
119
|
+
const puri = opt.mproxy ? lText.parseUrl(opt.mproxy.url) : null;
|
|
120
|
+
const timeout = opt.timeout ?? 10;
|
|
121
|
+
const hosts = opt.hosts ?? {};
|
|
122
|
+
const local = opt.local;
|
|
123
|
+
const mode = opt.mode ?? EFrameReceiveMode.SIMPLE;
|
|
124
|
+
const masking = opt.masking ?? true;
|
|
125
|
+
const headers: Record<string, types.Json> = {};
|
|
126
|
+
if (opt.headers) {
|
|
127
|
+
for (const key in opt.headers) {
|
|
128
|
+
headers[key.toLowerCase()] = opt.headers[key];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
headers['user-agent'] ??= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36';
|
|
132
|
+
// --- cookie 托管 ---
|
|
133
|
+
if (opt.cookie) {
|
|
134
|
+
headers['cookie'] = lNet.buildCookieQuery(opt.cookie, uri);
|
|
135
|
+
}
|
|
136
|
+
// --- ssl ---
|
|
137
|
+
const ca: string | null = puri ?
|
|
138
|
+
puri.protocol === 'wss:' ? await lNet.getCa() : null :
|
|
139
|
+
uri.protocol === 'wss:' ? await lNet.getCa() : null;
|
|
140
|
+
if (!ca && hosts[uri.hostname]) {
|
|
141
|
+
// --- 没有 ca,但是要设置 额外的 host ---
|
|
142
|
+
headers['host'] = uri.hostname + (uri.port ? ':' + uri.port : '');
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
// --- 重定义 IP ---
|
|
146
|
+
const host = puri?.hostname ?? uri.hostname ?? '';
|
|
147
|
+
const port = (puri ? puri.port : uri.port) ?? 443;
|
|
148
|
+
const path = puri ? puri.path + (puri.path?.includes('?') ? '&' : '?') + lText.queryStringify({
|
|
149
|
+
'url': u,
|
|
150
|
+
'auth': opt.mproxy?.auth ?? ''
|
|
151
|
+
}) : uri.path;
|
|
152
|
+
const cli = ca ?
|
|
153
|
+
await liws.wssConnect({
|
|
154
|
+
'hostname': hosts[host] ?? host,
|
|
155
|
+
'port': port,
|
|
156
|
+
'path': path,
|
|
157
|
+
'servername': host,
|
|
158
|
+
'headers': headers,
|
|
159
|
+
'connectTimeout': timeout * 1000,
|
|
160
|
+
'frameReceiveMode': mode,
|
|
161
|
+
'localAddress': local,
|
|
162
|
+
'ca': ca
|
|
163
|
+
}) :
|
|
164
|
+
await liws.wsConnect({
|
|
165
|
+
'hostname': hosts[host] ?? host,
|
|
166
|
+
'port': port,
|
|
167
|
+
'path': path,
|
|
168
|
+
'headers': headers,
|
|
169
|
+
'connectTimeout': timeout * 1000,
|
|
170
|
+
'frameReceiveMode': mode,
|
|
171
|
+
'localAddress': local
|
|
172
|
+
});
|
|
173
|
+
cli.setMasking(masking);
|
|
174
|
+
this._ws = cli;
|
|
175
|
+
this._bindEvent();
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** --- 创建成功后第一时间绑定事件 --- */
|
|
184
|
+
private _bindEvent(): void {
|
|
185
|
+
this._ws.on('message', (msg): void => {
|
|
186
|
+
(async (): Promise<void> => {
|
|
187
|
+
if (msg.opcode === EOpcode.CLOSE) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
let data: Buffer | string = '';
|
|
191
|
+
if ('data' in msg) {
|
|
192
|
+
data = Buffer.concat(msg.data);
|
|
193
|
+
if (msg.opcode === EOpcode.TEXT) {
|
|
194
|
+
data = data.toString();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
data = await (msg.opcode === EOpcode.TEXT ? msg.toString() : msg.toBuffer());
|
|
199
|
+
}
|
|
200
|
+
this._on.message({
|
|
201
|
+
'opcode': msg.opcode,
|
|
202
|
+
'data': data
|
|
203
|
+
}) as any;
|
|
204
|
+
})().catch(() => {
|
|
205
|
+
// --- nothing ---
|
|
206
|
+
});
|
|
207
|
+
}).on('drain', () => {
|
|
208
|
+
this._on.drain() as any;
|
|
209
|
+
}).on('error', (e) => {
|
|
210
|
+
this._on.error(e) as any;
|
|
211
|
+
}).on('end', () => {
|
|
212
|
+
this._on.end() as any;
|
|
213
|
+
}).on('close', () => {
|
|
214
|
+
this._on.close() as any;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** --- 还未开启监听时来的数据将存在这里 --- */
|
|
219
|
+
private readonly _waitMsg: Array<{
|
|
220
|
+
'opcode': EOpcode;
|
|
221
|
+
'data': Buffer | string;
|
|
222
|
+
}> = [];
|
|
223
|
+
|
|
224
|
+
/** --- 还未开启 error 监听时产生的 error 错误对象 --- */
|
|
225
|
+
private _error: any = null;
|
|
226
|
+
|
|
227
|
+
/** --- 还未开启 close 监听时是不是就已经 close --- */
|
|
228
|
+
private _close: boolean = false;
|
|
229
|
+
|
|
230
|
+
/** --- 未绑定自定义监听事件的默认执行函数 --- */
|
|
231
|
+
private _on = {
|
|
232
|
+
message: (msg: {
|
|
233
|
+
'opcode': EOpcode;
|
|
234
|
+
'data': Buffer | string;
|
|
235
|
+
}): void | Promise<void> => {
|
|
236
|
+
this._waitMsg.push(msg);
|
|
237
|
+
},
|
|
238
|
+
drain: (): void | Promise<void> => {
|
|
239
|
+
// --- nothing ---
|
|
240
|
+
},
|
|
241
|
+
error: (e: any): void | Promise<void> => {
|
|
242
|
+
this._error = e;
|
|
243
|
+
},
|
|
244
|
+
close: (): void | Promise<void> => {
|
|
245
|
+
this._close = true;
|
|
246
|
+
},
|
|
247
|
+
end: (): void | Promise<void> => {
|
|
248
|
+
// --- nothing ---
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/** --- 绑定监听 --- */
|
|
253
|
+
public on(event: 'message', cb: (msg: {
|
|
254
|
+
'opcode': EOpcode;
|
|
255
|
+
'data': Buffer | string;
|
|
256
|
+
}) => void | Promise<void>): this;
|
|
257
|
+
public on(event: 'error', cb: (error: any) => void | Promise<void>): this;
|
|
258
|
+
public on(event: 'drain' | 'close' | 'end', cb: () => void | Promise<void>): this;
|
|
259
|
+
public on(event: keyof typeof this._on, cb: (param?: any) => void | Promise<void>): this {
|
|
260
|
+
this._on[event] = cb;
|
|
261
|
+
switch (event) {
|
|
262
|
+
case 'message': {
|
|
263
|
+
for (const item of this._waitMsg) {
|
|
264
|
+
cb(item) as any;
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
case 'error': {
|
|
269
|
+
if (!this._error) {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
cb(this._error) as any;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case 'end': {
|
|
276
|
+
cb() as any;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
default: {
|
|
280
|
+
// --- close ---
|
|
281
|
+
if (!this._close) {
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
cb() as any;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public end(): void {
|
|
291
|
+
this._ws.end();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
public destroy(): void {
|
|
295
|
+
this._ws.destroy();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** --- 发送文本 --- */
|
|
299
|
+
public writeText(data: string): boolean {
|
|
300
|
+
if (!this._ws.writable) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
return this._ws.writeText(data);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** --- 发送结果对象字符串 --- */
|
|
307
|
+
public writeResult(data: types.Json): boolean {
|
|
308
|
+
if (!this._ws.writable) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
return this._ws.writeText(lText.stringifyResult(data));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** --- 发送二进制 --- */
|
|
315
|
+
public writeBinary(data: string | Buffer | Array<string | Buffer>): boolean {
|
|
316
|
+
if (!this._ws.writable) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
return this._ws.writeBinary(data);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** --- 当前是否是可写状态 --- */
|
|
323
|
+
public get writable(): boolean {
|
|
324
|
+
return this._ws.writable;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** --- 当前是否已经结束读取,并且无法继续读取 --- */
|
|
328
|
+
public get ended(): boolean {
|
|
329
|
+
return this._ws.ended;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** --- 当前是否已经结束写入,并且无法继续写入 --- */
|
|
333
|
+
public get finished(): boolean {
|
|
334
|
+
return this._ws.finished;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* --- 当前连接是不是服务器连接 ---
|
|
339
|
+
*/
|
|
340
|
+
public get isServer(): boolean {
|
|
341
|
+
return this._ws.isServer;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** --- 发送 ping --- */
|
|
345
|
+
public ping(data?: Buffer | string): boolean {
|
|
346
|
+
try {
|
|
347
|
+
this._ws.ping(data);
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** --- 发送 ping --- */
|
|
356
|
+
public pong(data?: Buffer | string): boolean {
|
|
357
|
+
try {
|
|
358
|
+
this._ws.pong(data);
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* --- 创建一个 ws 客户端发起 ws 请求 ---
|
|
370
|
+
* @param u 以 ws, wss 开头的地址
|
|
371
|
+
* @param opt 参数
|
|
372
|
+
*/
|
|
373
|
+
export function connect(u: string, opt: IConnectOptions = {}): Promise<Socket | null> {
|
|
374
|
+
const s = new Socket();
|
|
375
|
+
return s.connect(u, opt);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* --- 创建一个 ws 服务器接收处理器 ---
|
|
380
|
+
* @param request Http 请求端
|
|
381
|
+
* @param socket 响应双向 socket
|
|
382
|
+
*/
|
|
383
|
+
export function createServer(request: http.IncomingMessage, socket: net.Socket, options: {
|
|
384
|
+
'headers'?: http.OutgoingHttpHeaders;
|
|
385
|
+
'timeout'?: number;
|
|
386
|
+
} = {}): Socket {
|
|
387
|
+
return new Socket(request, socket, options);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* --- 绑定 socket 管道 ---
|
|
392
|
+
* @param s1 第一个 socket
|
|
393
|
+
* @param s2 第二个 socket
|
|
394
|
+
*/
|
|
395
|
+
function bindPipe(s1: Socket, s2: Socket): Promise<void> {
|
|
396
|
+
return new Promise<void>((resolve) => {
|
|
397
|
+
// --- 监听发送端的 ---
|
|
398
|
+
s1.on('message', (msg) => {
|
|
399
|
+
switch (msg.opcode) {
|
|
400
|
+
case EOpcode.TEXT:
|
|
401
|
+
case EOpcode.BINARY: {
|
|
402
|
+
if (typeof msg.data === 'string') {
|
|
403
|
+
s2.writeText(msg.data);
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
s2.writeBinary(msg.data);
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
case EOpcode.CLOSE: {
|
|
410
|
+
s2.end();
|
|
411
|
+
resolve();
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
case EOpcode.PING: {
|
|
415
|
+
s2.ping(msg.data);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
case EOpcode.PONG: {
|
|
419
|
+
s2.pong(msg.data);
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
default: {
|
|
423
|
+
// --- EOpcode.CONTINUATION ---
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}).on('close', () => {
|
|
427
|
+
resolve();
|
|
428
|
+
});
|
|
429
|
+
// --- 监听远程端的 ---
|
|
430
|
+
s2.on('message', (msg) => {
|
|
431
|
+
switch (msg.opcode) {
|
|
432
|
+
case EOpcode.TEXT:
|
|
433
|
+
case EOpcode.BINARY: {
|
|
434
|
+
if (typeof msg.data === 'string') {
|
|
435
|
+
s1.writeText(msg.data);
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
s1.writeBinary(msg.data);
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
case EOpcode.CLOSE: {
|
|
442
|
+
s1.end();
|
|
443
|
+
resolve();
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
case EOpcode.PING: {
|
|
447
|
+
s1.ping(msg.data);
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
case EOpcode.PONG: {
|
|
451
|
+
s1.pong(msg.data);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
default: {
|
|
455
|
+
// --- EOpcode.CONTINUATION ---
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}).on('close', () => {
|
|
459
|
+
resolve();
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* --- 正向 mproxy 代理,读取 get 的 url 为实际请求地址 ---
|
|
466
|
+
* --- get: url, auth ---
|
|
467
|
+
* @param ctr 当前控制器
|
|
468
|
+
* @param auth 校验字符串,读取 get 的 auth 和本参数做比对
|
|
469
|
+
* @param opt 参数
|
|
470
|
+
*/
|
|
471
|
+
export async function mproxy(
|
|
472
|
+
ctr: sCtr.Ctr,
|
|
473
|
+
auth: string,
|
|
474
|
+
opt: IMproxyOptions = {}
|
|
475
|
+
): Promise<number> {
|
|
476
|
+
const req = ctr.getPrototype('_req');
|
|
477
|
+
/** --- 请求端产生的双向 socket --- */
|
|
478
|
+
const socket = ctr.getPrototype('_socket');
|
|
479
|
+
/** --- 客户端请求中的 get 的数据 --- */
|
|
480
|
+
const get = ctr.getPrototype('_get');
|
|
481
|
+
if (get['auth'] !== auth) {
|
|
482
|
+
return 0;
|
|
483
|
+
}
|
|
484
|
+
if (!get['url']) {
|
|
485
|
+
return -1;
|
|
486
|
+
}
|
|
487
|
+
opt.headers ??= {};
|
|
488
|
+
Object.assign(opt.headers, lNet.filterProxyHeaders(req.headers));
|
|
489
|
+
// --- 发起请求 ---
|
|
490
|
+
/** --- 远程端的双向 socket --- */
|
|
491
|
+
const rsocket = await connect(get['url'], opt);
|
|
492
|
+
if (!rsocket) {
|
|
493
|
+
return -2;
|
|
494
|
+
}
|
|
495
|
+
await bindPipe(socket, rsocket);
|
|
496
|
+
return 1;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* --- 反向代理,将本 socket 连接反代到其他网址,在 ws 的 onLoad 事件中使用 ---
|
|
501
|
+
* @param ctr 当前控制器
|
|
502
|
+
* @param url 反代真实请求地址,如有 get 需要自行添加
|
|
503
|
+
* @param opt 参数
|
|
504
|
+
*/
|
|
505
|
+
export async function rproxy(
|
|
506
|
+
ctr: sCtr.Ctr,
|
|
507
|
+
url: string,
|
|
508
|
+
opt: IRproxyOptions = {}
|
|
509
|
+
): Promise<boolean> {
|
|
510
|
+
const req = ctr.getPrototype('_req');
|
|
511
|
+
/** --- 请求端产生的双向 socket --- */
|
|
512
|
+
const socket = ctr.getPrototype('_socket');
|
|
513
|
+
opt.headers ??= {};
|
|
514
|
+
Object.assign(opt.headers, lNet.filterProxyHeaders(req.headers));
|
|
515
|
+
// --- 发起请求 ---
|
|
516
|
+
/** --- 远程端的双向 socket --- */
|
|
517
|
+
const rsocket = await connect(url, opt);
|
|
518
|
+
if (!rsocket) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
await bindPipe(socket, rsocket);
|
|
522
|
+
return true;
|
|
523
|
+
}
|