Skip to content

Commit ab79a08

Browse files
committed
refactor: scenario architecture
1 parent db5377b commit ab79a08

27 files changed

+114
-77
lines changed

src/taskmaster.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ amqp.connect(`amqp://${config.AMQP.USER}:${config.AMQP.PASS}@${config.AMQP.HOST}
3232
const payload = JSON.parse(msg.content.toString())
3333

3434
let job
35-
if (payload.testcases) {
36-
job = new SubmitJob(payload)
37-
} else {
38-
job = new RunJob(payload)
35+
switch (payload.scenario) {
36+
case 'submit':
37+
job = new SubmitJob(payload)
38+
break
39+
case 'run':
40+
job = new RunJob(payload)
41+
break
42+
default:
43+
throw new Error("Scenario not declared")
3944
}
4045

4146
const jobResult = await execute(job)

src/tasks/index.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import config = require('../../config.js')
33
import {exec, mkdir, rm} from 'shelljs'
44
import * as path from 'path'
55

6-
import RunScenario from './run'
7-
import SubmissionScenario from './submission'
6+
import RunScenario from './scenarios/run'
7+
import SubmissionScenario from './scenarios/submission'
88
import { RunJob, SubmitJob, Job } from "./job";
99

1010
export function execute(job: RunJob): Promise<RunResult>
@@ -14,8 +14,6 @@ export async function execute (job: Job) {
1414
const currentJobDir = path.join(config.RUNBOX.DIR, job.id.toString())
1515
mkdir('-p', currentJobDir)
1616

17-
const LANG_CONFIG = config.LANGS[job.lang]
18-
1917
let scenario
2018
if (job instanceof RunJob) {
2119
scenario = RunScenario
@@ -24,22 +22,13 @@ export async function execute (job: Job) {
2422
}
2523

2624
// Setup RUNBOX
27-
await scenario.setup(currentJobDir, job) // TODO:
25+
await scenario.setup(currentJobDir, job)
2826

2927
// Run worker
30-
exec(`docker run \\
31-
--cpus="${LANG_CONFIG.CPU_SHARE}" \\
32-
--memory="${LANG_CONFIG.MEM_LIMIT}" \\
33-
--ulimit nofile=64:64 \\
34-
--rm \\
35-
-v "${currentJobDir}":/usr/src/runbox \\
36-
-w /usr/src/runbox \\
37-
codingblocks/judge-worker-${job.lang} \\
38-
/bin/judge.sh -t ${job.timelimit || 5}
39-
`)
28+
await scenario.run(currentJobDir, job)
4029

4130
// Get result
42-
const result = await scenario.result(currentJobDir, job.id)
31+
const result = await scenario.result(currentJobDir, job)
4332

4433
rm('-rf', currentJobDir)
4534

src/tasks/job.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ interface JobConstructorOpts {
22
id: number
33
source: string
44
lang: string
5+
scenario: "run" | "submit"
56
timelimit?: number
67
}
78
interface RunJobConstructorOpts extends JobConstructorOpts {
@@ -20,30 +21,32 @@ export class Job {
2021
id: number
2122
source: string
2223
lang: string
24+
scenario: string
2325
timelimit?: number
2426

25-
constructor({ id, source, lang, timelimit = 5 }: JobConstructorOpts) {
27+
constructor({ id, source, lang, timelimit = 5, scenario }: JobConstructorOpts) {
2628
this.id = id
2729
this.source = source
2830
this.lang = lang
2931
this.timelimit = timelimit
32+
this.scenario = scenario
3033
}
3134
}
3235

3336
export class RunJob extends Job {
3437
stdin: string
3538

36-
constructor({ id, source, lang, timelimit, stdin }: RunJobConstructorOpts) {
37-
super({id, source, lang, timelimit})
39+
constructor({ id, source, lang, timelimit, scenario, stdin }: RunJobConstructorOpts) {
40+
super({id, source, lang, timelimit, scenario})
3841
this.stdin = stdin
3942
}
4043
}
4144

4245
export class SubmitJob extends Job {
4346
testcases: Array<TestcaseOpts>
4447

45-
constructor({ id, source, lang, timelimit, testcases }: SubmitJobConstructorOpts) {
46-
super({id, source, lang, timelimit})
48+
constructor({ id, source, lang, timelimit, scenario, testcases }: SubmitJobConstructorOpts) {
49+
super({id, source, lang, timelimit, scenario})
4750
this.testcases = testcases
4851
}
4952
}

src/tasks/scenario.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import config = require('../../config');
2+
import { exec } from 'shelljs';
3+
import { Job } from "./job";
4+
import { Result } from "types/result";
5+
6+
export class Scenario {
7+
setup(currentJobDir: string, job: Job) {
8+
throw new Error("Not Implemented")
9+
}
10+
run(currentJobDir: string, job: Job) {
11+
const LANG_CONFIG = config.LANGS[job.lang]
12+
return exec(`docker run \\
13+
--cpus="${LANG_CONFIG.CPU_SHARE}" \\
14+
--memory="${LANG_CONFIG.MEM_LIMIT}" \\
15+
--ulimit nofile=64:64 \\
16+
--rm \\
17+
-v "${currentJobDir}":/usr/src/runbox \\
18+
-w /usr/src/runbox \\
19+
codingblocks/judge-worker-${job.lang} \\
20+
/bin/judge.sh -t ${job.timelimit || 5}
21+
`)
22+
}
23+
result(currentJobDir: string, job: Job): Promise<Result> {
24+
throw new Error("Not Implemented")
25+
}
26+
}

src/tasks/run.ts renamed to src/tasks/scenarios/run.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import config = require('../../config.js')
1+
import config = require('../../../config.js')
22
import {cat, exec, mkdir, rm, touch, head} from 'shelljs'
3-
import { RunJob } from './job'
3+
import { RunJob } from '../job'
44
import { RunResult } from 'types/result'
55
import * as path from 'path'
66
import * as fs from 'fs'
7-
import { Scenario } from 'types/scenario'
7+
import { Scenario } from '../scenario'
88

9-
class RunScenario implements Scenario {
9+
class RunScenario extends Scenario {
1010
setup(currentJobDir: string, job: RunJob) {
1111
const LANG_CONFIG = config.LANGS[job.lang]
1212

@@ -16,7 +16,7 @@ class RunScenario implements Scenario {
1616
(new Buffer(job.stdin, 'base64')).toString('ascii'))
1717
}
1818

19-
async result(currentJobDir: string, jobId: number): Promise<RunResult> {
19+
async result(currentJobDir: string, job: RunJob): Promise<RunResult> {
2020
const stdout = exec(`
2121
head -c ${config.MAX_OUTPUT_BUFFER} ${path.join(currentJobDir, 'run.stdout')}
2222
`)
@@ -29,7 +29,7 @@ class RunScenario implements Scenario {
2929
const code = cat(path.join(currentJobDir, 'runguard.code')).toString()
3030

3131
return {
32-
id: jobId,
32+
id: job.id,
3333
stderr: (new Buffer(stderr)).toString('base64'),
3434
stdout: (new Buffer(stdout)).toString('base64'),
3535
time: +run_time,

src/tasks/submission.ts renamed to src/tasks/scenarios/submission.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import config = require('../../config.js')
1+
import config = require('../../../config.js')
22
import { cat, ls, mkdir, exec } from 'shelljs'
3-
import { SubmitJob } from './job'
3+
import { SubmitJob } from '../job'
44
import { SubmissionResult } from 'types/result'
55
import * as path from 'path'
66
import * as fs from 'fs'
77
import * as https from 'https'
8-
import { Scenario } from 'types/scenario.js'
8+
import { Scenario } from '../scenario'
99
import { ClientRequest } from 'http';
1010

1111
export const download = (url: string, dest: string): Promise<ClientRequest> => {
@@ -22,7 +22,7 @@ export const download = (url: string, dest: string): Promise<ClientRequest> => {
2222
)
2323
}
2424

25-
class SubmissionScenario implements Scenario {
25+
class SubmissionScenario extends Scenario {
2626
setup(currentJobDir: string, job: SubmitJob) {
2727
const LANG_CONFIG = config.LANGS[job.lang]
2828

@@ -39,13 +39,13 @@ class SubmissionScenario implements Scenario {
3939
}))
4040
}
4141

42-
async result(currentJobDir: string, jobId: number): Promise<SubmissionResult> {
42+
async result(currentJobDir: string, job: SubmitJob): Promise<SubmissionResult> {
4343
// Check for compile_stderr if can't find a stdout file ; stdout can be ''
4444
const compile_stderr = cat(path.join(currentJobDir, 'compile.stderr')).toString()
4545

4646
if (compile_stderr) {
4747
return {
48-
id: jobId,
48+
id: job.id,
4949
stderr: (new Buffer(compile_stderr)).toString('base64'),
5050
testcases: []
5151
}
@@ -83,7 +83,7 @@ class SubmissionScenario implements Scenario {
8383
})
8484

8585
return {
86-
id: jobId,
86+
id: job.id,
8787
stderr: (new Buffer(compile_stderr)).toString('base64'),
8888
testcases
8989
}

src/types/scenario.d.ts

-7
This file was deleted.

test/run/run.c.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ int main () {
1515
return 0;
1616
}
1717
`)).toString('base64'),
18+
scenario: 'run',
1819
stdin: (new Buffer('World')).toString('base64')
1920
}))
2021
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World')

