woj-server/internal/service/runner/new_problem.go
2024-03-13 20:05:00 +08:00

116 lines
3.1 KiB
Go

package runner
import (
"fmt"
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/pkg/down"
"git.0x7f.app/WOJ/woj-server/pkg/file"
"git.0x7f.app/WOJ/woj-server/pkg/unzip"
"go.uber.org/zap"
"os"
"path/filepath"
"time"
)
func (s *service) DownloadProblem(meta *JudgeMeta, url string) e.Status {
zipPath := filepath.Join(TmpDir, fmt.Sprintf("%d.zip", meta.Run.Version))
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
err := down.Down(zipPath, url)
if err != nil {
s.log.Error("[new] download problem failed", zap.Error(err))
return e.RunnerDownloadFailed
}
err = unzip.Unzip(zipPath, problemPath)
if err != nil {
s.log.Warn("[new] unzip problem failed", zap.Error(err))
return e.RunnerUnzipFailed
}
return e.Success
}
func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e.Status {
if !s.ProblemExists(meta) {
return e.RunnerProblemNotExist
}
mark := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), ".mark.prebuild")
if force {
_ = os.Remove(mark)
} else if file.Exist(mark) {
return e.Success
}
prebuildScript := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge", "prebuild.Makefile")
if !file.Exist(prebuildScript) {
s.log.Info("[new] prebuild script not found", zap.String("path", prebuildScript), zap.Uint("version", meta.Run.Version))
return e.Success
}
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data")
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
args := &RunArgs{
Program: ProgramArgs{
Args: []string{"sh", "-c", "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild"},
},
Runtime: RuntimeArgs{
Rootfs: RootfsFullDir,
Pid: int64(config.Prebuild.NProcLimit + 3), // sh + bash + make
Memory: uint64(config.Prebuild.MemoryLimit * 1024 * 1024),
Timeout: time.Duration((config.Prebuild.TimeLimit+1000)/1000) * time.Second,
},
}
args.Runtime.Mount = []MountInfo{
{
Source: dataDir,
Destination: "/woj/problem/data",
Readonly: false,
},
{
Source: judgeDir,
Destination: "/woj/problem/judge",
Readonly: false,
},
}
id := s.JailRunPool(args)
ret := s.pool.WaitForTask(id)
if ret.Error != nil {
s.log.Warn("[new] prebuild problem failed", zap.Any("ret", ret), zap.Uint("version", meta.Run.Version))
return e.RunnerProblemPrebuildFailed
}
return e.Success
}
func (s *service) NewProblem(meta *JudgeMeta, url string, force bool) (*Config, e.Status) {
if force {
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
_ = os.RemoveAll(problemPath)
}
if !s.ProblemExists(meta) {
status := s.DownloadProblem(meta, url)
if status != e.Success {
return &Config{}, status
}
}
cfg, err := s.ParseConfig(meta, false)
if err != nil {
s.log.Info("[new] parse problem failed", zap.Error(err), zap.Uint("version", meta.Run.Version))
return &Config{}, e.RunnerProblemParseFailed
}
status := s.PrebuildProblem(meta, cfg, true)
if status != e.Success {
return &Config{}, status
}
return cfg, e.Success
}