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
|
||||
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),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user