11import PeerHandler from './modules/peer-handler.js' ;
2+ import { setRoomToken , getRoomId , getUserId } from '/js/utils.js' ;
23
34/*!
45 *
@@ -9,36 +10,31 @@ import PeerHandler from './modules/peer-handler.js';
910const socket = io ( ) ;
1011const peerHandler = new PeerHandler ( { send } ) ;
1112
13+ // connection info
1214let roomId ;
1315let userId ;
1416let remoteUserId ;
1517
16- // DOM
17- const $body = document . body ;
18- const $createWrap = document . querySelector ( '#create-wrap' ) ;
19- const $waitWrap = document . querySelector ( '#wait-wrap' ) ;
20- const $uniqueToken = document . querySelector ( '#unique-token' ) ;
18+ // data info
19+ let fileInfo = null ;
20+ let receiveBuffer = [ ] ;
21+ let receivedSize = 0 ;
2122
22- const bitrateDiv = document . querySelector ( '#bitrate' ) ;
23- const downloadAnchor = document . querySelector ( '#download' ) ;
24- const sendProgress = document . querySelector ( '#sendProgress' ) ;
25- const receiveProgress = document . querySelector ( '#receiveProgress' ) ;
26- const statusMessage = document . querySelector ( '#status' ) ;
23+ // analysis info
24+ let bytesPrev = 0 ;
25+ let timestampPrev = 0 ;
26+ let timestampStart = 0 ;
27+ let statsInterval = null ;
2728
28- const $fileInput = document . querySelector ( '#file' ) ;
29+ // DOM
30+ const $body = document . body ;
31+ const $file = document . querySelector ( '#file' ) ;
2932const $btnSend = document . querySelector ( '#btn-send' ) ;
30-
31- $fileInput . addEventListener ( 'change' , handleFileInputChange , false ) ;
32-
33- function handleFileInputChange ( ) {
34- const file = $fileInput . files [ 0 ] ;
35-
36- if ( ! file ) {
37- console . log ( 'No file chosen' ) ;
38- } else {
39- $btnSend . disabled = false ;
40- }
41- }
33+ const $download = document . querySelector ( '#download' ) ;
34+ const $sendProgress = document . querySelector ( '#send-progress' ) ;
35+ const $receiveProgress = document . querySelector ( '#receive-progress' ) ;
36+ const $bitrate = document . querySelector ( '#bitrate' ) ;
37+ const $status = document . querySelector ( '#status' ) ;
4238
4339/**
4440 * 입장 후 다른 참여자 발견시 호출
@@ -63,7 +59,7 @@ function onJoin(roomId, { userId: joinedUserId, participants }) {
6359 }
6460
6561 if ( userId !== joinedUserId ) {
66- console . log ( '상대방 들어옴 :>> ' , joinedUserId ) ;
62+ console . log ( '상대방 들어옴 ' , joinedUserId ) ;
6763 peerHandler . startRtcConnection ( ) ;
6864 }
6965}
@@ -113,40 +109,172 @@ function send(data) {
113109}
114110
115111/**
116- * 방 고유 접속 토큰 생성
112+ * 파일 전송 요청
113+ * @param file
114+ */
115+ function sendFile ( file ) {
116+ console . log ( `File is ${ [ file . name , file . size , file . type , file . lastModified ] . join ( ' ' ) } ` ) ;
117+
118+ peerHandler . sendData ( file ) ;
119+
120+ // set file size
121+ $status . textContent = '' ;
122+ $sendProgress . max = file . size ;
123+ }
124+
125+ /**
126+ * 파일 인풋 예외처리
117127 */
118- function setRoomToken ( ) {
119- const hashValue = ( Math . random ( ) * new Date ( ) . getTime ( ) ) . toString ( 32 ) . toUpperCase ( ) . replace ( / \. / g , '-' ) ;
128+ function bindFileInputChange ( ) {
129+ const file = $file . files [ 0 ] ;
120130
121- if ( location . hash . length < 2 ) {
122- location . hash = '#' + hashValue ;
131+ if ( ! file || file ?. size === 0 ) {
132+ $status . textContent = 'File is empty, please select a non-empty file' ;
133+ $btnSend . disabled = true ;
134+ return ;
135+ } else {
136+ $btnSend . disabled = false ;
123137 }
124138}
139+
140+ /**
141+ * 다운로드 버튼 정보 초기화
142+ */
143+ function resetDownloadButton ( ) {
144+ console . log ( 'resetDownloadButton' ) ;
145+ $download . textContent = '' ;
146+ $download . removeAttribute ( 'download' ) ;
147+
148+ if ( $download . href ) {
149+ URL . revokeObjectURL ( $download . href ) ;
150+ $download . removeAttribute ( 'href' ) ;
151+ }
152+ }
153+
154+ /**
155+ * 수신 데이터 핸들링
156+ * @param {* } event
157+ * @returns
158+ */
159+ async function onReceiveDataChannel ( event ) {
160+ console . log ( 'onReceiveDataChannel' , event ) ;
161+
162+ // 최초 전송 파일 정보 설정
163+ if ( typeof event . data === 'string' && event . data . match ( 'fileInfo' ) ) {
164+ fileInfo = JSON . parse ( event . data ) . fileInfo ;
165+ timestampStart = new Date ( ) . getTime ( ) ;
166+ timestampPrev = timestampStart ;
167+ receivedSize = 0 ;
168+ resetDownloadButton ( ) ;
169+ statsInterval = setInterval ( displayStats , 100 ) ;
170+ displayStats ( ) ;
171+ return ;
172+ }
173+
174+ receiveBuffer . push ( event . data ) ;
175+ receivedSize += event . data . byteLength ;
176+
177+ $receiveProgress . max = fileInfo . size ;
178+ $receiveProgress . value = receivedSize ;
179+
180+ // we are assuming that our signaling protocol told
181+ // about the expected file size (and name, hash, etc).
182+ if ( receivedSize === fileInfo . size ) {
183+ console . log ( 'Complete received file' , fileInfo ) ;
184+ const receivedFile = new Blob ( receiveBuffer ) ;
185+ $download . href = URL . createObjectURL ( receivedFile ) ;
186+ $download . download = fileInfo . name ;
187+ $download . textContent = `Click to download '${ fileInfo . name } ' (${ fileInfo . size . toLocaleString ( ) } bytes)` ;
188+ $download . style . display = 'block' ;
189+
190+ const bitrate = Math . round ( ( receivedSize * 8 ) / ( new Date ( ) . getTime ( ) - timestampStart ) ) ;
191+ $bitrate . innerHTML = `<strong>Average Bitrate:</strong> ${ bitrate . toLocaleString ( ) } kbits/sec` ;
192+
193+ if ( statsInterval ) {
194+ clearInterval ( statsInterval ) ;
195+ statsInterval = null ;
196+ }
197+
198+ // reset
199+ receiveBuffer = [ ] ;
200+ receivedSize = 0 ;
201+ fileInfo = null ;
202+ }
203+ }
204+
205+ /**
206+ * 수신 비트레이트 측정
207+ */
208+ async function displayStats ( ) {
209+ const peer = peerHandler . getPeer ( ) ;
210+ const stats = await peer . getStats ( ) ;
211+ let activeCandidatePair ;
212+
213+ stats . forEach ( ( report ) => {
214+ if ( report . type === 'transport' ) {
215+ activeCandidatePair = stats . get ( report . selectedCandidatePairId ) ;
216+ }
217+ } ) ;
218+
219+ if ( activeCandidatePair ) {
220+ if ( timestampPrev === activeCandidatePair . timestamp ) {
221+ return ;
222+ }
223+
224+ // calculate current bitrate
225+ const bytesNow = activeCandidatePair . bytesReceived ;
226+ const bitrate = Math . round ( ( ( bytesNow - bytesPrev ) * 8 ) / ( activeCandidatePair . timestamp - timestampPrev ) ) ;
227+ $bitrate . innerHTML = `<strong>Current Bitrate:</strong> ${ bitrate . toLocaleString ( ) } kbits/sec` ;
228+ timestampPrev = activeCandidatePair . timestamp ;
229+ bytesPrev = bytesNow ;
230+ }
231+ }
232+
233+ /**
234+ * 전송 진척도 표시
235+ */
236+ function onSendingProgress ( value ) {
237+ $sendProgress . value = value ;
238+ }
239+
125240/**
126241 * DOM 이벤트 바인딩
127242 */
128243function bindDomEvent ( ) {
129- $btnSend . addEventListener ( 'click' , ( ) => {
130- peerHandler . sendData ( $fileInput . files [ 0 ] ) ;
131- } ) ;
244+ $file . addEventListener ( 'change' , bindFileInputChange ) ;
245+ $btnSend . addEventListener ( 'click' , ( ) => sendFile ( $file . files [ 0 ] ) ) ;
132246}
133247
134248/**
135- * 초기 설정
249+ * peer 이벤트 바인딩
136250 */
137- function initialize ( ) {
138- setRoomToken ( ) ;
139- roomId = location . href . replace ( / \/ | : | # | % | \. | \[ | \] / g , '' ) ;
140- userId = Math . round ( Math . random ( ) * 99999 ) ;
251+ function bindPeerEvent ( ) {
252+ peerHandler . on ( 'sendDataChannelProgress' , onSendingProgress ) ;
253+ peerHandler . on ( 'receiveDataChannel' , onReceiveDataChannel ) ;
254+ }
141255
142- // 소켓 관련 이벤트 바인딩
256+ /**
257+ * 웹소켓 이벤트 바인딩
258+ */
259+ function bindSocketEvent ( ) {
143260 socket . emit ( 'enter' , roomId , userId ) ;
144261 socket . on ( 'join' , onJoin ) ;
145262 socket . on ( 'leave' , onLeave ) ;
146263 socket . on ( 'message' , onMessage ) ;
264+ }
265+
266+ /**
267+ * 초기 설정
268+ */
269+ function initialize ( ) {
270+ setRoomToken ( ) ;
271+ roomId = getRoomId ( ) ;
272+ userId = getUserId ( ) ;
147273
148- // DOM 이벤트 바인딩
274+ // 이벤트 바인딩
149275 bindDomEvent ( ) ;
276+ bindSocketEvent ( ) ;
277+ bindPeerEvent ( ) ;
150278}
151279
152280initialize ( ) ;
0 commit comments