From 2da659edcbb04114b57860ee26371a079439381f Mon Sep 17 00:00:00 2001 From: taoyu <1255803549@qq.com> Date: Wed, 5 Dec 2018 03:53:00 +0800 Subject: [PATCH 1/4] add JudgeServer client for go --- client/go/README.md | 19 +++++ client/go/client.go | 120 +++++++++++++++++++++++++++++ client/go/client_test.go | 56 ++++++++++++++ client/go/examples/example.go | 138 ++++++++++++++++++++++++++++++++++ client/go/judge.go | 46 ++++++++++++ client/go/judge_test.go | 76 +++++++++++++++++++ client/go/languages.go | 126 +++++++++++++++++++++++++++++++ client/go/options.go | 38 ++++++++++ 8 files changed, 619 insertions(+) create mode 100644 client/go/README.md create mode 100644 client/go/client.go create mode 100644 client/go/client_test.go create mode 100644 client/go/examples/example.go create mode 100644 client/go/judge.go create mode 100644 client/go/judge_test.go create mode 100644 client/go/languages.go create mode 100644 client/go/options.go diff --git a/client/go/README.md b/client/go/README.md new file mode 100644 index 0000000..80f72d8 --- /dev/null +++ b/client/go/README.md @@ -0,0 +1,19 @@ +# JudgeServer client for Golang + +# Installation + +Install: + +```shell +go get -d github.com/QingdaoU/JudgeServer/client/go +``` + +Import: + +```go +import "github.com/QingdaoU/JudgeServer/client/go" +``` + +# Examples + +[examples](https://github.com/QingdaoU/JudgeServer/tree/master/client/go/examples) \ No newline at end of file diff --git a/client/go/client.go b/client/go/client.go new file mode 100644 index 0000000..a783323 --- /dev/null +++ b/client/go/client.go @@ -0,0 +1,120 @@ +package judge + +import ( + "net/http" + "io/ioutil" + "io" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "time" + "bytes" + "fmt" +) + +type Resp struct { + RespData interface{} `json:"data"` + RespErr string `json:"err"` + err error `json:"-"` +} + +func (resp *Resp) Data() interface{} { + if resp == nil { + return nil + } + return resp.RespData +} + +func (resp *Resp) Err() error { + if resp == nil { + return nil + } + return resp.err +} + +func parseResp(body []byte) (*Resp, error) { + resp := &Resp{} + err := json.Unmarshal(body, resp) + if err != nil { + return nil, err + } + // 有错误的响应了 + if resp.RespErr != "" { + resp.err = fmt.Errorf("err: %s, data: %s", resp.RespErr, resp.RespData) + } + + return resp, nil +} + +type Client struct { + opts *options + sha256Token string + httpClient *http.Client +} + +func (c *Client) request(method, path string, body io.Reader) (resp *Resp, err error) { + req, err := http.NewRequest("POST", c.opts.EndpointURL+"/"+path, body) + if err != nil { + return + } + req.Header.Set("X-Judge-Server-Token", c.sha256Token) + req.Header.Set("Content-Type", "application/json") + + httpResp, err := c.httpClient.Do(req) + if err != nil { + return + } + b, err := ioutil.ReadAll(httpResp.Body) + if err != nil { + return + } + httpResp.Body.Close() + return parseResp(b) +} + +func (c *Client) post(path string, body io.Reader) (resp *Resp, err error) { + return c.request("POST", path, body) +} + +// Ping Judge server +func (c *Client) Ping() (resp *Resp, err error) { + resp, err = c.post("ping", nil) + return +} + +func (c *Client) CompileSpj(src, spjVersion string, spjCompileConfig *CompileConfig) (resp *Resp, err error) { + data := map[string]interface{}{ + "src": src, + "spj_version": spjVersion, + "spj_compile_config": spjCompileConfig, + } + b, err := json.Marshal(data) + if err != nil { + return + } + resp, err = c.post("compile_spj", bytes.NewReader(b)) + return +} + +func New(endpointURL, token string, timeout time.Duration) *Client { + return NewClient( + WithEndpointURL(endpointURL), + WithToken(token), + WithTimeout(timeout), + ) +} + +func NewClient(options ...Option) *Client { + opts := DefaultOptions + for _, o := range options { + o(opts) + } + sha256Token := sha256.Sum256([]byte(opts.Token)) + return &Client{ + opts: opts, + sha256Token: hex.EncodeToString(sha256Token[:]), + httpClient: &http.Client{ + Timeout: opts.Timeout, + }, + } +} diff --git a/client/go/client_test.go b/client/go/client_test.go new file mode 100644 index 0000000..f7ae7d7 --- /dev/null +++ b/client/go/client_test.go @@ -0,0 +1,56 @@ +package judge + +import ( + "testing" +) + +var client *Client + +func TestMain(m *testing.M) { + // 创建一个client。 这句代码等价于 New("http://127.0.0.1:12358", "YOUR_TOKEN_HERE", 0) + client = NewClient( + WithEndpointURL("http://127.0.0.1:12358"), + WithToken("YOUR_TOKEN_HERE"), + WithTimeout(0), + ) + m.Run() +} + +func TestClient_Ping(t *testing.T) { + resp, err := client.Ping() + if err != nil { + t.Errorf("unexpected error. error: %+v", err) + return + } + if resp.Err() != nil { + t.Errorf("unexpected error. error: %+v", resp.Err()) + return + } + + if resp.RespData == nil { + t.Error("resp.RespData unexpected nil") + return + } +} + +func TestClient_CompileSpj(t *testing.T) { + cSpjSrc := ` +#include +int main(){ + return 1; +} +` + resp, err := client.CompileSpj(cSpjSrc, "2", CLangSPJCompile) + if err != nil { + t.Errorf("unexpected error. error: %+v", err) + return + } + if resp.Err() != nil { + t.Errorf("unexpected error. error: %+v", resp.Err()) + return + } + if resp.RespData == nil { + t.Error("resp.RespData unexpected nil") + return + } +} diff --git a/client/go/examples/example.go b/client/go/examples/example.go new file mode 100644 index 0000000..e481c8c --- /dev/null +++ b/client/go/examples/example.go @@ -0,0 +1,138 @@ +package main + +import ( + "github.com/QingdaoU/JudgeServer/client/go" + "fmt" +) + +var ( + cSrc = ` +#include +int main(){ + int a, b; + scanf("%d%d", &a, &b); + printf("%d\n", a+b); + return 0; +} +` + cSPJSrc = ` +#include +int main(){ + return 1; +} +` + cppSrc = ` +#include + +using namespace std; + +int main() +{ + int a,b; + cin >> a >> b; + cout << a+b << endl; + return 0; +} +` + javaSrc = ` +import java.util.Scanner; +public class Main{ + public static void main(String[] args){ + Scanner in=new Scanner(System.in); + int a=in.nextInt(); + int b=in.nextInt(); + System.out.println(a + b); + } +} +` + py2Src = ` +s = raw_input() +s1 = s.split(" ") +print int(s1[0]) + int(s1[1]) +` + py3Src = ` +s = input() +s1 = s.split(" ") +print(int(s1[0]) + int(s1[1])) +` +) + +func main() { + // 创建一个client。 这句代码等价于 judge.New("http://127.0.0.1:12358", "YOUR_TOKEN_HERE", 0) + client := judge.NewClient( + judge.WithEndpointURL("http://127.0.0.1:12358"), + judge.WithToken("YOUR_TOKEN_HERE"), + judge.WithTimeout(0), + ) + + fmt.Println("ping:") + resp, err := client.Ping() + if err != nil { + // 这个 err 是发生在 client 这边的错误。 例如json编码失败 + fmt.Printf("ping client error. error is: %v.\n", err) + } else if resp.Err() != nil { + // 这个 resp.Err() 是 JudgeServer 响应的错误。 例如token错误 TokenVerificationFailed + fmt.Printf("ping server error. error is: %v.\n", resp.Err().Error()) + } else { + fmt.Println(resp.Data()) + } + fmt.Println() + + fmt.Println("cpp_judge") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: cppSrc, + LanguageConfig: judge.CPPLangConfig, + MaxCpuTime: 1000, + MaxMemory: 128 * 1024 * 1024, + TestCaseId: "normal", + }) + fmt.Println(resp, err) + fmt.Println() + + fmt.Println("java_judge") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: javaSrc, + LanguageConfig: judge.JavaLangConfig, + MaxCpuTime: 1000, + MaxMemory: 256 * 1024 * 1024, + TestCaseId: "normal", + }) + fmt.Println(resp, err) + fmt.Println() + + fmt.Println("c_spj_judge") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: cSrc, + LanguageConfig: judge.CLangConfig, + MaxCpuTime: 1000, + MaxMemory: 128 * 1024 * 1024, + TestCaseId: "spj", + SPJVersion: "3", + SPJConfig: judge.CLangSPJConfig, + SPJCompileConfig: judge.CLangSPJCompile, + SPJSrc: cSPJSrc, + }) + fmt.Println(resp, err) + fmt.Println() + + fmt.Println("py2_judge") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: py2Src, + LanguageConfig: judge.PY2LangConfig, + MaxCpuTime: 1000, + MaxMemory: 128 * 1024 * 1024, + TestCaseId: "normal", + }) + fmt.Println(resp, err) + fmt.Println() + + fmt.Println("py3_judge") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: py3Src, + LanguageConfig: judge.PY3LangConfig, + MaxCpuTime: 1000, + MaxMemory: 128 * 1024 * 1024, + TestCaseId: "normal", + }) + fmt.Println(resp, err) +} diff --git a/client/go/judge.go b/client/go/judge.go new file mode 100644 index 0000000..9cd14f8 --- /dev/null +++ b/client/go/judge.go @@ -0,0 +1,46 @@ +package judge + +import ( + "time" + "bytes" + "encoding/json" +) + +type JudgeRequest struct { + Src string `json:"src"` + LanguageConfig *LangConfig `json:"language_config"` + MaxCpuTime int64 `json:"max_cpu_time"` + MaxMemory int64 `json:"max_memory"` + TestCaseId string `json:"test_case_id"` + SPJVersion string `json:"spj_version"` + SPJConfig *SPJConfig `json:"spj_config"` + SPJCompileConfig *CompileConfig `json:"spj_compile_config"` + SPJSrc string `json:"spj_src"` + Output bool `json:"output"` +} + +// 这个方法为了模仿 php 和 python client 不推荐使用 +func (c *Client) Judge(src string, languageConfig *LangConfig, maxCpuTime time.Duration, maxMemory int64, testCaseId, +spjVersion string, spjConfig *SPJConfig, spjCompileConfig *CompileConfig, spjSrc string, output bool) (resp *Resp, err error) { + return c.JudgeWithRequest(&JudgeRequest{ + Src: src, + LanguageConfig: languageConfig, + MaxCpuTime: int64(maxCpuTime), + MaxMemory: maxMemory, + TestCaseId: testCaseId, + SPJVersion: spjVersion, + SPJConfig: spjConfig, + SPJCompileConfig: spjCompileConfig, + SPJSrc: spjSrc, + Output: output, + }) +} + +func (c *Client) JudgeWithRequest(req *JudgeRequest) (resp *Resp, err error) { + b, err := json.Marshal(req) + if err != nil { + return + } + resp, err = c.post("judge", bytes.NewReader(b)) + return +} diff --git a/client/go/judge_test.go b/client/go/judge_test.go new file mode 100644 index 0000000..12c6dc5 --- /dev/null +++ b/client/go/judge_test.go @@ -0,0 +1,76 @@ +package judge + +import "testing" + +func TestClient_JudgeWithRequest(t *testing.T) { + javaSrc := ` +import java.util.Scanner; + public class Main{ + public static void main(String[] args){ + Scanner in=new Scanner(System.in); + int a=in.nextInt(); + int b=in.nextInt(); + System.out.println(a + b); + } +} +` + cSrc := ` +#include +int main(){ + int a, b; + scanf("%d%d", &a, &b); + printf("%d\n", a+b); + return 0; +} +` + cSPJSrc := ` +#include +int main(){ + return 1; +} +` + var tests = []struct { + JudgeRequest *JudgeRequest + }{ + { + JudgeRequest: &JudgeRequest{ + Src: javaSrc, + LanguageConfig: JavaLangConfig, + MaxCpuTime: 1000, + MaxMemory: 256 * 1024 * 1024, + TestCaseId: "normal", + }, + }, + { + JudgeRequest: &JudgeRequest{ + Src: cSrc, + LanguageConfig: CLangConfig, + MaxCpuTime: 1000, + MaxMemory: 128 * 1024 * 1024, + TestCaseId: "spj", + SPJVersion: "3", + SPJConfig: CLangSPJConfig, + SPJCompileConfig: CLangSPJCompile, + SPJSrc: cSPJSrc, + }, + }, + } + + for _, test := range tests { + resp, err := client.JudgeWithRequest(test.JudgeRequest) + if err != nil { + t.Errorf("unexpected error. error: %+v", err) + return + } + if resp.Err() != nil { + t.Errorf("unexpected error. error: %+v", resp.Err()) + return + } + if resp.RespData == nil { + t.Error("resp.RespData unexpected nil") + return + } + + } + +} diff --git a/client/go/languages.go b/client/go/languages.go new file mode 100644 index 0000000..8fee9b2 --- /dev/null +++ b/client/go/languages.go @@ -0,0 +1,126 @@ +package judge + +type CompileConfig struct { + SrcName string `json:"src_name"` + ExeName string `json:"exe_name"` + MaxCpuTime int64 `json:"max_cpu_time"` + MaxRealTime int64 `json:"max_real_time"` + MaxMemory int64 `json:"max_memory"` + CompileCommand string `json:"compile_command"` +} + +var DefaultEnv = []string{"LANG=en_US.UTF-8", "LANGUAGE=en_US:en", "LC_ALL=en_US.UTF-8"} + +type RunConfig struct { + Command string `json:"command"` + SeccompRule string `json:"seccomp_rule"` + Env []string `json:"env"` + MemoryLimitCheckOnly int `json:"memory_limit_check_only"` +} + +type LangConfig struct { + CompileConfig CompileConfig `json:"compile"` + RunConfig RunConfig `json:"run"` +} + +type SPJConfig struct { + ExeName string `json:"exe_name"` + Command string `json:"command"` + SeccompRule string `json:"seccomp_rule"` +} + +var CLangConfig = &LangConfig{ + CompileConfig: CompileConfig{ + SrcName: "main.c", + ExeName: "main", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: 128 * 1024 * 1024, + CompileCommand: "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}", + }, + RunConfig: RunConfig{ + Command: "{exe_path}", + SeccompRule: "c_cpp", + Env: DefaultEnv, + }, +} + +var CLangSPJCompile = &CompileConfig{ + SrcName: "spj-{spj_version}.c", + ExeName: "spj-{spj_version}", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: 1024 * 1024 * 1024, + CompileCommand: "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}", +} + +var CLangSPJConfig = &SPJConfig{ + ExeName: "spj-{spj_version}", + Command: "{exe_path} {in_file_path} {user_out_file_path}", + SeccompRule: "c_cpp", +} + +var CPPLangConfig = &LangConfig{ + CompileConfig: CompileConfig{ + SrcName: "main.cpp", + ExeName: "main", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: 128 * 1024 * 1024, + CompileCommand: "/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}", + }, + RunConfig: RunConfig{ + Command: "{exe_path}", + SeccompRule: "c_cpp", + Env: DefaultEnv, + }, +} + +var JavaLangConfig = &LangConfig{ + CompileConfig: CompileConfig{ + SrcName: "Main.java", + ExeName: "Main", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: -1, + CompileCommand: "/usr/bin/javac {src_path} -d {exe_dir} -encoding UTF8", + }, + RunConfig: RunConfig{ + Command: "/usr/bin/java -cp {exe_dir} -XX:MaxRAM={max_memory}k -Djava.security.manager -Dfile.encoding=UTF-8 -Djava.security.policy==/etc/java_policy -Djava.awt.headless=true Main", + SeccompRule: "", + Env: DefaultEnv, + MemoryLimitCheckOnly: 1, + }, +} + +var PY2LangConfig = &LangConfig{ + CompileConfig: CompileConfig{ + SrcName: "solution.py", + ExeName: "solution.pyc", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: 128 * 1024 * 1024, + CompileCommand: "/usr/bin/python -m py_compile {src_path}", + }, + RunConfig: RunConfig{ + Command: "/usr/bin/python {exe_path}", + SeccompRule: "general", + Env: DefaultEnv, + }, +} + +var PY3LangConfig = &LangConfig{ + CompileConfig: CompileConfig{ + SrcName: "solution.py", + ExeName: "__pycache__/solution.cpython-35.pyc", + MaxCpuTime: 3000, + MaxRealTime: 5000, + MaxMemory: 128 * 1024 * 1024, + CompileCommand: "/usr/bin/python3 -m py_compile {src_path}", + }, + RunConfig: RunConfig{ + Command: "/usr/bin/python3 {exe_path}", + SeccompRule: "general", + Env: append(DefaultEnv, "PYTHONIOENCODING=UTF-8"), + }, +} diff --git a/client/go/options.go b/client/go/options.go new file mode 100644 index 0000000..b2bb556 --- /dev/null +++ b/client/go/options.go @@ -0,0 +1,38 @@ +package judge + +import "time" + +type options struct { + // scheme://host:port . + EndpointURL string + Token string + // 请求超时时间 + // 如果 Timeout 为 0,那么意味着不会超时 + Timeout time.Duration +} + +var DefaultOptions = &options{ + EndpointURL: "http://127.0.0.1:12358", + Token: "YOUR_TOKEN_HERE", + Timeout: 10 * time.Second, +} + +type Option func(*options) + +func WithEndpointURL(u string) Option { + return func(o *options) { + o.EndpointURL = u + } +} + +func WithToken(token string) Option { + return func(o *options) { + o.Token = token + } +} + +func WithTimeout(timeout time.Duration) Option { + return func(o *options) { + o.Timeout = timeout + } +} From 45125eb015d626886c6117112cd072ce28cb8b41 Mon Sep 17 00:00:00 2001 From: taoyu <1255803549@qq.com> Date: Mon, 10 Dec 2018 03:39:41 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BC=98=E5=8C=96judge=E7=9A=84resp=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86Data=E7=B1=BB=E5=9E=8B=EF=BC=8C?= =?UTF-8?q?=E5=85=B6=E7=B1=BB=E5=9E=8B=E5=8F=82=E8=80=83=E8=87=AAhttps://g?= =?UTF-8?q?ithub.com/QingdaoU/Judger/blob/b6414e7a6715eb013b1ffeb7cfb04626?= =?UTF-8?q?a3ff5b4e/src/runner.h#L73?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/go/client.go | 58 +++++++++++++++++++++++++++++++++++ client/go/examples/example.go | 41 +++++++++++++++++++------ 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/client/go/client.go b/client/go/client.go index a783323..22c0907 100644 --- a/client/go/client.go +++ b/client/go/client.go @@ -12,6 +12,20 @@ import ( "fmt" ) +// Data 成员的类型参考 https://github.com/QingdaoU/Judger/blob/b6414e7a6715eb013b1ffeb7cfb04626a3ff5b4e/src/runner.h#L73 +type Data struct { + CpuTime int + Result int + Memory int + RealTime int + Signal int + Error int + ExitCode int + OutputMd5 string + Output interface{} + TestCase string +} + type Resp struct { RespData interface{} `json:"data"` RespErr string `json:"err"` @@ -25,6 +39,50 @@ func (resp *Resp) Data() interface{} { return resp.RespData } +func (resp *Resp) StringData() string { + if resp == nil { + return "" + } + str, _ := resp.RespData.(string) + return str +} + +func (resp *Resp) SliceData() []*Data { + if resp == nil { + return nil + } + slice, _ := resp.RespData.([]interface{}) + data := make([]*Data, 0, len(slice)) + for _, s := range slice { + item, ok := s.(map[string]interface{}) + if ok { + cpuTimeF64, _ := item["cpu_time"].(float64) + resultF64, _ := item["result"].(float64) + memoryF64, _ := item["memory"].(float64) + realTimeF64, _ := item["real_time"].(float64) + signalF64, _ := item["signal"].(float64) + errorF64, _ := item["error"].(float64) + exitCodeF64, _ := item["exit_code"].(float64) + outputMd5, _ := item["output_md5"].(string) + testCase, _ := item["test_case"].(string) + data = append(data, &Data{ + CpuTime: int(cpuTimeF64), + Result: int(resultF64), + Memory: int(memoryF64), + RealTime: int(realTimeF64), + Signal: int(signalF64), + Error: int(errorF64), + ExitCode: int(exitCodeF64), + OutputMd5: outputMd5, + Output: item["output"], + TestCase: testCase, + }) + } + + } + return data +} + func (resp *Resp) Err() error { if resp == nil { return nil diff --git a/client/go/examples/example.go b/client/go/examples/example.go index e481c8c..c682bb8 100644 --- a/client/go/examples/example.go +++ b/client/go/examples/example.go @@ -79,29 +79,29 @@ func main() { fmt.Println() fmt.Println("cpp_judge") - resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + resp, _ = client.JudgeWithRequest(&judge.JudgeRequest{ Src: cppSrc, LanguageConfig: judge.CPPLangConfig, MaxCpuTime: 1000, MaxMemory: 128 * 1024 * 1024, TestCaseId: "normal", }) - fmt.Println(resp, err) + printSliceData(resp.SliceData()) fmt.Println() fmt.Println("java_judge") - resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + resp, _ = client.JudgeWithRequest(&judge.JudgeRequest{ Src: javaSrc, LanguageConfig: judge.JavaLangConfig, MaxCpuTime: 1000, MaxMemory: 256 * 1024 * 1024, TestCaseId: "normal", }) - fmt.Println(resp, err) + printSliceData(resp.SliceData()) fmt.Println() fmt.Println("c_spj_judge") - resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + resp, _ = client.JudgeWithRequest(&judge.JudgeRequest{ Src: cSrc, LanguageConfig: judge.CLangConfig, MaxCpuTime: 1000, @@ -112,27 +112,48 @@ func main() { SPJCompileConfig: judge.CLangSPJCompile, SPJSrc: cSPJSrc, }) - fmt.Println(resp, err) + printSliceData(resp.SliceData()) fmt.Println() fmt.Println("py2_judge") - resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + resp, _ = client.JudgeWithRequest(&judge.JudgeRequest{ Src: py2Src, LanguageConfig: judge.PY2LangConfig, MaxCpuTime: 1000, MaxMemory: 128 * 1024 * 1024, TestCaseId: "normal", }) - fmt.Println(resp, err) + printSliceData(resp.SliceData()) fmt.Println() fmt.Println("py3_judge") - resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + resp, _ = client.JudgeWithRequest(&judge.JudgeRequest{ Src: py3Src, LanguageConfig: judge.PY3LangConfig, MaxCpuTime: 1000, MaxMemory: 128 * 1024 * 1024, TestCaseId: "normal", }) - fmt.Println(resp, err) + printSliceData(resp.SliceData()) + fmt.Println() + + // CompileError example + fmt.Println("CompileError example") + resp, err = client.JudgeWithRequest(&judge.JudgeRequest{ + Src: "this bad code", + LanguageConfig: judge.JavaLangConfig, + MaxCpuTime: 1000, + MaxMemory: 256 * 1024 * 1024, + TestCaseId: "normal", + }) + // fmt.Println(resp.RespErr) // "CompileError" + fmt.Println(resp.StringData()) // 错误信息 +} + +func printSliceData(slice []*judge.Data) { + fmt.Print("[\n") + for _, item := range slice { + fmt.Printf("\t%#v,\n", item) + } + fmt.Print("]\n") } From 0bc50ecae240487b5825b24ae3b30ee7bc7d5ec7 Mon Sep 17 00:00:00 2001 From: taoyu <1255803549@qq.com> Date: Mon, 10 Dec 2018 19:39:13 +0800 Subject: [PATCH 3/4] =?UTF-8?q?add=20SetOptions=20method=20=E6=9C=89?= =?UTF-8?q?=E4=BA=86=E8=BF=99=E4=B8=AA=E6=96=B9=E6=B3=95=E5=B0=B1=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E9=9A=8F=E6=97=B6=E6=94=B9=E5=8F=98=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/go/client.go | 24 +++++++++++++++--------- client/go/examples/example.go | 21 +++++++++++++++------ client/go/options.go | 9 ++++++++- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/client/go/client.go b/client/go/client.go index 22c0907..6e08548 100644 --- a/client/go/client.go +++ b/client/go/client.go @@ -4,8 +4,6 @@ import ( "net/http" "io/ioutil" "io" - "crypto/sha256" - "encoding/hex" "encoding/json" "time" "bytes" @@ -105,9 +103,8 @@ func parseResp(body []byte) (*Resp, error) { } type Client struct { - opts *options - sha256Token string - httpClient *http.Client + opts *options + httpClient *http.Client } func (c *Client) request(method, path string, body io.Reader) (resp *Resp, err error) { @@ -115,7 +112,7 @@ func (c *Client) request(method, path string, body io.Reader) (resp *Resp, err e if err != nil { return } - req.Header.Set("X-Judge-Server-Token", c.sha256Token) + req.Header.Set("X-Judge-Server-Token", c.opts.sha256Token) req.Header.Set("Content-Type", "application/json") httpResp, err := c.httpClient.Do(req) @@ -162,15 +159,24 @@ func New(endpointURL, token string, timeout time.Duration) *Client { ) } +func (c *Client) SetOptions(options ...Option) { + originTimeout := c.opts.Timeout + for _, o := range options { + o(c.opts) + } + if c.opts.Timeout != originTimeout { + c.httpClient.Timeout = c.opts.Timeout + } +} + func NewClient(options ...Option) *Client { opts := DefaultOptions for _, o := range options { o(opts) } - sha256Token := sha256.Sum256([]byte(opts.Token)) + return &Client{ - opts: opts, - sha256Token: hex.EncodeToString(sha256Token[:]), + opts: opts, httpClient: &http.Client{ Timeout: opts.Timeout, }, diff --git a/client/go/examples/example.go b/client/go/examples/example.go index c682bb8..24c7369 100644 --- a/client/go/examples/example.go +++ b/client/go/examples/example.go @@ -58,12 +58,21 @@ print(int(s1[0]) + int(s1[1])) ) func main() { - // 创建一个client。 这句代码等价于 judge.New("http://127.0.0.1:12358", "YOUR_TOKEN_HERE", 0) - client := judge.NewClient( - judge.WithEndpointURL("http://127.0.0.1:12358"), - judge.WithToken("YOUR_TOKEN_HERE"), - judge.WithTimeout(0), - ) + // 创建一个client。 这句代码等价于 + + // 1. + //client := judge.NewClient( + // judge.WithEndpointURL("http://127.0.0.1:12358"), + // judge.WithToken("YOUR_TOKEN_HERE"), + // judge.WithTimeout(0), + //) + + // 2. + // client := judge.New("http://127.0.0.1:12358", "YOUR_TOKEN_HERE", 0) + + // 3. + client := judge.NewClient(judge.WithTimeout(0)) + client.SetOptions(judge.WithEndpointURL("http://127.0.0.1:12358"), judge.WithToken("YOUR_TOKEN_HERE")) fmt.Println("ping:") resp, err := client.Ping() diff --git a/client/go/options.go b/client/go/options.go index b2bb556..b45fc27 100644 --- a/client/go/options.go +++ b/client/go/options.go @@ -1,11 +1,16 @@ package judge -import "time" +import ( + "time" + "crypto/sha256" + "encoding/hex" +) type options struct { // scheme://host:port . EndpointURL string Token string + sha256Token string // 请求超时时间 // 如果 Timeout 为 0,那么意味着不会超时 Timeout time.Duration @@ -28,6 +33,8 @@ func WithEndpointURL(u string) Option { func WithToken(token string) Option { return func(o *options) { o.Token = token + sha256Token := sha256.Sum256([]byte(token)) + o.sha256Token = hex.EncodeToString(sha256Token[:]) } } From 0e90200dcaf5c3c830617322591d467b3c3cbe83 Mon Sep 17 00:00:00 2001 From: taoyu <1255803549@qq.com> Date: Tue, 11 Dec 2018 23:23:23 +0800 Subject: [PATCH 4/4] =?UTF-8?q?Data=20=E4=B8=AD=E7=9A=84=20Memory=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=94=B9=E4=B8=BAint64=E7=B1=BB=E5=9E=8B=20?= =?UTF-8?q?=E5=8F=82=E8=80=83https://github.com/QingdaoU/Judger/blob/b6414?= =?UTF-8?q?e7a6715eb013b1ffeb7cfb04626a3ff5b4e/src/runner.h#L76?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/go/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/go/client.go b/client/go/client.go index 6e08548..165aac4 100644 --- a/client/go/client.go +++ b/client/go/client.go @@ -14,7 +14,7 @@ import ( type Data struct { CpuTime int Result int - Memory int + Memory int64 // https://github.com/QingdaoU/Judger/blob/b6414e7a6715eb013b1ffeb7cfb04626a3ff5b4e/src/runner.h#L76 RealTime int Signal int Error int @@ -66,7 +66,7 @@ func (resp *Resp) SliceData() []*Data { data = append(data, &Data{ CpuTime: int(cpuTimeF64), Result: int(resultF64), - Memory: int(memoryF64), + Memory: int64(memoryF64), RealTime: int(realTimeF64), Signal: int(signalF64), Error: int(errorF64),