diff --git a/src/ami.js/eeprom.js b/src/ami.js/eeprom.js index 6c4e8cb..5729d07 100644 --- a/src/ami.js/eeprom.js +++ b/src/ami.js/eeprom.js @@ -1,33 +1,163 @@ -var AmiEEPROM = function() { - // -}; -AmiEEPROM.init = (function() { - var initialised = false; - - return function(callback) { - if(initialised) { - if(callback) - callback(true); - return; - } - initialised = true; +var AmiEEPROM = function(endPoint, getAuthLine) { + if(typeof endPoint !== 'string') + throw 'endPoint must be a string'; + if(typeof getAuthLine !== 'function') + throw 'getAuthLine must be a function'; - // cuts off "/uploads", this is little disgusting - var eepromScript = futami.get('eeprom').slice(0, -8) + '/eeprom.js'; + // when the pools rewrite happen, retrieve this from futami common + const appId = '1'; - var script = document.createElement('script'); - script.onload = function() { - if(callback) - callback(true); - }; - script.onerror = function() { - console.error('Failed to load EEPROM script!'); - if(callback) - callback(false); - }; - script.charset = 'utf-8'; - script.type = 'text/javascript'; - script.src = eepromScript; - document.body.appendChild(script); + return { + create: fileInput => { + if(!(fileInput instanceof File)) + throw 'fileInput must be an instance of window.File'; + + let userAborted = false; + let abortHandler; + let progressHandler; + + const reportProgress = ev => { + if(progressHandler !== undefined) + progressHandler({ + loaded: ev.loaded, + total: ev.total, + progress: ev.total <= 0 ? 0 : ev.loaded / ev.total, + }); + }; + + return { + abort: () => { + userAborted = true; + if(typeof abortHandler === 'function') + abortHandler(); + }, + onProgress: handler => { + if(typeof handler !== 'function') + throw 'handler must be a function'; + progressHandler = handler; + }, + start: (success, error) => { + const throwError = ex => { + if(typeof error === 'function') + error(ex); + else + console.error(ex); + }; + + try { + if(typeof success !== 'function') + throw 'success must be a callback function'; + + if(userAborted) + throw 'File upload was cancelled by the user, it cannot be restarted.'; + + try { + const formData = new FormData; + formData.append('src', appId); + formData.append('file', fileInput); + + const xhr = new XMLHttpRequest; + abortHandler = () => { xhr.abort(); }; + xhr.upload.onloadstart = reportProgress; + xhr.upload.onprogress = reportProgress; + xhr.upload.onloadend = reportProgress; + xhr.addEventListener('readystatechange', () => { + if(xhr.readyState !== XMLHttpRequest.DONE) + return; + + try { + const body = (() => { + try { + return JSON.parse(xhr.responseText); + } catch(ex) { + return null; + } + })(); + + // user cancel + if(xhr.status === 0) + throw ''; + + if(body === null) + throw "The upload server didn't return the metadata for some reason."; + + if(xhr.status !== 201) + throw body.english ?? body.error ?? `Upload failed with status code ${xhr.status}`; + + body.isImage = () => body.type.startsWith('image/'); + body.isVideo = () => body.type.startsWith('video/'); + body.isAudio = () => body.type.startsWith('audio/'); + body.isMedia = () => body.isImage() || body.isAudio() || body.isVideo(); + + success(Object.freeze(body)); + } catch(ex) { + throwError(ex); + } + }); + xhr.open('POST', `${endPoint}/uploads`); + xhr.setRequestHeader('Authorization', getAuthLine()); + xhr.send(formData); + } catch(ex) { + if(userAborted) + throw ''; + + console.error(ex); + throw ex; + } + } catch(ex) { + throwError(ex); + } + }, + }; + }, + + delete: (fileInfo, success, error) => { + const throwError = ex => { + if(typeof error === 'function') + error(ex); + else + console.error(ex); + }; + + try { + if(typeof fileInfo !== 'object') + throw 'fileInfo must be an object'; + if(typeof fileInfo.urlf !== 'string') + throw 'fileInfo.urlf must be a string'; + + const xhr = new XMLHttpRequest; + xhr.addEventListener('readystatechange', () => { + if(xhr.readyState !== XMLHttpRequest.DONE) + return; + + try { + const body = (() => { + try { + return JSON.parse(xhr.responseText); + } catch(ex) { + return null; + } + })(); + + if(xhr.status !== 204) { + if(body === null) + throw `Delete failed with status code ${xhr.status}`; + + throw body.english ?? body.error ?? `Delete failed with status code ${xhr.status}`; + } + + if(typeof success === 'function') + success(body); + } catch(ex) { + throwError(ex); + } + }); + xhr.open('DELETE', fileInfo.urlf); + xhr.setRequestHeader('Authorization', getAuthLine()); + xhr.send(); + } catch(ex) { + throwError(ex); + } + }, }; -})(); +}; diff --git a/src/ami.js/ts_chat.js b/src/ami.js/ts_chat.js index 25db503..7cb7246 100644 --- a/src/ami.js/ts_chat.js +++ b/src/ami.js/ts_chat.js @@ -1,6 +1,5 @@ #include ts_20_ui.js #include ts_10_user.js -#include eeprom.js #include z_eepromv1.js #include utility.js #include sidebars/channelssb.js @@ -596,13 +595,7 @@ var Chat = (function () { UI.RenderLanguage(); - AmiEEPROM.init(function(success) { - if(!success) - return; - - // set up old eeprom code - eepromInitialise(auth); - }); + eepromInitialise(auth); }; Chat.InsertBBCode = function (tag, arg) { if (arg === void 0) { arg = null; } diff --git a/src/ami.js/z_eepromv1.js b/src/ami.js/z_eepromv1.js index f9abc87..615fb13 100644 --- a/src/ami.js/z_eepromv1.js +++ b/src/ami.js/z_eepromv1.js @@ -1,4 +1,5 @@ #include common.js +#include eeprom.js #include utility.js var eepromAppl = 1, @@ -7,7 +8,7 @@ var eepromAppl = 1, eepromSupportVideoEmbed = true; var eepromInitialise = function(auth) { window.eepromHistory = {}; - window.eepromClient = new EEPROM(eepromAppl, futami.get('eeprom'), auth.getHttpAuth()); + window.eepromClient = new AmiEEPROM(futami.get('eeprom2'), auth.getHttpAuth); window.eepromUploadsTable = $i('uploadHistory'); $i('uploadSelector').onchange = function() { @@ -86,53 +87,11 @@ var eepromFileUpload = function(file) { prog.appendChild(progBar); uploadEntry.appendChild(prog); - var uploadTask = window.eepromClient.createUpload(file); + var uploadTask = window.eepromClient.create(file); - uploadTask.onProgress = function(progressInfo) { - progBar.style.width = progressInfo.progress.toString() + '%'; - }; - - uploadTask.onFailure = function(errorInfo) { - if(!errorInfo.userAborted) { - var errorText = 'Was unable to upload file.'; - - switch(errorInfo.error) { - case EEPROM.ERR_INVALID: - errorText = 'Upload request was invalid.'; - break; - case EEPROM.ERR_AUTH: - errorText = 'Upload authentication failed, refresh and try again.'; - break; - case EEPROM.ERR_ACCESS: - errorText = 'You\'re not allowed to upload files.'; - break; - case EEPROM.ERR_GONE: - errorText = 'Upload client has a configuration error or the server is gone.'; - break; - case EEPROM.ERR_DMCA: - errorText = 'This file has been uploaded before and was removed for copyright reasons, you cannot upload this file.'; - break; - case EEPROM.ERR_SERVER: - errorText = 'Upload server returned a critical error, try again later.'; - break; - case EEPROM.ERR_SIZE: - if(errorInfo.maxSize < 1) - errorText = 'Selected file is too large.'; - else { - var _t = ['bytes', 'KB', 'MB', 'GB', 'TB'], - _i = parseInt(Math.floor(Math.log(errorInfo.maxSize) / Math.log(1024))), - _s = Math.round(errorInfo.maxSize / Math.pow(1024, _i), 2); - - errorText = 'Upload may not be larger than %1 %2.'.replace('%1', _s).replace('%2', _t[_i]); - } - break; - } - - alert(errorText); - } - - uploadHistory.deleteRow(uploadEntryWrap.rowIndex); - }; + uploadTask.onProgress(function(progressInfo) { + progBar.style.width = `${progressInfo.progress * 100}%`; + }); name.onclick = function(ev) { if(ev.shiftKey) { @@ -140,30 +99,38 @@ var eepromFileUpload = function(file) { var fileInfo = window.eepromHistory[name.getAttribute('data-eeprom-id') || '']; if(fileInfo) { - window.eepromClient.deleteUpload(fileInfo).start(); - uploadHistory.deleteRow(uploadEntryWrap.rowIndex); + window.eepromClient.delete( + fileInfo, + () => { uploadHistory.deleteRow(uploadEntryWrap.rowIndex); }, + window.alert + ); } else uploadTask.abort(); } }; - uploadTask.onComplete = function(fileInfo) { - window.eepromHistory[fileInfo.id] = fileInfo; - name.style.textDecoration = null; - name.setAttribute('data-eeprom-id', fileInfo.id); - name.href = fileInfo.url; - uploadEntry.removeChild(prog); + uploadTask.start( + fileInfo => { + window.eepromHistory[fileInfo.id] = fileInfo; + name.style.textDecoration = null; + name.setAttribute('data-eeprom-id', fileInfo.id); + name.href = fileInfo.url; + uploadEntry.removeChild(prog); - var insertText = location.protocol + fileInfo.url; + var insertText = location.protocol + fileInfo.url; - if(eepromSupportImageEmbed && fileInfo.type.indexOf('image/') === 0) - insertText = '[img]' + fileInfo.url + '[/img]'; - else if(eepromSupportAudioEmbed && (fileInfo.type === 'application/x-font-gdos' || fileInfo.type.indexOf('audio/') === 0)) - insertText = '[audio]' + fileInfo.url + '[/audio]'; - else if(eepromSupportVideoEmbed && fileInfo.type.indexOf('video/') === 0) - insertText = '[video]' + fileInfo.url + '[/video]'; + if(eepromSupportImageEmbed && fileInfo.isImage()) + insertText = '[img]' + fileInfo.url + '[/img]'; + else if(eepromSupportAudioEmbed && fileInfo.isAudio()) + insertText = '[audio]' + fileInfo.url + '[/audio]'; + else if(eepromSupportVideoEmbed && fileInfo.isVideo()) + insertText = '[video]' + fileInfo.url + '[/video]'; - ami.chat.inputBox.insert(insertText); - }; - - uploadTask.start(); + ami.chat.inputBox.insert(insertText); + }, + ex => { + if(ex !== '') + alert(ex); + uploadHistory.deleteRow(uploadEntryWrap.rowIndex); + }, + ); };