PageSourceSearch

https://static.xycloud.com/www/assets/js/xyp2p-20190319.js

js xycloud.com collected 2026-10-09 17:03:48 UTC 13,097 bytes, 414 lines download raw bytes

1let isXYP2PDataDebug = true;
2
3class XYP2PDataChannel {
4    constructor() {
5        this.collideAddress = "wss://telescope.xycdn.com:8443/ws";
6        this.turnAddr = "wss://channel-demo.xycloud.com/api/v1/turn";
7        this.collideWs = null;
8        this.stunUrls = [];
9        this.peerConnection = null;
10        this.channel = null;
11        this.isRegister = false;
12        this.peerID = "";
13        this.remotePeerID = "";
14        this.innerMessageSize = 0;
15        this.flow = 0;
16        this.isRuning = false;
17        this.isRecvAnswer = false; // 是否收到answer消息
18        this.startFlowCheck();
19        this.isSupports = !!window.RTCPeerConnection && !!window.WebSocket;
20        this.isConnectToTurn = false;
21        this.ws = null;
22        this.isTurnMode = false;
23        console.log(this.isSupports ? '支持' : "不支持");
24    }
25
26    sendCmd(cmd, msg) {
27        this.collideWs.send(JSON.stringify({cmd, msg: JSON.stringify(msg)}));
28    };
29
30    updateSpeedStatistics(size) {
31        // console.log(size);
32        this.innerMessageSize += size;
33    }
34
35    startFlowCheck() {
36        const self = this;
37        setInterval(function () {
38            self.flow = self.innerMessageSize;
39            self.innerMessageSize = 0;
40        }, 1000);
41    }
42
43    getSpeed() {
44        return this.flow;
45    }
46
47    connectToCollider() {
48        let self = this;
49        this.collideWs = new WebSocket(this.collideAddress);
50        this.collideWs.onopen = function () {
51            console.log("collider websocket onopen");
52            //self.onLog("链接信令服务器成功");
53            //isRegisterToCollider = true;
54            self.sendCmd('register', {peerid: '', type: 'h5'});
55        };
56
57        this.collideWs.onerror = function () {
58            console.log("collider websocket onclose");
59        };
60
61        this.collideWs.onclose = function () {
62            console.log("准备重连collider");
63            setTimeout(function () {
64                self.connectToCollider();
65            }, 100);
66        };
67
68        this.collideWs.onmessage = function (event) {
69            let result = JSON.parse(event.data);
70            let msg = result.msg;
71            try {
72                msg = JSON.parse(result.msg);
73            } catch (err) {
74                console.warn('parse json failed', msg);
75                return;
76            }
77
78            if (result.cmd === 'heartbeatrsp') {
79                // console.log('onSignalMessage', result);
80                return;
81            } else if (result.cmd === 'sendrsp') {
82                if (msg[0].result === 'fail') {
83                    console.error('sendrsp failed');
84                }
85                return;
86            }
87
88            // console.log("收到 collider 消息", result.cmd);
89
90            if (result.cmd === 'push') {
91                self.onSignalData(self, msg.from, JSON.parse(msg.data));
92            } else if (result.cmd === 'registerrsp') {
93                self.isRegister = true;
94                self.peerID = msg.peerid;
95                self.onRegister(msg.peerid)
96                msg.coturn.forEach((host) => {
97                    self.stunUrls.push({url: 'stun:' + host});
98                });
99                self.startHeartBeat();
100                self.onSignalReady();
101                self.registerToTurn();
102            } else {
103                console.log('收到信令服务器未知消息:', result.cmd);
104            }
105        };
106    }
107
108    // 收到信令服务器数据
109    onSignalData(self, from, data) {
110        if (data.type === 'answer') {
111            console.log("收到 answer");
112            self.isRecvAnswer = true;
113            self.peerConnection.setRemoteDescription(new RTCSessionDescription(data));
114        } else if (data.type === 'offer') {
115            if (self.isRuning) {
116                // 正在运行的连接,又收到建连请求,忽略
117                return;
118            }
119            console.log('收到 offer');
120            self.peerConnection.setRemoteDescription(new RTCSessionDescription(data));
121            self.peerConnection.createAnswer().then(function(answer) {
122                console.log('创建 answer 成功');
123                self.peerConnection.setLocalDescription(answer);
124                self.sendCmd('send', [{
125                    peerid: from,
126                    data: JSON.stringify(answer),
127                }]);
128                self.onLog('发送 answer');
129            }, function(error) {
130                console.error('创建 answer 失败', error);
131            });
132        } else if (data.hasOwnProperty('candidate')) {
133            // console.log('收到 candidate');
134            self.peerConnection.addIceCandidate(new RTCIceCandidate(data)).then(() => {
135                console.log('添加对端 candidate 成功');
136                //console.log('channel:', channel);
137            }).catch((err) => {
138                console.error('添加 candidate 失败', err.name, err.message);
139            });
140        } else {
141            console.warn('收到信令服务器的未知消息:', data);
142        }
143    };
144
145    // 开始信令服务器心跳
146    startHeartBeat() {
147        setInterval(() => {
148            this.sendCmd('heartbeat', Date.now());
149        }, 10000);
150    }
151
152    // 信令服务器注册成功回调
153    onSignalReady() {
154        let self = this;
155        this.onLog('注册成功');
156        let config = {
157            iceServers: [
158                {urls: this.stunUrls[0].url},
159            ],
160        };
161        console.log('创建 RTCPeerConnection, iceServers:', this.stunUrls);
162        this.peerConnection = new RTCPeerConnection(config);
163        this.peerConnection.ondatachannel = function (event) {
164            self.isRuning = true;
165            console.log("被动通道建立");
166            self.channel = event.channel;
167            self.channel.onmessage = function (event) {
168                self.onMessage(event.data);
169                self.updateSpeedStatistics(event.data.length);
170            };
171            self.onDataChannel();
172        };
173    }
174
175    // 开始注册
176    register() {
177        if (!this.isSupports) {
178            this.onLog("该浏览器不支持,建议使用Chrome65以上版本。");
179            return;
180        }
181        this.onLog("开始注册");
182        this.connectToCollider();
183
184        this.connectToTurn();
185    }
186
187    // 主动建立连接
188    connect(id) {
189        if (this.isRuning){
190            this.onLog("不能建立多个连接,请重新打开或刷新页面。");
191            return;
192        }
193        let self = this;
194
195        if (!this.isRegister) {
196            this.onLog("未注册,不能建连。");
197            return;
198        }
199
200        if (id === ""){
201            this.onLog("请输入对方ID");
202            return;
203        }
204
205        if (id === this.peerID) {
206            this.onLog("不能与自己建立连接");
207            return;
208        }
209
210        if (this.channel !== null) {
211            this.onLog("已建立通道,不能发起连接");
212            return;
213        }
214
215        this.isRuning = true;
216        this.remotePeerID = id;
217        this.onLog("开始连接: " + id);
218        this.onLog("建立连接中,请稍后...");
219
220        ////////////
221        // self.onLog("进入中继模式");
222        // self.isTurnMode = true;
223        // self.onTurnDataChannel();
224        // return;
225        ////////////
226
227        this.channel = this.peerConnection.createDataChannel('fmtpChannel', {
228            ordered: false,
229            maxRetransmits: 0,
230            renegotiate: false,
231        });
232
233        let dataChannelConnectTimeout = setTimeout(function(){
234            self.channel.close();
235            self.onLog("建立P2P连接失败,进入中继模式");
236            self.isTurnMode = true;
237            self.onTurnDataChannel();
238        }, 5000);
239
240        this.channel.onopen = function () {
241            console.log('主动通道建立');
242            clearInterval(dataChannelConnectTimeout);
243            self.onDataChannel();
244        };
245        this.channel.onclose = function () {
246            console.log('通道关闭');
247            clearInterval(dataChannelConnectTimeout);
248            self.onDataChannelClose();
249        };
250        this.channel.onmessage = function (event) {
251            //console.log('DataChannel message', event);
252            self.onMessage(event.data);
253            self.updateSpeedStatistics(event.data.length);
254        };
255        this.channel.onerror = function (event) {
256            console.log('DataChannel error');
257            clearInterval(dataChannelConnectTimeout);
258            self.onDataChannelError(event);
259        };
260
261        this.peerConnection.onicecandidate = (e) => {
262            console.log('发送 candidate');
263            if (e.candidate) {
264                self.sendCmd('send', [{
265                    peerid: id,
266                    data: JSON.stringify(e.candidate),
267                }]);
268            }
269        };
270
271        this.peerConnection.createOffer().then((offer) => {
272            console.log('创建 offer');
273            self.peerConnection.setLocalDescription(offer);
274            self.sendCmd('send', [{
275                peerid: id,
276                data: JSON.stringify({sdp: offer.sdp, type: 'offer'}),
277            }]);
278            console.log('发送 offer');
279        }).catch((err) => {
280            console.error('创建 offer 失败:', err);
281        });
282    }
283
284    // 主动发送消息
285    send(msg) {
286        if (!this.isRuning){
287            // this.onLog("发送失败,未连接。");
288            return false;
289        }
290        if(this.isTurnMode){
291            // XYP2PDataLog("中继模式发送数据,长度"+msg.length);
292            this.ws.send(`{"cmd": 3, "from_id": "` + this.peerID + `", "to_id": "` + this.remotePeerID + `", "msg": "` + msg + `"}`);
293        }else{
294            switch (this.channel.readyState){
295                case "connecting":
296                    return true;
297                case "open":
298                    this.channel.send(msg);
299                    break;
300                case "closed":
301                    console.log('发送数据失败,通道关闭');
302                    this.clear();
303                    // this.onDataChannelClose();
304                    this.onLog("断线重连。");
305                    this.connect(this.remotePeerID);
306                    return false;
307                default:
308                    console.log(this.channel.readyState);
309                    return false;
310            }
311        }
312        this.updateSpeedStatistics(msg.length);
313        return true;
314    }
315
316    clear() {
317        if (this.channel){
318            this.channel.close();
319            this.channel = null;
320        }
321        if (this.isRuning) {
322            this.isRuning = false;
323        }
324    }
325
326    onRegister(id) {
327    }
328
329    onMessage(msg) {
330    }
331
332    onDataChannel() {
333    }
334
335    onTurnDataChannel() {
336        this.onDataChannel();
337    }
338
339    onDataChannelClose() {
340    }
341
342    onDataChannelError(event) {
343    }
344
345    onLog(msg) {
346    };
347
348    connectToTurn(){
349        let self = this;
350        XYP2PDataLog("连接turn服务", this.turnAddr);
351        self.ws = new WebSocket(this.turnAddr);
352
353        self.ws.onopen = function() {
354            self.isConnectToTurn = true;
355            XYP2PDataLog("turn服务器连接成功");
356            self.registerToTurn();
357            setInterval(()=>{
358                self.ws.send(`{"cmd": 10, "msg": ""}`);
359            }, 5000)
360        };
361
362        self.ws.onmessage = function(evt) {
363            let data = JSON.parse(evt.data);
364            //XYP2PDataLog("收到turn服务器数据", data)
365            switch (data.cmd){
366                case 2:
367                    XYP2PDataLog("Turn服务注册成功");
368                    break;
369                case 3:
370                    if (!self.isRuning) {
371                        self.isRuning = true;
372                        self.isTurnMode = true;
373                        self.onLog("P2P被动链接失败,启动中继模式 "+d
373ata.from_id);
374                        self.remotePeerID = data.from_id;
375                    }
376
377                    // XYP2PDataLog("收到Turn服务消息, 长度"+data.msg.length);
378                    self.onMessage(data.msg);
379                    self.updateSpeedStatistics(data.msg.length);
380                    break;
381
382                case 4:
383                    if (data.result_code !== 0){
384                        self.onLog("对方挂断");
385                        self.clear();
386                        // self.connect(self.remotePeerID);
387                    }
388            }
389        };
390
391        self.ws.onclose = function(evt) {
392            XYP2PDataLog("Turn服务器连接关闭", evt);
393        };
394
395        self.ws.onerror = function(evt) {
396            XYP2PDataLog("Turn服务异常", evt);
397        };
398    }
399
400    registerToTurn(){
401        if(!this.isConnectToTurn || this.peerID === "") {
402            return false;
403        }
404        XYP2PDataLog("向turn注册");
405        this.ws.send(`{"cmd": 1, "msg": "` + this.peerID + `"}`);
406    }
407}
408
409function XYP2PDataLog(...values){
410    if(!isXYP2PDataDebug) {
411        return
412    }
413    console.log(values);
414}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.