Skip to content

Commit

Permalink
implemented amplitude metrics (mozilla#1141)
Browse files Browse the repository at this point in the history
  • Loading branch information
dannycoates authored Feb 12, 2019
1 parent 1a483ca commit 9b37e92
Show file tree
Hide file tree
Showing 26 changed files with 782 additions and 536 deletions.
8 changes: 7 additions & 1 deletion app/archive.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global LIMITS */
/* global LIMITS DEFAULTS */
import { blobStream, concatStream } from './streams';

function isDupe(newFile, array) {
Expand All @@ -17,6 +17,9 @@ function isDupe(newFile, array) {
export default class Archive {
constructor(files = []) {
this.files = Array.from(files);
this.timeLimit = DEFAULTS.EXPIRE_SECONDS;
this.dlimit = 1;
this.password = null;
}

get name() {
Expand Down Expand Up @@ -73,5 +76,8 @@ export default class Archive {

clear() {
this.files = [];
this.dlimit = 1;
this.timeLimit = DEFAULTS.EXPIRE_SECONDS;
this.password = null;
}
}
120 changes: 63 additions & 57 deletions app/controller.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global DEFAULTS LIMITS */
/* global LIMITS */
import FileSender from './fileSender';
import FileReceiver from './fileReceiver';
import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
Expand Down Expand Up @@ -50,37 +50,27 @@ export default function(state, emitter) {

emitter.on('logout', () => {
state.user.logout();
state.timeLimit = DEFAULTS.EXPIRE_SECONDS;
state.downloadCount = 1;
metrics.loggedOut({ trigger: 'button' });
emitter.emit('pushState', '/');
});

emitter.on('changeLimit', async ({ file, value }) => {
const ok = await file.changeLimit(value, state.user);
if (!ok) {
return;
}
state.storage.writeFile(file);
metrics.changedDownloadLimit(file);
});

emitter.on('removeUpload', file => {
state.archive.remove(file);
render();
});

emitter.on('delete', async ({ file, location }) => {
emitter.on('delete', async ownedFile => {
try {
metrics.deletedUpload({
size: file.size,
time: file.time,
speed: file.speed,
type: file.type,
ttl: file.expiresAt - Date.now(),
size: ownedFile.size,
time: ownedFile.time,
speed: ownedFile.speed,
type: ownedFile.type,
ttl: ownedFile.expiresAt - Date.now(),
location
});
state.storage.remove(file.id);
await file.del();
state.storage.remove(ownedFile.id);
await ownedFile.del();
} catch (e) {
state.raven.captureException(e);
}
Expand All @@ -100,20 +90,35 @@ export default function(state, emitter) {
state.archive.addFiles(files, maxSize);
} catch (e) {
if (e.message === 'fileTooBig' && maxSize < LIMITS.MAX_FILE_SIZE) {
state.modal = signupDialog();
} else {
state.modal = okDialog(
state.translate(e.message, {
size: bytes(maxSize),
count: LIMITS.MAX_FILES_PER_ARCHIVE
})
);
return emitter.emit('signup-cta', 'size');
}
state.modal = okDialog(
state.translate(e.message, {
size: bytes(maxSize),
count: LIMITS.MAX_FILES_PER_ARCHIVE
})
);
}
render();
});

emitter.on('upload', async ({ type, dlimit, password }) => {
emitter.on('signup-cta', source => {
state.modal = signupDialog(source);
render();
});

emitter.on('authenticate', async (code, oauthState) => {
try {
await state.user.finishLogin(code, oauthState);
await state.user.syncFileList();
emitter.emit('replaceState', '/');
} catch (e) {
emitter.emit('replaceState', '/error');
setTimeout(render);
}
});

emitter.on('upload', async () => {
if (state.storage.files.length >= LIMITS.MAX_ARCHIVES_PER_USER) {
state.modal = okDialog(
state.translate('tooManyArchives', {
Expand All @@ -122,8 +127,7 @@ export default function(state, emitter) {
);
return render();
}
const size = state.archive.size;
if (!state.timeLimit) state.timeLimit = DEFAULTS.EXPIRE_SECONDS;
const archive = state.archive;
const sender = new FileSender();

sender.on('progress', updateProgress);
Expand All @@ -135,41 +139,38 @@ export default function(state, emitter) {

const links = openLinksInNewTab();
await delay(200);
const start = Date.now();
try {
metrics.startedUpload({ size, type });

const ownedFile = await sender.upload(
state.archive,
state.timeLimit,
dlimit,
state.user.bearerToken
);
ownedFile.type = type;
const ownedFile = await sender.upload(archive, state.user.bearerToken);
state.storage.totalUploads += 1;
metrics.completedUpload(ownedFile);
const duration = Date.now() - start;
metrics.completedUpload(archive, duration);

state.storage.addFile(ownedFile);
// TODO integrate password into /upload request
if (password) {
emitter.emit('password', { password, file: ownedFile });
if (archive.password) {
emitter.emit('password', {
password: archive.password,
file: ownedFile
});
}
state.modal = copyDialog(ownedFile.name, ownedFile.url);
} catch (err) {
if (err.message === '0') {
//cancelled. do nothing
metrics.cancelledUpload({ size, type });
const duration = Date.now() - start;
metrics.cancelledUpload(archive, duration);
render();
} else {
// eslint-disable-next-line no-console
console.error(err);
state.raven.captureException(err);
metrics.stoppedUpload({ size, type, err });
metrics.stoppedUpload(archive);
emitter.emit('pushState', '/error');
}
} finally {
openLinksInNewTab(links, false);
state.archive.clear();
state.password = '';
archive.clear();
state.uploading = false;
state.transfer = null;
await state.user.syncFileList();
Expand All @@ -183,7 +184,6 @@ export default function(state, emitter) {
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
Expand Down Expand Up @@ -220,31 +220,37 @@ export default function(state, emitter) {
state.transfer.on('complete', render);
const links = openLinksInNewTab();
const size = file.size;
const start = Date.now();
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);
state.storage.totalDownloads += 1;
metrics.completedDownload({ size, time, speed });
const duration = Date.now() - start;
metrics.completedDownload({
size,
duration,
password_protected: file.requiresPassword
});
} 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 });
const duration = Date.now() - start;
metrics.stoppedDownload({
size,
duration,
password_protected: file.requiresPassword
});
}
emitter.emit('pushState', location);
}
Expand All @@ -253,9 +259,9 @@ export default function(state, emitter) {
}
});

emitter.on('copy', ({ url, location }) => {
emitter.on('copy', ({ url }) => {
copyToClipboard(url);
metrics.copiedLink({ location });
// metrics.copiedLink({ location });
});

setInterval(() => {
Expand Down
32 changes: 13 additions & 19 deletions app/fileSender.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global DEFAULTS */
import Nanobus from 'nanobus';
import OwnedFile from './ownedFile';
import Keychain from './keychain';
Expand Down Expand Up @@ -42,29 +41,24 @@ export default class FileSender extends Nanobus {
}
}

async upload(
file,
timeLimit = DEFAULTS.EXPIRE_SECONDS,
dlimit = 1,
bearerToken
) {
async upload(archive, bearerToken) {
const start = Date.now();
if (this.cancelled) {
throw new Error(0);
}
this.msg = 'encryptingFile';
this.emit('encrypting');
const totalSize = encryptedSize(file.size);
const encStream = await this.keychain.encryptStream(file.stream);
const metadata = await this.keychain.encryptMetadata(file);
const totalSize = encryptedSize(archive.size);
const encStream = await this.keychain.encryptStream(archive.stream);
const metadata = await this.keychain.encryptMetadata(archive);
const authKeyB64 = await this.keychain.authKeyB64();

this.uploadRequest = uploadWs(
encStream,
metadata,
authKeyB64,
timeLimit,
dlimit,
archive.timeLimit,
archive.dlimit,
bearerToken,
p => {
this.progress = [p, totalSize];
Expand All @@ -88,18 +82,18 @@ export default class FileSender extends Nanobus {
const ownedFile = new OwnedFile({
id: result.id,
url: `${result.url}#${secretKey}`,
name: file.name,
size: file.size,
manifest: file.manifest,
name: archive.name,
size: archive.size,
manifest: archive.manifest,
time: time,
speed: file.size / (time / 1000),
speed: archive.size / (time / 1000),
createdAt: Date.now(),
expiresAt: Date.now() + timeLimit * 1000,
expiresAt: Date.now() + archive.timeLimit * 1000,
secretKey: secretKey,
nonce: this.keychain.nonce,
ownerToken: result.ownerToken,
dlimit,
timeLimit: timeLimit
dlimit: archive.dlimit,
timeLimit: archive.timeLimit
});

return ownedFile;
Expand Down
Loading

0 comments on commit 9b37e92

Please sign in to comment.