From 1f0fe639a73e1d91d4588fa05b44bd1008e996c5 Mon Sep 17 00:00:00 2001 From: criyle Date: Tue, 31 Dec 2019 12:46:03 +0800 Subject: [PATCH] add judge-v3 progress type --- client/syzojclient/api.md | 13 ++++- client/syzojclient/client.go | 15 ------ client/syzojclient/progress.go | 97 ++++++++++++++++++++++++++++++++++ client/syzojclient/task.go | 9 ++++ judger/loop.go | 44 +++++++-------- taskqueue/channel/channel.go | 9 ++-- taskqueue/interface.go | 4 +- 7 files changed, 148 insertions(+), 43 deletions(-) create mode 100644 client/syzojclient/progress.go diff --git a/client/syzojclient/api.md b/client/syzojclient/api.md index 1c985b7..18c9a98 100644 --- a/client/syzojclient/api.md +++ b/client/syzojclient/api.md @@ -161,8 +161,8 @@ TestcaseDetails ``` typescript interface { type: TestcaseResultType; - time: number; - memory: number; + time: number; // ms + memory: number; // kb input?: FileContent; output?: FileContent; // Output in test data scoringRate: number; // e.g. 0.5 @@ -172,3 +172,12 @@ interface { systemMessage?: string; } ``` + +FileContent + +``` typescript +interface FileContent { + content: string, + name: string +} +``` diff --git a/client/syzojclient/client.go b/client/syzojclient/client.go index f9cfaa0..7becfb0 100644 --- a/client/syzojclient/client.go +++ b/client/syzojclient/client.go @@ -204,21 +204,6 @@ type judgeParameter struct { // interaction } -type judgeProgress struct { - TaskID string `json:"taskId"` - Type int `json:"type"` - Progress judgeResultProgress `json:"progress"` -} - -type judgeResultProgress struct { - Subtasks []subtaskResult `json:"subtasks"` -} - -type subtaskResult struct { - Time uint64 `json:"time"` - Memory uint64 `json:"memory"` -} - func newTask(c *Client, msg *judgeTask, ackID uint64) client.Task { task := &types.JudgeTask{ Type: types.Standard, diff --git a/client/syzojclient/progress.go b/client/syzojclient/progress.go new file mode 100644 index 0000000..a143139 --- /dev/null +++ b/client/syzojclient/progress.go @@ -0,0 +1,97 @@ +package syzojclient + +type progressType int + +const ( + progressStarted progressType = iota + 1 + progressCompiled + progressProgress + progressFinished + progressReported +) + +type taskStatus int + +const ( + statusWaiting taskStatus = iota + statusRunning + statusDone + statusFailed + statusSkipped +) + +type errType int + +const ( + errSystem errType = iota + errData +) + +type testCaseResultType int + +const ( + resultAccepted testCaseResultType = iota + 1 + resultWrongAnswer + resultPartiallyCorrect + resultMemoryLimitExceeded + resultTimeLimitExceeded + resultOutputLimitExceeded + resultFileError + resultRuntimeError + resultJudgementFailed + resultInvalidInteraction +) + +type result struct { + TaskID string `json:"taskId"` + Type progressType `json:"type"` + Progress progress `json:"progress"` +} + +type progress struct { + Status taskStatus `json:"status"` + Message string `json:"message"` + + Error *errType `json:"error"` + SystemMessage *string `json:"systemMessage"` + Compile *compileResult `json:"compile"` + Judge *judgeResult `json:"judge"` +} + +type judgeResult struct { + Subtasks []subtaskResult `json:"subtasks"` +} + +type subtaskResult struct { + Score *float64 `json:"score"` + Cases []caseResult `json:"cases"` +} + +type caseResult struct { + Status taskStatus `json:"status"` + Result *testcaseDetails `json:"result"` + Error *string `json:"errorMessage"` +} + +type testcaseDetails struct { + Status testCaseResultType `json:"type"` + Time uint64 `json:"time"` // ms + Memory uint64 `json:"memory"` // kb + Input *fileContent `json:"input"` + Output *fileContent `json:"output"` + ScoringRate float64 `json:"scoringRate"` + UserOutput *string `json:"userOutput"` + UserError *string `json:"userError"` + SPJMessage *string `json:"spjError"` + SystemMessage *string `json:"systemMessage"` +} + +type fileContent struct { + Content string `json:"content"` + Name string `json:"name"` +} + +type compileResult struct { + Status taskStatus `json:"status"` + Message string `json:"message"` +} diff --git a/client/syzojclient/task.go b/client/syzojclient/task.go index df03452..53f3d84 100644 --- a/client/syzojclient/task.go +++ b/client/syzojclient/task.go @@ -16,6 +16,15 @@ type Task struct { ackID uint64 } +// NewTask creates new syzoj task +func NewTask(client *Client, task *types.JudgeTask, ackID uint64) *Task { + return &Task{ + client: client, + task: task, + ackID: ackID, + } +} + // Param param func (t *Task) Param() *types.JudgeTask { return t.task diff --git a/judger/loop.go b/judger/loop.go index 10abfbe..8170611 100644 --- a/judger/loop.go +++ b/judger/loop.go @@ -51,11 +51,10 @@ func (j *Judger) run(done <-chan struct{}, t client.Task) *types.JudgeResult { t.Parsed(&pConf) // compile - compileRet := make(chan types.RunTaskResult, 1) - err = j.Send(types.RunTask{ + compileRet, err := j.Send(types.RunTask{ Type: types.Compile, Compile: (*types.CompileTask)(&p.Code), - }, compileRet) + }) if err != nil { return errResult(err) } @@ -126,9 +125,8 @@ func (pj *problemJudger) runSubtask(done <-chan struct{}, s *types.SubTask, sInd defer wg.Done() c := s.Cases[i] - rtC := make(chan types.RunTaskResult) - pj.Send(types.RunTask{ + rtC, err := pj.Send(types.RunTask{ Type: pj.ProblemConfig.Type, Exec: &types.ExecTask{ Exec: pj.Exec, @@ -137,24 +135,28 @@ func (pj *problemJudger) runSubtask(done <-chan struct{}, s *types.SubTask, sInd InputFile: c.Input, AnswerFile: c.Answer, }, - }, rtC) + }) - rt := <-rtC + var ret types.TestCaseResult + if err != nil { + ret.Status = types.ProgressFailed + } else { + // receive result from queue + rt := <-rtC - // run task result -> test case result - ret := types.TestCaseResult{ - Status: types.ProgressStatus(rt.Status), - } - if execRt := rt.Exec; execRt != nil { - ret.Error = execRt.Error - ret.ScoreRate = execRt.ScoringRate - ret.Time = execRt.Time - ret.Memory = execRt.Memory - ret.Input = execRt.Input - ret.Answer = execRt.Answer - ret.UserOutput = execRt.UserOutput - ret.UserError = execRt.UserError - ret.SPJOutput = execRt.SPJOutput + // run task result -> test case result + ret.Status = types.ProgressStatus(rt.Status) + if execRt := rt.Exec; execRt != nil { + ret.Error = execRt.Error + ret.ScoreRate = execRt.ScoringRate + ret.Time = execRt.Time + ret.Memory = execRt.Memory + ret.Input = execRt.Input + ret.Answer = execRt.Answer + ret.UserOutput = execRt.UserOutput + ret.UserError = execRt.UserError + ret.SPJOutput = execRt.SPJOutput + } } // store result diff --git a/taskqueue/channel/channel.go b/taskqueue/channel/channel.go index 2d7da06..7c8b3d8 100644 --- a/taskqueue/channel/channel.go +++ b/taskqueue/channel/channel.go @@ -7,6 +7,8 @@ import ( const buffSize = 512 +var _ taskqueue.Queue = &Queue{} + // Queue implements taskqueue by buffered go channel type Queue struct { queue chan taskqueue.Task @@ -20,12 +22,13 @@ func New() taskqueue.Queue { } // Send puts task into run queue -func (q *Queue) Send(t types.RunTask, r chan<- types.RunTaskResult) error { +func (q *Queue) Send(t types.RunTask) (<-chan types.RunTaskResult, error) { + c := make(chan types.RunTaskResult, 1) q.queue <- Task{ task: t, - result: r, + result: c, } - return nil + return c, nil } // ReceiveC returns the underlying channel diff --git a/taskqueue/interface.go b/taskqueue/interface.go index ba853e0..1804936 100644 --- a/taskqueue/interface.go +++ b/taskqueue/interface.go @@ -4,8 +4,8 @@ import "github.com/criyle/go-judge/types" // 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 + // Send used to initial a RPC call and receive result from channel + Send(types.RunTask) (<-chan types.RunTaskResult, error) } // Receiver interface is used to receive run task from message queue