doc: remove mount

This commit is contained in:
criyle 2025-02-23 03:38:26 +00:00
parent 567b7702d7
commit 707297a66c
7 changed files with 4 additions and 1026 deletions

View File

@ -1,32 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
/judge
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# OS
.DS_Store
# Test Env
env*.sh
init.sql
# Documents
LICENSE
README.md
node_modules
# not release yet
package*.json
example.js
/go-judge*

View File

@ -1,24 +0,0 @@
FROM golang:alpine AS build
WORKDIR /go/judge
RUN apk update && apk add git
COPY go.mod go.sum /go/judge/
RUN go mod download -x
COPY ./ /go/judge
RUN go generate ./cmd/go-judge/version \
&& CGO_ENABLE=0 go build -v -tags grpcnotrace,nomsgpack -o go-judge ./cmd/go-judge
FROM alpine:latest
WORKDIR /opt
COPY --from=build /go/judge/go-judge /go/judge/mount.yaml /opt/
EXPOSE 5050/tcp 5051/tcp
ENTRYPOINT ["./go-judge"]

View File

@ -1,22 +0,0 @@
FROM golang:latest AS build
WORKDIR /go/judge
COPY go.mod go.sum /go/judge/
RUN go mod download -x
COPY ./ /go/judge
RUN go generate ./cmd/go-judge/version \
&& CGO_ENABLE=0 go build -v -tags grpcnotrace,nomsgpack -o go-judge ./cmd/go-judge
FROM debian:latest
WORKDIR /opt
COPY --from=build /go/judge/go-judge /go/judge/mount.yaml /opt/
EXPOSE 5050/tcp 5051/tcp
ENTRYPOINT ["./go-judge"]

View File