test/run/run.cpp.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ int main () {
1717
return 0;
1818
}
1919
`)).toString('base64'),
20+
scenario: 'run',
2021
stdin: (new Buffer('World')).toString('base64')
2122
}))
2223
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World')

test/run/run.csharp.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class HelloWorld {
1515
}
1616
}
1717
`)).toString('base64'),
18+
scenario: 'run',
1819
stdin: (new Buffer('World')).toString('base64')
1920
}))
2021
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.java8.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class Main {
1717
}
1818
}
1919
`)).toString('base64'),
20+
scenario: 'run',
2021
stdin: (new Buffer('World')).toString('base64')
2122
}))
2223
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.nodejs10.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rl.on('line', function (line) {
1717
console.log("Hello " + line);
1818
});
1919
`)).toString('base64'),
20+
scenario: 'run',
2021
stdin: (new Buffer('World')).toString('base64')
2122
}))
2223
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.nodejs8.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rl.on('line', function (line) {
1818
console.log("Hello " + line);
1919
});
2020
`)).toString('base64'),
21+
scenario: 'run',
2122
stdin: (new Buffer('World')).toString('base64')
2223
}))
2324
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.py2.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ describe('run - py2', () => {
1111
inp = raw_input()
1212
print("Hello " + inp)
1313
`)).toString('base64'),
14+
scenario: 'run',
1415
stdin: (new Buffer('World')).toString('base64')
1516
}))
1617
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.py3.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ describe('run - py3', () => {
1111
inp = input()
1212
print("Hello " + inp)
1313
`)).toString('base64'),
14+
scenario: 'run',
1415
stdin: (new Buffer('World')).toString('base64')
1516
}))
1617
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/run/run.ruby.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('run - ruby', () => {
1010
source: (new Buffer(`
1111
puts "Hello " + gets.to_s
1212
`)).toString('base64'),
13+
scenario: 'run',
1314
stdin: (new Buffer('World')).toString('base64')
1415
}))
1516
expect(new Buffer(runResult.stdout, 'base64').toString('ascii')).to.eq('Hello World\n')

test/runScenario.spec.ts renamed to test/scenarios/runScenario.spec.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { expect } from 'chai'
22
import { mkdir, rm } from 'shelljs'
3-
import RunScenario from '../src/tasks/run'
4-
import config = require('../config.js')
3+
import RunScenario from '../../src/tasks/scenarios/run'
4+
import config = require('../../config.js')
55
import * as path from 'path'
6-
import { RunJob } from '../src/tasks/job'
6+
import { RunJob } from '../../src/tasks/job'
77
import * as fs from 'fs'
88

99
describe('Run Scenario', () => {
@@ -16,6 +16,7 @@ describe('Run Scenario', () => {
1616
source: (new Buffer(source)).toString('base64'),
1717
lang: 'py3',
1818
timelimit: 5,
19+
scenario: 'run',
1920
stdin: (new Buffer(stdin)).toString('base64'),
2021
}
2122

test/submissionScenario.spec.ts renamed to test/scenarios/submissionScenario.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { expect } from 'chai'
2-
import { download } from '../src/tasks/submission'
32
import * as fs from 'fs'
43
import { mkdir, rm } from 'shelljs'
5-
import config = require('../config.js')
4+
import config = require('../../config.js')
65
import * as path from 'path'
7-
import SubmissionScenario from '../src/tasks/submission'
8-
import { SubmitJob } from '../src/tasks/job'
6+
import SubmissionScenario, { download } from '../../src/tasks/scenarios/submission'
7+
import { SubmitJob } from '../../src/tasks/job'
98

109
describe('Submission Scenario', () => {
1110
it('should download', async () => {
@@ -25,6 +24,7 @@ describe('Submission Scenario', () => {
2524
source: (new Buffer(source)).toString('base64'),
2625
lang: 'py3',
2726
timelimit: 5,
27+
scenario: 'submit',
2828
testcases: [{
2929
id: 122,
3030
input: 'https://minio.cb.lk/public/input',

test/submission/submit.c.spec.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@ describe('submit - c', () => {
1919
id: 1,
2020
lang: 'c',
2121
source: (new Buffer(source)).toString('base64'),
22+
scenario: 'submit',
2223
testcases: [{
2324
id: 1,
2425
input: 'https://minio.cb.lk/public/input',
2526
output: 'https://minio.cb.lk/public/output'
2627
}]
2728
}))
2829

29-
console.log(submitResult)
30-
3130
// assertions
3231
expect(submitResult.testcases[0].result).to.eq('Success')
3332
expect(submitResult.testcases[0].score).to.eq(100)

0 commit comments

Comments
 (0)