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.