diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/platform.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/platform.js | 83 |
1 files changed, 74 insertions, 9 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/platform.js b/packages/meshbay-hub/src/meshbay_hub/static/platform.js index 4b507dc..47e3a72 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/platform.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/platform.js @@ -238,21 +238,84 @@ export const push = { export const photoSync = { available: Boolean(bridge && bridge.photoSync), status() { return bridge.photoSync.status(); }, - permit() { return bridge.photoSync.permit(); }, - albums() { return bridge.photoSync.albums(); }, + permit(withVideos) { return bridge.photoSync.permit(withVideos); }, + albums(withVideos) { return bridge.photoSync.albums(withVideos); }, configure(settings) { return bridge.photoSync.configure(settings); }, estimate(settings) { return bridge.photoSync.estimate(settings); }, plan() { return bridge.photoSync.plan(); }, sent(token, dir, name) { return bridge.photoSync.sent(token, dir, name); }, + manifest() { return bridge.photoSync.manifest(); }, + manifestSent(token) { return bridge.photoSync.manifestSent(token); }, completed() { return bridge.photoSync.completed(); }, failed(code, text) { return bridge.photoSync.failed(code, text); }, keepAlive(on, text) { return bridge.photoSync.keepAlive(on, text); }, - /** The bytes of a photo the last plan issued, as a File named for the node. */ - async file(token, name) { - const r = await fetch(`/photosync/${encodeURIComponent(token)}`, { cache: 'no-store' }); - if (!r.ok) throw new Error('This photo is no longer on the phone'); - return new File([await r.blob()], name); - }, + file: (token, name, size) => rangedFile('/photosync/', token, name, size), +}; + +/** + * A file the phone issued under `token`, as what an upload reads (`name`, + * `size`, `slice(a, b).arrayBuffer()`): each slice is fetched from the phone + * when it is read, so a video of gigabytes is never whole in this page. The + * slice is in the address (`?range=a-b`), not a Range header: the WebView + * does not hand that header to the application that answers. + */ +function rangedFile(prefix, token, name, size) { + const url = `${prefix}${encodeURIComponent(token)}`; + const part = (start, end) => ({ + async arrayBuffer() { + if (end <= start) return new ArrayBuffer(0); + const r = await fetch(`${url}?range=${start}-${end - 1}`, { cache: 'no-store' }); + if (!r.ok) throw new Error('This file is no longer on the phone'); + return r.arrayBuffer(); + }, + }); + return { + name, size, + slice: (a = 0, b = size) => part(Math.max(0, a), Math.min(b, size)), + }; +} + +/** + * Backing up folders the person chose through the system's picker + * (docs/MESHBAY_DESIGN.md §9.13), to the destination every kind shares. + * Android only, like `photoSync`. See drive-sync.js. + */ +const driveBridge = bridge && bridge.driveSync; +export const driveSync = { + available: Boolean(driveBridge), + status() { return driveBridge.status(); }, + addFolder() { return driveBridge.addFolder(); }, + removeFolder(id) { return driveBridge.removeFolder(id); }, + configure(settings) { return driveBridge.configure(settings); }, + plan() { return driveBridge.plan(); }, + sent(token, dir, name) { return driveBridge.sent(token, dir, name); }, + manifest() { return driveBridge.manifest(); }, + manifestSent(token) { return driveBridge.manifestSent(token); }, + completed() { return driveBridge.completed(); }, + failed(code, text) { return driveBridge.failed(code, text); }, + keepAlive(on, text) { return driveBridge.keepAlive(on, text); }, + file: (token, name, size) => rangedFile('/drivesync/', token, name, size), +}; + +/** + * Backing up WhatsApp's own folder, chosen once through the picker (its + * encrypted chat backups, and its media if asked), like `driveSync`. + */ +const waBridge = bridge && bridge.whatsappSync; +export const whatsappSync = { + available: Boolean(waBridge), + status() { return waBridge.status(); }, + chooseFolder() { return waBridge.chooseFolder(); }, + forgetFolder(id) { return waBridge.forgetFolder(id); }, + configure(settings) { return waBridge.configure(settings); }, + plan() { return waBridge.plan(); }, + sent(token, dir, name) { return waBridge.sent(token, dir, name); }, + manifest() { return waBridge.manifest(); }, + manifestSent(token) { return waBridge.manifestSent(token); }, + completed() { return waBridge.completed(); }, + failed(code, text) { return waBridge.failed(code, text); }, + keepAlive(on, text) { return waBridge.keepAlive(on, text); }, + file: (token, name, size) => rangedFile('/wasync/', token, name, size), }; /** @@ -267,7 +330,7 @@ export const phoneSync = { }; /** - * Backing up one kind of this phone's data (contacts, messages) to the destination + * Backing up one kind of this phone's data (contacts, calendar, messages) to the destination * every kind shares (docs/MESHBAY_DESIGN.md §9.13). Android only, like * `photoSync`. See phone-sync.js. */ @@ -282,6 +345,7 @@ function docSync(name) { sent(token, dir, n) { return b.sent(token, dir, n); }, completed() { return b.completed(); }, failed(code, text) { return b.failed(code, text); }, + openSettings() { return b.openSettings(); }, /** The file the last plan wrote, as a File named for the node. */ async file(token, fileName) { const r = await fetch(`/phonesync/${encodeURIComponent(token)}`, { cache: 'no-store' }); @@ -292,6 +356,7 @@ function docSync(name) { } export const contactSync = docSync('contactSync'); +export const calendarSync = docSync('calendarSync'); /** Absent from the Play build, whose policy keeps text messages from it. */ export const messageSync = docSync('messageSync'); |