big refactor

This commit is contained in:
Danny Coates 2018-01-24 10:23:13 -08:00
parent dd448cb3ed
commit 565e47aef8
No known key found for this signature in database
GPG key ID: 4C442633C62E00CB
37 changed files with 1095 additions and 943 deletions

View file

@ -1,51 +1,15 @@
/* global EXPIRE_SECONDS */
import FileSender from './fileSender';
import FileReceiver from './fileReceiver';
import { copyToClipboard, delay, fadeOut, percent } from './utils';
import {
copyToClipboard,
delay,
fadeOut,
openLinksInNewTab,
percent,
saveFile
} from './utils';
import * as metrics from './metrics';
function saveFile(file) {
const dataView = new DataView(file.plaintext);
const blob = new Blob([dataView], { type: file.type });
const downloadUrl = URL.createObjectURL(blob);
if (window.navigator.msSaveBlob) {
return window.navigator.msSaveBlob(blob, file.name);
}
const a = document.createElement('a');
a.href = downloadUrl;
a.download = file.name;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(downloadUrl);
}
function openLinksInNewTab(links, should = true) {
links = links || Array.from(document.querySelectorAll('a:not([target])'));
if (should) {
links.forEach(l => {
l.setAttribute('target', '_blank');
l.setAttribute('rel', 'noopener noreferrer');
});
} else {
links.forEach(l => {
l.removeAttribute('target');
l.removeAttribute('rel');
});
}
return links;
}
async function getDLCounts(file) {
const url = `/api/metadata/${file.id}`;
const receiver = new FileReceiver(url, file);
try {
await receiver.getMetadata(file.nonce);
return receiver.file;
} catch (e) {
if (e.message === '404') return false;
}
}
export default function(state, emitter) {
let lastRender = 0;
let updateTitle = false;
@ -60,14 +24,11 @@ export default function(state, emitter) {
for (const file of files) {
const oldLimit = file.dlimit;
const oldTotal = file.dtotal;
const receivedFile = await getDLCounts(file);
if (!receivedFile) {
await file.updateDownloadCount();
if (file.dtotal === file.dlimit) {
state.storage.remove(file.id);
rerender = true;
} else if (
oldLimit !== receivedFile.dlimit ||
oldTotal !== receivedFile.dtotal
) {
} else if (oldLimit !== file.dlimit || oldTotal !== file.dtotal) {
rerender = true;
}
}
@ -92,16 +53,15 @@ export default function(state, emitter) {
checkFiles();
});
emitter.on('navigate', checkFiles);
// emitter.on('navigate', checkFiles);
emitter.on('render', () => {
lastRender = Date.now();
});
emitter.on('changeLimit', async ({ file, value }) => {
await FileSender.changeLimit(file.id, file.ownerToken, value);
file.dlimit = value;
state.storage.writeFiles();
await file.changeLimit(value);
state.storage.writeFile(file);
metrics.changedDownloadLimit(file);
});
@ -116,11 +76,10 @@ export default function(state, emitter) {
location
});
state.storage.remove(file.id);
await FileSender.delete(file.id, file.ownerToken);
await file.del();
} catch (e) {
state.raven.captureException(e);
}
state.fileInfo = null;
});
emitter.on('cancel', () => {
@ -134,32 +93,24 @@ export default function(state, emitter) {
sender.on('encrypting', render);
state.transfer = sender;
render();
const links = openLinksInNewTab();
await delay(200);
try {
const start = Date.now();
metrics.startedUpload({ size, type });
const info = await sender.upload();
const time = Date.now() - start;
const speed = size / (time / 1000);
metrics.completedUpload({ size, time, speed, type });
const ownedFile = await sender.upload(state.storage);
state.storage.totalUploads += 1;
metrics.completedUpload(ownedFile);
state.storage.addFile(ownedFile);
document.getElementById('cancel-upload').hidden = 'hidden';
await delay(1000);
await fadeOut('upload-progress');
info.name = file.name;
info.size = size;
info.type = type;
info.time = time;
info.speed = speed;
info.createdAt = Date.now();
info.url = `${info.url}#${info.secretKey}`;
info.expiresAt = Date.now() + EXPIRE_SECONDS * 1000;
state.fileInfo = info;
state.storage.addFile(state.fileInfo);
openLinksInNewTab(links, false);
state.transfer = null;
state.storage.totalUploads += 1;
emitter.emit('pushState', `/share/${info.id}`);
emitter.emit('pushState', `/share/${ownedFile.id}`);
} catch (err) {
console.error(err);
state.transfer = null;
@ -174,31 +125,29 @@ export default function(state, emitter) {
}
});
emitter.on('password', async ({ existingPassword, password, file }) => {
emitter.on('password', async ({ password, file }) => {
try {
await FileSender.setPassword(existingPassword, password, file);
await file.setPassword(password);
state.storage.writeFile(file);
metrics.addedPassword({ size: file.size });
file.password = password;
state.storage.writeFiles();
} catch (e) {
console.error(e);
} catch (err) {
console.error(err);
}
render();
});
emitter.on('preview', async () => {
emitter.on('getMetadata', async () => {
const file = state.fileInfo;
const url = `/api/download/${file.id}`;
const receiver = new FileReceiver(url, file);
receiver.on('progress', updateProgress);
receiver.on('decrypting', render);
state.transfer = receiver;
const receiver = new FileReceiver(file);
try {
await receiver.getMetadata(file.nonce);
await receiver.getMetadata();
receiver.on('progress', updateProgress);
receiver.on('decrypting', render);
state.transfer = receiver;
} catch (e) {
if (e.message === '401') {
file.password = null;
if (!file.pwd) {
if (!file.requiresPassword) {
return emitter.emit('pushState', '/404');
}
}
@ -214,7 +163,7 @@ export default function(state, emitter) {
try {
const start = Date.now();
metrics.startedDownload({ size: file.size, ttl: file.ttl });
const f = await state.transfer.download(file.nonce);
const f = await state.transfer.download();
const time = Date.now() - start;
const speed = size / (time / 1000);
await delay(1000);
@ -225,8 +174,11 @@ export default function(state, emitter) {
metrics.completedDownload({ size, time, speed });
emitter.emit('pushState', '/completed');
} catch (err) {
if (err.message === '0') {
// download cancelled
return render();
}
console.error(err);
// TODO cancelled download
const location = err.message === 'notfound' ? '/404' : '/error';
if (location === '/error') {
state.raven.captureException(err);
@ -244,6 +196,14 @@ export default function(state, emitter) {
metrics.copiedLink({ location });
});
setInterval(() => {
// poll for updates of the download counts
// TODO something for the share page: || state.route === '/share/:id'
if (state.route === '/') {
checkFiles();
}
}, 2 * 60 * 1000);
setInterval(() => {
// poll for rerendering the file list countdown timers
if (