@gogoqiu/tencent-http-server 0.0.3

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.
Files changed (84) hide show
  1. package/bin/gogoqiu-node-http-service +3 -0
  2. package/dist/build.d.ts +3 -0
  3. package/dist/build.d.ts.map +1 -0
  4. package/dist/build.js +3 -0
  5. package/dist/build.js.map +1 -0
  6. package/dist/routes/index.d.ts +4 -0
  7. package/dist/routes/index.d.ts.map +1 -0
  8. package/dist/routes/index.js +106 -0
  9. package/dist/routes/index.js.map +1 -0
  10. package/dist/server.d.ts +3 -0
  11. package/dist/server.d.ts.map +1 -0
  12. package/dist/server.js +318 -0
  13. package/dist/server.js.map +1 -0
  14. package/dist/serverCmd.d.ts +8 -0
  15. package/dist/serverCmd.d.ts.map +1 -0
  16. package/dist/serverCmd.js +44 -0
  17. package/dist/serverCmd.js.map +1 -0
  18. package/dist/shell/install.d.ts +5 -0
  19. package/dist/shell/install.d.ts.map +1 -0
  20. package/dist/shell/install.js +221 -0
  21. package/dist/shell/install.js.map +1 -0
  22. package/dist/shell/postinst.d.ts +2 -0
  23. package/dist/shell/postinst.d.ts.map +1 -0
  24. package/dist/shell/postinst.js +4 -0
  25. package/dist/shell/postinst.js.map +1 -0
  26. package/dist/shell.d.ts +2 -0
  27. package/dist/shell.d.ts.map +1 -0
  28. package/dist/shell.js +249 -0
  29. package/dist/shell.js.map +1 -0
  30. package/package.json +82 -0
  31. package/public/captures1//346/265/213/350/257/225/347/224/250captures +0 -0
  32. package/public/chat/offer.html +796 -0
  33. package/public/chat/options.html +58 -0
  34. package/public/chat/server-info.html +32 -0
  35. package/public/chat2.html +272 -0
  36. package/public/chat3.html +246 -0
  37. package/public/chat4.html +302 -0
  38. package/public/chat5.html +41 -0
  39. package/public/formdata.html +41 -0
  40. package/public/hls-player.htm +41 -0
  41. package/public/img/back.svg +1 -0
  42. package/public/img/offline.svg +1 -0
  43. package/public/img/online.svg +1 -0
  44. package/public/ip-record.html +28 -0
  45. package/public/js/encrypt.js +36 -0
  46. package/public/js/socket.io.min.js +7 -0
  47. package/public/js/socket.io.min.js.map +1 -0
  48. package/public/myhost/hostReg.html +35 -0
  49. package/public/mylog-chat.htm +260 -0
  50. package/public/mylog3.html +245 -0
  51. package/public/navbar.css +17 -0
  52. package/public/readme.txt +3 -0
  53. package/public/scroll.htm +139 -0
  54. package/public/ssh-client.html +0 -0
  55. package/public/upload-file.html +226 -0
  56. package/public/upload.html +23 -0
  57. package/public/uploads1/files-1757866537383-447469495.jpg +0 -0
  58. package/public/uploads1/files-1757867389485-764531720.jpg +0 -0
  59. package/public/uploads1/files-1757867518311-278635302.jpg +0 -0
  60. package/public/uploads1/files-1757867629687-688924576.jpg +0 -0
  61. package/public/uploads1/files-1757868630683-52261917.jpg +0 -0
  62. package/public/uploads1/files-1757869187061-619427683.jpg +0 -0
  63. package/public/uploads1/small_files-1757869187061-619427683.jpg +0 -0
  64. package/public/uploads1//346/265/213/350/257/225/347/224/250upload +0 -0
  65. package/public/utils.html +57 -0
  66. package/public/utils.js +161 -0
  67. package/public/webrtc/rtc-client.html +238 -0
  68. package/public/webrtc/rtc-file-transfer-client.html +238 -0
  69. package/public/webrtc/rtc-file-transfer-server.html +453 -0
  70. package/public/webrtc/rtc-server.html +453 -0
  71. package/public/webrtc/video-client-input.html +264 -0
  72. package/public/webrtc/video-server-input.html +312 -0
  73. package/public/webrtc/webrtc-chat-with-files.html +581 -0
  74. package/public/webrtc/webrtc-chat.html +367 -0
  75. package/public/webrtc/webrtc-file-offer.html +88 -0
  76. package/public/webrtc/webrtc1.html +186 -0
  77. package/readme.txt +71 -0
  78. package/views/chat.ejs +53 -0
  79. package/views/index.ejs +125 -0
  80. package/views/special-message.ejs +8 -0
  81. package/views/ssh.ejs +142 -0
  82. package/views/utils.ejs +0 -0
  83. package/views/webrtc/client.ejs +203 -0
  84. package/views/webrtc/server.ejs +365 -0
