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" "git.0x7f.app/WOJ/woj-server/pkg/utils" "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{"/bin/sh", "-c", "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild"}, }, Runtime: RuntimeArgs{ Rootfs: RootfsFullDir, Pid: int64(utils.If(config.Prebuild.NProcLimit == 0, 0, 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 }