Make AttProxy handle storing/loading the storage mapping object

This simplifies storage plugins as simple get/remove/save objects.
This commit is contained in:
Timothy Farrell 2018-06-22 07:59:06 -05:00
parent befe87dac2
commit a105cfb550
2 changed files with 53 additions and 45 deletions

View File

@ -1,9 +1,8 @@
import core from 'pouchdb-core'; import core from 'pouchdb-core';
import { PouchDBAttachmentProxy } from '../utils/attachmentProxy.js'; import { PouchDBAttachmentProxy } from '../utils/attachmentProxy.js';
import { deepAssign, blobToString } from '../utils/conversion.js'; import { deepAssign, blobToArrayBuffer } from '../utils/conversion.js';
import { prop, computed, stream } from 'frptools'; import { prop, computed, stream } from 'frptools';
import { sha1 } from '../utils/crypto.js';
const STORAGE_MIMETYPE = 'application/b2storagemap';
export const B2Adapter = function(b2apikey, b2secret, b2bucket) { export const B2Adapter = function(b2apikey, b2secret, b2bucket) {
const authDate = prop(null); const authDate = prop(null);
@ -72,62 +71,47 @@ export const B2Adapter = function(b2apikey, b2secret, b2bucket) {
return s.downloadUrl + '/b2api/v1/b2_download_file_by_id?fileId=' + fileId; return s.downloadUrl + '/b2api/v1/b2_download_file_by_id?fileId=' + fileId;
} }
async function readStorageMap(blob) {
return JSON.parse(await blobToString(blob));
}
return PouchDBAttachmentProxy({ return PouchDBAttachmentProxy({
getFn: async function getAttachment(docId, attName, att) { getFn: async function getAttachment(obj) {
if (att.type !== STORAGE_MIMETYPE) { const res = await fetch(await downloadUrl(obj.fileId), {
return att;
}
const storagemap = await readStorageMap(att);
const res = await fetch(await downloadUrl(storagemap.fileId), {
headers: await headers() headers: await headers()
}); });
return res.blob(); return res.blob();
}, },
remove: async function removeAttachment(docId, attName, rev, att) { remove: async function removeAttachment(obj) {
const s = await session(); const s = await session();
const storagemap = await readStorageMap(att);
return fetch('/api/v1/remove_file', { return fetch('/api/v1/remove_file', {
headers: await headers(), headers: await headers(),
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
fileName: storagemap.fileName, fileName: obj.fileName,
fileId: storagemap.fileId fileId: obj.fileId
}) })
}); });
}, },
save: async function saveAttachment(doc, attName, obj) { save: async function saveAttachment(blob) {
try { try {
const uploadAuth = await uploadAuthorization(); const uploadAuth = await uploadAuthorization();
const digest = await sha1(await blobToArrayBuffer(blob));
const res = await fetch(uploadAuth.uploadUrl, { const res = await fetch(uploadAuth.uploadUrl, {
method: 'POST', method: 'POST',
headers: await headers({ headers: await headers({
Authorization: uploadAuth.authorizationToken, Authorization: uploadAuth.authorizationToken,
'X-Bz-File-Name': encodeURIComponent(obj.data.name), 'X-Bz-File-Name': encodeURIComponent(blob.name),
'Content-Type': obj.data.type, 'Content-Type': blob.type,
'Content-Length': obj.data.size, 'Content-Length': blob.size,
'X-Bz-Content-Sha1': doc.digest 'X-Bz-Content-Sha1': digest
}), }),
body: obj.data body: blob
});
const resData = await res.json();
deepAssign(doc, {
_attachments: {
[attName]: {
content_type: STORAGE_MIMETYPE,
data: btoa(JSON.stringify(resData))
}
}
}); });
return {
ok: true,
id: await res.json()
};
} catch (e) { } catch (e) {
console.log('Error:', e);
return { ok: false, error: e }; return { ok: false, error: e };
} }
return { ok: true };
} }
}); });
}; };

View File

