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() {
tomlConfig := `
[[stages]]
name = "stage 0"
[stages.executor]
name = "sandbox"
[stages.executor.with]
args = [ "ls" ]
env = [ "PATH=/usr/bin:/bin" ]
cpuLimit = 10_000_000_000
memoryLimit = 104_857_600
procLimit = 50
copyOut = [ "stdout", "stderr" ]
[[stages.executor.with.files]]
content = ""
[[stages.executor.with.files]]
name = "stdout"
max = 4_096
[[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]]
name = "stage 0"
[stages.executor]
name = "sandbox"
[stages.executor.with]
args = [ "ls" ]
env = [ "PATH=/usr/bin:/bin" ]
cpuLimit = 10_000_000_000
memoryLimit = 104_857_600
procLimit = 50
copyOut = [ "stdout", "stderr" ]
[stages.executor.with.copyIn.test]
src = "/home/boyanzh/joint-online-judge/go-judge/go.mod"
[[stages.executor.with.files]]
content = ""
[[stages.executor.with.files]]
name = "stdout"
max = 4_096
[[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)
results := stage.Run(stages)

View File

@ -1,15 +1,15 @@
package dummy
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"
)
type Dummy struct{}
func (e *Dummy) Run(model.Cmd) (*model.Result, error) {
return &model.Result{
Status: model.Status(envexec.StatusInvalid),
func (e *Dummy) Run(stage.Cmd) (*stage.Result, error) {
return &stage.Result{
Status: stage.Status(envexec.StatusInvalid),
ExitStatus: 0,
Error: "I'm a dummy",
Time: 0,

View File

@ -3,12 +3,12 @@ package sandbox
import (
"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"
)
// 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
for _, c := range cmd {
ret = append(ret, &pb.Request_CmdType{
@ -36,7 +36,7 @@ func convertPBCmd(cmd []model.Cmd) []*pb.Request_CmdType {
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))
for k, i := range copyIn {
if i.Symlink != nil {
@ -63,7 +63,7 @@ func convertPBCopyOut(copyOut []string) []*pb.Request_CmdCopyOutFile {
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)
for k, v := range copyIn {
if v.Symlink == nil {
@ -74,7 +74,7 @@ func convertSymlink(copyIn map[string]model.CmdFile) map[string]string {
return ret
}
func convertPBFiles(files []*model.CmdFile) []*pb.Request_File {
func convertPBFiles(files []*stage.CmdFile) []*pb.Request_File {
var ret []*pb.Request_File
for _, f := range files {
if f == nil {
@ -86,7 +86,7 @@ func convertPBFiles(files []*model.CmdFile) []*pb.Request_File {
return ret
}
func convertPBFile(i model.CmdFile) *pb.Request_File {
func convertPBFile(i stage.CmdFile) *pb.Request_File {
switch {
case i.Src != nil:
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
}
func convertPBPipeMapping(pm []model.PipeMap) []*pb.Request_PipeMap {
var ret []*pb.Request_PipeMap
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
func convertPBResult(res []*pb.Response_Result) []stage.Result {
var ret []stage.Result
for _, r := range res {
ret = append(ret, model.Result{
Status: model.Status(r.Status),
ret = append(ret, stage.Result{
Status: stage.Status(r.Status),
ExitStatus: int(r.ExitStatus),
Error: r.Error,
Time: r.Time,
@ -150,25 +132,12 @@ func convertFiles(buf map[string][]byte) map[string]string {
return ret
}
func convertPBRequest(req *model.Request) *pb.StreamRequest {
ret := &pb.StreamRequest{
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
func convertPBFileError(fe []*pb.Response_FileError) []stage.FileError {
var ret []stage.FileError
for _, v := range fe {
ret = append(ret, model.FileError{
ret = append(ret, stage.FileError{
Name: v.Name,
Type: model.FileErrorType(v.Type),
Type: stage.FileErrorType(v.Type),
Message: v.Message,
})
}

View File

@ -5,7 +5,7 @@ import (
"fmt"
"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"
)
@ -13,9 +13,9 @@ type Sandbox struct {
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)
req := &pb.Request{Cmd: convertPBCmd([]model.Cmd{cmd})}
req := &pb.Request{Cmd: convertPBCmd([]stage.Cmd{cmd})}
ret, err := e.execClient.Exec(context.TODO(), req)
if err != nil {
return nil, err

View File

@ -5,7 +5,6 @@ import (
"log/slog"
"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/criyle/go-judge/cmd/go-judge/model"
"github.com/mitchellh/mapstructure"
)
@ -16,7 +15,7 @@ type Config 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,
) {
var config Config

View File

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

View File

@ -1,14 +1,157 @@
package stage
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 {
Name string
ExecutorName string
Executor Executor
ExecutorCmd model.Cmd
ExecutorCmd Cmd
ParserName string
Parser Parser
ParserConfig any
@ -29,7 +172,7 @@ type StagesConfig struct {
Name string
Executor struct {
Name string
With model.Cmd
With Cmd
}
Parser struct {
Name string

View File

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