Add a rageshake function to download the logs locally

For https://github.com/vector-im/riot-web/issues/3304

This generates something similar to what the rageshake server does, just in an easy package for people to use. tar-js was chosen over zip or anything else because it's small, simple, and stable. 

Note: this doesn't work in Chrome, but firefox seems to be okay with it. Chrome appears to be blocking the  download for some reason - the very first download was fine, but none afterwards
This commit is contained in:
Travis Ralston 2020-01-15 23:22:31 -07:00
parent cad9562f8d
commit 01a7a6987e
4 changed files with 95 additions and 20 deletions

View file

@ -97,6 +97,7 @@
"react-gemini-scrollbar": "github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594",
"resize-observer-polyfill": "^1.5.0",
"sanitize-html": "^1.18.4",
"tar-js": "^0.3.0",
"text-encoding-utf-8": "^1.0.1",
"url": "^0.11.0",
"velocity-animate": "^1.5.2",

View file

@ -418,6 +418,7 @@
"Collecting app version information": "Collecting app version information",
"Collecting logs": "Collecting logs",
"Uploading report": "Uploading report",
"Downloading report": "Downloading report",
"Waiting for response from server": "Waiting for response from server",
"Messages containing my display name": "Messages containing my display name",
"Messages containing my username": "Messages containing my username",

View file

@ -21,6 +21,7 @@ import pako from 'pako';
import {MatrixClientPeg} from '../MatrixClientPeg';
import PlatformPeg from '../PlatformPeg';
import { _t } from '../languageHandler';
import Tar from "tar-js";
import * as rageshake from './rageshake';
@ -33,26 +34,7 @@ if (!TextEncoder) {
TextEncoder = TextEncodingUtf8.TextEncoder;
}
/**
* Send a bug report.
*
* @param {string} bugReportEndpoint HTTP url to send the report to
*
* @param {object} opts optional dictionary of options
*
* @param {string} opts.userText Any additional user input.
*
* @param {boolean} opts.sendLogs True to send logs
*
* @param {function(string)} opts.progressCallback Callback to call with progress updates
*
* @return {Promise} Resolved when the bug report is sent.
*/
export default async function sendBugReport(bugReportEndpoint, opts) {
if (!bugReportEndpoint) {
throw new Error("No bug report endpoint has been set.");
}
async function collectBugReport(opts) {
opts = opts || {};
const progressCallback = opts.progressCallback || (() => {});
@ -106,10 +88,96 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
}
}
return body;
}
/**
* Send a bug report.
*
* @param {string} bugReportEndpoint HTTP url to send the report to
*
* @param {object} opts optional dictionary of options
*
* @param {string} opts.userText Any additional user input.
*
* @param {boolean} opts.sendLogs True to send logs
*
* @param {function(string)} opts.progressCallback Callback to call with progress updates
*
* @return {Promise} Resolved when the bug report is sent.
*/
export default async function sendBugReport(bugReportEndpoint, opts) {
if (!bugReportEndpoint) {
throw new Error("No bug report endpoint has been set.");
}
opts = opts || {};
const progressCallback = opts.progressCallback || (() => {});
const body = await collectBugReport(opts);
progressCallback(_t("Uploading report"));
await _submitReport(bugReportEndpoint, body, progressCallback);
}
/**
* Downloads the files from a bug report. This is the same as sendBugReport,
* but instead causes the browser to download the files locally.
*
* @param {object} opts optional dictionary of options
*
* @param {string} opts.userText Any additional user input.
*
* @param {boolean} opts.sendLogs True to send logs
*
* @param {function(string)} opts.progressCallback Callback to call with progress updates
*
* @return {Promise} Resolved when the bug report is downloaded (or started).
*/
export async function downloadBugReport(opts) {
opts = opts || {};
const progressCallback = opts.progressCallback || (() => {});
const body = await collectBugReport(opts);
progressCallback(_t("Downloading report"));
let metadata = "";
const tape = new Tar();
let i = 0;
for (const e of body.entries()) {
if (e[0] === 'compressed-log') {
await new Promise((resolve => {
const reader = new FileReader();
reader.addEventListener('loadend', ev => {
tape.append(`log-${i++}.log`, pako.ungzip(ev.target.result));
resolve();
});
reader.readAsArrayBuffer(e[1]);
}))
} else {
metadata += `${e[0]} = ${e[1]}\n`;
}
}
tape.append('issue.txt', metadata);
// We have to create a new anchor to download if we want a filename. Otherwise we could
// just use window.open.
const dl = document.createElement('a');
dl.href = `data:application/octet-stream;base64,${btoa(uint8ToString(tape.out))}`;
dl.download = 'rageshake.tar';
document.body.appendChild(dl);
dl.click();
document.body.removeChild(dl);
}
// Source: https://github.com/beatgammit/tar-js/blob/master/examples/main.js
function uint8ToString(buf) {
let i, length, out = '';
for (i = 0, length = buf.length; i < length; i += 1) {
out += String.fromCharCode(buf[i]);
}
return out;
}
function _submitReport(endpoint, body, progressCallback) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();

View file

@ -8251,6 +8251,11 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tar-js@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/tar-js/-/tar-js-0.3.0.tgz#6949aabfb0ba18bb1562ae51a439fd0f30183a17"
integrity sha1-aUmqv7C6GLsVYq5RpDn9DzAYOhc=
tar@^4:
version "4.4.13"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"