mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
update design
This commit is contained in:
parent
10ba885724
commit
9f1f7de770
24
README.md
24
README.md
@ -6,22 +6,30 @@ The goal to to reimplement [syzoj/judge-v3](https://github.com/syzoj/judge-v3) i
|
|||||||
|
|
||||||
## Planned Design
|
## Planned Design
|
||||||
|
|
||||||
|
Container Root Filesystem:
|
||||||
|
|
||||||
|
+ necessary lib / exec / compiler / header readonly bind mounted from current file system: /lib /lib64 /bin /usr
|
||||||
|
+ work directory tmpfs mount: /w (work dir), /tmp (compiler temp files)
|
||||||
|
+ additional compiler scripts / exec readonly bind mounted: /c
|
||||||
|
+ additional header readonly bind mounted: /i
|
||||||
|
|
||||||
Brokers and interfaces:
|
Brokers and interfaces:
|
||||||
|
|
||||||
+ client: receive pushed judge tasks from website (web-socket / socket.io / RabbitMQ)
|
+ client: receive pushed judge tasks from website (websocket / socket.io / RabbitMQ)
|
||||||
+ data: interface to download, cache and access test files from website by id
|
+ data: interface to download, cache, lock and access test data files from website by data_id
|
||||||
+ taskqueue: send to and receive from a queue to run task (GO channel / (RabbitMQ, Redis)) and also including upload / download executable files from compile task
|
+ taskqueue: message queue to send run task and receive result (GO channel / (RabbitMQ, Redis))
|
||||||
+ file: general file interface (local / memory)
|
+ file: general file interface (disk / memory)
|
||||||
+ language: language configuration for runner
|
+ language: programming language compile & execute configurations
|
||||||
|
|
||||||
Workers:
|
Workers:
|
||||||
|
|
||||||
+ judger: execute judge tasks and distribute as run task to queue
|
+ judger: execute judge logics (compile / standard / interactive / answer submit) and distribute as run task to queue
|
||||||
+ runner: receive run task and execute in sandbox (compile / standard / interactive / answer submit)
|
+ runner: receive run task and execute in sandbox (dumb runner)
|
||||||
|
|
||||||
Models:
|
Models:
|
||||||
|
|
||||||
+ JudgeTask: judge task pushed from website (type, data)
|
+ JudgeTask: judge task pushed from website (type, source, data)
|
||||||
|
+ JudgeResult: judge task result send back to website
|
||||||
+ JudgeSetting: problem setting (from yaml) and JudgeCase
|
+ JudgeSetting: problem setting (from yaml) and JudgeCase
|
||||||
+ RunTask: run task parameters send to run_queue
|
+ RunTask: run task parameters send to run_queue
|
||||||
+ RunResult: run task result sent back from queue
|
+ RunResult: run task result sent back from queue
|
||||||
|
|||||||
@ -4,14 +4,19 @@ import "github.com/criyle/go-judge/types"
|
|||||||
|
|
||||||
// Task contains a single task received from web
|
// Task contains a single task received from web
|
||||||
type Task interface {
|
type Task interface {
|
||||||
|
// Param get the judge task
|
||||||
Param() *types.JudgeTask
|
Param() *types.JudgeTask
|
||||||
Progress(p types.JudgeProgress)
|
|
||||||
Finish(p types.JudgeResult)
|
// Progress emits current progress to website
|
||||||
|
Progress(*types.JudgeProgress)
|
||||||
|
|
||||||
|
// Finish emits the final result to website
|
||||||
|
Finish(*types.JudgeResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client should connect to web service and receive works from web
|
// Client should connect to web service and receive works from web
|
||||||
// it should sent received work through go channel (have background goroutine(s))
|
// it should sent received work through go channel (have background goroutine(s))
|
||||||
type Client interface {
|
type Client interface {
|
||||||
// C should return channel to receive works
|
// C return channel to receive works
|
||||||
C() <-chan Task
|
C() <-chan Task
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,13 @@ import "os"
|
|||||||
// File defines file name with its content
|
// File defines file name with its content
|
||||||
// file could on file system or memory
|
// file could on file system or memory
|
||||||
type File interface {
|
type File interface {
|
||||||
|
// Name get the file name
|
||||||
Name() string
|
Name() string
|
||||||
Content() ([]byte, error) // get content of the file
|
|
||||||
Open() (*os.File, error) // get readonly fd of the file
|
// Content reads the file content
|
||||||
|
Content() ([]byte, error)
|
||||||
|
|
||||||
|
// Open opens the file in readonly mode
|
||||||
|
// caller should close afterwards
|
||||||
|
Open() (*os.File, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,23 +3,26 @@ package localfile
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/criyle/go-judge/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
// File stores a path to represent a local file
|
// File stores a path to represent a local file
|
||||||
type File struct {
|
type File struct {
|
||||||
path string
|
name, path string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creats a wrapper to path
|
// New creates a wrapper to file system by path
|
||||||
func New(path string) *File {
|
func New(name, path string) file.File {
|
||||||
return &File{
|
return &File{
|
||||||
|
name: name,
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name get the path
|
// Name get the path
|
||||||
func (f *File) Name() string {
|
func (f *File) Name() string {
|
||||||
return f.path
|
return f.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content reads file content
|
// Content reads file content
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/criyle/go-judge/file"
|
||||||
"github.com/criyle/go-sandbox/pkg/memfd"
|
"github.com/criyle/go-sandbox/pkg/memfd"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,9 +14,8 @@ type File struct {
|
|||||||
content []byte
|
content []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// New create a file interface, content should not be modified after
|
// New create a file interface from content and content should not be modified afterwards
|
||||||
// NewMemFile
|
func New(name string, content []byte) file.File {
|
||||||
func New(name string, content []byte) *File {
|
|
||||||
return &File{
|
return &File{
|
||||||
name: name,
|
name: name,
|
||||||
content: content,
|
content: content,
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -2,4 +2,4 @@ module github.com/criyle/go-judge
|
|||||||
|
|
||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require github.com/criyle/go-sandbox v0.0.0-20190915221016-9898c301d566
|
require github.com/criyle/go-sandbox v0.0.0-20190929004305-4001c7c7671f
|
||||||
|
|||||||
8
go.sum
8
go.sum
@ -1,5 +1,5 @@
|
|||||||
github.com/criyle/go-sandbox v0.0.0-20190915221016-9898c301d566 h1:JB33qewgHSIHojNHn9tnFu1HaBwRkh8zBDP0LAu6Ars=
|
github.com/criyle/go-sandbox v0.0.0-20190929004305-4001c7c7671f h1:2VJ5GhYvEEXOwIeRF2SNepXp5TQ98ZjELGIriGWQIps=
|
||||||
github.com/criyle/go-sandbox v0.0.0-20190915221016-9898c301d566/go.mod h1:V5llzm3jeoB8pq2XEwX/tSVK3RQxjPl+vTSBDFGUO4A=
|
github.com/criyle/go-sandbox v0.0.0-20190929004305-4001c7c7671f/go.mod h1:xAafqqJsAlGuL8gMgnrbNtYLmCtAWzOZQ4kM9y6/zdk=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7 h1:wYqz/tQaWUgGKyx+B/rssSE6wkIKdY5Ee6ryOmzarIg=
|
golang.org/x/sys v0.0.0-20190927073244-c990c680b611 h1:q9u40nxWT5zRClI/uU9dHCiYGottAg6Nzz4YUQyHxdA=
|
||||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|||||||
@ -9,6 +9,6 @@ import (
|
|||||||
// Judger receives task from client and translate to task for runner
|
// Judger receives task from client and translate to task for runner
|
||||||
type Judger struct {
|
type Judger struct {
|
||||||
client.Client
|
client.Client
|
||||||
taskqueue.Queue
|
taskqueue.Sender
|
||||||
problem.Builder
|
problem.Builder
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,11 +30,11 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Judger) run(done <-chan struct{}, t client.Task) types.JudgeResult {
|
func (j *Judger) run(done <-chan struct{}, t client.Task) *types.JudgeResult {
|
||||||
var result types.JudgeResult
|
var result types.JudgeResult
|
||||||
errResult := func(err error) types.JudgeResult {
|
errResult := func(err error) *types.JudgeResult {
|
||||||
result.Error = err.Error()
|
result.Error = err.Error()
|
||||||
return result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
p := t.Param()
|
p := t.Param()
|
||||||
@ -45,7 +45,7 @@ func (j *Judger) run(done <-chan struct{}, t client.Task) types.JudgeResult {
|
|||||||
|
|
||||||
// compile
|
// compile
|
||||||
compileRet := make(chan types.RunTaskResult)
|
compileRet := make(chan types.RunTaskResult)
|
||||||
err = j.Enqueue(types.RunTask{
|
err = j.Send(types.RunTask{
|
||||||
Type: "compile",
|
Type: "compile",
|
||||||
Language: p.Language,
|
Language: p.Language,
|
||||||
Code: p.Code,
|
Code: p.Code,
|
||||||
@ -78,7 +78,7 @@ func (j *Judger) run(done <-chan struct{}, t client.Task) types.JudgeResult {
|
|||||||
for range pconf.Subtasks {
|
for range pconf.Subtasks {
|
||||||
result.SubTasks = append(result.SubTasks, <-subTaskResult)
|
result.SubTasks = append(result.SubTasks, <-subTaskResult)
|
||||||
}
|
}
|
||||||
return result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
type problemJudger struct {
|
type problemJudger struct {
|
||||||
@ -94,12 +94,12 @@ func (pj *problemJudger) runSubtask(done <-chan struct{}, exec []file.File, s *t
|
|||||||
var result types.JudgeSubTaskResult
|
var result types.JudgeSubTaskResult
|
||||||
caseResult := make(chan types.RunTaskResult, len(s.Cases))
|
caseResult := make(chan types.RunTaskResult, len(s.Cases))
|
||||||
for _, c := range s.Cases {
|
for _, c := range s.Cases {
|
||||||
pj.Enqueue(types.RunTask{
|
pj.Send(types.RunTask{
|
||||||
Type: pj.ProblemConfig.Type,
|
Type: pj.ProblemConfig.Type,
|
||||||
Language: pj.Language,
|
Language: pj.Language,
|
||||||
TimeLimit: pj.TileLimit,
|
TimeLimit: pj.TileLimit,
|
||||||
MemoryLimit: pj.MemoryLimit,
|
MemoryLimit: pj.MemoryLimit,
|
||||||
Executables: exec,
|
ExtraFiles: exec,
|
||||||
InputFile: c.Input,
|
InputFile: c.Input,
|
||||||
AnswerFile: c.Answer,
|
AnswerFile: c.Answer,
|
||||||
}, caseResult)
|
}, caseResult)
|
||||||
@ -121,7 +121,7 @@ func (pj *problemJudger) runSubtask(done <-chan struct{}, exec []file.File, s *t
|
|||||||
result.Score += rt.ScoringRate
|
result.Score += rt.ScoringRate
|
||||||
// report prograss
|
// report prograss
|
||||||
atomic.AddInt32(&pj.count, 1)
|
atomic.AddInt32(&pj.count, 1)
|
||||||
pj.Progress(types.JudgeProgress{
|
pj.Progress(&types.JudgeProgress{
|
||||||
Message: fmt.Sprintf("%d/%d", pj.count, pj.total),
|
Message: fmt.Sprintf("%d/%d", pj.count, pj.total),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type pool struct {
|
type pool struct {
|
||||||
queue chan *daemon.Master
|
builder *daemon.Builder
|
||||||
count int32
|
queue chan *daemon.Master
|
||||||
root string
|
count int32
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxPoolSize = 64
|
const maxPoolSize = 64
|
||||||
|
|
||||||
func newPool(root string) *pool {
|
func newPool(builder *daemon.Builder) *pool {
|
||||||
return &pool{
|
return &pool{
|
||||||
queue: make(chan *daemon.Master, maxPoolSize),
|
queue: make(chan *daemon.Master, maxPoolSize),
|
||||||
root: root,
|
builder: builder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ func (p *pool) Get() (*daemon.Master, error) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
atomic.AddInt32(&p.count, 1)
|
atomic.AddInt32(&p.count, 1)
|
||||||
return daemon.New(p.root)
|
return p.builder.Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pool) Put(master *daemon.Master) {
|
func (p *pool) Put(master *daemon.Master) {
|
||||||
|
|||||||
@ -21,7 +21,9 @@ const cgroupPrefix = "go-judge"
|
|||||||
const minCPUPercent = 40 // 40%
|
const minCPUPercent = 40 // 40%
|
||||||
const checkIntervalMS = 50
|
const checkIntervalMS = 50
|
||||||
|
|
||||||
var env = []string{"PATH=/usr/local/bin:/usr/bin:/bin"}
|
var env = []string{
|
||||||
|
"PATH=/usr/local/bin:/usr/bin:/bin",
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Runner) run(done <-chan struct{}, task *types.RunTask) *types.RunTaskResult {
|
func (r *Runner) run(done <-chan struct{}, task *types.RunTask) *types.RunTaskResult {
|
||||||
t := language.TypeExec
|
t := language.TypeExec
|
||||||
@ -80,7 +82,7 @@ func (r *Runner) run(done <-chan struct{}, task *types.RunTask) *types.RunTaskRe
|
|||||||
SyncFunc: cg.AddProc,
|
SyncFunc: cg.AddProc,
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyin source code for compile or executables for exec
|
// copyin source code for compile or exec files for exec
|
||||||
if t == language.TypeCompile {
|
if t == language.TypeCompile {
|
||||||
source := memfile.New("source", []byte(task.Code))
|
source := memfile.New("source", []byte(task.Code))
|
||||||
sourceFile, err := source.Open()
|
sourceFile, err := source.Open()
|
||||||
@ -92,7 +94,7 @@ func (r *Runner) run(done <-chan struct{}, task *types.RunTask) *types.RunTaskRe
|
|||||||
return errResult(err.Error())
|
return errResult(err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, f := range task.Executables {
|
for _, f := range task.ExecFiles {
|
||||||
execFile, err := f.Open()
|
execFile, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errResult(err.Error())
|
return errResult(err.Error())
|
||||||
@ -131,7 +133,7 @@ func (r *Runner) run(done <-chan struct{}, task *types.RunTask) *types.RunTaskRe
|
|||||||
var lastCPUUsage uint64
|
var lastCPUUsage uint64
|
||||||
var totalTime time.Duration
|
var totalTime time.Duration
|
||||||
var rt stypes.Result
|
var rt stypes.Result
|
||||||
var rtreceived bool
|
var rtReceived bool
|
||||||
lastCheckTime := time.Now()
|
lastCheckTime := time.Now()
|
||||||
|
|
||||||
// wait task finish
|
// wait task finish
|
||||||
@ -156,7 +158,7 @@ loop:
|
|||||||
lastCPUUsage = cpuUsage
|
lastCPUUsage = cpuUsage
|
||||||
|
|
||||||
case rt = <-rc: // returned
|
case rt = <-rc: // returned
|
||||||
rtreceived = true
|
rtReceived = true
|
||||||
break loop
|
break loop
|
||||||
|
|
||||||
case <-outputPipe.Done: // outputlimit exceeded
|
case <-outputPipe.Done: // outputlimit exceeded
|
||||||
@ -169,7 +171,7 @@ loop:
|
|||||||
|
|
||||||
// get result if did not received
|
// get result if did not received
|
||||||
cancelC.cancel()
|
cancelC.cancel()
|
||||||
if !rtreceived {
|
if !rtReceived {
|
||||||
rt = <-rc
|
rt = <-rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,38 +5,49 @@ import (
|
|||||||
|
|
||||||
"github.com/criyle/go-judge/language"
|
"github.com/criyle/go-judge/language"
|
||||||
"github.com/criyle/go-judge/taskqueue"
|
"github.com/criyle/go-judge/taskqueue"
|
||||||
|
"github.com/criyle/go-sandbox/daemon"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runner is the task runner
|
// Runner is the task runner
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
Queue taskqueue.Queue
|
// Queue is the message queue to receive run tasks
|
||||||
|
Queue taskqueue.Receiver
|
||||||
|
|
||||||
|
// Builder builds the sandbox runner
|
||||||
|
Builder *daemon.Builder
|
||||||
|
|
||||||
Language language.Language
|
Language language.Language
|
||||||
Root string
|
|
||||||
pool *pool
|
// pool of sandbox to use
|
||||||
once sync.Once
|
pool *pool
|
||||||
|
once sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) init() {
|
func (r *Runner) init() {
|
||||||
r.pool = newPool(r.Root)
|
r.pool = newPool(r.Builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop status a runner in a forever loop, waiting for task and execute
|
// Loop status a runner in a forever loop, waiting for task and execute
|
||||||
// call it in new goroutine
|
// call it in new goroutine
|
||||||
func (r *Runner) Loop(done <-chan struct{}) error {
|
func (r *Runner) Loop(done <-chan struct{}) error {
|
||||||
r.once.Do(r.init)
|
r.once.Do(r.init)
|
||||||
c := r.Queue.C()
|
c := r.Queue.ReceiveC()
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
break loop
|
break loop
|
||||||
|
|
||||||
case task := <-c:
|
case task := <-c:
|
||||||
select {
|
task.Done(r.run(done, task.Task()))
|
||||||
case <-done:
|
}
|
||||||
break loop
|
|
||||||
default:
|
// check if cancel is signaled
|
||||||
task.Finish(r.run(done, task.Task()))
|
select {
|
||||||
}
|
case <-done:
|
||||||
|
break loop
|
||||||
|
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -7,20 +7,20 @@ import (
|
|||||||
|
|
||||||
const buffSize = 512
|
const buffSize = 512
|
||||||
|
|
||||||
// Queue implements taskqueue by go channel
|
// Queue implements taskqueue by buffered go channel
|
||||||
type Queue struct {
|
type Queue struct {
|
||||||
queue chan taskqueue.Task
|
queue chan taskqueue.Task
|
||||||
}
|
}
|
||||||
|
|
||||||
// New craetes new Queue with buffed go channel
|
// New creates new Queue with buffed go channel
|
||||||
func New() *Queue {
|
func New() taskqueue.Queue {
|
||||||
return &Queue{
|
return &Queue{
|
||||||
queue: make(chan taskqueue.Task, buffSize),
|
queue: make(chan taskqueue.Task, buffSize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue puts task into run queue
|
// Send puts task into run queue
|
||||||
func (q *Queue) Enqueue(t types.RunTask, r chan<- types.RunTaskResult) error {
|
func (q *Queue) Send(t types.RunTask, r chan<- types.RunTaskResult) error {
|
||||||
q.queue <- Task{
|
q.queue <- Task{
|
||||||
task: t,
|
task: t,
|
||||||
result: r,
|
result: r,
|
||||||
@ -28,8 +28,8 @@ func (q *Queue) Enqueue(t types.RunTask, r chan<- types.RunTaskResult) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// C returns the underlying channel
|
// ReceiveC returns the underlying channel
|
||||||
func (q *Queue) C() <-chan taskqueue.Task {
|
func (q *Queue) ReceiveC() <-chan taskqueue.Task {
|
||||||
return q.queue
|
return q.queue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ func (t Task) Task() *types.RunTask {
|
|||||||
return &t.task
|
return &t.task
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish returns the run task result
|
// Done returns the run task result
|
||||||
func (t Task) Finish(r *types.RunTaskResult) {
|
func (t Task) Done(r *types.RunTaskResult) {
|
||||||
t.result <- *r
|
t.result <- *r
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,29 @@ package taskqueue
|
|||||||
|
|
||||||
import "github.com/criyle/go-judge/types"
|
import "github.com/criyle/go-judge/types"
|
||||||
|
|
||||||
// Queue provides asynchronous message queue to run execution tasks
|
// Sender interface is used to send run task into message queue
|
||||||
|
type Sender interface {
|
||||||
|
// Send used to initial a RPC call and receive result to channel (should have enough space)
|
||||||
|
Send(types.RunTask, chan<- types.RunTaskResult) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receiver interface is used to receive run task from message queue
|
||||||
|
type Receiver interface {
|
||||||
|
// ReceiveC get the channel to receive tasks
|
||||||
|
ReceiveC() <-chan Task
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue provides asynchronous message queue for run tasks
|
||||||
type Queue interface {
|
type Queue interface {
|
||||||
// Enqueue used to initial a RPC call and receive result to channel
|
Sender
|
||||||
Enqueue(types.RunTask, chan<- types.RunTaskResult) error
|
Receiver
|
||||||
C() <-chan Task
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task represent a single task to run
|
// Task represent a single task to run
|
||||||
type Task interface {
|
type Task interface {
|
||||||
|
// Task gets the run task parameter
|
||||||
Task() *types.RunTask
|
Task() *types.RunTask
|
||||||
Finish(*types.RunTaskResult)
|
|
||||||
|
// Done returns the run task result for the run task (should be called only once at end)
|
||||||
|
Done(*types.RunTaskResult)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,17 +15,17 @@ type RunTask struct {
|
|||||||
// Used for run tasks
|
// Used for run tasks
|
||||||
TimeLimit uint64 // ms
|
TimeLimit uint64 // ms
|
||||||
MemoryLimit uint64 // kb
|
MemoryLimit uint64 // kb
|
||||||
Executables []file.File
|
ExecFiles []file.File
|
||||||
InputFile file.File
|
InputFile file.File
|
||||||
AnswerFile file.File
|
AnswerFile file.File
|
||||||
|
|
||||||
// Used for standard run task
|
// Used for standard run task
|
||||||
SpjLanguage string
|
SpjLanguage string
|
||||||
SpjExecutables []file.File
|
SpjExecFiles []file.File
|
||||||
|
|
||||||
// Used for interaction run task
|
// Used for interaction run task
|
||||||
InteractorLanguage string
|
InteractorLanguage string
|
||||||
InteractorExecutables []file.File
|
InteractorExecFiles []file.File
|
||||||
|
|
||||||
// Used for answer submission run task
|
// Used for answer submission run task
|
||||||
UserAnswer file.File
|
UserAnswer file.File
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user