refactor uploading files

This commit is contained in:
zadam 2023-06-30 15:25:45 +02:00
parent 0802b81807
commit a0d958bf12
8 changed files with 77 additions and 108 deletions

View file

@ -315,14 +315,25 @@ class Froca {
}
/** @returns {Promise<FAttachment>} */
async getAttachment(attachmentId) {
async getAttachment(attachmentId, silentNotFoundError = false) {
const attachment = this.attachments[attachmentId];
if (attachment) {
return attachment;
}
// load all attachments for the given note even if one is requested, don't load one by one
const attachmentRows = await server.get(`attachments/${attachmentId}/all`);
let attachmentRows;
try {
attachmentRows = await server.get(`attachments/${attachmentId}/all`);
}
catch (e) {
if (silentNotFoundError) {
logInfo(`Attachment '${attachmentId} not found, but silentNotFoundError is enabled: ` + e.message);
} else {
throw e;
}
}
const attachments = this.processAttachmentRows(attachmentRows);
if (attachments.length) {

View file

@ -7,8 +7,6 @@ import froca from "./froca.js";
import linkService from "./link.js";
function setupGlobs() {
window.glob.PROFILING_LOG = false;
window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile;

View file

@ -1,8 +1,6 @@
import utils from './utils.js';
import ValidationError from "./validation_error.js";
const REQUEST_LOGGING_ENABLED = false;
async function getHeaders(headers) {
const appContext = (await import('../components/app_context.js')).default;
const activeNoteContext = appContext.tabManager ? appContext.tabManager.getActiveContext() : null;
@ -50,6 +48,21 @@ async function remove(url, componentId) {
return await call('DELETE', url, null, {'trilium-component-id': componentId});
}
async function upload(url, fileToUpload) {
const formData = new FormData();
formData.append('upload', fileToUpload);
return await $.ajax({
url: window.glob.baseApiUrl + url,
headers: await getHeaders(),
data: formData,
type: 'PUT',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
});
}
let i = 1;
const reqResolves = {};
const reqRejects = {};
@ -59,8 +72,6 @@ let maxKnownEntityChangeId = 0;
async function call(method, url, data, headers = {}) {
let resp;
const start = Date.now();
headers = await getHeaders(headers);
if (utils.isElectron()) {
@ -71,10 +82,6 @@ async function call(method, url, data, headers = {}) {
reqResolves[requestId] = resolve;
reqRejects[requestId] = reject;
if (REQUEST_LOGGING_ENABLED) {
console.log(utils.now(), `Request #${requestId} to ${method} ${url}`);
}
ipc.send('server-request', {
requestId: requestId,
headers: headers,
@ -88,12 +95,6 @@ async function call(method, url, data, headers = {}) {
resp = await ajax(url, method, data, headers);
}
const end = Date.now();
if (glob.PROFILING_LOG) {
console.log(`${method} ${url} took ${end - start}ms`);
}
const maxEntityChangeIdStr = resp.headers['trilium-max-entity-change-id'];
if (maxEntityChangeIdStr && maxEntityChangeIdStr.trim()) {
@ -103,33 +104,6 @@ async function call(method, url, data, headers = {}) {
return resp.body;
}
async function reportError(method, url, statusCode, response) {
const toastService = (await import("./toast.js")).default;
let message = response;
if (typeof response === 'string') {
try {
response = JSON.parse(response);
message = response.message;
}
catch (e) {}
}
if ([400, 404].includes(statusCode) && response && typeof response === 'object') {
toastService.showError(message);
throw new ValidationError({
requestUrl: url,
method,
statusCode,
...response
});
} else {
const title = `${statusCode} ${method} ${url}`;
toastService.showErrorTitleAndMessage(title, message);
toastService.throwError(`${title} - ${message}`);
}
}
function ajax(url, method, data, headers) {
return new Promise((res, rej) => {
const options = {
@ -175,24 +149,8 @@ if (utils.isElectron()) {
const ipc = utils.dynamicRequire('electron').ipcRenderer;
ipc.on('server-response', async (event, arg) => {
if (REQUEST_LOGGING_ENABLED) {
console.log(utils.now(), `Response #${arg.requestId}: ${arg.statusCode}`);
}
if (arg.statusCode >= 200 && arg.statusCode < 300) {
if (arg.headers['Content-Type'] === 'application/json') {
arg.body = JSON.parse(arg.body);
}
if (!(arg.requestId in reqResolves)) {
// this can happen when reload happens between firing up the request and receiving the response
throw new Error(`Unknown requestId="${arg.requestId}"`);
}
reqResolves[arg.requestId]({
body: arg.body,
headers: arg.headers
});
handleSuccessfulResponse(arg);
}
else {
await reportError(arg.method, arg.url, arg.statusCode, arg.body);
@ -203,6 +161,49 @@ if (utils.isElectron()) {
delete reqResolves[arg.requestId];
delete reqRejects[arg.requestId];
});
function handleSuccessfulResponse(arg) {
if (arg.headers['Content-Type'] === 'application/json') {
arg.body = JSON.parse(arg.body);
}
if (!(arg.requestId in reqResolves)) {
// this can happen when reload happens between firing up the request and receiving the response
throw new Error(`Unknown requestId="${arg.requestId}"`);
}
reqResolves[arg.requestId]({
body: arg.body,
headers: arg.headers
});
}
}
async function reportError(method, url, statusCode, response) {
const toastService = (await import("./toast.js")).default;
let message = response;
if (typeof response === 'string') {
try {
response = JSON.parse(response);
message = response.message;
}
catch (e) {}
}
if ([400, 404].includes(statusCode) && response && typeof response === 'object') {
toastService.showError(message);
throw new ValidationError({
requestUrl: url,
method,
statusCode,
...response
});
} else {
const title = `${statusCode} ${method} ${url}`;
toastService.showErrorTitleAndMessage(title, message);
toastService.throwError(`${title} - ${message}`);
}
}
export default {
@ -211,7 +212,7 @@ export default {
put,
patch,
remove,
ajax,
upload,
// don't remove, used from CKEditor image upload!
getHeaders,
getMaxKnownEntityChangeId: () => maxKnownEntityChangeId

View file

@ -64,18 +64,7 @@ export default class AttachmentActionsWidget extends BasicWidget {
const fileToUpload = this.$uploadNewRevisionInput[0].files[0]; // copy to allow reset below
this.$uploadNewRevisionInput.val('');
const formData = new FormData();
formData.append('upload', fileToUpload);
const result = await $.ajax({
url: `${window.glob.baseApiUrl}attachments/${this.attachmentId}/file`,
headers: await server.getHeaders(),
data: formData,
type: 'PUT',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
});
const result = await server.upload(`attachments/${this.attachmentId}/file`, fileToUpload);
if (result.uploaded) {
toastService.showMessage("New attachment revision has been uploaded.");

View file

@ -49,16 +49,8 @@ export default class NoteContextAwareWidget extends BasicWidget {
async refresh() {
if (this.isEnabled()) {
const start = Date.now();
this.toggleInt(true);
await this.refreshWithNote(this.note);
const end = Date.now();
if (glob.PROFILING_LOG && end - start > 10) {
console.log(`Refresh of ${this.componentId} took ${end-start}ms`);
}
}
else {
this.toggleInt(false);

View file

@ -100,18 +100,7 @@ export default class FilePropertiesWidget extends NoteContextAwareWidget {
const fileToUpload = this.$uploadNewRevisionInput[0].files[0]; // copy to allow reset below
this.$uploadNewRevisionInput.val('');
const formData = new FormData();
formData.append('upload', fileToUpload);
const result = await $.ajax({
url: `${window.glob.baseApiUrl}notes/${this.noteId}/file`,
headers: await server.getHeaders(),
data: formData,
type: 'PUT',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
});
const result = await server.upload(`notes/${this.noteId}/file`, fileToUpload);
if (result.uploaded) {
toastService.showMessage("New file revision has been uploaded.");

View file

@ -84,18 +84,7 @@ export default class ImagePropertiesWidget extends NoteContextAwareWidget {
const fileToUpload = this.$uploadNewRevisionInput[0].files[0]; // copy to allow reset below
this.$uploadNewRevisionInput.val('');
const formData = new FormData();
formData.append('upload', fileToUpload);
const result = await $.ajax({
url: `${window.glob.baseApiUrl}images/${this.noteId}`,
headers: await server.getHeaders(),
data: formData,
type: 'PUT',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
});
const result = await server.upload(`images/${this.noteId}`, fileToUpload);
if (result.uploaded) {
toastService.showMessage("New image revision has been uploaded.");

View file

@ -57,7 +57,7 @@ export default class AttachmentDetailTypeWidget extends TypeWidget {
})
);
const attachment = await froca.getAttachment(this.attachmentId);
const attachment = await froca.getAttachment(this.attachmentId, true);
if (!attachment) {
this.$wrapper.html("<strong>This attachment has been deleted.</strong>");