System.register(["socket.io-client"], function (exports_1, context_1) { "use strict"; var socket_io_client_1, WebRTCFileClient; var __moduleName = context_1 && context_1.id; return { setters: [ function (socket_io_client_1_1) { socket_io_client_1 = socket_io_client_1_1; } ], execute: function () { WebRTCFileClient = class WebRTCFileClient { constructor(serverUrl = window.location.origin) { this.peerConnection = null; this.dataChannel = null; this.receivedSize = 0; this.fileSize = 0; this.fileName = ''; this.fileChunks = []; this.onProgressCallback = null; this.onCompleteCallback = null; this.onErrorCallback = null; this.onFilesListCallback = null; this.socket = socket_io_client_1.io(serverUrl); this.setupSocketListeners(); } setupSocketListeners() { this.socket.on('connect', () => { console.log('Connected to server, socket ID:', this.socket.id); }); this.socket.on('offer', (data) => { console.log('Received offer from server'); this.fileName = data.fileInfo.name; this.fileSize = data.fileInfo.size; this.setupPeerConnection(); this.handleOffer(data.sdp); }); this.socket.on('ice-candidate', (candidate) => { if (this.peerConnection) { this.peerConnection.addIceCandidate(new RTCIceCandidate(candidate)) .catch(err => console.error('Error adding received ice candidate', err)); } }); this.socket.on('error', (errorMessage) => { console.error('Server error:', errorMessage); if (this.onErrorCallback) { this.onErrorCallback(errorMessage); } }); this.socket.on('files-list', (files) => { console.log('Received files list:', files); if (this.onFilesListCallback) { this.onFilesListCallback(files); } }); this.socket.on('disconnect', () => { console.log('Disconnected from server'); this.cleanupFileTransfer(); }); } setupPeerConnection() { if (this.peerConnection) { this.peerConnection.close(); } const configuration = { iceServers: [ { urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' } ] }; this.peerConnection = new RTCPeerConnection(configuration); this.fileChunks = []; this.receivedSize = 0; this.peerConnection.onicecandidate = (event) => { if (event.candidate) { this.socket.emit('ice-candidate', event.candidate); } }; this.peerConnection.ondatachannel = (event) => { this.dataChannel = event.channel; this.setupDataChannel(); }; } setupDataChannel() { if (!this.dataChannel) return; this.dataChannel.binaryType = 'arraybuffer'; this.dataChannel.onopen = () => { console.log('Data channel is open'); }; this.dataChannel.onmessage = (event) => { const data = event.data; if (typeof data === 'string') { try { const message = JSON.parse(data); if (message.type === 'file-info') { this.fileName = message.name; this.fileSize = message.size; this.fileChunks = []; this.receivedSize = 0; console.log(`Receiving file: ${this.fileName}, Size: ${this.formatFileSize(this.fileSize)}`); } else if (message.type === 'file-complete') { this.completeFileTransfer(); } else if (message.type === 'error') { if (this.onErrorCallback) { this.onErrorCallback(message.message); } } } catch (e) { console.error('Error parsing message:', e); } } else if (data instanceof ArrayBuffer) { this.fileChunks.push(new Uint8Array(data)); this.receivedSize += data.byteLength; if (this.onProgressCallback && this.fileSize > 0) { const progress = Math.min((this.receivedSize / this.fileSize) * 100, 100); this.onProgressCallback(progress); } } }; this.dataChannel.onclose = () => { console.log('Data channel closed'); }; this.dataChannel.onerror = (error) => { console.error('Data channel error:', error); if (this.onErrorCallback) { this.onErrorCallback('Data channel error'); } }; } async handleOffer(sdp) { if (!this.peerConnection) return; try { await this.peerConnection.setRemoteDescription(new RTCSessionDescription(sdp)); const answer = await this.peerConnection.createAnswer(); await this.peerConnection.setLocalDescription(answer); this.socket.emit('answer', answer); } catch (error) { console.error('Error handling offer:', error); if (this.onErrorCallback) { this.onErrorCallback('Failed to establish connection'); } } } completeFileTransfer() { if (this.fileChunks.length === 0) { console.error('No file data received'); if (this.onErrorCallback) { this.onErrorCallback('No file data received'); } return; } let totalLength = 0; for (const chunk of this.fileChunks) { totalLength += chunk.length; } const completeFile = new Uint8Array(totalLength); let offset = 0; for (const chunk of this.fileChunks) { completeFile.set(chunk, offset); offset += chunk.length; } const fileBlob = new Blob([completeFile]); console.log(`File transfer complete: ${this.fileName}, Size: ${this.formatFileSize(fileBlob.size)}`); if (this.onCompleteCallback) { this.onCompleteCallback(fileBlob, this.fileName); } this.cleanupFileTransfer(); } cleanupFileTransfer() { this.fileChunks = []; this.receivedSize = 0; if (this.dataChannel) { this.dataChannel.close(); this.dataChannel = null; } if (this.peerConnection) { this.peerConnection.close(); this.peerConnection = null; } } formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } getFilesList() { this.socket.emit('get-files'); } requestFile(fileName) { this.socket.emit('request-file', fileName); } onProgress(callback) { this.onProgressCallback = callback; } onComplete(callback) { this.onCompleteCallback = callback; } onError(callback) { this.onErrorCallback = callback; } onFilesList(callback) { this.onFilesListCallback = callback; } saveFile(blob, fileName) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); window.setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 0); } disconnect() { this.socket.disconnect(); this.cleanupFileTransfer(); } }; exports_1("WebRTCFileClient", WebRTCFileClient); } }; });