Skip to content

Commit 5d40c97

Browse files
committed
Compile and run java code in docker
1 parent 396ef5f commit 5d40c97

File tree

11 files changed

+96
-65
lines changed

11 files changed

+96
-65
lines changed

docker/images/java/Dockerfile

Lines changed: 0 additions & 1 deletion
This file was deleted.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "2.0.0",
44
"description": "Algorithm Visualizer",
55
"scripts": {
6+
"postinstall": "docker pull baekjoon/onlinejudge-java:1.8",
67
"dev": "NODE_ENV=development node bin/www",
78
"start": "NODE_ENV=production node bin/www",
89
"build": "npm run build:frontend && npm run build:backend",

src/backend/apis/index.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import Promise from 'bluebird';
22
import axios from 'axios';
3-
import fs from 'fs-extra';
3+
import fs from 'fs';
44
import { githubClientId, githubClientSecret } from '/environment';
55

6-
axios.interceptors.request.use(request => {
6+
const instance = axios.create();
7+
8+
instance.interceptors.request.use(request => {
79
request.params = { client_id: githubClientId, client_secret: githubClientSecret, ...request.params };
810
return request;
911
});
1012

11-
axios.interceptors.response.use(response => {
13+
instance.interceptors.response.use(response => {
1214
return response.data;
1315
}, error => {
1416
return Promise.reject(error.response.data);
@@ -28,43 +30,43 @@ const request = (url, process) => {
2830
const GET = URL => {
2931
return request(URL, (mappedURL, args) => {
3032
const [params] = args;
31-
return axios.get(mappedURL, { params });
33+
return instance.get(mappedURL, { params });
3234
});
3335
};
3436

3537
const DELETE = URL => {
3638
return request(URL, (mappedURL, args) => {
3739
const [params] = args;
38-
return axios.delete(mappedURL, { params });
40+
return instance.delete(mappedURL, { params });
3941
});
4042
};
4143

4244
const POST = URL => {
4345
return request(URL, (mappedURL, args) => {
4446
const [body, params] = args;
45-
return axios.post(mappedURL, body, { params });
47+
return instance.post(mappedURL, body, { params });
4648
});
4749
};
4850

4951
const PUT = URL => {
5052
return request(URL, (mappedURL, args) => {
5153
const [body, params] = args;
52-
return axios.put(mappedURL, body, { params });
54+
return instance.put(mappedURL, body, { params });
5355
});
5456
};
5557

5658
const PATCH = URL => {
5759
return request(URL, (mappedURL, args) => {
5860
const [body, params] = args;
59-
return axios.patch(mappedURL, body, { params });
61+
return instance.patch(mappedURL, body, { params });
6062
});
6163
};
6264

6365
const GitHubApi = {
6466
listCommits: GET('/repos/:owner/:repo/commits'),
65-
getAccessToken: code => axios.post('https://github.com/login/oauth/access_token', { code }, { headers: { Accept: 'application/json' } }),
67+
getAccessToken: code => instance.post('https://github.com/login/oauth/access_token', { code }, { headers: { Accept: 'application/json' } }),
6668
getLatestRelease: GET('/repos/:owner/:repo/releases/latest'),
67-
download: (url, path) => axios({
69+
download: (url, path) => instance({
6870
method: 'get',
6971
url,
7072
responseType: 'stream',

src/backend/common/error.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
class ApplicationError extends Error {
2+
toJSON() {
3+
return { message: this.message };
4+
}
25
}
36

47
class NotFoundError extends ApplicationError {
@@ -10,9 +13,17 @@ class PermissionError extends ApplicationError {
1013
class AuthorizationError extends ApplicationError {
1114
}
1215

16+
class CompileError extends ApplicationError {
17+
}
18+
19+
class RuntimeError extends ApplicationError {
20+
}
21+
1322
export {
1423
ApplicationError,
1524
NotFoundError,
1625
PermissionError,
1726
AuthorizationError,
27+
CompileError,
28+
RuntimeError,
1829
};

src/backend/controllers/categories.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import express from 'express';
2-
import fs from 'fs-extra';
2+
import fs from 'fs';
33
import path from 'path';
44
import { NotFoundError } from '/common/error';
55
import { exec } from 'child_process';

src/backend/controllers/compilers.js

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/backend/controllers/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { default as auth } from './auth';
22
export { default as categories } from './categories';
3-
export { default as compilers } from './compilers';
3+
export { default as tracers } from './tracers';

src/backend/controllers/tracers.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Promise from 'bluebird';
2+
import express from 'express';
3+
import fs from 'fs-extra';
4+
import uuid from 'uuid';
5+
import path from 'path';
6+
import child_process from 'child_process';
7+
import { GitHubApi } from '/apis';
8+
import { __PROD__ } from '/environment';
9+
import { CompileError, RuntimeError } from '/common/error';
10+
11+
const router = express.Router();
12+
13+
const getLibPath = (...args) => path.resolve(__dirname, '..', 'public', 'libs', ...args);
14+
15+
const downloadLibs = () => {
16+
GitHubApi.getLatestRelease('algorithm-visualizer', 'tracers').then(release => {
17+
return Promise.each(release.assets, asset => GitHubApi.download(asset.browser_download_url, getLibPath(asset.name)));
18+
});
19+
};
20+
if (__PROD__) downloadLibs(); // TODO: download again when webhooked
21+
22+
const getJsWorker = (req, res, next) => {
23+
res.sendFile(getLibPath('js.js'));
24+
};
25+
26+
const execute = (imageId, srcPath, command, ErrorClass) => new Promise((resolve, reject) => {
27+
const libPath = getLibPath();
28+
const dockerCommand = `docker run --rm -w=/usr/judge -t -v=${libPath}:/usr/bin/tracers:ro -v=${srcPath}:/usr/judge:rw -e MAX_TRACES=1000000 -e MAX_TRACERS=100 ${imageId}`;
29+
child_process.exec(`${dockerCommand} ${command}`, (error, stdout, stderr) => {
30+
if (error) return reject(new ErrorClass(stdout));
31+
resolve();
32+
});
33+
});
34+
35+
const trace = ({ imageId, compileCommand, runCommand }) => (req, res, next) => {
36+
const { code } = req.body;
37+
const srcPath = path.resolve(__dirname, '..', 'public', 'codes', uuid.v4());
38+
fs.outputFile(path.resolve(srcPath, 'code.java'), code)
39+
.then(() => execute(imageId, srcPath, compileCommand, CompileError))
40+
.then(() => execute(imageId, srcPath, runCommand, RuntimeError))
41+
.then(() => res.sendFile(path.resolve(srcPath, 'traces.json')))
42+
.catch(next)
43+
.finally(() => fs.remove(srcPath));
44+
};
45+
46+
router.route('/js')
47+
.get(getJsWorker);
48+
49+
router.route('/java')
50+
.post(trace({
51+
imageId: 'baekjoon/onlinejudge-java:1.8',
52+
compileCommand: 'javac -cp /usr/bin/tracers/java.jar code.java',
53+
runCommand: 'java -cp /usr/bin/tracers/java.jar:. Main',
54+
}));
55+
56+
export default router;

src/frontend/apis/index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,19 @@ const GitHubApi = {
6969
};
7070

7171
let jsWorker = null;
72-
const CompilerApi = {
73-
js: code => new Promise((resolve, reject) => {
72+
const TracerApi = {
73+
js: ({ code }) => new Promise((resolve, reject) => {
7474
if (jsWorker) jsWorker.terminate();
75-
jsWorker = new Worker('/api/compilers/js');
75+
jsWorker = new Worker('/api/tracers/js');
7676
jsWorker.onmessage = e => resolve(e.data);
7777
jsWorker.onerror = reject;
7878
jsWorker.postMessage(code);
7979
}),
80+
java: POST('/tracers/java'),
8081
};
8182

8283
export {
8384
CategoryApi,
8485
GitHubApi,
85-
CompilerApi,
86+
TracerApi,
8687
};

src/frontend/components/ToastContainer/stylesheet.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
padding: 16px;
1414
margin: 8px;
1515
font-size: $font-size-large;
16+
white-space: pre-line;
1617

1718
&.success {
1819
border-color: rgb(0, 150, 0);

0 commit comments

Comments
 (0)