123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /* global MAXFILESIZE */
- import FileSender from './fileSender';
- import FileReceiver from './fileReceiver';
- import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
- import * as metrics from './metrics';
- import { hasPassword } from './api';
- import Archive from './archive';
- import { bytes } from './utils';
- export default function(state, emitter) {
- let lastRender = 0;
- let updateTitle = false;
- function render() {
- emitter.emit('render');
- }
- async function checkFiles() {
- const files = state.storage.files.slice();
- let rerender = false;
- for (const file of files) {
- const oldLimit = file.dlimit;
- const oldTotal = file.dtotal;
- await file.updateDownloadCount();
- if (file.dtotal === file.dlimit) {
- state.storage.remove(file.id);
- rerender = true;
- } else if (oldLimit !== file.dlimit || oldTotal !== file.dtotal) {
- rerender = true;
- }
- }
- if (rerender) {
- render();
- }
- }
- function updateProgress() {
- if (updateTitle) {
- emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
- }
- render();
- }
- emitter.on('DOMContentLoaded', () => {
- document.addEventListener('blur', () => (updateTitle = true));
- document.addEventListener('focus', () => {
- updateTitle = false;
- emitter.emit('DOMTitleChange', 'Firefox Send');
- });
- checkFiles();
- });
- emitter.on('navigate', checkFiles);
- emitter.on('render', () => {
- lastRender = Date.now();
- });
- emitter.on('changeLimit', async ({ file, value }) => {
- await file.changeLimit(value);
- state.storage.writeFile(file);
- metrics.changedDownloadLimit(file);
- });
- emitter.on('removeUpload', async ({ index }) => {
- state.archive.remove(index);
- render();
- });
- emitter.on('delete', async ({ file, location }) => {
- try {
- metrics.deletedUpload({
- size: file.size,
- time: file.time,
- speed: file.speed,
- type: file.type,
- ttl: file.expiresAt - Date.now(),
- location
- });
- state.storage.remove(file.id);
- await file.del();
- } catch (e) {
- state.raven.captureException(e);
- }
- });
- emitter.on('cancel', () => {
- state.transfer.cancel();
- });
- emitter.on('addFiles', async ({ files }) => {
- if (state.archive) {
- if (!state.archive.addFiles(files)) {
- // eslint-disable-next-line no-alert
- alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
- return;
- }
- } else {
- const archive = new Archive(files);
- if (!archive.checkSize()) {
- // eslint-disable-next-line no-alert
- alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
- return;
- }
- state.archive = archive;
- }
- render();
- });
- emitter.on('upload', async ({ type, dlCount, password }) => {
- if (!state.archive) return;
- const size = state.archive.size;
- const sender = new FileSender(state.archive);
- sender.on('progress', updateProgress);
- sender.on('encrypting', render);
- sender.on('complete', render);
- state.transfer = sender;
- state.uploading = true;
- render();
- const links = openLinksInNewTab();
- await delay(200);
- try {
- metrics.startedUpload({ size, type });
- const ownedFile = await sender.upload();
- ownedFile.type = type;
- state.storage.totalUploads += 1;
- metrics.completedUpload(ownedFile);
- state.storage.addFile(ownedFile);
- if (password) {
- emitter.emit('password', { password, file: ownedFile });
- }
- emitter.emit('changeLimit', { file: ownedFile, value: dlCount });
- const cancelBtn = document.getElementById('cancel-upload');
- if (cancelBtn) {
- cancelBtn.hidden = 'hidden';
- }
- if (document.querySelector('.page')) {
- await delay(1000);
- }
- emitter.emit('pushState', `/share/${ownedFile.id}`);
- } catch (err) {
- if (err.message === '0') {
- //cancelled. do nothing
- metrics.cancelledUpload({ size, type });
- render();
- } else {
- // eslint-disable-next-line no-console
- console.error(err);
- state.raven.captureException(err);
- metrics.stoppedUpload({ size, type, err });
- emitter.emit('pushState', '/error');
- }
- } finally {
- openLinksInNewTab(links, false);
- state.files = [];
- state.password = '';
- state.uploading = false;
- state.transfer = null;
- }
- });
- emitter.on('password', async ({ password, file }) => {
- try {
- state.settingPassword = true;
- render();
- await file.setPassword(password);
- state.storage.writeFile(file);
- metrics.addedPassword({ size: file.size });
- await delay(1000);
- } catch (err) {
- // eslint-disable-next-line no-console
- console.error(err);
- state.passwordSetError = err;
- } finally {
- state.settingPassword = false;
- }
- render();
- });
- emitter.on('getPasswordExist', async ({ id }) => {
- try {
- state.fileInfo = await hasPassword(id);
- render();
- } catch (e) {
- if (e.message === '404') {
- return emitter.emit('pushState', '/404');
- }
- }
- });
- emitter.on('getMetadata', async () => {
- const file = state.fileInfo;
- const receiver = new FileReceiver(file);
- try {
- await receiver.getMetadata();
- state.transfer = receiver;
- } catch (e) {
- if (e.message === '401') {
- file.password = null;
- if (!file.requiresPassword) {
- return emitter.emit('pushState', '/404');
- }
- }
- }
- render();
- });
- emitter.on('download', async file => {
- state.transfer.on('progress', updateProgress);
- state.transfer.on('decrypting', render);
- state.transfer.on('complete', render);
- const links = openLinksInNewTab();
- const size = file.size;
- try {
- const start = Date.now();
- metrics.startedDownload({ size: file.size, ttl: file.ttl });
- const dl = state.transfer.download({
- stream: state.capabilities.streamDownload
- });
- render();
- await dl;
- const time = Date.now() - start;
- const speed = size / (time / 1000);
- if (document.querySelector('.page')) {
- await delay(1000);
- }
- state.storage.totalDownloads += 1;
- state.transfer.reset();
- metrics.completedDownload({ size, time, speed });
- } catch (err) {
- if (err.message === '0') {
- // download cancelled
- state.transfer.reset();
- render();
- } else {
- // eslint-disable-next-line no-console
- console.error(err);
- state.transfer = null;
- const location = err.message === '404' ? '/404' : '/error';
- if (location === '/error') {
- state.raven.captureException(err);
- metrics.stoppedDownload({ size, err });
- }
- emitter.emit('pushState', location);
- }
- } finally {
- openLinksInNewTab(links, false);
- }
- });
- emitter.on('copy', ({ url, location }) => {
- copyToClipboard(url);
- 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 (
- state.route === '/' &&
- state.storage.files.length > 0 &&
- Date.now() - lastRender > 30000
- ) {
- render();
- }
- }, 60000);
- }
|