chore(internal/stage): organize models to separated files
This commit is contained in:
parent
ad549a4499
commit
b6edc2c571
|
@ -1,8 +1,6 @@
|
||||||
package dummy
|
package dummy
|
||||||
|
|
||||||
import (
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *Dummy) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Dummy) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
var res []stage.ExecutorResult
|
var res []stage.ExecutorResult
|
||||||
|
|
47
internal/stage/cmd.go
Normal file
47
internal/stage/cmd.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package stage
|
||||||
|
|
||||||
|
// copied from https://github.com/criyle/go-judge/blob/master/cmd/go-judge/model/model.go
|
||||||
|
// CmdFile defines file from multiple source including local / memory / cached or pipe collector
|
||||||
|
type CmdFile struct {
|
||||||
|
Src *string `json:"src"`
|
||||||
|
Content *string `json:"content"`
|
||||||
|
FileID *string `json:"fileId"`
|
||||||
|
Name *string `json:"name"`
|
||||||
|
Max *int64 `json:"max"`
|
||||||
|
Symlink *string `json:"symlink"`
|
||||||
|
StreamIn bool `json:"streamIn"`
|
||||||
|
StreamOut bool `json:"streamOut"`
|
||||||
|
Pipe bool `json:"pipe"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd defines command and limits to start a program using in envexec
|
||||||
|
type Cmd struct {
|
||||||
|
Args []string `json:"args"`
|
||||||
|
Env []string `json:"env,omitempty"`
|
||||||
|
Stdin *CmdFile `json:"stdin,omitempty"`
|
||||||
|
Stdout *CmdFile `json:"stdout,omitempty"`
|
||||||
|
Stderr *CmdFile `json:"stderr,omitempty"`
|
||||||
|
|
||||||
|
CPULimit uint64 `json:"cpuLimit"` // ns
|
||||||
|
RealCPULimit uint64 `json:"realCpuLimit"` // deprecated: use clock limit instead (still working)
|
||||||
|
ClockLimit uint64 `json:"clockLimit"` // ns
|
||||||
|
MemoryLimit uint64 `json:"memoryLimit"` // byte
|
||||||
|
StackLimit uint64 `json:"stackLimit"` // byte
|
||||||
|
ProcLimit uint64 `json:"procLimit"`
|
||||||
|
CPURateLimit uint64 `json:"cpuRateLimit"` // limit cpu usage (1000 equals 1 cpu)
|
||||||
|
CPUSetLimit string `json:"cpuSetLimit"` // set the cpuSet for cgroup
|
||||||
|
|
||||||
|
CopyIn map[string]CmdFile `json:"copyIn"`
|
||||||
|
CopyInCached map[string]string `json:"copyInCached"`
|
||||||
|
CopyInDir string `json:"copyInDir"`
|
||||||
|
|
||||||
|
CopyOut []string `json:"copyOut"`
|
||||||
|
CopyOutCached []string `json:"copyOutCached"`
|
||||||
|
CopyOutMax uint64 `json:"copyOutMax"`
|
||||||
|
CopyOutDir string `json:"copyOutDir"`
|
||||||
|
|
||||||
|
TTY bool `json:"tty,omitempty"`
|
||||||
|
StrictMemoryLimit bool `json:"strictMemoryLimit"`
|
||||||
|
DataSegmentLimit bool `json:"dataSegmentLimit"`
|
||||||
|
AddressSpaceLimit bool `json:"addressSpaceLimit"`
|
||||||
|
}
|
|
@ -1,5 +1,11 @@
|
||||||
package stage
|
package stage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
var executorMap = map[string]Executor{}
|
var executorMap = map[string]Executor{}
|
||||||
|
|
||||||
type Executor interface {
|
type Executor interface {
|
||||||
|
@ -10,3 +16,87 @@ type Executor interface {
|
||||||
func RegisterExecutor(name string, executor Executor) {
|
func RegisterExecutor(name string, executor Executor) {
|
||||||
executorMap[name] = executor
|
executorMap[name] = executor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutorResult defines single command result
|
||||||
|
type ExecutorResult struct {
|
||||||
|
Status Status `json:"status"`
|
||||||
|
ExitStatus int `json:"exitStatus"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Time uint64 `json:"time"` // ns (cgroup recorded time)
|
||||||
|
Memory uint64 `json:"memory"` // byte
|
||||||
|
RunTime uint64 `json:"runTime"` // ns (wall clock time)
|
||||||
|
Files map[string]string `json:"files,omitempty"`
|
||||||
|
FileIDs map[string]string `json:"fileIds,omitempty"`
|
||||||
|
FileError []FileError `json:"fileError,omitempty"`
|
||||||
|
|
||||||
|
Buffs map[string][]byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutorResultSummary struct {
|
||||||
|
Status Status `json:"status"`
|
||||||
|
ExitStatus int `json:"exitStatus"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Time uint64 `json:"time"` // ns (cgroup recorded time)
|
||||||
|
Memory uint64 `json:"memory"` // byte
|
||||||
|
RunTime uint64 `json:"runTime"` // ns (wall clock time)
|
||||||
|
Files map[string]string `json:"files,omitempty"`
|
||||||
|
FileIDs map[string]string `json:"fileIds,omitempty"`
|
||||||
|
FileError []FileError `json:"fileError,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ExecutorResult) String() string {
|
||||||
|
d := ExecutorResultSummary{
|
||||||
|
Status: r.Status,
|
||||||
|
ExitStatus: r.ExitStatus,
|
||||||
|
Error: r.Error,
|
||||||
|
Time: r.Time,
|
||||||
|
Memory: r.Memory,
|
||||||
|
RunTime: r.RunTime,
|
||||||
|
Files: make(map[string]string),
|
||||||
|
FileIDs: r.FileIDs,
|
||||||
|
FileError: r.FileError,
|
||||||
|
}
|
||||||
|
for k, v := range r.Files {
|
||||||
|
d.Files[k] = "len:" + strconv.Itoa(len(v))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%+v", d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ExecutorResult) MarshalJSON() ([]byte, error) {
|
||||||
|
d := ExecutorResultSummary{
|
||||||
|
Status: r.Status,
|
||||||
|
ExitStatus: r.ExitStatus,
|
||||||
|
Error: r.Error,
|
||||||
|
Time: r.Time,
|
||||||
|
Memory: r.Memory,
|
||||||
|
RunTime: r.RunTime,
|
||||||
|
Files: make(map[string]string),
|
||||||
|
FileIDs: r.FileIDs,
|
||||||
|
FileError: r.FileError,
|
||||||
|
}
|
||||||
|
for k, v := range r.Files {
|
||||||
|
d.Files[k] = "len:" + strconv.Itoa(len(v))
|
||||||
|
}
|
||||||
|
return json.Marshal(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SummarizeExecutorResults(results []ExecutorResult) ExecutorResultSummary {
|
||||||
|
var summary ExecutorResultSummary
|
||||||
|
summary.Status = StatusAccepted
|
||||||
|
for _, result := range results {
|
||||||
|
if result.Status != StatusAccepted &&
|
||||||
|
summary.Status == StatusAccepted {
|
||||||
|
summary.Status = result.Status
|
||||||
|
}
|
||||||
|
if result.ExitStatus != 0 && summary.ExitStatus == 0 {
|
||||||
|
summary.ExitStatus = result.ExitStatus
|
||||||
|
}
|
||||||
|
if result.Error != "" && summary.Error == "" {
|
||||||
|
summary.Error = result.Error
|
||||||
|
}
|
||||||
|
summary.Time += result.Time
|
||||||
|
summary.Memory += result.Memory
|
||||||
|
summary.RunTime += result.RunTime
|
||||||
|
}
|
||||||
|
return summary
|
||||||
|
}
|
||||||
|
|
|
@ -1,205 +0,0 @@
|
||||||
package stage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// copied from https://github.com/criyle/go-judge/blob/master/cmd/go-judge/model/model.go
|
|
||||||
// CmdFile defines file from multiple source including local / memory / cached or pipe collector
|
|
||||||
type CmdFile struct {
|
|
||||||
Src *string `json:"src"`
|
|
||||||
Content *string `json:"content"`
|
|
||||||
FileID *string `json:"fileId"`
|
|
||||||
Name *string `json:"name"`
|
|
||||||
Max *int64 `json:"max"`
|
|
||||||
Symlink *string `json:"symlink"`
|
|
||||||
StreamIn bool `json:"streamIn"`
|
|
||||||
StreamOut bool `json:"streamOut"`
|
|
||||||
Pipe bool `json:"pipe"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cmd defines command and limits to start a program using in envexec
|
|
||||||
type Cmd struct {
|
|
||||||
Args []string `json:"args"`
|
|
||||||
Env []string `json:"env,omitempty"`
|
|
||||||
Stdin *CmdFile `json:"stdin,omitempty"`
|
|
||||||
Stdout *CmdFile `json:"stdout,omitempty"`
|
|
||||||
Stderr *CmdFile `json:"stderr,omitempty"`
|
|
||||||
|
|
||||||
CPULimit uint64 `json:"cpuLimit"` // ns
|
|
||||||
RealCPULimit uint64 `json:"realCpuLimit"` // deprecated: use clock limit instead (still working)
|
|
||||||
ClockLimit uint64 `json:"clockLimit"` // ns
|
|
||||||
MemoryLimit uint64 `json:"memoryLimit"` // byte
|
|
||||||
StackLimit uint64 `json:"stackLimit"` // byte
|
|
||||||
ProcLimit uint64 `json:"procLimit"`
|
|
||||||
CPURateLimit uint64 `json:"cpuRateLimit"` // limit cpu usage (1000 equals 1 cpu)
|
|
||||||
CPUSetLimit string `json:"cpuSetLimit"` // set the cpuSet for cgroup
|
|
||||||
|
|
||||||
CopyIn map[string]CmdFile `json:"copyIn"`
|
|
||||||
CopyInCached map[string]string `json:"copyInCached"`
|
|
||||||
CopyInDir string `json:"copyInDir"`
|
|
||||||
|
|
||||||
CopyOut []string `json:"copyOut"`
|
|
||||||
CopyOutCached []string `json:"copyOutCached"`
|
|
||||||
CopyOutMax uint64 `json:"copyOutMax"`
|
|
||||||
CopyOutDir string `json:"copyOutDir"`
|
|
||||||
|
|
||||||
TTY bool `json:"tty,omitempty"`
|
|
||||||
StrictMemoryLimit bool `json:"strictMemoryLimit"`
|
|
||||||
DataSegmentLimit bool `json:"dataSegmentLimit"`
|
|
||||||
AddressSpaceLimit bool `json:"addressSpaceLimit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PipeIndex defines indexing for a pipe fd
|
|
||||||
type PipeIndex struct {
|
|
||||||
Index int `json:"index"`
|
|
||||||
Fd int `json:"fd"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PipeMap defines in / out pipe for multiple program
|
|
||||||
type PipeMap struct {
|
|
||||||
In PipeIndex `json:"in"`
|
|
||||||
Out PipeIndex `json:"out"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Max int64 `json:"max"`
|
|
||||||
Proxy bool `json:"proxy"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request defines single worker request
|
|
||||||
type Request struct {
|
|
||||||
RequestID string `json:"requestId"`
|
|
||||||
Cmd []Cmd `json:"cmd"`
|
|
||||||
PipeMapping []PipeMap `json:"pipeMapping"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecutorResult defines single command result
|
|
||||||
type ExecutorResult struct {
|
|
||||||
Status Status `json:"status"`
|
|
||||||
ExitStatus int `json:"exitStatus"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
Time uint64 `json:"time"` // ns (cgroup recorded time)
|
|
||||||
Memory uint64 `json:"memory"` // byte
|
|
||||||
RunTime uint64 `json:"runTime"` // ns (wall clock time)
|
|
||||||
Files map[string]string `json:"files,omitempty"`
|
|
||||||
FileIDs map[string]string `json:"fileIds,omitempty"`
|
|
||||||
FileError []FileError `json:"fileError,omitempty"`
|
|
||||||
|
|
||||||
Buffs map[string][]byte `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExecutorResultSummary struct {
|
|
||||||
Status Status `json:"status"`
|
|
||||||
ExitStatus int `json:"exitStatus"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
Time uint64 `json:"time"` // ns (cgroup recorded time)
|
|
||||||
Memory uint64 `json:"memory"` // byte
|
|
||||||
RunTime uint64 `json:"runTime"` // ns (wall clock time)
|
|
||||||
Files map[string]string `json:"files,omitempty"`
|
|
||||||
FileIDs map[string]string `json:"fileIds,omitempty"`
|
|
||||||
FileError []FileError `json:"fileError,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ExecutorResult) String() string {
|
|
||||||
d := ExecutorResultSummary{
|
|
||||||
Status: r.Status,
|
|
||||||
ExitStatus: r.ExitStatus,
|
|
||||||
Error: r.Error,
|
|
||||||
Time: r.Time,
|
|
||||||
Memory: r.Memory,
|
|
||||||
RunTime: r.RunTime,
|
|
||||||
Files: make(map[string]string),
|
|
||||||
FileIDs: r.FileIDs,
|
|
||||||
FileError: r.FileError,
|
|
||||||
}
|
|
||||||
for k, v := range r.Files {
|
|
||||||
d.Files[k] = "len:" + strconv.Itoa(len(v))
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%+v", d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ExecutorResult) MarshalJSON() ([]byte, error) {
|
|
||||||
d := ExecutorResultSummary{
|
|
||||||
Status: r.Status,
|
|
||||||
ExitStatus: r.ExitStatus,
|
|
||||||
Error: r.Error,
|
|
||||||
Time: r.Time,
|
|
||||||
Memory: r.Memory,
|
|
||||||
RunTime: r.RunTime,
|
|
||||||
Files: make(map[string]string),
|
|
||||||
FileIDs: r.FileIDs,
|
|
||||||
FileError: r.FileError,
|
|
||||||
}
|
|
||||||
for k, v := range r.Files {
|
|
||||||
d.Files[k] = "len:" + strconv.Itoa(len(v))
|
|
||||||
}
|
|
||||||
return json.Marshal(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SummarizeExecutorResults(results []ExecutorResult) ExecutorResultSummary {
|
|
||||||
var summary ExecutorResultSummary
|
|
||||||
summary.Status = StatusAccepted
|
|
||||||
for _, result := range results {
|
|
||||||
if result.Status != StatusAccepted &&
|
|
||||||
summary.Status == StatusAccepted {
|
|
||||||
summary.Status = result.Status
|
|
||||||
}
|
|
||||||
if result.ExitStatus != 0 && summary.ExitStatus == 0 {
|
|
||||||
summary.ExitStatus = result.ExitStatus
|
|
||||||
}
|
|
||||||
if result.Error != "" && summary.Error == "" {
|
|
||||||
summary.Error = result.Error
|
|
||||||
}
|
|
||||||
summary.Time += result.Time
|
|
||||||
summary.Memory += result.Memory
|
|
||||||
summary.RunTime += result.RunTime
|
|
||||||
}
|
|
||||||
return summary
|
|
||||||
}
|
|
||||||
|
|
||||||
type StageExecutor struct {
|
|
||||||
Name string
|
|
||||||
Cmds []Cmd
|
|
||||||
}
|
|
||||||
type StageParser struct {
|
|
||||||
Name string
|
|
||||||
Conf any
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stage struct {
|
|
||||||
Name string
|
|
||||||
Executor StageExecutor
|
|
||||||
Parsers []StageParser
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParserResult struct {
|
|
||||||
Score int `json:"score"`
|
|
||||||
Comment string `json:"comment"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NonNullSlice[T any] []T
|
|
||||||
|
|
||||||
func (s NonNullSlice[T]) MarshalJSON() ([]byte, error) {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return []byte("[]"), nil
|
|
||||||
}
|
|
||||||
return json.Marshal([]T(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
type StageResult struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Results NonNullSlice[ParserResult] `json:"results"`
|
|
||||||
ForceQuit bool `json:"force_quit"` // underscore as it will dump to file
|
|
||||||
}
|
|
||||||
|
|
||||||
type CaseDetail struct {
|
|
||||||
Index int `json:"index"`
|
|
||||||
ExecutorResult ExecutorResult `json:"executorResult"`
|
|
||||||
ParserScores map[string]int `json:"parserScores"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type StageDetail struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
CaseDetails []CaseDetail `json:"caseDetails"`
|
|
||||||
}
|
|
|
@ -9,3 +9,8 @@ type Parser interface {
|
||||||
func RegisterParser(name string, parser Parser) {
|
func RegisterParser(name string, parser Parser) {
|
||||||
parserMap[name] = parser
|
parserMap[name] = parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ParserResult struct {
|
||||||
|
Score int `json:"score"`
|
||||||
|
Comment string `json:"comment"`
|
||||||
|
}
|
||||||
|
|
44
internal/stage/stage.go
Normal file
44
internal/stage/stage.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package stage
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
type StageExecutor struct {
|
||||||
|
Name string
|
||||||
|
Cmds []Cmd
|
||||||
|
}
|
||||||
|
type StageParser struct {
|
||||||
|
Name string
|
||||||
|
Conf any
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stage struct {
|
||||||
|
Name string
|
||||||
|
Executor StageExecutor
|
||||||
|
Parsers []StageParser
|
||||||
|
}
|
||||||
|
|
||||||
|
type NonNullSlice[T any] []T
|
||||||
|
|
||||||
|
func (s NonNullSlice[T]) MarshalJSON() ([]byte, error) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return []byte("[]"), nil
|
||||||
|
}
|
||||||
|
return json.Marshal([]T(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
type StageResult struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Results NonNullSlice[ParserResult] `json:"results"`
|
||||||
|
ForceQuit bool `json:"force_quit"` // underscore as it will dump to file
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaseDetail struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
ExecutorResult ExecutorResult `json:"executorResult"`
|
||||||
|
ParserScores map[string]int `json:"parserScores"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StageDetail struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
CaseDetails []CaseDetail `json:"caseDetails"`
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package stage
|
package stage
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// copied from https://github.com/criyle/go-judge/blob/master/envexec/run_status.go
|
// copied from https://github.com/criyle/go-judge/blob/master/envexec/run_status.go
|
||||||
// Status defines run task Status return status
|
// Status defines run task Status return status
|
Loading…
Reference in New Issue
Block a user