[extension] Improve code running
This commit is contained in:
parent
3d81cf91a6
commit
dfa16b714a
@ -70,8 +70,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
const resData = await res.json();
|
const resData = await res.json();
|
||||||
if (resData.success !== true) {
|
if (res.status !== 200 || resData.success !== true) {
|
||||||
throw new Error(resData.error.message);
|
vscode.window.showErrorMessage('BWContest: Invalid Login');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const sessionToken = resData.token;
|
const sessionToken = resData.token;
|
||||||
this.context.globalState.update('token', sessionToken);
|
this.context.globalState.update('token', sessionToken);
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { getNonce } from './getNonce';
|
import { getNonce } from './getNonce';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
|
import { extensionSettings } from './extension';
|
||||||
|
import { runJava } from './run/java';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { TeamData } from './SidebarProvider';
|
||||||
|
|
||||||
export type ProblemData = {
|
export type ProblemData = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -10,8 +14,21 @@ export type ProblemData = {
|
|||||||
sampleOutput: string;
|
sampleOutput: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
export type MessageType = { msg: 'onRequestProblemData' };
|
export type MessageType =
|
||||||
export type WebviewMessageType = { msg: 'onProblemData'; data: ProblemData };
|
| { msg: 'onRequestProblemData' }
|
||||||
|
| { msg: 'onRun'; data: { problemId: number; input: string } }
|
||||||
|
| { msg: 'onKill' };
|
||||||
|
export type WebviewMessageType =
|
||||||
|
| { msg: 'onProblemData'; data: ProblemData }
|
||||||
|
| { msg: 'onRunning' }
|
||||||
|
| { msg: 'onRunningDone' }
|
||||||
|
| { msg: 'onRunningOutput'; data: string };
|
||||||
|
|
||||||
|
type RunningProgram = {
|
||||||
|
problemId: number;
|
||||||
|
outputBuffer: string[];
|
||||||
|
kill: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton class for problem panel
|
* Singleton class for problem panel
|
||||||
@ -19,8 +36,8 @@ export type WebviewMessageType = { msg: 'onProblemData'; data: ProblemData };
|
|||||||
export class BWPanel {
|
export class BWPanel {
|
||||||
public static currentPanel: BWPanel | undefined;
|
public static currentPanel: BWPanel | undefined;
|
||||||
|
|
||||||
private running: boolean = false;
|
private runningProgram: RunningProgram | undefined;
|
||||||
// private kill: () => void | null = null;
|
private problemData: ProblemData | undefined;
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
private readonly context: vscode.ExtensionContext,
|
private readonly context: vscode.ExtensionContext,
|
||||||
@ -29,6 +46,7 @@ export class BWPanel {
|
|||||||
private readonly webUrl: string
|
private readonly webUrl: string
|
||||||
) {
|
) {
|
||||||
this.update();
|
this.update();
|
||||||
|
panel.onDidDispose(() => this.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static show(context: vscode.ExtensionContext, webUrl: string) {
|
public static show(context: vscode.ExtensionContext, webUrl: string) {
|
||||||
@ -37,7 +55,7 @@ export class BWPanel {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
// Show panel if exists
|
// Show panel if exists
|
||||||
if (BWPanel.currentPanel) {
|
if (BWPanel.currentPanel !== undefined) {
|
||||||
BWPanel.currentPanel.panel.reveal(column);
|
BWPanel.currentPanel.panel.reveal(column);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -66,7 +84,6 @@ export class BWPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this.panel.dispose();
|
|
||||||
BWPanel.currentPanel = undefined;
|
BWPanel.currentPanel = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +97,13 @@ export class BWPanel {
|
|||||||
this.panel.webview.html = this._getHtmlForWebview(webview);
|
this.panel.webview.html = this._getHtmlForWebview(webview);
|
||||||
webview.onDidReceiveMessage(async (m: MessageType) => {
|
webview.onDidReceiveMessage(async (m: MessageType) => {
|
||||||
switch (m.msg) {
|
switch (m.msg) {
|
||||||
// case 'onKill': {
|
case 'onKill': {
|
||||||
// if (!this.running || !this.kill) {
|
if (this.runningProgram !== undefined) {
|
||||||
// break;
|
this.runningProgram.kill();
|
||||||
// }
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
// this.kill();
|
// this.kill();
|
||||||
// }
|
// }
|
||||||
// case 'onSubmit': {
|
// case 'onSubmit': {
|
||||||
@ -113,66 +133,73 @@ export class BWPanel {
|
|||||||
// vscode.window.showInformationMessage('Submitted!');
|
// vscode.window.showInformationMessage('Submitted!');
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// case 'onRun': {
|
case 'onRun': {
|
||||||
// if (this.running === true) {
|
const teamData: TeamData | undefined = this.context.globalState.get('teamData');
|
||||||
// vscode.window.showErrorMessage('Already running');
|
if (teamData === undefined) {
|
||||||
// break;
|
return;
|
||||||
// }
|
}
|
||||||
// await vscode.workspace.saveAll();
|
if (this.problemData === undefined) {
|
||||||
// if (!data.value) {
|
return;
|
||||||
// break;
|
}
|
||||||
// }
|
if (this.runningProgram !== undefined) {
|
||||||
// const repoDir = extensionSettings().repoClonePath;
|
vscode.window.showErrorMessage('Already Running');
|
||||||
// this.running = true;
|
return;
|
||||||
// const process = await runJava(
|
}
|
||||||
// join(
|
const problem = this.problemData.find((p) => (p.id = m.data.problemId));
|
||||||
// repoDir,
|
if (problem === undefined) {
|
||||||
// 'BWContest',
|
return;
|
||||||
// data.value.contestId.toString(),
|
}
|
||||||
// data.value.teamId.toString(),
|
await vscode.workspace.saveAll();
|
||||||
// data.value.problemPascalName.toString()
|
const repoDir = extensionSettings().repoClonePath;
|
||||||
// ),
|
const outputBuffer: string[] = [];
|
||||||
// join(
|
this.webviewPostMessage({ msg: 'onRunning' });
|
||||||
// repoDir,
|
this.webviewPostMessage({ msg: 'onRunningOutput', data: '[Compiling...]' });
|
||||||
// 'BWContest',
|
|
||||||
// data.value.contestId.toString(),
|
const killFunc = await runJava(
|
||||||
// data.value.teamId.toString(),
|
join(
|
||||||
// data.value.problemPascalName.toString(),
|
repoDir,
|
||||||
// `${data.value.problemPascalName}.java`
|
'BWContest',
|
||||||
// ),
|
teamData.contestId.toString(),
|
||||||
// data.value.problemPascalName,
|
teamData.teamId.toString(),
|
||||||
// data.value.input
|
problem.pascalName
|
||||||
// );
|
),
|
||||||
// if (!process) {
|
join(
|
||||||
// this.panel.webview.postMessage({
|
repoDir,
|
||||||
// type: 'onOutput',
|
'BWContest',
|
||||||
// value: '[An error occurred while running]'
|
teamData.contestId.toString(),
|
||||||
// });
|
teamData.teamId.toString(),
|
||||||
// break;
|
problem.pascalName,
|
||||||
// }
|
`${problem.pascalName}.java`
|
||||||
// process.output
|
),
|
||||||
// .then((output) => {
|
problem.pascalName,
|
||||||
// this.panel.webview.postMessage({ type: 'onOutput', value: output });
|
m.data.input,
|
||||||
// this.running = false;
|
(data: string) => {
|
||||||
// this.kill = null;
|
outputBuffer.push(data);
|
||||||
// })
|
this.webviewPostMessage({ msg: 'onRunningOutput', data: outputBuffer.join('') });
|
||||||
// .catch(() => {
|
},
|
||||||
// this.panel.webview.postMessage({
|
() => {
|
||||||
// type: 'onOutput',
|
this.runningProgram = undefined;
|
||||||
// value: '[An error occurred while running]'
|
this.webviewPostMessage({ msg: 'onRunningDone' });
|
||||||
// });
|
}
|
||||||
// this.running = false;
|
);
|
||||||
// this.kill = null;
|
if (killFunc !== undefined) {
|
||||||
// });
|
this.runningProgram = {
|
||||||
// this.kill = process.kill;
|
problemId: m.data.problemId,
|
||||||
// break;
|
outputBuffer: outputBuffer,
|
||||||
// }
|
kill: killFunc
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.webviewPostMessage({ msg: 'onRunningDone' });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'onRequestProblemData': {
|
case 'onRequestProblemData': {
|
||||||
const token: string | undefined = this.context.globalState.get('token');
|
const token: string | undefined = this.context.globalState.get('token');
|
||||||
if (token !== undefined) {
|
if (token !== undefined) {
|
||||||
const res = await fetch(urlJoin(this.webUrl, `/api/contest/${token}`));
|
const res = await fetch(urlJoin(this.webUrl, `/api/contest/${token}`));
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success === true) {
|
if (data.success === true) {
|
||||||
|
this.problemData = data.problems;
|
||||||
this.webviewPostMessage({
|
this.webviewPostMessage({
|
||||||
msg: 'onProblemData',
|
msg: 'onProblemData',
|
||||||
data: data.problems
|
data: data.problems
|
||||||
|
@ -13,62 +13,72 @@ export async function runJava(
|
|||||||
srcDir: string,
|
srcDir: string,
|
||||||
mainFile: string,
|
mainFile: string,
|
||||||
mainClass: string,
|
mainClass: string,
|
||||||
input: string
|
input: string,
|
||||||
): Promise<{ output: Promise<string>; kill: () => void | null }> {
|
outputCallback: (data: string) => void,
|
||||||
|
doneCallback: () => void
|
||||||
|
): Promise<(() => void) | undefined> {
|
||||||
const javaPath = extensionSettings().javaPath;
|
const javaPath = extensionSettings().javaPath;
|
||||||
if (javaPath == '') {
|
if (javaPath == '') {
|
||||||
throw error('Java path not set');
|
throw error('Java path not set');
|
||||||
}
|
}
|
||||||
const tempDir = os.tmpdir();
|
const tempDir = os.tmpdir();
|
||||||
const buildDir = join(tempDir, 'bwcontest_java');
|
const buildDir = join(tempDir, 'bwcontest_java');
|
||||||
if (fs.existsSync(buildDir)) {
|
if (await fs.exists(buildDir)) {
|
||||||
fs.removeSync(buildDir);
|
await fs.remove(buildDir);
|
||||||
}
|
}
|
||||||
fs.mkdirSync(buildDir);
|
await fs.mkdir(buildDir);
|
||||||
|
|
||||||
const compileCommand = `${join(javaPath, 'javac')} -cp ${srcDir} ${mainFile} -d ${buildDir}`;
|
const compileCommand = `${join(javaPath, 'javac')} -cp ${srcDir} ${mainFile} -d ${buildDir}`;
|
||||||
await execPromise(compileCommand);
|
try {
|
||||||
|
await execPromise(compileCommand);
|
||||||
|
} catch (error) {
|
||||||
|
outputCallback('[Compile Error]\n\n');
|
||||||
|
outputCallback(String(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const runCommand = `${join(javaPath, 'java')} -cp "${buildDir}" ${mainClass}`;
|
const runCommand = `${join(javaPath, 'java')} -cp "${buildDir}" ${mainClass}`;
|
||||||
|
|
||||||
const child = spawn(runCommand, { shell: true });
|
const child = spawn(runCommand, { shell: true });
|
||||||
let outputBuffer = '';
|
|
||||||
return {
|
|
||||||
output: new Promise((resolve) => {
|
|
||||||
child.stdout.setEncoding('utf8');
|
|
||||||
child.stdout.on('data', (data) => {
|
|
||||||
outputBuffer += data.toString();
|
|
||||||
});
|
|
||||||
child.stderr.setEncoding('utf8');
|
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
outputBuffer += data.toString();
|
|
||||||
});
|
|
||||||
child.stdin.write(input);
|
|
||||||
child.stdin.end();
|
|
||||||
|
|
||||||
let resolved = false;
|
child.stdout.setEncoding('utf8');
|
||||||
|
child.stdout.on('data', (data) => {
|
||||||
|
outputCallback(data.toString());
|
||||||
|
});
|
||||||
|
child.stderr.setEncoding('utf8');
|
||||||
|
child.stderr.on('data', (data) => {
|
||||||
|
outputCallback(data.toString());
|
||||||
|
});
|
||||||
|
child.stdin.write(input);
|
||||||
|
child.stdin.end();
|
||||||
|
|
||||||
child.on('close', () => {
|
let done = false;
|
||||||
if (!resolved) {
|
|
||||||
resolved = true;
|
|
||||||
resolve(outputBuffer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
child.on('close', () => {
|
||||||
if (!resolved) {
|
if (done === false) {
|
||||||
console.log('30 seconds reached, killing process');
|
done = true;
|
||||||
resolved = true;
|
doneCallback();
|
||||||
child.kill('SIGKILL');
|
}
|
||||||
resolve(outputBuffer + '\n[Timeout after 30 seconds]');
|
});
|
||||||
}
|
|
||||||
}, 30000);
|
setTimeout(() => {
|
||||||
}),
|
if (done === false) {
|
||||||
kill: () => {
|
console.log('\n[30 seconds reached, killing process...]');
|
||||||
|
done = true;
|
||||||
if (child.pid) {
|
if (child.pid) {
|
||||||
outputBuffer += '\n[Manually stopped]';
|
|
||||||
kill(child.pid);
|
kill(child.pid);
|
||||||
}
|
}
|
||||||
|
outputCallback('\n[Timeout after 30 seconds]');
|
||||||
|
doneCallback();
|
||||||
|
}
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (child.pid) {
|
||||||
|
done = true;
|
||||||
|
kill(child.pid);
|
||||||
|
outputCallback('\n[Manually stopped]');
|
||||||
|
doneCallback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onRun() {
|
function onRun() {
|
||||||
// if (problemData !== undefined && running === false) {
|
if (problemData !== undefined) {
|
||||||
// postMessage({
|
postMessage({
|
||||||
// type: 'requestRun',
|
msg: 'onRun',
|
||||||
// value: {
|
data: { input: sampleInputValue, problemId: problemData[activeProblemIndex].id }
|
||||||
// problemId: problemData[activeProblemIndex].id,
|
});
|
||||||
// input: sampleInputValue
|
}
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTextBoxes() {
|
function updateTextBoxes() {
|
||||||
@ -68,7 +65,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onKill() {
|
function onKill() {
|
||||||
// postMessage({ type: 'onKill' });
|
postMessage({ msg: 'onKill' });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -77,12 +74,15 @@
|
|||||||
|
|
||||||
window.addEventListener('message', async (event) => {
|
window.addEventListener('message', async (event) => {
|
||||||
const m = (event as MessageEvent).data as WebviewMessageType;
|
const m = (event as MessageEvent).data as WebviewMessageType;
|
||||||
// if (message.msg === 'onOutput') {
|
|
||||||
// outputValue = message.value;
|
|
||||||
// running = false;
|
|
||||||
if (m.msg === 'onProblemData') {
|
if (m.msg === 'onProblemData') {
|
||||||
problemData = m.data;
|
problemData = m.data;
|
||||||
updateTextBoxes();
|
updateTextBoxes();
|
||||||
|
} else if (m.msg === 'onRunning') {
|
||||||
|
running = true;
|
||||||
|
} else if (m.msg === 'onRunningDone') {
|
||||||
|
running = false;
|
||||||
|
} else if (m.msg === 'onRunningOutput') {
|
||||||
|
outputValue = m.data;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user