mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
Implements multiple command & update example
This commit is contained in:
parent
fa072e373f
commit
8e8cc17123
81
README.md
81
README.md
@ -117,6 +117,8 @@ interface Result {
|
|||||||
|
|
||||||
Example Request & Response:
|
Example Request & Response:
|
||||||
|
|
||||||
|
Single:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"cmd": [{
|
"cmd": [{
|
||||||
@ -146,21 +148,90 @@ Example Request & Response:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
[
|
||||||
|
{
|
||||||
"status": "Accepted",
|
"status": "Accepted",
|
||||||
"time": 324879037,
|
"time": 303225231,
|
||||||
"memory": 32378880,
|
"memory": 32243712,
|
||||||
"files": {
|
"files": {
|
||||||
"stderr": "",
|
"stderr": "",
|
||||||
"stdout": ""
|
"stdout": ""
|
||||||
},
|
},
|
||||||
"fileIds": {
|
"fileIds": {
|
||||||
"a": "Yj6uHXVnTrBtUNeq",
|
"a": "5LWIZAA45JHX4Y4Z",
|
||||||
"a.cc": "uYJTBTdtKWXaP4xE"
|
"a.cc": "NOHPGGDTYQUFRSLJ"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cmd": [{
|
||||||
|
"args": ["/bin/cat", "1"],
|
||||||
|
"env": ["PATH=/usr/bin:/bin"],
|
||||||
|
"files": [{
|
||||||
|
"content": ""
|
||||||
|
}, null, {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 10240
|
||||||
|
}],
|
||||||
|
"cpuLimit": 1,
|
||||||
|
"memoryLimit": 1048576,
|
||||||
|
"procLimit": 50,
|
||||||
|
"copyIn": {
|
||||||
|
"1": { "content": "TEST 1" }
|
||||||
|
},
|
||||||
|
"copyOut": ["stderr"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": ["/bin/cat"],
|
||||||
|
"env": ["PATH=/usr/bin:/bin"],
|
||||||
|
"files": [null, {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 10240
|
||||||
|
}, {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 10240
|
||||||
|
}],
|
||||||
|
"cpuLimit": 1,
|
||||||
|
"memoryLimit": 1048576,
|
||||||
|
"procLimit": 50,
|
||||||
|
"copyOut": ["stdout", "stderr"]
|
||||||
|
}],
|
||||||
|
"pipeMapping": [{
|
||||||
|
"in" : {"index": 0, "fd": 1 },
|
||||||
|
"out" : {"index": 1, "fd" : 0 }
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"status": "Accepted",
|
||||||
|
"time": 1545123,
|
||||||
|
"memory": 253952,
|
||||||
|
"files": {
|
||||||
|
"stderr": ""
|
||||||
|
},
|
||||||
|
"fileIds": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "Accepted",
|
||||||
|
"time": 1501463,
|
||||||
|
"memory": 253952,
|
||||||
|
"files": {
|
||||||
|
"stderr": "",
|
||||||
|
"stdout": "TEST 1"
|
||||||
|
},
|
||||||
|
"fileIds": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
### Workflow
|
### Workflow
|
||||||
|
|
||||||
``` text
|
``` text
|
||||||
|
|||||||
@ -15,7 +15,7 @@ const maxWaiting = 512
|
|||||||
|
|
||||||
type workRequest struct {
|
type workRequest struct {
|
||||||
*request
|
*request
|
||||||
resultCh chan<- response
|
resultCh chan<- []response
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -55,52 +55,19 @@ func workerLoop() {
|
|||||||
|
|
||||||
func workDoCmd(req workRequest) {
|
func workDoCmd(req workRequest) {
|
||||||
if len(req.Cmd) == 1 {
|
if len(req.Cmd) == 1 {
|
||||||
req.resultCh <- workDoSingle(req.Cmd[0])
|
req.resultCh <- []response{workDoSingle(req.Cmd[0])}
|
||||||
} else {
|
} else {
|
||||||
req.resultCh <- response{
|
req.resultCh <- workDoGroup(req.Cmd, req.PipeMapping)
|
||||||
Error: "not implemented yet TAT",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func workDoSingle(rc cmd) (res response) {
|
func workDoSingle(rc cmd) (res response) {
|
||||||
files, pipeFileName, err := prepareCmdFiles(rc.Files)
|
c, copyOutSet, err := prepareCmd(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Status = status(envexec.StatusInternalError)
|
res.Status = status(envexec.StatusInternalError)
|
||||||
res.Error = err.Error()
|
res.Error = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copyIn, err := prepareCopyIn(rc.CopyIn)
|
|
||||||
|
|
||||||
copyOutSet := make(map[string]bool)
|
|
||||||
copyOut := make([]string, 0, len(rc.CopyOut)+len(rc.CopyOutCached))
|
|
||||||
for _, fn := range rc.CopyOut {
|
|
||||||
if !pipeFileName[fn] {
|
|
||||||
copyOut = append(copyOut, fn)
|
|
||||||
}
|
|
||||||
copyOutSet[fn] = true
|
|
||||||
}
|
|
||||||
for _, fn := range rc.CopyOutCached {
|
|
||||||
if !pipeFileName[fn] {
|
|
||||||
copyOut = append(copyOut, fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &waiter{
|
|
||||||
timeLimit: time.Duration(rc.CPULimit * float64(time.Second)),
|
|
||||||
realTimeLimit: time.Duration(rc.RealCPULimit * float64(time.Second)),
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &envexec.Cmd{
|
|
||||||
Args: rc.Args,
|
|
||||||
Env: rc.Env,
|
|
||||||
Files: files,
|
|
||||||
MemoryLimit: runner.Size(rc.MemoryLimit),
|
|
||||||
ProcLimit: rc.ProcLimit,
|
|
||||||
CopyIn: copyIn,
|
|
||||||
CopyOut: copyOut,
|
|
||||||
Waiter: w.Wait,
|
|
||||||
}
|
|
||||||
s := &envexec.Single{
|
s := &envexec.Single{
|
||||||
CgroupPool: cgroupPool,
|
CgroupPool: cgroupPool,
|
||||||
EnvironmentPool: envPool,
|
EnvironmentPool: envPool,
|
||||||
@ -141,6 +108,114 @@ func workDoSingle(rc cmd) (res response) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func workDoGroup(rc []cmd, pm []pipeMap) (rts []response) {
|
||||||
|
p := preparePipeMapping(pm)
|
||||||
|
cs := make([]*envexec.Cmd, 0, len(rc))
|
||||||
|
copyOutSets := make([]map[string]bool, 0, len(rc))
|
||||||
|
for _, cc := range rc {
|
||||||
|
c, os, err := prepareCmd(cc)
|
||||||
|
if err != nil {
|
||||||
|
rts = []response{{Status: status(envexec.StatusInternalError), Error: err.Error()}}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cs = append(cs, c)
|
||||||
|
copyOutSets = append(copyOutSets, os)
|
||||||
|
}
|
||||||
|
g := envexec.Group{
|
||||||
|
CgroupPool: cgroupPool,
|
||||||
|
EnvironmentPool: envPool,
|
||||||
|
|
||||||
|
Cmd: cs,
|
||||||
|
Pipes: p,
|
||||||
|
}
|
||||||
|
results, err := g.Run()
|
||||||
|
if err != nil {
|
||||||
|
rts = []response{{Status: status(envexec.StatusInternalError), Error: err.Error()}}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rts = make([]response, 0, len(results))
|
||||||
|
for i, result := range results {
|
||||||
|
var res response
|
||||||
|
res.Status = status(result.Status)
|
||||||
|
res.Error = result.Error
|
||||||
|
res.Time = uint64(result.Time)
|
||||||
|
res.Memory = uint64(result.Memory)
|
||||||
|
res.Files = make(map[string]string)
|
||||||
|
res.FileIDs = make(map[string]string)
|
||||||
|
|
||||||
|
for name, fi := range result.Files {
|
||||||
|
b, err := fi.Content()
|
||||||
|
if err != nil {
|
||||||
|
res.Status = status(envexec.StatusFileError)
|
||||||
|
res.Error = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if copyOutSets[i][name] {
|
||||||
|
res.Files[name] = string(b)
|
||||||
|
} else {
|
||||||
|
id, err := fs.Add(name, b)
|
||||||
|
if err != nil {
|
||||||
|
res.Status = status(envexec.StatusFileError)
|
||||||
|
res.Error = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.FileIDs[name] = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rts = append(rts, res)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareCmd(rc cmd) (*envexec.Cmd, map[string]bool, error) {
|
||||||
|
files, pipeFileName, err := prepareCmdFiles(rc.Files)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
copyIn, err := prepareCopyIn(rc.CopyIn)
|
||||||
|
|
||||||
|
copyOutSet := make(map[string]bool)
|
||||||
|
copyOut := make([]string, 0, len(rc.CopyOut)+len(rc.CopyOutCached))
|
||||||
|
for _, fn := range rc.CopyOut {
|
||||||
|
if !pipeFileName[fn] {
|
||||||
|
copyOut = append(copyOut, fn)
|
||||||
|
}
|
||||||
|
copyOutSet[fn] = true
|
||||||
|
}
|
||||||
|
for _, fn := range rc.CopyOutCached {
|
||||||
|
if !pipeFileName[fn] {
|
||||||
|
copyOut = append(copyOut, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &waiter{
|
||||||
|
timeLimit: time.Duration(rc.CPULimit * float64(time.Second)),
|
||||||
|
realTimeLimit: time.Duration(rc.RealCPULimit * float64(time.Second)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &envexec.Cmd{
|
||||||
|
Args: rc.Args,
|
||||||
|
Env: rc.Env,
|
||||||
|
Files: files,
|
||||||
|
MemoryLimit: runner.Size(rc.MemoryLimit),
|
||||||
|
ProcLimit: rc.ProcLimit,
|
||||||
|
CopyIn: copyIn,
|
||||||
|
CopyOut: copyOut,
|
||||||
|
Waiter: w.Wait,
|
||||||
|
}, copyOutSet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func preparePipeMapping(pm []pipeMap) []*envexec.Pipe {
|
||||||
|
rt := make([]*envexec.Pipe, 0, len(pm))
|
||||||
|
for _, p := range pm {
|
||||||
|
rt = append(rt, &envexec.Pipe{
|
||||||
|
In: envexec.PipeIndex{Index: p.In.Index, Fd: p.In.Fd},
|
||||||
|
Out: envexec.PipeIndex{Index: p.Out.Index, Fd: p.Out.Fd},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rt
|
||||||
|
}
|
||||||
|
|
||||||
func prepareCopyIn(cf map[string]cmdFile) (map[string]file.File, error) {
|
func prepareCopyIn(cf map[string]cmdFile) (map[string]file.File, error) {
|
||||||
rt := make(map[string]file.File)
|
rt := make(map[string]file.File)
|
||||||
for name, f := range cf {
|
for name, f := range cf {
|
||||||
@ -194,8 +269,8 @@ func prepareCmdFile(f *cmdFile) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func submitRequest(req *request) <-chan response {
|
func submitRequest(req *request) <-chan []response {
|
||||||
ch := make(chan response, 1)
|
ch := make(chan []response, 1)
|
||||||
workCh <- workRequest{
|
workCh <- workRequest{
|
||||||
request: req,
|
request: req,
|
||||||
resultCh: ch,
|
resultCh: ch,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user