Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 77f6905

Browse files
committed
move to fetch from xmlhttpreq for better async
1 parent 85bf40a commit 77f6905

1 file changed

Lines changed: 118 additions & 120 deletions

File tree

runestone/activecode/js/livecode.js

Lines changed: 118 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,28 @@ export default class LiveCode extends ActiveCode {
4444
this.stdin_el = input;
4545
}
4646
createErrorOutput() {}
47+
48+
/* Main runProg method for livecode
49+
*
50+
*/
51+
async runProg() {
52+
await this.runSetup();
53+
try {
54+
let res = await this.submitToJobe();
55+
let runResults = await res.json();
56+
this.processJobeResponse(runResults);
57+
} catch (e) {
58+
this.addJobeErrorMessage($.i18n("msg_activecode_server_comm_err"));
59+
$(this.runButton).removeAttr("disabled");
60+
}
61+
return Promise.resolve("done");
62+
}
4763
/**
4864
* Note:
4965
* In order to check for supplemental files in java and deal with asynchronicity
5066
* I split the original runProg into two functions: runProg and runProg_callback
5167
*/
52-
async runProg() {
68+
async runSetup() {
5369
var stdin;
5470
var scrubber_dfd, history_dfd;
5571
var source;
@@ -64,9 +80,11 @@ export default class LiveCode extends ActiveCode {
6480
};
6581
var sourcefilename = "";
6682
var testdrivername = "";
83+
var file_checkp;
6784

85+
// extract the class names so files can be named properly
6886
if (this.suffix && this.language == "java") {
69-
let classMatch = new RegExp(/public class\s+(\w+)[\s+\{]/);
87+
let classMatch = new RegExp(/public class\s+(\w+)[\s+{]/);
7088
source = this.buildProg(false);
7189
let m = source.match(classMatch);
7290
if (m) {
@@ -80,18 +98,21 @@ export default class LiveCode extends ActiveCode {
8098
} else {
8199
source = this.buildProg(true);
82100
}
83-
// Validate the data is convertable to Base64. If not then error out now
101+
// Validate the data is convertible to Base64. If not then error out now
84102
try {
85-
let contentsb64 = btoa(source);
103+
btoa(source);
86104
} catch (e) {
87105
alert(
88106
"Error: Bad Characters in the activecode window. Likely a quote character that has been copy/pasted. 🙁"
89107
);
90108
return;
91109
}
110+
92111
var __ret = this.manage_scrubber(scrubber_dfd, history_dfd, saveCode);
93112
history_dfd = __ret.history_dfd;
94113
saveCode = __ret.saveCode;
114+
115+
// assemble parameters for JOBE
95116
var paramlist = [
96117
"compileargs",
97118
"linkargs",
@@ -115,6 +136,7 @@ export default class LiveCode extends ActiveCode {
115136
if (!this.sourcefile) {
116137
this.sourcefile = sfilemap[this.language];
117138
}
139+
118140
$(this.output).html($.i18n("msg_activecode_compiling_running"));
119141
var files = [];
120142
var content, base64;
@@ -179,7 +201,6 @@ export default class LiveCode extends ActiveCode {
179201
System.out.println("You got " + corr + " out of " + total + " correct. " + String.format("%.2f", (100.0 * corr / total)) + "%");
180202
}
181203
}
182-
183204
`;
184205
if (this.suffix && this.language == "java") {
185206
files.push({ name: sourcefilename, content: source });
@@ -202,8 +223,8 @@ export default class LiveCode extends ActiveCode {
202223
runspec.input = stdin;
203224
}
204225
if (files.length === 0) {
205-
let data = JSON.stringify({ run_spec: runspec });
206-
this.runProg_callback(data);
226+
this.json_runspec = JSON.stringify({ run_spec: runspec });
227+
file_checkp = Promise.resolve("ready");
207228
} else {
208229
runspec["file_list"] = [];
209230
var promises = [];
@@ -224,130 +245,107 @@ export default class LiveCode extends ActiveCode {
224245
})
225246
);
226247
}
227-
let data = JSON.stringify({ run_spec: runspec });
248+
this.json_runspec = JSON.stringify({ run_spec: runspec });
228249
this.div2id = instance.div2id;
229-
Promise.all(promises)
230-
.then(function () {
231-
// console.log("All files on Server");
232-
instance.runProg_callback(data);
233-
})
234-
.catch(function (err) {
235-
console.log("Error: " + err);
236-
});
250+
file_checkp = Promise.all(promises).catch(function (err) {
251+
console.log("Error: " + err);
252+
});
237253
}
254+
return file_checkp;
238255
}
239-
async runProg_callback(data) {
240-
var xhr;
241-
var host, source;
242-
var saveCode = "True";
243-
source = this.editor.getValue();
244-
xhr = new XMLHttpRequest();
245-
var result;
246-
host = this.JOBE_SERVER + this.resource;
247-
var odiv = this.output;
248-
var pdiv = this.outDiv;
256+
257+
/* Submit the assembled job to the JOBE server and await the results.
258+
*
259+
*/
260+
async submitToJobe() {
261+
var data = this.json_runspec;
262+
let host = this.JOBE_SERVER + this.resource;
249263
$(this.runButton).attr("disabled", "disabled");
250264
$(this.outDiv).show({ duration: 700, queue: false });
251265
$(this.errDiv).remove();
252266
$(this.output).css("visibility", "visible");
253-
xhr.open("POST", host, true);
254-
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
255-
xhr.setRequestHeader("Accept", "application/json");
256-
xhr.setRequestHeader("X-API-KEY", this.API_KEY);
257-
xhr.onload = function () {
258-
var logresult;
259-
$(this.runButton).removeAttr("disabled");
260-
try {
261-
result = JSON.parse(xhr.responseText);
262-
} catch (e) {
263-
result = {};
264-
result.outcome = -1;
265-
}
266-
if (result.outcome === 15) {
267-
logresult = "success";
268-
} else {
269-
logresult = result.outcome;
270-
}
271-
this.logRunEvent({
272-
div_id: this.divid,
273-
code: source,
274-
errinfo: logresult,
275-
to_save: saveCode,
276-
lang: this.language,
277-
event: "livecode",
278-
partner: this.partner,
279-
});
280-
switch (result.outcome) {
281-
case 15: {
282-
let parsedOutput = new JUnitTestParser(
283-
result.stdout,
284-
this.divid
285-
);
286-
$(odiv).html(parsedOutput.stdout);
287-
let rdiv = document.getElementById(
288-
`${this.divid}_unit_results`
289-
);
290-
if (rdiv) {
291-
rdiv.remove();
292-
}
293-
if (parsedOutput.table) {
294-
pdiv.appendChild(parsedOutput.table);
295-
}
296-
rdiv = document.getElementById(
297-
`${this.divid}_unit_results`
298-
);
299-
if (rdiv) {
300-
rdiv.appendChild(parsedOutput.pctString);
301-
}
302-
if (this.suffix) {
303-
if (parsedOutput.pct === undefined) {
304-
parsedOutput.pct = parsedOutput.passed = parsedOutput.failed = 0;
305-
}
306-
this.logBookEvent({
307-
event: "unittest",
308-
act: `percent:${parsedOutput.pct}:passed:${parsedOutput.passed}:failed:${parsedOutput.failed}`,
309-
div_id: this.divid,
310-
});
267+
268+
let headers = new Headers({
269+
"Content-type": "application/json; charset=utf-8",
270+
Accept: "application/json",
271+
"X-API-KEY": this.API_KEY,
272+
});
273+
let request = new Request(host, {
274+
method: "POST",
275+
headers: headers,
276+
body: data,
277+
});
278+
return fetch(request);
279+
280+
///$("#" + divid + "_errinfo").remove();
281+
}
282+
283+
processJobeResponse(result) {
284+
var logresult;
285+
var odiv = this.output;
286+
$(this.runButton).removeAttr("disabled");
287+
if (result.outcome === 15) {
288+
logresult = "success";
289+
} else {
290+
logresult = result.outcome;
291+
}
292+
this.saveCode = "True";
293+
this.errinfo = logresult;
294+
switch (result.outcome) {
295+
case 15: {
296+
let parsedOutput = new JUnitTestParser(
297+
result.stdout,
298+
this.divid
299+
);
300+
$(odiv).html(parsedOutput.stdout);
301+
if (this.suffix) {
302+
if (parsedOutput.pct === undefined) {
303+
parsedOutput.pct = parsedOutput.passed = parsedOutput.failed = 0;
311304
}
312-
break;
305+
this.unit_results = `percent:${parsedOutput.pct}:passed:${parsedOutput.passed}:failed:${parsedOutput.failed}`;
313306
}
314-
case 11: // compiler error
315-
$(odiv).html($.i18n("msg_activecode_were_compiling_err"));
316-
this.addJobeErrorMessage(result.cmpinfo);
317-
break;
318-
case 12: // run time error
319-
$(odiv).html(result.stdout.replace(/\n/g, "<br>"));
320-
if (result.stderr) {
321-
this.addJobeErrorMessage(result.stderr);
322-
}
323-
break;
324-
case 13: // time limit
325-
$(odiv).html(result.stdout.replace(/\n/g, "<br>"));
307+
break;
308+
}
309+
case 11: // compiler error
310+
$(odiv).html($.i18n("msg_activecode_were_compiling_err"));
311+
this.addJobeErrorMessage(result.cmpinfo);
312+
break;
313+
case 12: // run time error
314+
$(odiv).html(result.stdout.replace(/\n/g, "<br>"));
315+
if (result.stderr) {
316+
this.addJobeErrorMessage(result.stderr);
317+
}
318+
break;
319+
case 13: // time limit
320+
$(odiv).html(result.stdout.replace(/\n/g, "<br>"));
321+
this.addJobeErrorMessage(
322+
$.i18n("msg_activecode_time_limit_exc")
323+
);
324+
break;
325+
default:
326+
if (result.stderr) {
327+
$(odiv).html(result.stderr.replace(/\n/g, "<br>"));
328+
} else {
326329
this.addJobeErrorMessage(
327-
$.i18n("msg_activecode_time_limit_exc")
330+
$.i18n("msg_activecode_server_err")
328331
);
329-
break;
330-
default:
331-
if (result.stderr) {
332-
$(odiv).html(result.stderr.replace(/\n/g, "<br>"));
333-
} else {
334-
this.addJobeErrorMessage(
335-
$.i18n(
336-
"msg_activecode_server_err",
337-
xhr.status,
338-
xhr.statusText
339-
)
340-
);
341-
}
342-
}
343-
// todo: handle server busy and timeout errors too
344-
}.bind(this);
345-
///$("#" + divid + "_errinfo").remove();
346-
xhr.onerror = function () {
347-
this.addJobeErrorMessage($.i18n("msg_activecode_server_comm_err"));
348-
$(this.runButton).removeAttr("disabled");
349-
}.bind(this);
350-
xhr.send(data);
332+
}
333+
}
334+
// todo: handle server busy and timeout errors too
335+
}
336+
337+
renderFeedback() {
338+
let rdiv = document.getElementById(`${this.divid}_unit_results`);
339+
if (rdiv) {
340+
rdiv.remove();
341+
}
342+
if (this.parsedOutput.table) {
343+
this.outDiv.appendChild(this.parsedOutput.table);
344+
}
345+
rdiv = document.getElementById(`${this.divid}_unit_results`);
346+
if (rdiv) {
347+
rdiv.appendChild(this.parsedOutput.pctString);
348+
}
351349
}
352350

353351
addJobeErrorMessage(err) {

0 commit comments

Comments
 (0)