add syzoj progress

This commit is contained in:
criyle 2020-01-01 19:35:02 +08:00
parent b9fc4032b3
commit b0345501e3
3 changed files with 179 additions and 20 deletions

View File

@ -37,7 +37,8 @@ type Client struct {
socket engineio.Conn
tasks chan client.Task
progress chan *types.ProgressProgressed
progress chan *result
result chan *result
finish chan *types.JudgeResult
request chan struct{}
ack chan ack
@ -60,7 +61,8 @@ func NewClient(url, token string) (*Client, chan error, error) {
token: token,
socket: socket,
tasks: make(chan client.Task, buffSize),
progress: make(chan *types.ProgressProgressed, buffSize),
progress: make(chan *result, buffSize),
result: make(chan *result, buffSize),
finish: make(chan *types.JudgeResult, buffSize),
request: make(chan struct{}, 1),
ack: make(chan ack, 1),
@ -153,6 +155,27 @@ func (c *Client) writeLoop() (err error) {
return err
}
sendProgress := func(event string, p interface{}) error {
var d []byte
if err := codec.NewEncoderBytes(&d, &codec.MsgpackHandle{}).Encode(p); err != nil {
return err
}
// binary encoding
buff := &parser.Buffer{
Data: d,
}
if err := c.encoder.Encode(parser.Header{
Type: parser.Event,
Namespace: namespace,
NeedAck: true,
}, []interface{}{event, c.token, buff}); err != nil {
return err
}
return nil
}
for {
select {
case <-c.Done:
@ -167,6 +190,16 @@ func (c *Client) writeLoop() (err error) {
return err
}
case p := <-c.progress:
if err := sendProgress("reportProgress", p); err != nil {
return err
}
case r := <-c.result:
if err := sendProgress("reportResult", r); err != nil {
return err
}
case a := <-c.ack:
if err := c.encoder.Encode(parser.Header{
Type: parser.Ack,
@ -219,6 +252,7 @@ func newTask(c *Client, msg *judgeTask, ackID uint64) client.Task {
client: c,
task: task,
ackID: ackID,
taskID: msg.Content.TaskID,
parsed: make(chan *types.ProblemConfig),
compiled: make(chan *types.ProgressCompiled),

View File

@ -49,41 +49,41 @@ type result struct {
}
type progress struct {
Status taskStatus `json:"status"`
Message string `json:"message"`
Status taskStatus `json:"status,omitempty"`
Message string `json:"message,omitempty"`
Error *errType `json:"error"`
SystemMessage *string `json:"systemMessage"`
Compile *compileResult `json:"compile"`
Judge *judgeResult `json:"judge"`
Error *errType `json:"error,omitempty"`
SystemMessage *string `json:"systemMessage,omitempty"`
Compile *compileResult `json:"compile,omitempty"`
Judge *judgeResult `json:"judge,omitempty"`
}
type judgeResult struct {
Subtasks []subtaskResult `json:"subtasks"`
Subtasks []subtaskResult `json:"subtasks,omitempty"`
}
type subtaskResult struct {
Score *float64 `json:"score"`
Cases []caseResult `json:"cases"`
Score float64 `json:"score,omitempty"`
Cases []caseResult `json:"cases,omitempty"`
}
type caseResult struct {
Status taskStatus `json:"status"`
Result *testcaseDetails `json:"result"`
Error *string `json:"errorMessage"`
Result *testcaseDetails `json:"result,omitempty"`
Error string `json:"errorMessage,omitempty"`
}
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"`
Input *fileContent `json:"input,omitempty"`
Output *fileContent `json:"output,omitempty"`
ScoringRate float64 `json:"scoringRate,omitempty"`
UserOutput *string `json:"userOutput,omitempty"`
UserError *string `json:"userError,omitempty"`
SPJMessage *string `json:"spjError,omitempty"`
SystemMessage *string `json:"systemMessage,omitempty"`
}
type fileContent struct {

View File

@ -14,6 +14,7 @@ type Task struct {
client *Client
task *types.JudgeTask
ackID uint64
taskID string
parsed chan *types.ProblemConfig
compiled chan *types.ProgressCompiled
@ -47,24 +48,148 @@ func (t *Task) Finished(r *types.JudgeResult) {
}
func (t *Task) loop() {
var (
jr judgeResult
cr *compileResult
)
loop:
for {
select {
case pConf := <-t.parsed:
log.Println(pConf)
initResult(pConf, &jr)
rt := &result{
TaskID: t.taskID,
Type: progressStarted,
}
t.client.progress <- rt
case compiled := <-t.compiled:
log.Println(compiled)
cr = &compileResult{
Status: convertStatus(compiled.Status),
Message: compiled.Message,
}
rt := &result{
TaskID: t.taskID,
Type: progressCompiled,
Progress: progress{
Status: convertStatus(compiled.Status),
Message: compiled.Message,
},
}
t.client.progress <- rt
t.client.result <- rt
case progressed := <-t.progressed:
log.Println(progressed)
updateResult(progressed, &jr)
rt := &result{
TaskID: t.taskID,
Type: progressProgress,
Progress: progress{
Compile: cr,
Judge: &jr,
},
}
t.client.progress <- rt
case finished := <-t.finished:
log.Println(finished)
rt := &result{
TaskID: t.taskID,
Type: progressFinished,
Progress: progress{
Compile: cr,
Judge: &jr,
},
}
t.client.progress <- rt
t.client.result <- rt
t.client.ack <- ack{id: t.ackID}
t.client.request <- struct{}{}
break loop
}
}
}
func initResult(p *types.ProblemConfig, jr *judgeResult) {
jr.Subtasks = make([]subtaskResult, len(p.Subtasks))
for i := range jr.Subtasks {
initSubtaskResult(&p.Subtasks[i], &jr.Subtasks[i])
}
}
func initSubtaskResult(p *types.SubTask, sr *subtaskResult) {
sr.Cases = make([]caseResult, len(p.Cases))
}
func convertStatus(s types.ProgressStatus) taskStatus {
switch s {
case types.ProgressSucceeded:
return statusDone
default:
return statusFailed
}
}
func convertResultTypes(s types.Status) testCaseResultType {
switch s {
case types.StatusAccepted:
return resultAccepted
case types.StatusWrongAnswer:
return resultWrongAnswer
case types.StatusPartiallyCorrect:
return resultPartiallyCorrect
case types.StatusMemoryLimitExceeded:
return resultMemoryLimitExceeded
case types.StatusTimeLimitExceeded:
return resultTimeLimitExceeded
case types.StatusOutputLimitExceeded:
return resultOutputLimitExceeded
case types.StatusFileError:
return resultFileError
case types.StatusRuntimeError:
return resultRuntimeError
case types.StatusJudgementFailed:
return resultJudgementFailed
case types.StatusInvalidInteraction:
return resultInvalidInteraction
default:
return resultRuntimeError
}
}
func updateResult(p *types.ProgressProgressed, jr *judgeResult) {
st := &jr.Subtasks[p.SubTaskIndex]
st.Score += 100 * p.ScoreRate / float64(len(jr.Subtasks[p.SubTaskIndex].Cases))
cr := &st.Cases[p.TestCaseIndex]
cr.Status = convertStatus(p.Status)
cr.Error = p.Error
cr.Result = &testcaseDetails{
Status: convertResultTypes(p.ExecStatus),
Time: p.Time,
Memory: p.Memory,
Input: getFileContent("input", p.Input),
Output: getFileContent("output", p.Answer),
ScoringRate: p.ScoreRate,
UserOutput: getStringP(p.UserOutput),
UserError: getStringP(p.UserError),
SPJMessage: getStringP(p.SPJOutput),
}
}
func getFileContent(name string, b []byte) *fileContent {
return &fileContent{
Name: name,
Content: string(b),
}
}
func getStringP(b []byte) *string {
s := string(b)
return &s
}