@@ -0,0 +1,453 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+
5
+ <head>
6
+
7
+ <meta charset="utf-8">
8
+ <meta name="description" content="WebRTC code samples">
9
+ <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
10
+ <meta itemprop="description" content="Client-side WebRTC code samples">
11
+ <meta itemprop="image" content="../../../images/webrtc-icon-192x192.png">
12
+ <meta itemprop="name" content="WebRTC code samples">
13
+ <meta name="mobile-web-app-capable" content="yes">
14
+ <meta id="theme-color" name="theme-color" content="#ffffff">
15
+
16
+ <base target="_blank">
17
+
18
+ <title>手动构建WebRTC/Server</title>
19
+
20
+ <!--link rel="icon" sizes="192x192" href="../../../images/webrtc-icon-192x192.png">
21
+ <link href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
22
+ <link rel="stylesheet" href="../../../css/main.css" />
23
+ <link rel="stylesheet" href="css/main.css" /-->
24
+ <script src="/js/socket.io.min.js"></script>
25
+ <style>
26
+ video {
27
+ width: 400px;
28
+ height: 300px;
29
+ }
30
+ </style>
31
+ </head>
32
+
33
+ <body>
34
+
35
+ <div id="container">
36
+
37
+ <h1><a href="/"><span>SERVER</span></a></h1>
38
+ <video id="srcVideo" controls muted crossorigin="anonymous">
39
+ <!-- NB CORS: https://bugzilla.mozilla.org/show_bug.cgi?id=1177793 -->
40
+ <source src="http://git.my.host:28888/200_pages1/mnt/disk2/sd2.3.2.mp4" type="video/mp4" />
41
+ <source src="http://git.my.host:28888/200_pages1/mnt/disk2/sd2.3.1.mp4" type="video/mp4" />
42
+ <p>This browser does not support the video element.</p>
43
+ </video>
44
+ <div>
45
+ <!--reflect-->
46
+ <!--copy出去-->
47
+ <textarea id="candidate" placeholder="candidate from ice"></textarea>
48
+ </div>
49
+ <div>
50
+ <!--gen-->
51
+ <!--copy出去-->
52
+ <textarea id="offer" placeholder="offer by gen"></textarea>
53
+ </div>
54
+ <div>
55
+ <!--get-->
56
+ <!--copy进来-->
57
+ <textarea id="client-candidate" placeholder="copy candidate from client"></textarea>
58
+ <button id="" onclick="setClientCandidate()">setClientCandidate</button>
59
+ <textarea id="answer" placeholder="copy answer from client"></textarea>
60
+ <button id="set-answer" onclick="setAnswer()">set Answer</button>
61
+ </div>
62
+ <p>获取stun/turn回掉</p>
63
+ <div>
64
+ 使用方法:
65
+ 两处分别打开server/client, 服务器端分别点击init/call, 就能实现视频的同步播放。
66
+ </div>
67
+ <!--
68
+ 操作次序:
69
+ 点击"发起请求",
70
+ copy本页offer到client, 点击client"set offer",copy本页candidate到client, 点击setServerCandidate
71
+ copy客户页answer到本页,点击client"set answer", copy客户页candidate到本页, 点击setClientCandidate
72
+ 建立提议/建立回复
73
+ -->
74
+ <button onclick="createOffer()">建立提议(涵盖数据通道)</button>
75
+ <div>
76
+ <input id="messageInput" type="text" value="" />
77
+ <button onclick="sendMessage()">发消息</button>
78
+ <input type="file" id="fileInput" />
79
+ <button onclick="sendFile()">发文件</button>
80
+ </div>
81
+ <!--button onclick="init()">初始化PeerConnect</button>
82
+ <p>建立offer</p>
83
+ <button onclick="call()">发起请求</button-->
84
+ <!--button>播放</button-->
85
+
86
+ <!--video id="rightVideo" autoplay controls></video-->
87
+
88
+ </div>
89
+
90
+ <script>
91
+
92
+ 'use strict';
93
+
94
+ function setClientCandidate() {
95
+ const candidate = document.getElementById('client-candidate').value
96
+ const cds = JSON.parse(candidate)
97
+ cds.forEach(element => {
98
+ pc.addIceCandidate(element)
99
+ .then(() => {
100
+ console.log('addIceCandidate success', candidate)
101
+ })
102
+ .catch(function (err) {
103
+ console.error('Error adding candidate:' + err)
104
+ });
105
+ })
106
+ }
107
+
108
+ //client set local/remote by once, server set local/remote by twice
109
+ function setAnswer() {
110
+ const desc = document.getElementById('answer').value
111
+ if (!desc) {
112
+ alert('Please enter answer')
113
+ return false;
114
+ }
115
+ //pc.remoteDescription
116
+ pc.setRemoteDescription(JSON.parse(desc), function () {
117
+ console.log('!!!!!!setRemoteDescription ok');
118
+ }, (error) => console.log('Failed to set session description: ' + error.toString()));
119
+ }
120
+
121
+ var srcVideo
122
+ var stream;
123
+ var pc;
124
+ var cds = []
125
+ let currentFile
126
+ let dataChannel
127
+
128
+ /*
129
+ 选择连接对象, 通过ws发送消息
130
+ */
131
+ function createOffer() {
132
+ cds = []
133
+ var offerOptions = {
134
+ offerToReceiveAudio: 1,
135
+ offerToReceiveVideo: 1
136
+ };
137
+ // 创建数据通道用于文本聊天和文件传输
138
+ dataChannel = pc.createDataChannel('chatAndFile', {
139
+ ordered: true, // 保证数据顺序
140
+ maxRetransmits: 3 // 最大重传次数
141
+ });
142
+ setupDataChannel(dataChannel);
143
+
144
+ // 监听远程数据通道
145
+ pc.ondatachannel = (event) => {
146
+ dataChannel = event.channel;
147
+ setupDataChannel(dataChannel);
148
+ };
149
+ /*
150
+ offer信息拷贝到客户端,candiate信息拷贝到客户端
151
+ 建立answer
152
+ */
153
+ pc.createOffer(
154
+ (desc) => {
155
+ console.log(desc)
156
+ document.getElementById('offer').value = JSON.stringify(desc, null, 2);
157
+ pc.setLocalDescription(desc, function () {
158
+ console.log("!!!!!!SetLocalSuccess ok");
159
+ }, (err) => {
160
+ console.error("SetLocalFailed", err);
161
+ });
162
+ },
163
+ (error) => console.log('Failed to create session description: '
164
+ + error.toString()),
165
+ offerOptions);
166
+ }
167
+
168
+ // 配置数据通道
169
+ function setupDataChannel(channel) {
170
+ channel.onopen = () => {
171
+ //updateStatus('数据通道已打开,可以发送消息和文件');
172
+ console.log('数据通道已打开,可以发送消息和文件');
173
+ //sendButton.disabled = false;
174
+ if (pc.iceConnectionState === 'connected') {
175
+ //sendFileButton.disabled = false;
176
+ }
177
+ };
178
+
179
+ channel.onmessage = (event) => {
180
+ handleIncomingData(event.data);
181
+ };
182
+
183
+ channel.onclose = () => {
184
+ console.log('数据通道已关闭');
185
+ //updateStatus('数据通道已关闭');
186
+ //sendButton.disabled = true;
187
+ //sendFileButton.disabled = true;
188
+ };
189
+
190
+ channel.onerror = (error) => {
191
+ console.error('数据通道错误:', error);
192
+ //updateStatus(`消息发送失败: ${error}`, true);
193
+ };
194
+ }
195
+
196
+ function addMessage(message) {
197
+ console.log( "addMessage", message )
198
+ }
199
+
200
+ function updateProgress( percent ){
201
+ console.log( "updateProgress", percent )
202
+ }
203
+
204
+ // 处理接收到的数据
205
+ function handleIncomingData(data) {
206
+ // 如果是文件元数据
207
+ if (typeof data === 'string' && data.startsWith('FILE_METADATA:')) {
208
+ const metadata = JSON.parse(data.replace('FILE_METADATA:', ''));
209
+ expectedFileSize = metadata.size;
210
+ receivedSize = 0;
211
+ receivedChunks = [];
212
+
213
+ addMessage(`正在接收文件: ${metadata.name} (${(metadata.size)})`);
214
+ //showProgress(metadata.name, 0);
215
+ return;
216
+ }
217
+
218
+ // 如果是文件结束标记
219
+ if (typeof data === 'string' && data === 'FILE_COMPLETE') {
220
+ const blob = new Blob(receivedChunks);
221
+ const fileUrl = URL.createObjectURL(blob);
222
+ addMessage(currentFileName, false, true, fileUrl);
223
+
224
+ // 清理
225
+ receivedChunks = [];
226
+ expectedFileSize = 0;
227
+ receivedSize = 0;
228
+ //hideProgress();
229
+ return;
230
+ }
231
+
232
+ // 如果是文件分片
233
+ if (data instanceof Blob) {
234
+ data.arrayBuffer().then(buffer => {
235
+ receivedChunks.push(buffer);
236
+ receivedSize += buffer.byteLength;
237
+
238
+ const percent = Math.round((receivedSize / expectedFileSize) * 100);
239
+ updateProgress(percent);
240
+ });
241
+ return;
242
+ }
243
+
244
+ // 否则是普通文本消息
245
+ addMessage(`对方: ${data}`, false);
246
+ }
247
+
248
+ function sendMessage() {
249
+ // dataChannel.send("hello")
250
+ const messageInput = document.getElementById("messageInput");
251
+ const message = messageInput.value.trim();
252
+ if (message && dataChannel && dataChannel.readyState === 'open') {
253
+ dataChannel.send(message);
254
+ addMessage(`我: ${message}`, true);
255
+ messageInput.value = '';
256
+ }
257
+ }
258
+
259
+ function sendFile() {
260
+ const fileInput = document.getElementById("fileInput");
261
+ //dataChannel && dataChannel.readyState === 'open'
262
+ if( fileInput.files.length==0 )
263
+ return;
264
+ currentFile = fileInput.files[0];
265
+ if ( currentFile.size > 100 * 1024 * 1024) { // 限制100MB
266
+ alert('文件过大,请选择小于100MB的文件');
267
+ currentFile = null;
268
+ sendFileButton.disabled = true;
269
+ return;
270
+ }
271
+
272
+ // 确认channel状态
273
+ if (!currentFile || !dataChannel || dataChannel.readyState !== 'open') return;
274
+
275
+ // 发送文件元数据
276
+ const metadata = {
277
+ name: currentFile.name,
278
+ size: currentFile.size,
279
+ type: currentFile.type
280
+ };
281
+
282
+ dataChannel.send(`FILE_METADATA:${JSON.stringify(metadata)}`);
283
+ addMessage(`正在发送文件: ${currentFile.name} (${formatFileSize(currentFile.size)})`, true);
284
+
285
+ // 显示进度条
286
+ //showProgress(currentFile.name, 0);
287
+
288
+ // 分片读取并发送文件
289
+ let offset = 0;
290
+ fileReader = new FileReader();
291
+ // 读取文件
292
+ fileReader.onload = (e) => {
293
+ if (e.target.readyState === FileReader.DONE) {
294
+ // 发送分片
295
+ dataChannel.send(e.target.result);
296
+
297
+ // 更新进度
298
+ offset += e.target.result.byteLength;
299
+ const percent = Math.round((offset / currentFile.size) * 100);
300
+ updateProgress(percent);
301
+
302
+ // 继续读取下一分片
303
+ if (offset < currentFile.size) {
304
+ readNextChunk();
305
+ } else {
306
+ // 发送完成标记
307
+ dataChannel.send('FILE_COMPLETE');
308
+ addMessage(`文件发送完成: ${currentFile.name}`, true);
309
+ }
310
+ }
311
+ };
312
+
313
+ // 开始读取第一分片
314
+ readNextChunk();
315
+
316
+ function readNextChunk() {
317
+ const fileSlice = currentFile.slice(offset, offset + CHUNK_SIZE);
318
+ fileReader.readAsArrayBuffer(fileSlice);
319
+ }
320
+ }
321
+
322
+ function fillLocalAndRemote() {
323
+ createOffer()
324
+ }
325
+
326
+ function initPC() {
327
+ const configuration = {
328
+ iceServers: [
329
+ //stun协议服务器。反馈外网信息
330
+ { urls: 'stun:stun.l.google.com:19302' },
331
+ /*
332
+ {
333
+ urls: 'turn:yourturnserver.com:3478',
334
+ username: 'yourusername',
335
+ credential: 'yourpassword'
336
+ }*/
337
+ ]
338
+ };
339
+ pc = new RTCPeerConnection(configuration);
340
+ //console.log('Created local peer connection object pc');
341
+ pc.onicecandidate = function (e) {
342
+ //addIceCandidate
343
+ /*
344
+ // 首先发送ice-candidate的是客户端?
345
+ */
346
+ //socket.emit('webrtc ice-candidate', { host: hostId, candidate: (event.candidate) });
347
+ console.log('onicecandidate', e.candidate)
348
+ cds.push(e.candidate)
349
+ document.getElementById('candidate').value = JSON.stringify(cds, null, 2);
350
+ };
351
+ pc.oniceconnectionstatechange = function (e) {
352
+ //onIceStateChange(pc, e);
353
+ console.log('ICE state change event: ', e);
354
+ return;
355
+ //
356
+ e.target
357
+ e.currentTarget
358
+ const currentState = e.target.iceConnectionState;
359
+ console.log('ICE 连接状态变化:', currentState);
360
+
361
+ // 根据不同状态处理
362
+ switch (currentState) {
363
+ case 'new':
364
+ // 初始状态:连接尚未开始建立
365
+ console.log('ICE 连接已创建,尚未开始连接');
366
+ break;
367
+ case 'checking':
368
+ // 正在检查连接:ICE 正在尝试不同的候选地址(如本地地址、STUN 反射地址、TURN 中继地址)
369
+ console.log('ICE 正在检查连接候选地址...');
370
+ break;
371
+ case 'connected':
372
+ // 部分连接成功:至少有一个 P2P 连接已建立(可能仍在检查其他候选以优化连接)
373
+ console.log('ICE 已建立部分连接,通信可正常进行');
374
+ break;
375
+ case 'completed':
376
+ // 完全连接成功:所有 ICE 候选检查完成,最佳 P2P 连接已确定
377
+ console.log('ICE 连接完全建立,已确定最佳通信路径');
378
+ break;
379
+ case 'failed':
380
+ // 连接失败:所有 ICE 候选检查都失败,P2P 连接无法建立(需考虑用 TURN 中继或提示用户)
381
+ console.error('ICE 连接失败,无法建立 P2P 通信');
382
+ // 可选:触发重试逻辑或提示用户
383
+ retryConnection();
384
+ break;
385
+ case 'disconnected':
386
+ // 连接断开:之前建立的连接丢失(如网络波动、对方离线)
387
+ console.warn('ICE 连接已断开,尝试重连...');
388
+ // 可选:尝试重新收集 ICE 候选并重连
389
+ //peerConnection.restartIce();
390
+ console.error('ICE 连接失败,尝试重启...');
391
+ // 重启 ICE 流程(会重新收集候选并尝试连接)
392
+ peerConnection.restartIce()
393
+ .then(() => console.log('ICE 重启成功,正在重新连接...'))
394
+ .catch(err => console.error('ICE 重启失败:', err));
395
+ break;
396
+ case 'closed':
397
+ // 连接已关闭:主动调用 peerConnection.close() 后触发
398
+ console.log('ICE 连接已主动关闭');
399
+ // 可选:释放资源、清理 UI
400
+ cleanupConnection();
401
+ break;
402
+ }
403
+ };
404
+
405
+ //建立offer前注入stream
406
+ stream.getTracks().forEach(
407
+ function (track) {
408
+ pc.addTrack(
409
+ track,
410
+ stream
411
+ );
412
+ }
413
+ );
414
+ }
415
+
416
+ function initVideo() {
417
+ srcVideo = document.getElementById('srcVideo');
418
+ if (srcVideo.captureStream) {
419
+ // 从video里获取流?媒体流
420
+ stream = srcVideo.captureStream();
421
+ console.log('Captured stream from srcVideo with captureStream',
422
+ stream);
423
+ //call();
424
+ } else if (srcVideo.mozCaptureStream) {
425
+ stream = srcVideo.mozCaptureStream();
426
+ console.log('Captured stream from srcVideo with mozCaptureStream()',
427
+ stream);
428
+ //call();
429
+ } else {
430
+ console.error('captureStream() not supported');
431
+ }
432
+ var videoTracks = stream.getVideoTracks();
433
+ var audioTracks = stream.getAudioTracks();
434
+ if (videoTracks.length > 0) {
435
+ console.log('Using video device: ' + videoTracks[0].label);
436
+ }
437
+ if (audioTracks.length > 0) {
438
+ console.log('Using audio device: ' + audioTracks[0].label);
439
+ }
440
+ }
441
+
442
+ window.onload = function () {
443
+ initVideo()
444
+ initPC()
445
+ /*
446
+ 产生offer,粘帖过去, client获得answer,粘帖过来
447
+ */
448
+ };
449
+ </script>
450
+
451
+ </body>
452
+
453
+ </html>