Skip to content

Commit 9ea1981

Browse files
committed
setup scenarios
1 parent cf41224 commit 9ea1981

File tree

8 files changed

+144
-126
lines changed

8 files changed

+144
-126
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"mocha-parallel-tests": "^2.0.0",
1717
"nyc": "^11.3.0",
1818
"ts-node": "^7.0.0",
19-
"typescript": "^2.6.1"
19+
"typescript": "^3.8.3"
2020
},
2121
"dependencies": {
2222
"amqplib": "^0.5.2",

src/taskmaster.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ const nr = require('newrelic');
22
import * as Raven from 'raven'
33
import * as amqp from 'amqplib/callback_api'
44
import {Connection} from 'amqplib/callback_api'
5-
import {RunJob, RunResult} from './types/job'
6-
import {execRun} from './tasks/run'
5+
import {RunJob, RunResult, SubmissionResult} from './types/job'
6+
import { executor } from './tasks'
77
import config = require('../config.js')
88

99
// =============== Setup Raven
@@ -27,8 +27,9 @@ amqp.connect(`amqp://${config.AMQP.USER}:${config.AMQP.PASS}@${config.AMQP.HOST}
2727
channel.consume(jobQ, async (msg) => {
2828
try {
2929
const job: RunJob = JSON.parse(msg.content.toString())
30-
const jobResult: RunResult = await execRun(job)
30+
const jobResult: RunResult|SubmissionResult = await executor(job)
3131

32+
// TODO
3233
channel.sendToQueue(successQ, (new Buffer(JSON.stringify(<RunResult>{
3334
id: job.id,
3435
stderr: jobResult.stderr,
@@ -41,7 +42,5 @@ amqp.connect(`amqp://${config.AMQP.USER}:${config.AMQP.PASS}@${config.AMQP.HOST}
4142
Raven.captureException(err);
4243
}
4344
})
44-
45-
4645
})
4746
})

src/tasks/index.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { RunJob, SubmissionJob, RunResult, SubmissionResult } from "types/job";
2+
import config = require('../../config.js')
3+
import {exec, mkdir, rm} from 'shelljs'
4+
import * as path from 'path'
5+
6+
import RunScenario from './run'
7+
import SubmissionScenario from './submission'
8+
9+
export const executor = async (job: RunJob|SubmissionJob): Promise<RunResult|SubmissionResult> => {
10+
// Create RUNBOX
11+
rm('-rf', config.RUNBOX.DIR)
12+
mkdir('-p', config.RUNBOX.DIR)
13+
const currentJobDir = path.join(config.RUNBOX.DIR, job.id.toString())
14+
mkdir('-p', currentJobDir)
15+
16+
const LANG_CONFIG = config.LANGS[job.lang]
17+
const scenario = job.hasOwnProperty('testcases') ? SubmissionScenario : RunScenario
18+
19+
// Setup RUNBOX
20+
await scenario.setup(currentJobDir, <RunJob&SubmissionJob>job) // TODO:
21+
22+
// Run worker
23+
exec(`docker run \\
24+
--cpus="${LANG_CONFIG.CPU_SHARE}" \\
25+
--memory="${LANG_CONFIG.MEM_LIMIT}" \\
26+
--ulimit nofile=64:64 \\
27+
--rm \\
28+
--read-only \\
29+
-v "${currentJobDir}":/usr/src/runbox \\
30+
-w /usr/src/runbox \\
31+
codingblocks/judge-worker-${job.lang} \\
32+
/bin/judge.sh -t ${job.timelimit || 5}
33+
`)
34+
35+
// Get result
36+
const result = await scenario.result(currentJobDir, job.id)
37+
38+
rm('-rf', currentJobDir)
39+
40+
return result
41+
}

src/tasks/run.ts

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,41 @@ import {cat, exec, mkdir, rm, touch, head} from 'shelljs'
33
import {RunJob, RunResult} from '../types/job'
44
import * as path from 'path'
55
import * as fs from 'fs'
6+
import { Scenario } from 'types/scenario.js'
67

78
rm('-rf', config.RUNBOX.DIR)
89
mkdir('-p', config.RUNBOX.DIR)
910

