@@ -21,6 +21,7 @@ import pako from 'pako';
2121import { MatrixClientPeg } from '../MatrixClientPeg' ;
2222import PlatformPeg from '../PlatformPeg' ;
2323import { _t } from '../languageHandler' ;
24+ import Tar from "tar-js" ;
2425
2526import * as rageshake from './rageshake' ;
2627
@@ -33,26 +34,7 @@ if (!TextEncoder) {
3334 TextEncoder = TextEncodingUtf8 . TextEncoder ;
3435}
3536
36- /**
37- * Send a bug report.
38- *
39- * @param {string } bugReportEndpoint HTTP url to send the report to
40- *
41- * @param {object } opts optional dictionary of options
42- *
43- * @param {string } opts.userText Any additional user input.
44- *
45- * @param {boolean } opts.sendLogs True to send logs
46- *
47- * @param {function(string) } opts.progressCallback Callback to call with progress updates
48- *
49- * @return {Promise } Resolved when the bug report is sent.
50- */
51- export default async function sendBugReport ( bugReportEndpoint , opts ) {
52- if ( ! bugReportEndpoint ) {
53- throw new Error ( "No bug report endpoint has been set." ) ;
54- }
55-
37+ async function collectBugReport ( opts ) {
5638 opts = opts || { } ;
5739 const progressCallback = opts . progressCallback || ( ( ) => { } ) ;
5840
@@ -106,10 +88,96 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
10688 }
10789 }
10890
91+ return body ;
92+ }
93+
94+ /**
95+ * Send a bug report.
96+ *
97+ * @param {string } bugReportEndpoint HTTP url to send the report to
98+ *
99+ * @param {object } opts optional dictionary of options
100+ *
101+ * @param {string } opts.userText Any additional user input.
102+ *
103+ * @param {boolean } opts.sendLogs True to send logs
104+ *
105+ * @param {function(string) } opts.progressCallback Callback to call with progress updates
106+ *
107+ * @return {Promise } Resolved when the bug report is sent.
108+ */
109+ export default async function sendBugReport ( bugReportEndpoint , opts ) {
110+ if ( ! bugReportEndpoint ) {
111+ throw new Error ( "No bug report endpoint has been set." ) ;
112+ }
113+
114+ opts = opts || { } ;
115+ const progressCallback = opts . progressCallback || ( ( ) => { } ) ;
116+ const body = await collectBugReport ( opts ) ;
117+
109118 progressCallback ( _t ( "Uploading report" ) ) ;
110119 await _submitReport ( bugReportEndpoint , body , progressCallback ) ;
111120}
112121
122+ /**
123+ * Downloads the files from a bug report. This is the same as sendBugReport,
124+ * but instead causes the browser to download the files locally.
125+ *
126+ * @param {object } opts optional dictionary of options
127+ *
128+ * @param {string } opts.userText Any additional user input.
129+ *
130+ * @param {boolean } opts.sendLogs True to send logs
131+ *
132+ * @param {function(string) } opts.progressCallback Callback to call with progress updates
133+ *
134+ * @return {Promise } Resolved when the bug report is downloaded (or started).
135+ */
136+ export async function downloadBugReport ( opts ) {
137+ opts = opts || { } ;
138+ const progressCallback = opts . progressCallback || ( ( ) => { } ) ;
139+ const body = await collectBugReport ( opts ) ;
140+
141+ progressCallback ( _t ( "Downloading report" ) ) ;
142+ let metadata = "" ;
143+ const tape = new Tar ( ) ;
144+ let i = 0 ;
145+ for ( const e of body . entries ( ) ) {
146+ if ( e [ 0 ] === 'compressed-log' ) {
147+ await new Promise ( ( resolve => {
148+ const reader = new FileReader ( ) ;
149+ reader . addEventListener ( 'loadend' , ev => {
150+ tape . append ( `log-${ i ++ } .log` , pako . ungzip ( ev . target . result ) ) ;
151+ resolve ( ) ;
152+ } ) ;
153+ reader . readAsArrayBuffer ( e [ 1 ] ) ;
154+ } ) )
155+ } else {
156+ metadata += `${ e [ 0 ] } = ${ e [ 1 ] } \n` ;
157+ }
158+ }
159+ tape . append ( 'issue.txt' , metadata ) ;
160+
161+ // We have to create a new anchor to download if we want a filename. Otherwise we could
162+ // just use window.open.
163+ const dl = document . createElement ( 'a' ) ;
164+ dl . href = `data:application/octet-stream;base64,${ btoa ( uint8ToString ( tape . out ) ) } ` ;
165+ dl . download = 'rageshake.tar' ;
166+ document . body . appendChild ( dl ) ;
167+ dl . click ( ) ;
168+ document . body . removeChild ( dl ) ;
169+ }
170+
171+ // Source: https://github.com/beatgammit/tar-js/blob/master/examples/main.js
172+ function uint8ToString ( buf ) {
173+ let i , length , out = '' ;
174+ for ( i = 0 , length = buf . length ; i < length ; i += 1 ) {
175+ out += String . fromCharCode ( buf [ i ] ) ;
176+ }
177+
178+ return out ;
179+ }
180+
113181function _submitReport ( endpoint , body , progressCallback ) {
114182 return new Promise ( ( resolve , reject ) => {
115183 const req = new XMLHttpRequest ( ) ;
0 commit comments