Skip to content

Commit 8ae7f02

Browse files
committed
feat: 파일 전송 뷰단 로직 main으로 분리
1 parent 3501949 commit 8ae7f02

File tree

6 files changed

+257
-238
lines changed

6 files changed

+257
-238
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Object.size = function (obj) {
2+
let size = 0;
3+
4+
for (let key in obj) {
5+
if (obj.hasOwnProperty(key)) {
6+
size++;
7+
}
8+
}
9+
return size;
10+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const RTCPeerConnection =
2+
window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
3+
export const RTCSessionDescription =
4+
window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
5+
export const RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
6+
7+
export const getDefaultIceServers = () => [
8+
{
9+
urls: ['stun:stun.l.google.com:19302', 'stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'],
10+
},
11+
{
12+
urls: ['turn:107.150.19.220:3478'],
13+
credential: 'turnserver',
14+
username: 'subrosa',
15+
},
16+
];

frontend/contents/js/utils.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
Object.size = function(obj) {
2-
let size = 0;
1+
export const setRoomToken = () => {
2+
const hashValue = (Math.random() * new Date().getTime()).toString(32).toUpperCase().replace(/\./g, '-');
33

4-
for (let key in obj) {
5-
if (obj.hasOwnProperty(key)) {
6-
size++;
7-
}
4+
if (location.hash.length < 2) {
5+
location.hash = '#' + hashValue;
86
}
9-
return size;
107
};
8+
9+
export const getRoomId = () => location.href.replace(/\/|:|#|%|\.|\[|\]/g, '');
10+
11+
export const getUserId = () => Math.round(Math.random() * 99999);

frontend/views/examples/data-channel/js/main.js

Lines changed: 167 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 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';
910
const socket = io();
1011
const peerHandler = new PeerHandler({ send });
1112

13+
// connection info
1214
let roomId;
1315
let userId;
1416
let 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');
2932
const $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
*/
128243
function 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

152280
initialize();

0 commit comments

Comments
 (0)