10-
async function execRun (job: RunJob): Promise<RunResult> {
11-
let currentJobDir = path.join(config.RUNBOX.DIR, job.id.toString())
12-
mkdir('-p', currentJobDir)
13-
const LANG_CONFIG = config.LANGS[job.lang]
14-
15-
fs.writeFileSync(path.join(currentJobDir, LANG_CONFIG.SOURCE_FILE),
16-
(new Buffer(job.source, 'base64')).toString('ascii'))
17-
fs.writeFileSync(path.join(currentJobDir, 'run.stdin'),
18-
(new Buffer(job.stdin, 'base64')).toString('ascii'))
19-
20-
exec(`docker run \\
21-
--cpus="${LANG_CONFIG.CPU_SHARE}" \\
22-
--memory="${LANG_CONFIG.MEM_LIMIT}" \\
23-
--ulimit nofile=64:64 \\
24-
--rm \\
25-
--read-only \\
26-
-v "${currentJobDir}":/usr/src/runbox \\
27-
-w /usr/src/runbox \\
28-
codingblocks/judge-worker-${job.lang} \\
29-
/bin/judge.sh -t ${job.timelimit || 5}
30-
`)
31-
32-
const stdout = exec(`
33-
head -c 65536 ${path.join(currentJobDir, 'run.stdout')}
34-
`)
35-
36-
// Check for compile_stderr if can't find a stdout file ; stdout can be ''
37-
const compile_stderr = cat(path.join(currentJobDir, 'compile.stderr')).toString()
38-
let stderr = compile_stderr || cat((path.join(currentJobDir, 'run.stderr')).toString())
39-
40-
const run_time = cat(path.join(currentJobDir, 'runguard.time')).toString()
41-
const code = cat(path.join(currentJobDir, 'runguard.code')).toString()
42-
43-
rm('-rf', currentJobDir)
44-
45-
return {
46-
id: job.id,
47-
stderr: (new Buffer(stderr)).toString('base64'),
48-
stdout: (new Buffer(stdout)).toString('base64'),
49-
time: +run_time,
50-
code: +code
11+
class RunScenario implements Scenario {
12+
setup(currentJobDir: string, job: RunJob) {
13+
const LANG_CONFIG = config.LANGS[job.lang]
14+
15+
fs.writeFileSync(path.join(currentJobDir, LANG_CONFIG.SOURCE_FILE),
16+
(new Buffer(job.source, 'base64')).toString('ascii'))
17+
fs.writeFileSync(path.join(currentJobDir, 'run.stdin'),
18+
(new Buffer(job.stdin, 'base64')).toString('ascii'))
5119
}
52-
}
5320

54-
export {
55-
execRun
21+
async result(currentJobDir: string, jobId: number): Promise<RunResult> {
22+
const stdout = exec(`
23+
head -c 65536 ${path.join(currentJobDir, 'run.stdout')}
24+
`)
25+
26+
// Check for compile_stderr if can't find a stdout file ; stdout can be ''
27+
const compile_stderr = cat(path.join(currentJobDir, 'compile.stderr')).toString()
28+
let stderr = compile_stderr || cat((path.join(currentJobDir, 'run.stderr')).toString())
29+
30+
const run_time = cat(path.join(currentJobDir, 'runguard.time')).toString()
31+
const code = cat(path.join(currentJobDir, 'runguard.code')).toString()
32+
33+
return {
34+
id: jobId,
35+
stderr: (new Buffer(stderr)).toString('base64'),
36+
stdout: (new Buffer(stdout)).toString('base64'),
37+
time: +run_time,
38+
code: +code
39+
}
40+
}
5641
}
42+
43+
export default new RunScenario()

src/tasks/submission.ts

Lines changed: 27 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,37 @@ import { SubmissionJob, SubmissionResult } from '../types/job'
44
import * as path from 'path'
55
import * as fs from 'fs'
66
import http = require('http')
7+
import { Scenario } from 'types/scenario.js'
78

89
rm('-rf', config.RUNBOX.DIR)
910
mkdir('-p', config.RUNBOX.DIR)
1011

11-
async function execSubmission(job: SubmissionJob): Promise<SubmissionResult> {
12-
let currentJobDir = path.join(config.RUNBOX.DIR, job.id.toString())
13-
mkdir('-p', currentJobDir)
14-
const LANG_CONFIG = config.LANGS[job.lang]
15-
16-
job.testcases.map(testcase => {
17-
mkdir('-p', `currentJobDir/${testcase.id}`)
18-
// const file = fs.createWriteStream();
19-
Promise.all([http.get(testcase.input), http.get(testcase.output)])
20-
.then(values => {
21-
values.map(value => {
22-
12+
class SubmissionScenario implements Scenario {
13+
setup(currentJobDir: string, job: SubmissionJob) {
14+
const LANG_CONFIG = config.LANGS[job.lang]
15+
16+
job.testcases.map(testcase => {
17+
mkdir('-p', `currentJobDir/${testcase.id}`)
18+
// const file = fs.createWriteStream();
19+
Promise.all([http.get(testcase.input), http.get(testcase.output)])
20+
.then(values => {
21+
values.map(value => {
22+
23+
})
2324
})
24-
})
25-
})
26-
const request = http.get(job.testcases, function (response) {
27-
response.pipe(file);
28-
});
29-
30-
31-
32-
fs.writeFileSync(path.join(currentJobDir, LANG_CONFIG.SOURCE_FILE),
33-
(new Buffer(job.source, 'base64')).toString('ascii'))
34-
fs.writeFileSync(path.join(currentJobDir, ),
35-
(new Buffer(job.testcases)))
36-
37-
exec(`docker run \\
38-
--cpus="${LANG_CONFIG.CPU_SHARE}" \\
39-
--memory="${LANG_CONFIG.MEM_LIMIT}" \\
40-
--ulimit nofile=64:64 \\
41-
--rm \\
42-
--read-only \\
43-
-v "${currentJobDir}":/usr/src/runbox \\
44-
-w /usr/src/runbox \\
45-
codingblocks/judge-worker-${job.lang} \\
46-
/bin/judge.sh -t ${job.timelimit || 5}
47-
`)
48-
49-
const stdout = exec(`
50-
head -c 65536 ${path.join(currentJobDir, 'run.stdout')}
51-
`)
52-
53-
54-
55-
// Check for compile_stderr if can't find a stdout file ; stdout can be ''
56-
const compile_stderr = cat(path.join(currentJobDir, 'compile.stderr')).toString()
57-
let stderr = compile_stderr || cat((path.join(currentJobDir, 'run.stderr')).toString())
58-
59-
rm('-rf', currentJobDir)
60-
25+
})
26+
fs.writeFileSync(path.join(currentJobDir, LANG_CONFIG.SOURCE_FILE),
27+
(new Buffer(job.source, 'base64')).toString('ascii'))
28+
fs.writeFileSync(path.join(currentJobDir, ),
29+
(new Buffer(job.testcases)))
30+
}
31+
32+
async result(currentJobDir: string): Promise<SubmissionResult> {
33+
// TODO
34+
return {
35+
36+
}
37+
}
6138
}
6239

63-
return {
64-
65-
}
66-
67-
export {
68-
execSubmission
69-
}
40+
export default new SubmissionScenario()

src/types/job.d.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,42 @@
1-
export interface RunJob {
1+
export interface Job {
2+
id: number,
23
source: string,
34
lang: string,
4-
stdin: string,
5-
timelimit?: number,
6-
id: number
5+
timelimit?: number
6+
}
7+
8+
export interface Result {
9+
id: number,
10+
stderr: string
711
}
812

9-
export interface RunResult {
13+
export interface TestcaseJob {
14+
id: number,
15+
input: string,
16+
output: string
17+
}
18+
19+
export interface TestcaseResult {
20+
id: number,
21+
score: number,
22+
time: string,
23+
result: string
24+
}
25+
26+
export interface RunJob extends Job {
27+
stdin: string
28+
}
29+
30+
export interface RunResult extends Result {
1031
stdout: string,
11-
stderr: string,
1232
time: number,
1333
code: number
14-
id: number
1534
}
1635

17-
export interface SubmissionJob {
18-
id: number
19-
source: string,
20-
lang: string,
21-
timelimit?: number,
22-
testcases: [{ id: number, input: string, output: string }],
36+
export interface SubmissionJob extends Job {
37+
testcases: Array<TestcaseJob>
2338
}
2439

25-
export interface SubmissionResult {
26-
id: number,
27-
stderr: string,
28-
testcases: [{ id: number, sscore: number, time: string, result: string }]
40+
export interface SubmissionResult extends Result {
41+
testcases: Array<TestcaseResult>
2942
}

src/types/scenario.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Job, Result } from "./job";
2+
3+
export interface Scenario {
4+
setup(currentJobDir: string, job: Job)
5+
result(currentJobDir: string, jobId: number): Promise<Result>
6+
}

yarn.lock

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,9 +1695,10 @@ typedarray@^0.0.6:
16951695
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
16961696
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
16971697

1698-
typescript@^2.6.1:
1699-
version "2.6.1"
1700-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
1698+
typescript@^3.8.3:
1699+
version "3.8.3"
1700+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
1701+
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
17011702

17021703
uglify-js@^2.6:
17031704
version "2.8.29"

0 commit comments

Comments
 (0)