@ -1,9 +1,16 @@
import core from 'pouchdb-core'; import core from 'pouchdb-core';
import { backgroundTask } from '../utils/event.js'; import { backgroundTask } from '../utils/event.js';
import { deepAssign, blobToString } from '../utils/conversion.js';
import { error, log } from '../services/console.js';
const pouchBulkDocs = core.prototype.bulkDocs; const pouchBulkDocs = core.prototype.bulkDocs;
const pouchGetAttachment = core.prototype.getAttachment; const pouchGetAttachment = core.prototype.getAttachment;
const pouchRemoveAttachment = core.prototype.removeAttachment; const pouchRemoveAttachment = core.prototype.removeAttachment;
const STORAGE_MIMETYPE = 'application/b2storagemap';
async function readStorageMap(blob) {
return JSON.parse(await blobToString(blob));
}
export function PouchDBAttachmentProxy({ save, getFn, remove }) { export function PouchDBAttachmentProxy({ save, getFn, remove }) {
const override = {}; const override = {};
@ -11,18 +18,22 @@ export function PouchDBAttachmentProxy({ save, getFn, remove }) {
if (getFn) { if (getFn) {
override.getAttachment = async function getAttachment(...args) { override.getAttachment = async function getAttachment(...args) {
const att = await pouchGetAttachment.apply(this, args); const att = await pouchGetAttachment.apply(this, args);
return await getFn.apply(this, args.concat(att)); if (att.type !== STORAGE_MIMETYPE) {
return att;
}
return await getFn.call(this, await readStorageMap(att));
}; };
} }
if (remove) { if (remove) {
override.removeAttachment = async function removeAttachment(...args) { override.removeAttachment = async function removeAttachment(...args) {
const att = await pouchGetAttachment.apply(this, args); const att = await pouchGetAttachment.apply(this, args);
try { if (att.type === STORAGE_MIMETYPE) {
await remove.apply(this, args.concat(att)); try {
} catch (e) { await remove.call(this, await readStorageMap(att));
console.log('Error:', e); } catch (e) {
return; error(`Failed to remove attachment ${args}`, e);
}
} }
return await pouchRemoveAttachment.apply(this, args); return await pouchRemoveAttachment.apply(this, args);
}; };
@ -30,8 +41,6 @@ export function PouchDBAttachmentProxy({ save, getFn, remove }) {
if (save || remove) { if (save || remove) {
override.bulkDocs = function bulkDocs(...args) { override.bulkDocs = function bulkDocs(...args) {
console.log('fad', ...args);
let docs; let docs;
if (Array.isArray(args[0])) { if (Array.isArray(args[0])) {
docs = args[0]; docs = args[0];
@ -49,8 +58,8 @@ export function PouchDBAttachmentProxy({ save, getFn, remove }) {
return; return;
} }
if (f._attachments && f._attachments.data.data instanceof Blob) { if (f._attachments && f._attachments.data.data instanceof Blob) {
console.log(`Saving File ${f._id} attachment`); log(`Saving File ${f._id} attachment`);
attachments.push([f, 'data', f._attachments.data]); attachments.push([f, 'data', f._attachments.data.data]);
delete f._attachments.data; delete f._attachments.data;
} }
}); });
@ -58,7 +67,22 @@ export function PouchDBAttachmentProxy({ save, getFn, remove }) {
deletedFiles.forEach(cleanupFiles); deletedFiles.forEach(cleanupFiles);
return Promise.all( return Promise.all(
attachments.map(([doc, attName, obj]) => save.call(this, doc, attName, obj)) attachments.map(([doc, attName, blob]) =>
save.call(this, blob).then(resData => {
if (resData && resData.ok) {
deepAssign(doc, {
_attachments: {
[attName]: {
content_type: STORAGE_MIMETYPE,
data: btoa(JSON.stringify(resData.id))
}
}
});
} else {
error(`Failed to save attachment ${doc._id}[${attName}]`, resData);
}
})
)
).then(() => { ).then(() => {
return pouchBulkDocs.call(this, ...args); return pouchBulkDocs.call(this, ...args);
}); });