@ -34,385 +34,13 @@ docker run -it --rm --privileged --shm-size=256m -p 5050:5050 --name=go-judge cr
### REST API 接口定义 ### REST API 接口定义
```typescript [接口数据类型定义](https://docs.goj.ac/cn/api#rest-api-接口定义)
interface LocalFile {
src: string; // 文件绝对路径
}
interface MemoryFile {
content: string | Buffer; // 文件内容
}
interface PreparedFile {
fileId: string; // 文件 id
}
interface Collector {
name: string; // copyOut 文件名
max: number; // 最大大小限制
pipe?: boolean; // 通过管道收集默认值为false文件收集
}
interface Symlink {
symlink: string; // 符号连接目标 (v1.6.0+)
}
interface StreamIn {
streamIn: boolean; // 流式输入 (v1.8.1+)
}
interface StreamOut {
streamOut: boolean; // 流式输出 (v1.8.1+)
}
interface Cmd {
args: string[]; // 程序命令行参数
env?: string[]; // 程序环境变量
// 指定 标准输入、标准输出和标准错误的文件 (null 是为了 pipe 的使用情况准备的,而且必须被 pipeMapping 的 in / out 指定)
files?: (LocalFile | MemoryFile | PreparedFile | Collector | StreamIn | StreamOut | null)[];
tty?: boolean; // 开启 TTY (需要保证标准输出和标准错误为同一文件)同时需要指定 TERM 环境变量 (例如 TERM=xterm
// 资源限制
cpuLimit?: number; // CPU时间限制单位纳秒
clockLimit?: number; // 等待时间限制,单位纳秒 (通常为 cpuLimit 两倍)
memoryLimit?: number; // 内存限制,单位 byte
stackLimit?: number; // 栈内存限制,单位 byte
procLimit?: number; // 线程数量限制
cpuRateLimit?: number; // 仅 LinuxCPU 使用率限制1000 等于单核 100%
cpuSetLimit?: string; // 仅 Linux限制 CPU 使用,使用方式和 cpuset cgroup 相同 (例如,`0` 表示限制仅使用第一个核)
strictMemoryLimit?: boolean; // deprecated: 使用 dataSegmentLimit (这个选项依然有效)
dataSegmentLimit?: boolean; // 仅linux开启 rlimit 堆空间限制如果不使用cgroup默认开启
addressSpaceLimit?: boolean; // 仅linux开启 rlimit 虚拟内存空间限制(非常严格,在所以申请时触发限制)
// 在执行程序之前复制进容器的文件列表
copyIn?: {[dst:string]:LocalFile | MemoryFile | PreparedFile | Symlink};
// 在执行程序后从容器文件系统中复制出来的文件列表
// 在文件名之后加入 '?' 来使文件变为可选,可选文件不存在的情况不会触发 FileError
copyOut?: string[];
// 和 copyOut 相同,不过文件不返回内容,而是返回一个对应文件 ID ,内容可以通过 /file/:fileId 接口下载
copyOutCached?: string[];
// 指定 copyOut 复制文件大小限制,单位 byte
copyOutMax?: number;
}
enum Status {
Accepted = 'Accepted', // 正常情况
MemoryLimitExceeded = 'Memory Limit Exceeded', // 内存超限
TimeLimitExceeded = 'Time Limit Exceeded', // 时间超限
OutputLimitExceeded = 'Output Limit Exceeded', // 输出超限
FileError = 'File Error', // 文件错误
NonzeroExitStatus = 'Nonzero Exit Status', // 非 0 退出值
Signalled = 'Signalled', // 进程被信号终止
InternalError = 'Internal Error', // 内部错误
}
interface PipeIndex {
index: number; // cmd 的下标
fd: number; // cmd 的 fd
}
interface PipeMap {
in: PipeIndex; // 管道的输入端
out: PipeIndex; // 管道的输出端
// 开启管道代理,传输内容会从输出端复制到输入端
// 输入端内容在输出端关闭以后会丢弃 (防止 SIGPIPE
proxy?: boolean;
name?: string; // 如果代理开启,内容会作为 copyOut 放在输入端 (用来 debug
// 限制 copyOut 的最大大小,代理会在超出大小之后正常复制
max?: number;
}
enum FileErrorType {
CopyInOpenFile = 'CopyInOpenFile',
CopyInCreateFile = 'CopyInCreateFile',
CopyInCopyContent = 'CopyInCopyContent',
CopyOutOpen = 'CopyOutOpen',
CopyOutNotRegularFile = 'CopyOutNotRegularFile',
CopyOutSizeExceeded = 'CopyOutSizeExceeded',
CopyOutCreateFile = 'CopyOutCreateFile',
CopyOutCopyContent = 'CopyOutCopyContent',
CollectSizeExceeded = 'CollectSizeExceeded',
}
interface FileError {
name: string; // 错误文件名称
type: FileErrorType; // 错误代码
message?: string; // 错误信息
}
interface Request {
requestId?: string; // 给 WebSocket 使用来区分返回值的来源请求
cmd: Cmd[];
pipeMapping: PipeMap[];
}
interface CancelRequest {
cancelRequestId: string; // 取消某个正在进行中的请求
};
// WebSocket 请求
type WSRequest = Request | CancelRequest;
interface Result {
status: Status;
error?: string; // 详细错误信息
exitStatus: number; // 程序返回值
time: number; // 程序运行 CPU 时间,单位纳秒
memory: number; // 程序运行内存,单位 byte
procPeak?: number; // 程序运行最大线程数量(需要内核版本>=6.1,且开启 cgroup v2
runTime: number; // 程序运行现实时间,单位纳秒
// copyOut 和 pipeCollector 指定的文件内容
files?: {[name:string]:string};
// copyFileCached 指定的文件 id
fileIds?: {[name:string]:string};
// 文件错误详细信息
fileError?: FileError[];
}
// WebSocket 结果
interface WSResult {
requestId: string;
results: Result[];
error?: string;
}
// 流式请求 / 响应
interface Resize {
index: number;
fd: number;
rows: number;
cols: number;
x: number;
y: number;
}
interface Input {
index: number;
fd: number;
content: Buffer;
}
interface Output {
index: number;
fd: number;
content: Buffer;
}
```
### 示例 ### 示例
请使用 postman 或其他 REST API 调试工具向 http://localhost:5050/run 发送请求 请使用 postman 或其他 REST API 调试工具向 http://localhost:5050/run 发送请求
<details><summary>单个c++文件编译运行</summary> [请求实例](https://docs.goj.ac/cn/example)
这个例子需要安装 `g++`。如果在 docker 环境中运行,请在容器中(`docker exec -it go-judge /bin/bash`)执行 `apt update && apt install g++`
需要注意,在生产环境中 `copyOutCached` 产生的文件在使用完之后需要使用(`DELETE /file/:id`)删除避免内存泄露
```json
{
"cmd": [{
"args": ["/usr/bin/g++", "a.cc", "-o", "a"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a.cc": {
"content": "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
}
},
"copyOut": ["stdout", "stderr"],
"copyOutCached": ["a"]
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 303225231,
"memory": 32243712,
"runTime": 524177700,
"files": {
"stderr": "",
"stdout": ""
},
"fileIds": {
"a": "5LWIZAA45JHX4Y4Z"
}
}
]
```
```json
{
"cmd": [{
"args": ["a"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": "1 1"
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a": {
"fileId": "5LWIZAA45JHX4Y4Z" // 这个缓存文件的 ID 来自上一个请求返回的 fileIds
}
}
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 1173000,
"memory": 10637312,
"runTime": 1100200,
"files": {
"stderr": "",
"stdout": "2\n"
}
}
]
```
</details>
<details><summary>多个程序(例如交互题)</summary>
```json
{
"cmd": [{
"args": ["/bin/cat", "1"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, null, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 1000000000,
"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": 1000000000,
"memoryLimit": 1048576,
"procLimit": 50,
"copyOut": ["stdout", "stderr"]
}],
"pipeMapping": [{
"in" : {"index": 0, "fd": 1 },
"out" : {"index": 1, "fd" : 0 }
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 1545123,
"memory": 253952,
"runTime": 4148800,
"files": {
"stderr": ""
},
"fileIds": {}
},
{
"status": "Accepted",
"exitStatus": 0,
"time": 1501463,
"memory": 253952,
"runTime": 5897700,
"files": {
"stderr": "",
"stdout": "TEST 1"
},
"fileIds": {}
}
]
```
</details>
<details><summary>开启 CPURate 限制的死循环</summary>
```json
{
"cmd": [{
"args": ["/usr/bin/python3", "1.py"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{"content": ""}, {"name": "stdout","max": 10240}, {"name": "stderr","max": 10240}],
"cpuLimit": 3000000000,
"clockLimit": 4000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"cpuRate": 0.1,
"copyIn": {
"1.py": {
"content": "while True:\n pass"
}
}}]
}
```
```json
[
{
"status": "Time Limit Exceeded",
"exitStatus": 9,
"time": 414803599,
"memory": 3657728,
"runTime": 4046054900,
"files": {
"stderr": "",
"stdout": ""
}
}
]
```
</details>
## 进阶设置 ## 进阶设置
@ -475,12 +103,6 @@ interface Output {
所有命令行参数都可以通过环境变量的形式来指定,(类似 `ES_HTTP_ADDR` 来指定 `-http-addr`)。使用 `go-judge --help` 查看所有环境变量 所有命令行参数都可以通过环境变量的形式来指定,(类似 `ES_HTTP_ADDR` 来指定 `-http-addr`)。使用 `go-judge --help` 查看所有环境变量
### 编译 docker
终端中运行 `docker build -t go-judge -f Dockerfile.exec .`
沙箱服务需要特权级别 docker 来创建子容器和提供 cgroup 资源限制。
### 编译沙箱终端 ### 编译沙箱终端
编译 `go build ./cmd/go-judge-shell` 编译 `go build ./cmd/go-judge-shell`

563
README.md
View File

@ -34,566 +34,11 @@ A REST service to run program in restricted environment (Listening on `localhost
### REST API Interface ### REST API Interface
```typescript [API Interface Structure Definition](https://docs.goj.ac/api#rest-api-interface)
interface LocalFile {
src: string; // absolute path for the file
}
interface MemoryFile {
content: string | Buffer; // file contents
}
interface PreparedFile {
fileId: string; // fileId defines file uploaded by /file
}
interface Collector {
name: string; // file name in copyOut
max: number; // maximum bytes to collect from pipe
pipe?: boolean; // collect over pipe or not (default false)
}
interface Symlink {
symlink: string; // symlink destination (v1.6.0+)
}
interface StreamIn {
streamIn: boolean; // stream input (v1.8.1+)
}
interface StreamOut {
streamOut: boolean; // stream output (v1.8.1+)
}
interface Cmd {
args: string[]; // command line argument
env?: string[]; // environment
// specifies file input / pipe collector for program file descriptors (null is reserved for pipe mapping and must be filled by in / out)
files?: (LocalFile | MemoryFile | PreparedFile | Collector | StreamIn | StreamOut null)[];
tty?: boolean; // enables tty on the input and output pipes (should have just one input & one output)
// Notice: must have TERM environment variables (e.g. TERM=xterm)
// limitations
cpuLimit?: number; // ns
realCpuLimit?: number; // deprecated: use clock limit instead (still working)
clockLimit?: number; // ns
memoryLimit?: number; // byte
stackLimit?: number; // byte (N/A on windows, macOS cannot set over 32M)
procLimit?: number;
cpuRateLimit?: number; // limit cpu usage (1000 equals 1 cpu)
cpuSetLimit?: string; // Linux only: set the cpuSet for cgroup
strictMemoryLimit?: boolean; // deprecated: use dataSegmentLimit instead (still working)
dataSegmentLimit?: boolean; // Linux only: use (+ rlimit_data limit) enable by default if cgroup not enabled
addressSpaceLimit?: boolean; // Linux only: use (+ rlimit_address_space limit)
// copy the correspond file to the container dst path
copyIn?: {[dst:string]:LocalFile | MemoryFile | PreparedFile | Symlink};
// copy out specifies files need to be copied out from the container after execution
// append '?' after file name will make the file optional and do not cause FileError when missing
copyOut?: string[];
// similar to copyOut but stores file in go judge and returns fileId, later download through /file/:fileId
copyOutCached?: string[];
// specifies the directory to dump container /w content
copyOutDir: string
// specifies the max file size to copy out
copyOutMax?: number; // byte
}
enum Status {
Accepted = 'Accepted', // normal
MemoryLimitExceeded = 'Memory Limit Exceeded', // mle
TimeLimitExceeded = 'Time Limit Exceeded', // tle
OutputLimitExceeded = 'Output Limit Exceeded', // ole
FileError = 'File Error', // fe
NonzeroExitStatus = 'Nonzero Exit Status',
Signalled = 'Signalled',
InternalError = 'Internal Error', // system error
}
interface PipeIndex {
index: number; // the index of cmd
fd: number; // the fd number of cmd
}
interface PipeMap {
in: PipeIndex; // input end of the pipe
out: PipeIndex; // output end of the pipe
// enable pipe proxy from in to out,
// content from in will be discarded if out closes
proxy?: boolean;
name?: string; // copy out proxy content if proxy enabled
// limit the copy out content size,
// proxy will still functioning after max
max?: number;
}
enum FileErrorType {
CopyInOpenFile = 'CopyInOpenFile',
CopyInCreateFile = 'CopyInCreateFile',
CopyInCopyContent = 'CopyInCopyContent',
CopyOutOpen = 'CopyOutOpen',
CopyOutNotRegularFile = 'CopyOutNotRegularFile',
CopyOutSizeExceeded = 'CopyOutSizeExceeded',
CopyOutCreateFile = 'CopyOutCreateFile',
CopyOutCopyContent = 'CopyOutCopyContent',
CollectSizeExceeded = 'CollectSizeExceeded',
}
interface FileError {
name: string; // error file name
type: FileErrorType; // type
message?: string; // detailed message
}
interface Request {
requestId?: string; // for WebSocket requests
cmd: Cmd[];
pipeMapping?: PipeMap[];
}
interface CancelRequest {
cancelRequestId: string;
};
// WebSocket request
type WSRequest = Request | CancelRequest;
interface Result {
status: Status;
error?: string; // potential system error message
exitStatus: number;
time: number; // ns (cgroup recorded time)
memory: number; // byte
runTime: number; // ns (wall clock time)
procPeak?: number; // peak number of process (cgroup v2, kernel >= 6.1)
// copyFile name -> content
files?: {[name:string]:string};
// copyFileCached name -> fileId
fileIds?: {[name:string]:string};
// fileError contains detailed file errors
fileError?: FileError[];
}
// WebSocket results
interface WSResult {
requestId: string;
results: Result[];
error?: string;
}
// Stream request & responses
interface Resize {
index: number;
fd: number;
rows: number;
cols: number;
x: number;
y: number;
}
interface Input {
index: number;
fd: number;
content: Buffer;
}
interface Output {
index: number;
fd: number;
content: Buffer;
}
```
### Example Request & Response ### Example Request & Response
<details><summary>FFI</summary> [Example Request & Response](https://docs.goj.ac/example)
```javascript
var ffi = require('ffi-napi');
var go_judge = ffi.Library('./go_judge', {
'Init': ['int', ['string']],
'Exec': ['string', ['string']],
'FileList': ['string', []],
'FileAdd': ['string', ['string']],
'FileGet': ['string', ['string']],
'FileDelete': ['string', ['string']]
});
if (go_judge.Init(JSON.stringify({
cinitPath: "/judge/cinit",
parallelism: 4,
}))) {
console.log("Failed to init go judge");
}
const result = JSON.parse(go_judge.Exec(JSON.stringify({
"cmd": [{
"args": ["/bin/cat", "test.txt"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"test.txt": {
"content": "TEST"
}
}
}]
})));
console.log(result);
// Async
go_judge.Exec.async(JSON.stringify({
"cmd": [{
"args": ["/bin/cat", "test.txt"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"test.txt": {
"content": "TEST"
}
}
}]
}), (err, res) => {
if (err) throw err;
console.log(JSON.parse(res));
});
const fileAdd = (param) => new Promise((resolve, reject) => {
go_judge.FileAdd.async(JSON.stringify(param), (err, res) => {
if (err != null) { reject(err); } else { resolve(res); }
});
});
const fileList = () => new Promise((resolve, reject) => {
go_judge.FileList.async((err, res) => {
if (err != null && res == null) { reject(err); } else { resolve(JSON.parse(res)); }
});
});
const fileGet = (param) => new Promise((resolve, reject) => {
go_judge.FileGet.async(JSON.stringify(param), (err, res) => {
if (err != null && res == null) { reject(err); } else { resolve(res); }
});
});
const fileDelete = (param) => new Promise((resolve, reject) => {
go_judge.FileDelete.async(JSON.stringify(param), (err, res) => {
if (err != null && res == null) { reject(err); } else { resolve(res); }
});
});
const fileOps = async () => {
const fileId = await fileAdd({ name: 'Name', content: 'Content' });
console.log(fileId);
const list = await fileList();
console.log(list);
const file = await fileGet({ id: fileId });
console.log(file);
const d = await fileDelete({ id: fileId });
console.log(d);
const e = await fileList();
console.log(e);
};
fileOps();
```
Output:
```javascript
{
requestId: '',
results: [
{
status: 'Accepted',
exitStatus: 0,
time: 814048,
memory: 253952,
files: [Object]
}
]
}
```
</details>
Please use PostMan or similar tools to send request to `http://localhost:5050/run`
<details><summary>Single (this example require `apt install g++` inside the container)</summary>
```json
{
"cmd": [{
"args": ["/usr/bin/g++", "a.cc", "-o", "a"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a.cc": {
"content": "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
}
},
"copyOut": ["stdout", "stderr"],
"copyOutCached": ["a.cc", "a"]
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 303225231,
"memory": 32243712,
"runTime": 524177700,
"files": {
"stderr": "",
"stdout": ""
},
"fileIds": {
"a": "5LWIZAA45JHX4Y4Z",
"a.cc": "NOHPGGDTYQUFRSLJ"
}
}
]
```
```json
{
"cmd": [{
"args": ["a"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": "1 1"
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a": {
"fileId": "5LWIZAA45JHX4Y4Z"
}
}
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 1173000,
"memory": 10637312,
"runTime": 1100200,
"files": {
"stderr": "",
"stdout": "2\n"
}
}
]
```
</details>
<details><summary>Multiple (interaction problem)</summary>
```json
{
"cmd": [{
"args": ["/bin/cat", "1"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, null, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 1000000000,
"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": 1000000000,
"memoryLimit": 1048576,
"procLimit": 50,
"copyOut": ["stdout", "stderr"]
}],
"pipeMapping": [{
"in" : {"index": 0, "fd": 1 },
"out" : {"index": 1, "fd" : 0 }
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 1545123,
"memory": 253952,
"runTime": 4148800,
"files": {
"stderr": ""
},
"fileIds": {}
},
{
"status": "Accepted",
"exitStatus": 0,
"time": 1501463,
"memory": 253952,
"runTime": 5897700,
"files": {
"stderr": "",
"stdout": "TEST 1"
},
"fileIds": {}
}
]
```
</details>
<details><summary>Compile On Windows (cygwin)</summary>
```json
{
"cmd": [{
"args": ["C:\\Cygwin\\bin\\g++", "a.cc", "-o", "a"],
"env": ["PATH=C:\\Cygwin\\bin;"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a.cc": {
"content": "#include <iostream>\n#include <signal.h>\n#include <unistd.h>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
}
},
"copyOutCached": ["a.exe"]
}]
}
```
```json
[
{
"status": "Accepted",
"exitStatus": 0,
"time": 140625000,
"memory": 36286464,
"files": {
"stderr": "",
"stdout": ""
},
"fileIds": {
"a.exe": "HLQH2OF4MXUUJBCB"
}
}
]
```
</details>
<details><summary>Infinite loop with cpu rate control</summary>
```json
{
"cmd": [{
"args": ["/usr/bin/python3", "1.py"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{"content": ""}, {"name": "stdout","max": 10240}, {"name": "stderr","max": 10240}],
"cpuLimit": 3000000000,
"clockLimit": 4000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"cpuRate": 0.1,
"copyIn": {
"1.py": {
"content": "while True:\n pass"
}
}}]
}
```
```json
[
{
"status": "Time Limit Exceeded",
"exitStatus": 9,
"time": 414803599,
"memory": 3657728,
"runTime": 4046054900,
"files": {
"stderr": "",
"stdout": ""
}
}
]
```
</details>
## Documentation ## Documentation
@ -659,10 +104,6 @@ Sandbox:
Environment variable will be override by command line arguments if they both present and all command line arguments have its correspond environment variable (e.g. `ES_HTTP_ADDR`). Run `go-judge --help` to see all the environment variable configurations. Environment variable will be override by command line arguments if they both present and all command line arguments have its correspond environment variable (e.g. `ES_HTTP_ADDR`). Run `go-judge --help` to see all the environment variable configurations.
### Build go judge
Build by your own `docker build -t go-judge -f Dockerfile.exec .`
### Build Shared object ### Build Shared object
Build container init `cinit`: Build container init `cinit`:

View File

@ -1,2 +0,0 @@
root:x:0:0::/w:/bin/bash
go-judge:x:1536:1536::/w:/bin/bash

5
dotenv
View File

@ -1,5 +0,0 @@
# /.env file should contain environment variable line by line
# empty line or line start with # are ignored
# double quote is not parsed and should not be used
TESTENV=true