refactor: copy go-judge cmd model codes

This commit is contained in:
张泊明518370910136 2024-03-04 00:05:26 -05:00
parent d5a104e7c4
commit 4d594e1d87
GPG Key ID: D47306D7062CDA9D
8 changed files with 204 additions and 89 deletions

View File

@ -10,30 +10,40 @@ import (
func main() { func main() {
tomlConfig := ` tomlConfig := `
[[stages]] [[stages]]
name = "stage 0" name = "stage 0"
[stages.executor]
name = "sandbox" [stages.executor]
[stages.executor.with] name = "sandbox"
args = [ "ls" ]
env = [ "PATH=/usr/bin:/bin" ] [stages.executor.with]
cpuLimit = 10_000_000_000 args = [ "ls" ]
memoryLimit = 104_857_600 env = [ "PATH=/usr/bin:/bin" ]
procLimit = 50 cpuLimit = 10_000_000_000
copyOut = [ "stdout", "stderr" ] memoryLimit = 104_857_600
[[stages.executor.with.files]] procLimit = 50
content = "" copyOut = [ "stdout", "stderr" ]
[[stages.executor.with.files]]
name = "stdout" [stages.executor.with.copyIn.test]
max = 4_096 src = "/home/boyanzh/joint-online-judge/go-judge/go.mod"
[[stages.executor.with.files]]
name = "stderr" [[stages.executor.with.files]]
max = 4_096 content = ""
[stages.parser]
name = "dummy" [[stages.executor.with.files]]
[stages.parser.with] name = "stdout"
score = 100 max = 4_096
comment = "dummy comment for stage 0"
[[stages.executor.with.files]]
name = "stderr"
max = 4_096
[stages.parser]
name = "dummy"
[stages.parser.with]
score = 100
comment = "dummy comment for stage 0"
` `
stages := stage.ParseStages(tomlConfig) stages := stage.ParseStages(tomlConfig)
results := stage.Run(stages) results := stage.Run(stages)

View File

@ -1,15 +1,15 @@
package dummy package dummy
import ( import (
"github.com/criyle/go-judge/cmd/go-judge/model" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/criyle/go-judge/envexec" "github.com/criyle/go-judge/envexec"
) )
type Dummy struct{} type Dummy struct{}
func (e *Dummy) Run(model.Cmd) (*model.Result, error) { func (e *Dummy) Run(stage.Cmd) (*stage.Result, error) {
return &model.Result{ return &stage.Result{
Status: model.Status(envexec.StatusInvalid), Status: stage.Status(envexec.StatusInvalid),
ExitStatus: 0, ExitStatus: 0,
Error: "I'm a dummy", Error: "I'm a dummy",
Time: 0, Time: 0,

View File

@ -3,12 +3,12 @@ package sandbox
import ( import (
"strings" "strings"
"github.com/criyle/go-judge/cmd/go-judge/model" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/criyle/go-judge/pb" "github.com/criyle/go-judge/pb"
) )
// copied from https://github.com/criyle/go-judge/blob/master/cmd/go-judge-shell/grpc.go // copied from https://github.com/criyle/go-judge/blob/master/cmd/go-judge-shell/grpc.go
func convertPBCmd(cmd []model.Cmd) []*pb.Request_CmdType { func convertPBCmd(cmd []stage.Cmd) []*pb.Request_CmdType {
var ret []*pb.Request_CmdType var ret []*pb.Request_CmdType
for _, c := range cmd { for _, c := range cmd {
ret = append(ret, &pb.Request_CmdType{ ret = append(ret, &pb.Request_CmdType{
@ -36,7 +36,7 @@ func convertPBCmd(cmd []model.Cmd) []*pb.Request_CmdType {
return ret return ret
} }
func convertPBCopyIn(copyIn map[string]model.CmdFile) map[string]*pb.Request_File { func convertPBCopyIn(copyIn map[string]stage.CmdFile) map[string]*pb.Request_File {
rt := make(map[string]*pb.Request_File, len(copyIn)) rt := make(map[string]*pb.Request_File, len(copyIn))
for k, i := range copyIn { for k, i := range copyIn {
if i.Symlink != nil { if i.Symlink != nil {
@ -63,7 +63,7 @@ func convertPBCopyOut(copyOut []string) []*pb.Request_CmdCopyOutFile {
return rt return rt
} }
func convertSymlink(copyIn map[string]model.CmdFile) map[string]string { func convertSymlink(copyIn map[string]stage.CmdFile) map[string]string {
ret := make(map[string]string) ret := make(map[string]string)
for k, v := range copyIn { for k, v := range copyIn {
if v.Symlink == nil { if v.Symlink == nil {
@ -74,7 +74,7 @@ func convertSymlink(copyIn map[string]model.CmdFile) map[string]string {
return ret return ret
} }
func convertPBFiles(files []*model.CmdFile) []*pb.Request_File { func convertPBFiles(files []*stage.CmdFile) []*pb.Request_File {
var ret []*pb.Request_File var ret []*pb.Request_File
for _, f := range files { for _, f := range files {
if f == nil { if f == nil {
@ -86,7 +86,7 @@ func convertPBFiles(files []*model.CmdFile) []*pb.Request_File {
return ret return ret
} }
func convertPBFile(i model.CmdFile) *pb.Request_File { func convertPBFile(i stage.CmdFile) *pb.Request_File {
switch { switch {
case i.Src != nil: case i.Src != nil:
return &pb.Request_File{File: &pb.Request_File_Local{Local: &pb.Request_LocalFile{Src: *i.Src}}} return &pb.Request_File{File: &pb.Request_File_Local{Local: &pb.Request_LocalFile{Src: *i.Src}}}
@ -105,29 +105,11 @@ func convertPBFile(i model.CmdFile) *pb.Request_File {
return nil return nil
} }
func convertPBPipeMapping(pm []model.PipeMap) []*pb.Request_PipeMap { func convertPBResult(res []*pb.Response_Result) []stage.Result {
var ret []*pb.Request_PipeMap var ret []stage.Result
for _, p := range pm {
ret = append(ret, &pb.Request_PipeMap{
In: convertPBPipeIndex(p.In),
Out: convertPBPipeIndex(p.Out),
Name: p.Name,
Proxy: p.Proxy,
Max: uint64(p.Max),
})
}
return ret
}
func convertPBPipeIndex(pi model.PipeIndex) *pb.Request_PipeMap_PipeIndex {
return &pb.Request_PipeMap_PipeIndex{Index: int32(pi.Index), Fd: int32(pi.Fd)}
}
func convertPBResult(res []*pb.Response_Result) []model.Result {
var ret []model.Result
for _, r := range res { for _, r := range res {
ret = append(ret, model.Result{ ret = append(ret, stage.Result{
Status: model.Status(r.Status), Status: stage.Status(r.Status),
ExitStatus: int(r.ExitStatus), ExitStatus: int(r.ExitStatus),
Error: r.Error, Error: r.Error,
Time: r.Time, Time: r.Time,
@ -150,25 +132,12 @@ func convertFiles(buf map[string][]byte) map[string]string {
return ret return ret
} }
func convertPBRequest(req *model.Request) *pb.StreamRequest { func convertPBFileError(fe []*pb.Response_FileError) []stage.FileError {
ret := &pb.StreamRequest{ var ret []stage.FileError
Request: &pb.StreamRequest_ExecRequest{
ExecRequest: &pb.Request{
RequestID: req.RequestID,
Cmd: convertPBCmd(req.Cmd),
PipeMapping: convertPBPipeMapping(req.PipeMapping),
},
},
}
return ret
}
func convertPBFileError(fe []*pb.Response_FileError) []model.FileError {
var ret []model.FileError
for _, v := range fe { for _, v := range fe {
ret = append(ret, model.FileError{ ret = append(ret, stage.FileError{
Name: v.Name, Name: v.Name,
Type: model.FileErrorType(v.Type), Type: stage.FileErrorType(v.Type),
Message: v.Message, Message: v.Message,
}) })
} }

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"github.com/criyle/go-judge/cmd/go-judge/model" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/criyle/go-judge/pb" "github.com/criyle/go-judge/pb"
) )
@ -13,9 +13,9 @@ type Sandbox struct {
execClient pb.ExecutorClient execClient pb.ExecutorClient
} }
func (e *Sandbox) Run(cmd model.Cmd) (*model.Result, error) { func (e *Sandbox) Run(cmd stage.Cmd) (*stage.Result, error) {
slog.Info("sandbox run", "cmd", cmd) slog.Info("sandbox run", "cmd", cmd)
req := &pb.Request{Cmd: convertPBCmd([]model.Cmd{cmd})} req := &pb.Request{Cmd: convertPBCmd([]stage.Cmd{cmd})}
ret, err := e.execClient.Exec(context.TODO(), req) ret, err := e.execClient.Exec(context.TODO(), req)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -5,7 +5,6 @@ import (
"log/slog" "log/slog"
"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/criyle/go-judge/cmd/go-judge/model"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
@ -16,7 +15,7 @@ type Config struct {
type Dummy struct{} type Dummy struct{}
func (e *Dummy) Run(result *model.Result, configAny any) ( func (e *Dummy) Run(result *stage.Result, configAny any) (
*stage.ParserResult, error, *stage.ParserResult, error,
) { ) {
var config Config var config Config

View File

@ -1,13 +1,9 @@
package stage package stage
import (
"github.com/criyle/go-judge/cmd/go-judge/model"
)
var executorMap = map[string]Executor{} var executorMap = map[string]Executor{}
type Executor interface { type Executor interface {
Run(model.Cmd) (*model.Result, error) Run(Cmd) (*Result, error)
} }
func RegisterExecutor(name string, executor Executor) { func RegisterExecutor(name string, executor Executor) {

View File

@ -1,14 +1,157 @@
package stage package stage
import ( import (
"github.com/criyle/go-judge/cmd/go-judge/model" "fmt"
"strconv"
"time"
"github.com/criyle/go-judge/envexec"
) )
// copied from https://github.com/criyle/go-judge/blob/master/cmd/go-judge/model/model.go
// FileError defines the location, file name and the detailed message for a failed file operation
type FileError = envexec.FileError
// FileErrorType defines the location that file operation fails
type FileErrorType = envexec.FileErrorType
// 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"`
Files []*CmdFile `json:"files,omitempty"`
CPULimit uint64 `json:"cpuLimit"`
RealCPULimit uint64 `json:"realCpuLimit"`
ClockLimit uint64 `json:"clockLimit"`
MemoryLimit uint64 `json:"memoryLimit"`
StackLimit uint64 `json:"stackLimit"`
ProcLimit uint64 `json:"procLimit"`
CPURateLimit uint64 `json:"cpuRateLimit"`
CPUSetLimit string `json:"cpuSetLimit"`
CopyIn map[string]CmdFile `json:"copyIn"`
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"`
}
// Status offers JSON marshal for envexec.Status
type Status envexec.Status
// String converts status to string
func (s Status) String() string {
return envexec.Status(s).String()
}
// MarshalJSON convert status into string
func (s Status) MarshalJSON() ([]byte, error) {
return []byte("\"" + envexec.Status(s).String() + "\""), nil
}
// UnmarshalJSON convert string into status
func (s *Status) UnmarshalJSON(b []byte) error {
str := string(b)
v, err := envexec.StringToStatus(str)
if err != nil {
return err
}
*s = Status(v)
return nil
}
// Result defines single command result
type Result struct {
Status Status `json:"status"`
ExitStatus int `json:"exitStatus"`
Error string `json:"error,omitempty"`
Time uint64 `json:"time"`
Memory uint64 `json:"memory"`
RunTime uint64 `json:"runTime"`
Files map[string]string `json:"files,omitempty"`
FileIDs map[string]string `json:"fileIds,omitempty"`
FileError []FileError `json:"fileError,omitempty"`
files []string
Buffs map[string][]byte `json:"-"`
}
func (r Result) String() string {
type Result struct {
Status Status
ExitStatus int
Error string
Time time.Duration
RunTime time.Duration
Memory envexec.Size
Files map[string]string
FileIDs map[string]string
FileError []FileError
}
d := Result{
Status: r.Status,
ExitStatus: r.ExitStatus,
Error: r.Error,
Time: time.Duration(r.Time),
RunTime: time.Duration(r.RunTime),
Memory: envexec.Size(r.Memory),
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)
}
type Stage struct { type Stage struct {
Name string Name string
ExecutorName string ExecutorName string
Executor Executor Executor Executor
ExecutorCmd model.Cmd ExecutorCmd Cmd
ParserName string ParserName string
Parser Parser Parser Parser
ParserConfig any ParserConfig any
@ -29,7 +172,7 @@ type StagesConfig struct {
Name string Name string
Executor struct { Executor struct {
Name string Name string
With model.Cmd With Cmd
} }
Parser struct { Parser struct {
Name string Name string

View File

@ -1,11 +1,9 @@
package stage package stage
import "github.com/criyle/go-judge/cmd/go-judge/model"
var parserMap = map[string]Parser{} var parserMap = map[string]Parser{}
type Parser interface { type Parser interface {
Run(*model.Result, any) (*ParserResult, error) Run(*Result, any) (*ParserResult, error)
} }
func RegisterParser(name string, parser Parser) { func RegisterParser(name string, parser Parser) {