import _ from 'underscore'; import uuid from 'uuid'; export default class FileHandler { constructor(darkwire, socket, chat) { this.localFileQueue = []; if (window.File && window.FileReader && window.FileList && window.Blob && window.btoa && window.atob && window.Blob && window.URL) { this._isSupported = true; this.darkwire = darkwire; this.socket = socket; this.chat = chat; this.listen(); } else { this._isSupported = false; } } get isSupported() { return this._isSupported; } set isSupported(state) { this._isSupported = state; return this; } confirmTransfer(event) { const validFileTypes = ['png','jpg','jpeg','gif','zip','rar','gzip','pdf','txt','json','doc','docx','csv','js','html','css']; const file = event.target.files && event.target.files[0]; if (file) { const fileExt = file.name.split('.').pop().toLowerCase(); if (validFileTypes.indexOf(fileExt) <= -1) { alert('file type not supported'); return false; } // Support for only 1MB if (file.size > 1000000) { console.log(file); alert('Max filesize is 1MB.'); return false; } let fileId = uuid.v4(); let confirmMessage = 'You are about to send ' + file.name + ' to all participants in this chat. Confirm | Cancel'; let fileData = { id: fileId, file: file }; this.localFileQueue.push(fileData); this.chat.addChatMessage({ username: username, message: confirmMessage }); this.filesSent++; } return false; } encodeFile(fileId) { const fileData = _.findWhere(this.localFileQueue, {id: fileId}); const file = fileData.file || false; if (file) { // TODO: Remove file from local queue } else { return false; } const reader = new FileReader(); const fileType = file.type || 'file'; reader.onload = (readerEvent) => { const base64 = window.btoa(readerEvent.target.result); const additionalData = { fileId: fileId, fileName: file.name }; this.darkwire.encodeMessage(base64, fileType, additionalData).then((socketData) => { this.chat.replaceMessage('#transfer-' + fileId, 'Sent ' + file.name + ''); this.socket.emit('new message', socketData); }); this.resetInput(); }; reader.readAsBinaryString(file); } destroyFile(fileId) { const file = _.findWhere(this.localFileQueue, {id: fileId}); this.localFileQueue = _.without(this.localFileQueue, file); this.resetInput(); return this.chat.replaceMessage('#transfer-' + fileId, 'The file transfer for ' + file.file.name + ' has been canceled.'); } createBlob(base64, fileType) { base64 = unescape(base64); return new Promise((resolve, reject) => { const sliceSize = 1024; let byteCharacters = window.atob(base64); let byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { let slice = byteCharacters.slice(offset, offset + sliceSize); let byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } let byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } resolve(new window.Blob(byteArrays, {type: fileType})); }); } createUrlFromBlob(blob) { return window.URL.createObjectURL(blob); } listen() { // browser API document.getElementById('fileInput').addEventListener('change', this.confirmTransfer.bind(this), false); return this; } resetInput() { document.getElementById('fileInput').value = ''; } }