@maiyunnet/kebab 2.0.13 → 2.0.15
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/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +39 -15
- package/lib/core.js +139 -144
- package/lib/db.d.ts +1 -1
- package/lib/db.js +29 -70
- package/lib/fs.js +17 -9
- package/lib/jwt.js +1 -1
- package/lib/session.js +1 -1
- package/lib/sql.d.ts +1 -1
- package/lib/sql.js +4 -34
- package/lib/text.d.ts +5 -0
- package/lib/text.js +8 -0
- package/lib/ws.js +1 -1
- package/package.json +5 -4
- package/sys/child.js +37 -78
- package/sys/cmd.js +1 -0
- package/sys/ctr.d.ts +2 -2
- package/sys/master.js +123 -1
- package/sys/route.js +12 -12
- package/www/example/ctr/test.d.ts +1 -0
- package/www/example/ctr/test.js +62 -9
- package/www/example/ws/test.js +2 -1
package/sys/ctr.d.ts
CHANGED
|
@@ -34,9 +34,9 @@ export declare class Ctr {
|
|
|
34
34
|
/** --- Cookie 数组 --- */
|
|
35
35
|
protected _cookie: Record<string, string>;
|
|
36
36
|
/** --- Jwt 数组 --- */
|
|
37
|
-
protected _jwt: Record<string,
|
|
37
|
+
protected _jwt: Record<string, any>;
|
|
38
38
|
/** --- Session 数组 --- */
|
|
39
|
-
protected _session: Record<string,
|
|
39
|
+
protected _session: Record<string, any>;
|
|
40
40
|
/** --- Session --- 对象 */
|
|
41
41
|
protected _sess: session.Session | null;
|
|
42
42
|
/** --- 页面浏览器客户端缓存 --- */
|
package/sys/master.js
CHANGED
|
@@ -130,7 +130,7 @@ function createRpcListener() {
|
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
if (lCore.globalConfig.rpcSecret === 'MUSTCHANGE') {
|
|
133
|
-
res.end(
|
|
133
|
+
res.end(`The rpcSecret is not set. It's recommended to set it to: ${lCore.random(32, lCore.RANDOM_LUN)}`);
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
136
|
switch (msg.action) {
|
|
@@ -235,9 +235,19 @@ function createRpcListener() {
|
|
|
235
235
|
}
|
|
236
236
|
// --- 看文件夹是否存在 ---
|
|
237
237
|
if (pat && !await lFs.isDir(to + pat)) {
|
|
238
|
+
if (rtn.post['strict'] === '1') {
|
|
239
|
+
res.end('Path not found: ' + to + pat);
|
|
240
|
+
await sRoute.unlinkUploadFiles(rtn.files);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
238
243
|
await lFs.mkdir(to + pat);
|
|
239
244
|
}
|
|
240
245
|
// --- 覆盖或创建文件 ---
|
|
246
|
+
if ((rtn.post['strict'] === '1') && !await lFs.isFile(to + pat + fname)) {
|
|
247
|
+
res.end('Path not found: ' + to + pat + fname);
|
|
248
|
+
await sRoute.unlinkUploadFiles(rtn.files);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
241
251
|
await lFs.putContent(to + pat + fname, ls[path]);
|
|
242
252
|
}
|
|
243
253
|
await sRoute.unlinkUploadFiles(rtn.files);
|
|
@@ -252,6 +262,118 @@ function createRpcListener() {
|
|
|
252
262
|
}
|
|
253
263
|
break;
|
|
254
264
|
}
|
|
265
|
+
case 'log': {
|
|
266
|
+
// --- 获取日志信息 ---
|
|
267
|
+
const path = kebab.LOG_CWD + msg.hostname + (msg.fend ?? '') + '/' + msg.path + '.csv';
|
|
268
|
+
if (!await lFs.isFile(path)) {
|
|
269
|
+
res.end(lText.stringifyJson({
|
|
270
|
+
'result': 1,
|
|
271
|
+
'data': false,
|
|
272
|
+
}));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
/** --- 剩余 limit --- */
|
|
276
|
+
let limit = msg.limit ?? 100;
|
|
277
|
+
/** --- 剩余 offset --- */
|
|
278
|
+
let offset = msg.offset ?? 0;
|
|
279
|
+
const rtn = await new Promise((resolve) => {
|
|
280
|
+
const list = [];
|
|
281
|
+
/** --- 当前行号 --- */
|
|
282
|
+
let line = 0;
|
|
283
|
+
/** --- 当前行数据 --- */
|
|
284
|
+
let packet = '';
|
|
285
|
+
lFs.createReadStream(path, {
|
|
286
|
+
'encoding': 'utf8',
|
|
287
|
+
'start': msg.start,
|
|
288
|
+
}).on('data', (buf) => {
|
|
289
|
+
if (typeof buf !== 'string') {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
while (true) {
|
|
293
|
+
// --- 分包 ---
|
|
294
|
+
const index = buf.indexOf('\n');
|
|
295
|
+
if (index === -1) {
|
|
296
|
+
// --- 本次包还没有结束 ---
|
|
297
|
+
packet += buf;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
// --- 本次行结束了 ---
|
|
301
|
+
if (limit === 0) {
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
packet += buf.slice(0, index);
|
|
305
|
+
buf = buf.slice(index + 1);
|
|
306
|
+
++line;
|
|
307
|
+
// --- 先执行下本次完成的 ---
|
|
308
|
+
if (line > 1) {
|
|
309
|
+
if (offset === 0) {
|
|
310
|
+
if (!msg.search || packet.includes(msg.search)) {
|
|
311
|
+
const result = [];
|
|
312
|
+
let currentField = '';
|
|
313
|
+
let inQuotes = false;
|
|
314
|
+
for (let i = 0; i < packet.length; ++i) {
|
|
315
|
+
const char = packet[i];
|
|
316
|
+
if (char === '"') {
|
|
317
|
+
if (inQuotes && packet[i + 1] === '"') {
|
|
318
|
+
currentField += '"';
|
|
319
|
+
++i;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
inQuotes = !inQuotes;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else if (char === ',' && !inQuotes) {
|
|
326
|
+
result.push(currentField);
|
|
327
|
+
currentField = '';
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
currentField += char;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
result.push(currentField);
|
|
334
|
+
list.push(result);
|
|
335
|
+
--limit;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
--offset;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// --- 处理结束 ---
|
|
343
|
+
packet = '';
|
|
344
|
+
// --- 看看还有没有后面的粘连包 ---
|
|
345
|
+
if (!buf.length) {
|
|
346
|
+
// --- 没粘连包 ---
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
// --- 有粘连包 ---
|
|
350
|
+
}
|
|
351
|
+
}).on('end', () => {
|
|
352
|
+
resolve(list);
|
|
353
|
+
}).on('error', () => {
|
|
354
|
+
resolve(false);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
res.end(lText.stringifyJson({
|
|
358
|
+
'result': 1,
|
|
359
|
+
'data': rtn,
|
|
360
|
+
}));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
case 'ls': {
|
|
364
|
+
// --- 获取目录内文件/文件夹列表 ---
|
|
365
|
+
const path = lText.urlResolve(kebab.ROOT_CWD, msg.path);
|
|
366
|
+
res.end(lText.stringifyJson({
|
|
367
|
+
'result': 1,
|
|
368
|
+
'data': (await lFs.readDir(path, msg.encoding)).map(item => ({
|
|
369
|
+
'isFile': item.isFile(),
|
|
370
|
+
'isDirectory': item.isDirectory(),
|
|
371
|
+
'isSymbolicLink': item.isSymbolicLink(),
|
|
372
|
+
'name': item.name,
|
|
373
|
+
})),
|
|
374
|
+
}));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
255
377
|
default: {
|
|
256
378
|
res.end('Not command: ' + msg.action);
|
|
257
379
|
return;
|
package/sys/route.js
CHANGED
|
@@ -303,7 +303,7 @@ async function run(data) {
|
|
|
303
303
|
cctr.setPrototype('_socket', wsSocket);
|
|
304
304
|
}
|
|
305
305
|
catch (e) {
|
|
306
|
-
|
|
306
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
307
307
|
data.socket.destroy();
|
|
308
308
|
return true;
|
|
309
309
|
}
|
|
@@ -312,12 +312,12 @@ async function run(data) {
|
|
|
312
312
|
cctr.setPrototype('_headers', headers);
|
|
313
313
|
cctr.setPrototype('_get', get);
|
|
314
314
|
cctr.setPrototype('_cookie', cookies);
|
|
315
|
-
|
|
315
|
+
lCore.log(cctr, '', '-visit');
|
|
316
316
|
try {
|
|
317
317
|
rtn = await cctr.onLoad();
|
|
318
318
|
}
|
|
319
319
|
catch (e) {
|
|
320
|
-
|
|
320
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
321
321
|
data.socket.destroy();
|
|
322
322
|
return true;
|
|
323
323
|
}
|
|
@@ -374,7 +374,7 @@ async function run(data) {
|
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
376
|
catch (e) {
|
|
377
|
-
|
|
377
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
378
378
|
}
|
|
379
379
|
break;
|
|
380
380
|
}
|
|
@@ -387,16 +387,16 @@ async function run(data) {
|
|
|
387
387
|
await cctr['onDrain']();
|
|
388
388
|
}
|
|
389
389
|
catch (e) {
|
|
390
|
-
|
|
390
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
391
391
|
}
|
|
392
|
-
}).on('error',
|
|
393
|
-
|
|
392
|
+
}).on('error', (e) => {
|
|
393
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
394
394
|
}).on('close', async () => {
|
|
395
395
|
try {
|
|
396
396
|
await cctr['onClose']();
|
|
397
397
|
}
|
|
398
398
|
catch (e) {
|
|
399
|
-
|
|
399
|
+
lCore.log(cctr, lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
400
400
|
}
|
|
401
401
|
resolve();
|
|
402
402
|
});
|
|
@@ -443,7 +443,7 @@ async function run(data) {
|
|
|
443
443
|
rtn = await middle.onLoad();
|
|
444
444
|
}
|
|
445
445
|
catch (e) {
|
|
446
|
-
|
|
446
|
+
lCore.log(middle, '(E03)' + lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
447
447
|
data.res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
448
448
|
data.res.setHeader('content-length', 25);
|
|
449
449
|
data.res.writeHead(500);
|
|
@@ -495,7 +495,7 @@ async function run(data) {
|
|
|
495
495
|
cctr.setPrototype('_cacheTTL', middle.getPrototype('_cacheTTL'));
|
|
496
496
|
cctr.setPrototype('_xsrf', middle.getPrototype('_xsrf'));
|
|
497
497
|
cctr.setPrototype('_httpCode', middle.getPrototype('_httpCode'));
|
|
498
|
-
|
|
498
|
+
lCore.log(cctr, '', '-visit');
|
|
499
499
|
// --- 强制 HTTPS ---
|
|
500
500
|
if (config.set.mustHttps && !config.const.https) {
|
|
501
501
|
data.res.setHeader('location', data.req.url ?? '');
|
|
@@ -553,7 +553,7 @@ async function run(data) {
|
|
|
553
553
|
httpCode = cctr.getPrototype('_httpCode');
|
|
554
554
|
}
|
|
555
555
|
catch (e) {
|
|
556
|
-
|
|
556
|
+
lCore.log(cctr, '(E04)' + lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
557
557
|
data.res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
558
558
|
data.res.setHeader('content-length', 25);
|
|
559
559
|
data.res.writeHead(500);
|
|
@@ -820,7 +820,7 @@ async function waitCtr(cctr) {
|
|
|
820
820
|
// --- 有事务未关闭 ---
|
|
821
821
|
const msg = 'transaction(' + waitInfo.transaction + ') not be closed';
|
|
822
822
|
lCore.display('[ERROR][ROUTE][WAITCTR] ' + msg + ': ', cctr.getPrototype('_config').const.path);
|
|
823
|
-
|
|
823
|
+
lCore.log(cctr, msg, '-error');
|
|
824
824
|
}
|
|
825
825
|
// --- 彻底结束,删除文件 ---
|
|
826
826
|
await unlinkUploadFiles(cctr);
|
package/www/example/ctr/test.js
CHANGED
|
@@ -165,6 +165,7 @@ class default_1 extends sCtr.Ctr {
|
|
|
165
165
|
`<br><a href="${this._config.const.urlBase}test/core-checktype">View "test/core-checktype"</a>`,
|
|
166
166
|
`<br><a href="${this._config.const.urlBase}test/core-muid">View "test/core-muid"</a>`,
|
|
167
167
|
`<br><a href="${this._config.const.urlBase}test/core-getlog">View "test/core-getlog"</a>`,
|
|
168
|
+
`<br><a href="${this._config.const.urlBase}test/core-ls">View "test/core-ls"</a>`,
|
|
168
169
|
`<br><a href="${this._config.const.urlBase}test/core-reload">View "test/core-reload"</a>`,
|
|
169
170
|
`<br><a href="${this._config.const.urlBase}test/core-restart">View "test/core-restart"</a>`,
|
|
170
171
|
`<br><a href="${this._config.const.urlBase}test/core-global">View "test/core-global"</a>`,
|
|
@@ -1030,13 +1031,14 @@ for (let i = 0; i < 30000; ++i) {
|
|
|
1030
1031
|
async coreGetlog() {
|
|
1031
1032
|
const path = lTime.format(null, 'Y/m/d/H');
|
|
1032
1033
|
const list = await lCore.getLog({
|
|
1033
|
-
'
|
|
1034
|
+
'hostname': this._config.const.hostname,
|
|
1034
1035
|
'path': path,
|
|
1035
1036
|
'fend': '-visit',
|
|
1036
1037
|
});
|
|
1037
1038
|
const echo = [];
|
|
1038
|
-
echo.push('<table style="width: 100%;"
|
|
1039
|
+
echo.push('<table style="width: 100%;">');
|
|
1039
1040
|
if (list) {
|
|
1041
|
+
echo.push('<tr><th>TIME</th><th>UNIX</th><th>URL</th><th>COOKIE</th><th>SESSION</th><th>JWT</th><th>USER_AGENT</th><th>REALIP</th><th>CLIENTIP</th><th>MESSAGE</th></tr>');
|
|
1040
1042
|
for (const row of list) {
|
|
1041
1043
|
echo.push('<tr>');
|
|
1042
1044
|
for (const item of row) {
|
|
@@ -1046,7 +1048,41 @@ for (let i = 0; i < 30000; ++i) {
|
|
|
1046
1048
|
}
|
|
1047
1049
|
}
|
|
1048
1050
|
else {
|
|
1049
|
-
echo.push('<th>' + JSON.stringify(list) + '</th></tr>');
|
|
1051
|
+
echo.push('<tr><th>' + JSON.stringify(list) + '</th></tr>');
|
|
1052
|
+
}
|
|
1053
|
+
echo.push('</table>');
|
|
1054
|
+
return echo.join('') + '<br>' + this._getEnd();
|
|
1055
|
+
}
|
|
1056
|
+
async coreLs() {
|
|
1057
|
+
const echo = [
|
|
1058
|
+
'./'
|
|
1059
|
+
];
|
|
1060
|
+
const list = await lCore.ls({
|
|
1061
|
+
'path': './',
|
|
1062
|
+
});
|
|
1063
|
+
echo.push('<table style="width: 100%;">');
|
|
1064
|
+
for (const item of list) {
|
|
1065
|
+
echo.push('<tr>');
|
|
1066
|
+
echo.push('<td>' + lText.htmlescape(item.name) + '</td>');
|
|
1067
|
+
echo.push('<td>isDirectory:' + (item.isDirectory ? 'true' : 'false') + '</td>');
|
|
1068
|
+
echo.push('<td>isFile:' + (item.isFile ? 'true' : 'false') + '</td>');
|
|
1069
|
+
echo.push('<td>isSymbolicLink:' + (item.isSymbolicLink ? 'true' : 'false') + '</td>');
|
|
1070
|
+
echo.push('</tr>');
|
|
1071
|
+
}
|
|
1072
|
+
echo.push('</table>');
|
|
1073
|
+
// --- source/ ---
|
|
1074
|
+
echo.push('source/');
|
|
1075
|
+
const list2 = await lCore.ls({
|
|
1076
|
+
'path': 'source/',
|
|
1077
|
+
});
|
|
1078
|
+
echo.push('<table style="width: 100%;">');
|
|
1079
|
+
for (const item of list2) {
|
|
1080
|
+
echo.push('<tr>');
|
|
1081
|
+
echo.push('<td>' + lText.htmlescape(item.name) + '</td>');
|
|
1082
|
+
echo.push('<td>isDirectory:' + (item.isDirectory ? 'true' : 'false') + '</td>');
|
|
1083
|
+
echo.push('<td>isFile:' + (item.isFile ? 'true' : 'false') + '</td>');
|
|
1084
|
+
echo.push('<td>isSymbolicLink:' + (item.isSymbolicLink ? 'true' : 'false') + '</td>');
|
|
1085
|
+
echo.push('</tr>');
|
|
1050
1086
|
}
|
|
1051
1087
|
echo.push('</table>');
|
|
1052
1088
|
return echo.join('') + '<br>' + this._getEnd();
|
|
@@ -2620,6 +2656,7 @@ ${lTime.format(null, 'd|D|j|l|N|w|Y|y|F|M|m|H|h|i|s|T')}`;
|
|
|
2620
2656
|
<div style="margin-top: 10px; display: flex;">
|
|
2621
2657
|
<input id="text" style="flex: 1;">
|
|
2622
2658
|
<input id="send" type="button" value="Send" onclick="send()" disabled style="margin-left: 10px;">
|
|
2659
|
+
<input type="button" value="!Ping" onclick="pinging = !pinging; this.value = pinging ? 'Ping' : '!Ping';" style="margin-left: 10px;">
|
|
2623
2660
|
</div>
|
|
2624
2661
|
<script>
|
|
2625
2662
|
var ws = null;
|
|
@@ -2630,6 +2667,12 @@ var stopEl = document.getElementById('stop');
|
|
|
2630
2667
|
|
|
2631
2668
|
var textEl = document.getElementById('text');
|
|
2632
2669
|
var sendEl = document.getElementById('send');
|
|
2670
|
+
|
|
2671
|
+
function dateStr() {
|
|
2672
|
+
const date = new Date();
|
|
2673
|
+
return date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0') + ':' + date.getSeconds().toString().padStart(2, '0');
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2633
2676
|
function enter() {
|
|
2634
2677
|
var nick = nickEl.value.trim();
|
|
2635
2678
|
if (nick === '') {
|
|
@@ -2638,27 +2681,27 @@ function enter() {
|
|
|
2638
2681
|
}
|
|
2639
2682
|
nickEl.disabled = true;
|
|
2640
2683
|
btnEl.disabled = true;
|
|
2641
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Connecting...</div>');
|
|
2684
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Connecting...</div>');
|
|
2642
2685
|
ws = new WebSocket('ws${this._config.const.https ? 's' : ''}://${this._config.const.host}/${this._get['ac'] === 'rproxy' ? 'rproxy' : 'test'}');
|
|
2643
2686
|
ws.onopen = function() {
|
|
2644
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Event: onOpen.</div>');
|
|
2687
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Event: onOpen.</div>');
|
|
2645
2688
|
ws.send('Hello: ' + nick);
|
|
2646
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Client: send "Hello: ' + nick + '".</div>');
|
|
2689
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Client: send "Hello: ' + nick + '".</div>');
|
|
2647
2690
|
stopEl.disabled = false;
|
|
2648
2691
|
sendEl.disabled = false;
|
|
2649
2692
|
};
|
|
2650
2693
|
ws.onmessage = function(ev) {
|
|
2651
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Server: ' + ev.data + '.</div>');
|
|
2694
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Server: ' + ev.data + '.</div>');
|
|
2652
2695
|
};
|
|
2653
2696
|
ws.onclose = function() {
|
|
2654
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Event: onClose.</div>');
|
|
2697
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Event: onClose.</div>');
|
|
2655
2698
|
nickEl.disabled = false;
|
|
2656
2699
|
btnEl.disabled = false;
|
|
2657
2700
|
stopEl.disabled = true;
|
|
2658
2701
|
sendEl.disabled = true;
|
|
2659
2702
|
};
|
|
2660
2703
|
ws.onerror = function(ev) {
|
|
2661
|
-
listEl.insertAdjacentHTML('afterbegin', '<div>Event: onError.</div>');
|
|
2704
|
+
listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Event: onError.</div>');
|
|
2662
2705
|
nickEl.disabled = false;
|
|
2663
2706
|
btnEl.disabled = false;
|
|
2664
2707
|
stopEl.disabled = true;
|
|
@@ -2673,6 +2716,16 @@ function send() {
|
|
|
2673
2716
|
ws.send(textEl.value);
|
|
2674
2717
|
textEl.value = '';
|
|
2675
2718
|
}
|
|
2719
|
+
var pinging = false;
|
|
2720
|
+
setInterval(() => {
|
|
2721
|
+
if (!ws) {
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
if (!pinging) {
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
ws.send('ping');
|
|
2728
|
+
}, 5_000);
|
|
2676
2729
|
</script>`;
|
|
2677
2730
|
return echo + '<br>' + this._getEnd();
|
|
2678
2731
|
}
|
package/www/example/ws/test.js
CHANGED
|
@@ -47,7 +47,7 @@ class default_1 extends sCtr.Ctr {
|
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
this._writeText('Other message, host: ' + this._config.const.host);
|
|
50
|
-
},
|
|
50
|
+
}, 2_000);
|
|
51
51
|
return true;
|
|
52
52
|
}
|
|
53
53
|
onData(data) {
|
|
@@ -59,6 +59,7 @@ class default_1 extends sCtr.Ctr {
|
|
|
59
59
|
return 'Base64: ' + lCrypto.base64Encode(data);
|
|
60
60
|
}
|
|
61
61
|
// --- 用户消息 ---
|
|
62
|
+
console.log('[' + Date.now() + '] WebSocket test onData, data: ' + data);
|
|
62
63
|
return '<b>' + this._nick + ':</b> ' + data;
|
|
63
64
|
}
|
|
64
65
|
onClose() {
|