Implement EEPROM client directly into the chat.
This commit is contained in:
parent
7f0428a4ef
commit
12bb564613
3 changed files with 183 additions and 138 deletions
src/mami.js
|
@ -1,37 +1,105 @@
|
|||
#include eeprom/script.jsx
|
||||
#include utility.js
|
||||
|
||||
const MamiEEPROM = function(baseUrl, getAuthLine) {
|
||||
if(typeof baseUrl !== 'string')
|
||||
throw 'baseUrl must be a string';
|
||||
const MamiEEPROM = function(endPoint, getAuthLine) {
|
||||
if(typeof endPoint !== 'string')
|
||||
throw 'endPoint must be a string';
|
||||
if(typeof getAuthLine !== 'function')
|
||||
throw 'getAuthLine must be a function';
|
||||
|
||||
// when the pools rewrite happen, retrieve this from futami common
|
||||
const appId = '1';
|
||||
let client;
|
||||
|
||||
return {
|
||||
get client() {
|
||||
return client;
|
||||
},
|
||||
|
||||
init: async () => {
|
||||
await MamiEEPROMLoadScript(baseUrl);
|
||||
client = new EEPROM(appId, baseUrl, getAuthLine);
|
||||
},
|
||||
|
||||
create: fileInput => {
|
||||
if(client === undefined)
|
||||
throw 'eeprom client is uninitialised';
|
||||
if(!(fileInput instanceof File))
|
||||
throw 'fileInput must be an instance of window.File';
|
||||
|
||||
return client.create(fileInput);
|
||||
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: async () => {
|
||||
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 result = await $x.post(`${endPoint}/uploads`, {
|
||||
type: 'json',
|
||||
headers: {
|
||||
Authorization: getAuthLine(),
|
||||
},
|
||||
upload: reportProgress,
|
||||
abort: handler => abortHandler = handler,
|
||||
}, formData);
|
||||
const body = result.body();
|
||||
console.log(body);
|
||||
if(body === null)
|
||||
throw "The upload server didn't return the metadata for some reason.";
|
||||
|
||||
if(result.status !== 201)
|
||||
throw body.english ?? body.error ?? `Upload failed with status code ${result.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();
|
||||
|
||||
return Object.freeze(body);
|
||||
} catch(ex) {
|
||||
if(userAborted)
|
||||
throw 'Upload has been cancelled by the user.';
|
||||
|
||||
console.error(ex);
|
||||
throw ex;
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
delete: async fileInfo => {
|
||||
if(client === undefined)
|
||||
throw 'eeprom client is uninitialised';
|
||||
if(typeof fileInfo !== 'object')
|
||||
throw 'fileInfo must be an object';
|
||||
if(typeof fileInfo.urlf !== 'string')
|
||||
throw 'fileInfo.urlf must be a string';
|
||||
|
||||
await client.delete(fileInfo);
|
||||
const result = await $x.delete(fileInfo.urlf, {
|
||||
type: 'json',
|
||||
headers: {
|
||||
Authorization: getAuthLine(),
|
||||
},
|
||||
});
|
||||
|
||||
if(result.status !== 204) {
|
||||
const body = result.body();
|
||||
if(body === null)
|
||||
throw `Delete failed with status code ${result.status}`;
|
||||
|
||||
throw body.english ?? body.error ?? `Delete failed with status code ${result.status}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#include utility.js
|
||||
|
||||
const MamiEEPROMLoadScript = baseUrl => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if(typeof baseUrl !== 'string')
|
||||
throw 'baseUrl must be a string';
|
||||
|
||||
const src = `${baseUrl}/scripts/eepromv1a.js`;
|
||||
|
||||
let script = $q(`script[src="${src}"]`);
|
||||
if(script instanceof Element) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
script = <script src={src} onload={() => { resolve(); }} onerror={() => { $r(script); reject(); }} />;
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
};
|
|
@ -716,112 +716,108 @@ const MamiInit = async args => {
|
|||
});
|
||||
|
||||
|
||||
let doUpload;
|
||||
ctx.eeprom = new MamiEEPROM(futami.get('eeprom2'), MamiMisuzuAuth.getLine);
|
||||
ctx.eeprom.init()
|
||||
.catch(ex => { console.error('Failed to initialise EEPROM.', ex); })
|
||||
.then(() => {
|
||||
sbUploads.addOption({
|
||||
name: 'view',
|
||||
text: 'View upload',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: entry => window.open(entry.uploadInfo.url),
|
||||
});
|
||||
sbUploads.addOption({
|
||||
name: 'insert',
|
||||
text: 'Insert into message',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: entry => {
|
||||
const upload = entry.uploadInfo;
|
||||
|
||||
let text;
|
||||
if(upload.isImage()) {
|
||||
text = `[img]${upload.url}[/img]`;
|
||||
} else if(upload.isAudio()) {
|
||||
text = `[audio]${upload.url}[/audio]`;
|
||||
} else if(upload.isVideo()) {
|
||||
text = `[video]${upload.url}[/video]`;
|
||||
} else
|
||||
text = location.protocol + upload.url;
|
||||
sbUploads.addOption({
|
||||
name: 'view',
|
||||
text: 'View upload',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: entry => window.open(entry.uploadInfo.url),
|
||||
});
|
||||
sbUploads.addOption({
|
||||
name: 'insert',
|
||||
text: 'Insert into message',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: entry => {
|
||||
const upload = entry.uploadInfo;
|
||||
|
||||
chatForm.input.insertAtCursor(text);
|
||||
},
|
||||
});
|
||||
sbUploads.addOption({
|
||||
name: 'delete',
|
||||
text: 'Delete upload',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: async entry => {
|
||||
try {
|
||||
await ctx.eeprom.delete(entry.uploadInfo);
|
||||
sbUploads.deleteEntry(entry);
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
await ctx.msgbox.show({ body: ['An error occurred while trying to delete an uploaded file:', ex] });
|
||||
}
|
||||
},
|
||||
});
|
||||
let text;
|
||||
if(upload.isImage()) {
|
||||
text = `[img]${upload.url}[/img]`;
|
||||
} else if(upload.isAudio()) {
|
||||
text = `[audio]${upload.url}[/audio]`;
|
||||
} else if(upload.isVideo()) {
|
||||
text = `[video]${upload.url}[/video]`;
|
||||
} else
|
||||
text = location.protocol + upload.url;
|
||||
|
||||
doUpload = async file => {
|
||||
const entry = sbUploads.createEntry(file);
|
||||
chatForm.input.insertAtCursor(text);
|
||||
},
|
||||
});
|
||||
sbUploads.addOption({
|
||||
name: 'delete',
|
||||
text: 'Delete upload',
|
||||
condition: entry => entry.uploadInfo !== undefined,
|
||||
onclick: async entry => {
|
||||
try {
|
||||
await ctx.eeprom.delete(entry.uploadInfo);
|
||||
sbUploads.deleteEntry(entry);
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
await ctx.msgbox.show({ body: ['An error occurred while trying to delete an uploaded file:', ex] });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const task = ctx.eeprom.create(file);
|
||||
task.onProgress(prog => {
|
||||
entry.progress = prog.progress;
|
||||
});
|
||||
entry.addOption({
|
||||
name: 'cancel',
|
||||
text: 'Cancel upload',
|
||||
onclick: () => { task.abort(); },
|
||||
});
|
||||
const doUpload = async file => {
|
||||
const entry = sbUploads.createEntry(file);
|
||||
|
||||
try {
|
||||
const fileInfo = await task.start();
|
||||
|
||||
entry.optionsVisible = false;
|
||||
entry.uploadInfo = fileInfo;
|
||||
entry.removeOption('cancel');
|
||||
entry.nukeProgress();
|
||||
sbUploads.reloadOptionsFor(entry);
|
||||
|
||||
if(settings.get('eepromAutoInsert'))
|
||||
entry.clickOption('insert');
|
||||
} catch(ex) {
|
||||
if(!ex.aborted) {
|
||||
console.error(ex);
|
||||
ctx.msgbox.show({ body: ['An error occurred while trying to upload a file:', ex] });
|
||||
}
|
||||
|
||||
sbUploads.deleteEntry(entry);
|
||||
}
|
||||
};
|
||||
|
||||
const uploadForm = $e({
|
||||
tag: 'input',
|
||||
attrs: {
|
||||
type: 'file',
|
||||
multiple: true,
|
||||
style: { display: 'none' },
|
||||
onchange: ev => {
|
||||
for(const file of ev.target.files)
|
||||
doUpload(file);
|
||||
},
|
||||
},
|
||||
});
|
||||
args.parent.appendChild(uploadForm);
|
||||
|
||||
chatForm.input.createButton({
|
||||
title: 'Upload',
|
||||
icon: 'fas fa-file-upload',
|
||||
onclick: () => { uploadForm.click(); },
|
||||
});
|
||||
|
||||
ctx.events.watch('form:upload', ev => {
|
||||
console.info(ev);
|
||||
for(const file of ev.detail.files)
|
||||
doUpload(file);
|
||||
});
|
||||
const task = ctx.eeprom.create(file);
|
||||
task.onProgress(prog => {
|
||||
entry.progress = prog.progress;
|
||||
});
|
||||
entry.addOption({
|
||||
name: 'cancel',
|
||||
text: 'Cancel upload',
|
||||
onclick: () => { task.abort(); },
|
||||
});
|
||||
|
||||
try {
|
||||
const fileInfo = await task.start();
|
||||
|
||||
entry.optionsVisible = false;
|
||||
entry.uploadInfo = fileInfo;
|
||||
entry.removeOption('cancel');
|
||||
entry.nukeProgress();
|
||||
sbUploads.reloadOptionsFor(entry);
|
||||
|
||||
if(settings.get('eepromAutoInsert'))
|
||||
entry.clickOption('insert');
|
||||
} catch(ex) {
|
||||
if(!ex.aborted) {
|
||||
console.error(ex);
|
||||
ctx.msgbox.show({ body: ['An error occurred while trying to upload a file:', ex] });
|
||||
}
|
||||
|
||||
sbUploads.deleteEntry(entry);
|
||||
}
|
||||
};
|
||||
|
||||
const uploadForm = $e({
|
||||
tag: 'input',
|
||||
attrs: {
|
||||
type: 'file',
|
||||
multiple: true,
|
||||
style: { display: 'none' },
|
||||
onchange: ev => {
|
||||
for(const file of ev.target.files)
|
||||
doUpload(file);
|
||||
},
|
||||
},
|
||||
});
|
||||
args.parent.appendChild(uploadForm);
|
||||
|
||||
chatForm.input.createButton({
|
||||
title: 'Upload',
|
||||
icon: 'fas fa-file-upload',
|
||||
onclick: () => { uploadForm.click(); },
|
||||
});
|
||||
|
||||
ctx.events.watch('form:upload', ev => {
|
||||
console.info(ev);
|
||||
for(const file of ev.detail.files)
|
||||
doUpload(file);
|
||||
});
|
||||
|
||||
// figure out how to display a UI for this someday
|
||||
//args.parent.addEventListener('dragenter', ev => { console.info('dragenter', ev); });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue