mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
add syzoj progress
This commit is contained in:
parent
b9fc4032b3
commit
b0345501e3
@ -37,7 +37,8 @@ type Client struct {
|
|||||||
|
|
||||||
socket engineio.Conn
|
socket engineio.Conn
|
||||||
tasks chan client.Task
|
tasks chan client.Task
|
||||||
progress chan *types.ProgressProgressed
|
progress chan *result
|
||||||
|
result chan *result
|
||||||
finish chan *types.JudgeResult
|
finish chan *types.JudgeResult
|
||||||
request chan struct{}
|
request chan struct{}
|
||||||
ack chan ack
|
ack chan ack
|
||||||
@ -60,7 +61,8 @@ func NewClient(url, token string) (*Client, chan error, error) {
|
|||||||
token: token,
|
token: token,
|
||||||
socket: socket,
|
socket: socket,
|
||||||
tasks: make(chan client.Task, buffSize),
|
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),
|
finish: make(chan *types.JudgeResult, buffSize),
|
||||||
request: make(chan struct{}, 1),
|
request: make(chan struct{}, 1),
|
||||||
ack: make(chan ack, 1),
|
ack: make(chan ack, 1),
|
||||||
@ -153,6 +155,27 @@ func (c *Client) writeLoop() (err error) {
|
|||||||
return err
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-c.Done:
|
case <-c.Done:
|
||||||
@ -167,6 +190,16 @@ func (c *Client) writeLoop() (err error) {
|
|||||||
return err
|
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:
|
case a := <-c.ack:
|
||||||
if err := c.encoder.Encode(parser.Header{
|
if err := c.encoder.Encode(parser.Header{
|
||||||
Type: parser.Ack,
|
Type: parser.Ack,
|
||||||
@ -219,6 +252,7 @@ func newTask(c *Client, msg *judgeTask, ackID uint64) client.Task {
|
|||||||
client: c,
|
client: c,
|
||||||
task: task,
|
task: task,
|
||||||
ackID: ackID,
|
ackID: ackID,
|
||||||
|
taskID: msg.Content.TaskID,
|
||||||
|
|
||||||
parsed: make(chan *types.ProblemConfig),
|
parsed: make(chan *types.ProblemConfig),
|
||||||
compiled: make(chan *types.ProgressCompiled),
|
compiled: make(chan *types.ProgressCompiled),
|
||||||
|
|||||||
@ -49,41 +49,41 @@ type result struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type progress struct {
|
type progress struct {
|
||||||
Status taskStatus `json:"status"`
|
Status taskStatus `json:"status,omitempty"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message,omitempty"`
|
||||||
|
|
||||||
Error *errType `json:"error"`
|
Error *errType `json:"error,omitempty"`
|
||||||
SystemMessage *string `json:"systemMessage"`
|
SystemMessage *string `json:"systemMessage,omitempty"`
|
||||||
Compile *compileResult `json:"compile"`
|
Compile *compileResult `json:"compile,omitempty"`
|
||||||
Judge *judgeResult `json:"judge"`
|
Judge *judgeResult `json:"judge,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type judgeResult struct {
|
type judgeResult struct {
|
||||||
Subtasks []subtaskResult `json:"subtasks"`
|
Subtasks []subtaskResult `json:"subtasks,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type subtaskResult struct {
|
type subtaskResult struct {
|
||||||
Score *float64 `json:"score"`
|
Score float64 `json:"score,omitempty"`
|
||||||
Cases []caseResult `json:"cases"`
|
Cases []caseResult `json:"cases,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type caseResult struct {
|
type caseResult struct {
|
||||||
Status taskStatus `json:"status"`
|
Status taskStatus `json:"status"`
|
||||||
Result *testcaseDetails `json:"result"`
|
Result *testcaseDetails `json:"result,omitempty"`
|
||||||
Error *string `json:"errorMessage"`
|
Error string `json:"errorMessage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type testcaseDetails struct {
|
type testcaseDetails struct {
|
||||||
Status testCaseResultType `json:"type"`
|
Status testCaseResultType `json:"type"`
|
||||||
Time uint64 `json:"time"` // ms
|
Time uint64 `json:"time"` // ms
|
||||||
Memory uint64 `json:"memory"` // kb
|
Memory uint64 `json:"memory"` // kb
|
||||||
Input *fileContent `json:"input"`
|
Input *fileContent `json:"input,omitempty"`
|
||||||
Output *fileContent `json:"output"`
|
Output *fileContent `json:"output,omitempty"`
|
||||||
ScoringRate float64 `json:"scoringRate"`
|
ScoringRate float64 `json:"scoringRate,omitempty"`
|
||||||
UserOutput *string `json:"userOutput"`
|
UserOutput *string `json:"userOutput,omitempty"`
|
||||||
UserError *string `json:"userError"`
|
UserError *string `json:"userError,omitempty"`
|
||||||
SPJMessage *string `json:"spjError"`
|
SPJMessage *string `json:"spjError,omitempty"`
|
||||||
SystemMessage *string `json:"systemMessage"`
|
SystemMessage *string `json:"systemMessage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileContent struct {
|
type fileContent struct {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type Task struct {
|
|||||||
client *Client
|
client *Client
|
||||||
task *types.JudgeTask
|
task *types.JudgeTask
|
||||||
ackID uint64
|
ackID uint64
|
||||||
|
taskID string
|
||||||
|
|
||||||
parsed chan *types.ProblemConfig
|
parsed chan *types.ProblemConfig
|
||||||
compiled chan *types.ProgressCompiled
|
compiled chan *types.ProgressCompiled
|
||||||
@ -47,24 +48,148 @@ func (t *Task) Finished(r *types.JudgeResult) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) loop() {
|
func (t *Task) loop() {
|
||||||
|
var (
|
||||||
|
jr judgeResult
|
||||||
|
cr *compileResult
|
||||||
|
)
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case pConf := <-t.parsed:
|
case pConf := <-t.parsed:
|
||||||
log.Println(pConf)
|
log.Println(pConf)
|
||||||
|
initResult(pConf, &jr)
|
||||||
|
rt := &result{
|
||||||
|
TaskID: t.taskID,
|
||||||
|
Type: progressStarted,
|
||||||
|
}
|
||||||
|
t.client.progress <- rt
|
||||||
|
|
||||||
case compiled := <-t.compiled:
|
case compiled := <-t.compiled:
|
||||||
log.Println(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:
|
case progressed := <-t.progressed:
|
||||||
log.Println(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:
|
case finished := <-t.finished:
|
||||||
log.Println(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.ack <- ack{id: t.ackID}
|
||||||
t.client.request <- struct{}{}
|
t.client.request <- struct{}{}
|
||||||
break loop
|
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
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user