├── .gitattributes ├── etc ├── icon │ ├── install.ico │ └── uninstall.ico ├── header │ ├── install.bmp │ └── uninstall.bmp └── wizard │ ├── install.bmp │ └── uninstall.bmp ├── .travis.yml ├── judge ├── judge.go ├── task.go ├── gather.go ├── native.go └── ccpp.go ├── main.go ├── models ├── init.go ├── session.go └── task.go ├── .gitignore ├── router └── router.go ├── Dockerfile ├── core ├── controller.go ├── sqlite.go ├── http.go ├── gen_script.go ├── init.go ├── README.md ├── config.go └── tcp.go ├── test └── client_test.go ├── conf ├── config_docker.ini └── config.ini ├── README.md ├── controller ├── status.go ├── gather.go └── judge.go ├── LICENSE ├── client └── client.go └── installer.nsi /.gitattributes: -------------------------------------------------------------------------------- 1 | /sandbox/c/deps/* linguist-vendored 2 | 3 | -------------------------------------------------------------------------------- /etc/icon/install.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/icon/install.ico -------------------------------------------------------------------------------- /etc/header/install.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/header/install.bmp -------------------------------------------------------------------------------- /etc/header/uninstall.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/header/uninstall.bmp -------------------------------------------------------------------------------- /etc/icon/uninstall.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/icon/uninstall.ico -------------------------------------------------------------------------------- /etc/wizard/install.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/wizard/install.bmp -------------------------------------------------------------------------------- /etc/wizard/uninstall.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojudge/judger/HEAD/etc/wizard/uninstall.bmp -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | branches: 3 | only: 4 | - master 5 | go: 6 | - tip 7 | install: 8 | - go get 9 | script: 10 | - go build -------------------------------------------------------------------------------- /judge/judge.go: -------------------------------------------------------------------------------- 1 | // judge the output result 2 | package judge 3 | 4 | import ( 5 | // "fmt" 6 | ) 7 | 8 | func Judge(raw string, expect string) string { 9 | return "" 10 | } 11 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gojudge/judger/core" 5 | _ "github.com/gojudge/judger/router" 6 | ) 7 | 8 | func main() { 9 | 10 | core.Judger() 11 | } 12 | -------------------------------------------------------------------------------- /models/init.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | ) 6 | 7 | func init() { 8 | orm.RegisterModel(new(SessionTab)) 9 | orm.RegisterModel(new(TaskTab)) 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build 2 | /build/ 3 | /script/ 4 | 5 | # linux 6 | *.swp 7 | 8 | # go build 9 | /judger 10 | *.exe 11 | 12 | # tools 13 | /tools/ 14 | 15 | # database file 16 | *.db 17 | 18 | # debug 19 | *.debug 20 | 21 | # log 22 | *.LOG 23 | *.out 24 | 25 | .idea/ 26 | -------------------------------------------------------------------------------- /router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gojudge/judger/controller" 5 | "github.com/gojudge/judger/core" 6 | ) 7 | 8 | func init() { 9 | core.Router("login", &controller.LoginController{}) 10 | core.Router("task_add", &controller.TaskAddController{}) 11 | core.Router("task_info", &controller.GatherController{}) 12 | core.Router("ping", &controller.PingController{}) 13 | } 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM google/golang 2 | MAINTAINER duguying2008@gmail.com 3 | 4 | RUN apt-get update -y 5 | RUN apt-get upgrade -y 6 | RUN go env 7 | 8 | ADD . /go/src/github.com/gojudge/judger 9 | 10 | # set the working directory and add current stuff 11 | WORKDIR /go/src/github.com/gojudge/judger 12 | RUN export GOBIN=$GOPATH/bin 13 | RUN go get 14 | RUN go build 15 | 16 | EXPOSE 1004 1005 17 | ENTRYPOINT [] 18 | CMD ["./judger","-c=/data/config_docker.ini","-mode=docker"] 19 | -------------------------------------------------------------------------------- /core/controller.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type ControllerInterface interface { 8 | Tcp(data map[string]interface{}, cli *Client) 9 | Http(data map[string]interface{}, w http.ResponseWriter, r *http.Request) 10 | } 11 | 12 | var RouterMap map[string]ControllerInterface 13 | 14 | func Router(actionName string, c ControllerInterface) { 15 | if nil == RouterMap { 16 | RouterMap = make(map[string]ControllerInterface) 17 | } 18 | RouterMap[actionName] = c 19 | } 20 | -------------------------------------------------------------------------------- /test/client_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/duguying/judger/client" 6 | "testing" 7 | ) 8 | 9 | func Test_TCP(t *testing.T) { 10 | cli, err := client.New("duguying.net", 1004, "123456789") 11 | 12 | if err != nil { 13 | fmt.Println(err) 14 | } 15 | 16 | response, err := cli.AddTask(12, "C", "int main(){return 0;}") 17 | 18 | if err != nil { 19 | fmt.Println(err) 20 | } else { 21 | fmt.Println(response) 22 | } 23 | 24 | response, err = cli.GetStatus(12) 25 | 26 | if err != nil { 27 | fmt.Println(err) 28 | } else { 29 | fmt.Println(response) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /conf/config_docker.ini: -------------------------------------------------------------------------------- 1 | # public 2 | 3 | password = 123456789 4 | 5 | # windows 6 | 7 | [windows] 8 | buildpath = build 9 | compiler_c = script/gcc.bat 10 | postfix_c = c 11 | gcc_path = C:\Dev-Cpp 12 | 13 | compiler_cpp = script/g++.bat 14 | postfix_cpp = cpp 15 | 16 | compiler_java = javac.exe 17 | postfix_java = java 18 | 19 | run_script = script/run.bat 20 | 21 | # linux 22 | 23 | [linux] 24 | buildpath = build 25 | compiler_c = script/gcc.sh 26 | postfix_c = c 27 | 28 | compiler_cpp = script/g++.sh 29 | postfix_cpp = cpp 30 | 31 | compiler_java = javac.exe 32 | postfix_java = java 33 | 34 | run_script = script/run.sh 35 | 36 | executer_config = /data/executer.json 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # judger 2 | 3 | | windows | linux-travis | 4 | |---------|--------------| 5 | | [![Build status](https://ci.appveyor.com/api/projects/status/4n48mdcqoss6nhsm?svg=true)](https://ci.appveyor.com/project/duguying/judger-5bddq) | [![Build Status](https://travis-ci.org/gojudge/judger.svg?branch=master)](https://travis-ci.org/gojudge/judger) | 6 | 7 | the judger server of online judge system 8 | 9 | ## Build 10 | 11 | ```shell 12 | go get 13 | go build 14 | ``` 15 | 16 | ## Install from Docker 17 | 18 | ```shell 19 | docker pull duguying/judger 20 | ``` 21 | 22 | ```shell 23 | mkdir /var/goj/judger 24 | docker run -d -p 1004:1004 -p 1005:1005 -v /var/goj/judger:/data duguying/judger 25 | ``` 26 | 27 | ## License # 28 | 29 | MIT License 30 | -------------------------------------------------------------------------------- /controller/status.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/gogather/com" 5 | "github.com/gojudge/judger/core" 6 | "io" 7 | "net/http" 8 | ) 9 | 10 | // login controller 11 | type PingController struct { 12 | core.ControllerInterface 13 | } 14 | 15 | func (this *PingController) Tcp(data map[string]interface{}, cli *core.Client) { 16 | result, _ := com.JsonEncode(map[string]interface{}{ 17 | "result": true, 18 | "msg": "pong", 19 | }) 20 | cli.Write(result) 21 | } 22 | 23 | func (this *PingController) Http(data map[string]interface{}, w http.ResponseWriter, r *http.Request) { 24 | result, _ := com.JsonEncode(map[string]interface{}{ 25 | "result": true, 26 | "msg": "pong", 27 | }) 28 | 29 | io.WriteString(w, result) 30 | } 31 | -------------------------------------------------------------------------------- /models/session.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | "github.com/gogather/com" 6 | "time" 7 | ) 8 | 9 | type SessionTab struct { 10 | Id int 11 | Session string 12 | CreateTime time.Time 13 | } 14 | 15 | func (this *SessionTab) TableName() string { 16 | return "session" 17 | } 18 | 19 | // create session and add session into database 20 | func (this *SessionTab) CreateSession() (string, error) { 21 | sid := com.Md5(com.CreateGUID()) 22 | sid = com.SubString(sid, 0, 7) 23 | o := orm.NewOrm() 24 | var sess SessionTab 25 | 26 | sess.Session = sid 27 | sess.CreateTime = time.Now() 28 | 29 | _, err := o.Insert(&sess) 30 | 31 | return sid, err 32 | } 33 | 34 | // get session from database 35 | func (this *SessionTab) GetSession(sid string) (SessionTab, error) { 36 | o := orm.NewOrm() 37 | var sess SessionTab 38 | 39 | sess.Session = sid 40 | err := o.Read(&sess, "session") 41 | 42 | return sess, err 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rex Lee(李俊) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /judge/task.go: -------------------------------------------------------------------------------- 1 | package judge 2 | 3 | import ( 4 | "errors" 5 | // "fmt" 6 | "github.com/gojudge/judger/core" 7 | "html" 8 | "runtime" 9 | ) 10 | 11 | func AddTask(data map[string]interface{}) error { 12 | compiler := Compile{} 13 | var ok bool 14 | 15 | // HTML反转义 16 | code, ok := data["code"].(string) 17 | code = html.UnescapeString(code) 18 | if !ok { 19 | return errors.New("invalid code, should be string") 20 | } 21 | 22 | // language 23 | lang, ok := data["language"].(string) 24 | if !ok { 25 | return errors.New("invalid language, should be string") 26 | } 27 | 28 | // id 29 | id, ok := data["id"].(float64) 30 | if !ok { 31 | return errors.New("invalid language, should be string") 32 | } 33 | 34 | // session id 35 | sid, ok := data["sid"].(string) 36 | if !ok { 37 | return errors.New("invalid language, should be string") 38 | } 39 | 40 | // run compiling 41 | compiler.NewCompile() 42 | runPath, err := compiler.Run(code, lang, int(id), sid) 43 | 44 | if err == nil { 45 | // execute the binary in sandbox 46 | err = RunNativeInSandbox(core.C.Get(runtime.GOOS, "run_script"), runPath, 0, 0) 47 | } 48 | 49 | // TODO gather result 50 | 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /conf/config.ini: -------------------------------------------------------------------------------- 1 | # public 2 | 3 | password = 123456789 4 | 5 | # windows 6 | 7 | [windows] 8 | buildpath = build 9 | compiler_c = script/gcc.bat 10 | postfix_c = c 11 | gcc_path = C:\Dev-Cpp 12 | executer_path = sandbox\c\build\executer.exe 13 | 14 | compiler_cpp = script/g++.bat 15 | postfix_cpp = cpp 16 | 17 | compiler_java = javac.exe 18 | postfix_java = java 19 | 20 | run_script = script/run.bat 21 | 22 | # linux 23 | 24 | [linux] 25 | buildpath = build 26 | compiler_c = script/gcc.sh 27 | postfix_c = c 28 | executer_path = sandbox/c/build/executer 29 | 30 | compiler_cpp = script/g++.sh 31 | postfix_cpp = cpp 32 | 33 | compiler_java = javac.exe 34 | postfix_java = java 35 | 36 | run_script = script/run.sh 37 | 38 | executer_config = /root/gopath/src/github.com/duguying/judger/sandbox/c/build/executer.json 39 | 40 | [darwin] 41 | buildpath = build 42 | compiler_c = script/gcc.sh 43 | postfix_c = c 44 | executer_path = sandbox/c/build/executer 45 | 46 | compiler_cpp = script/g++.sh 47 | postfix_cpp = cpp 48 | 49 | compiler_java = javac.exe 50 | postfix_java = java 51 | 52 | run_script = script/run.sh 53 | 54 | executer_config = /root/gopath/src/github.com/duguying/judger/sandbox/c/build/executer.json 55 | 56 | -------------------------------------------------------------------------------- /controller/gather.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/gogather/com" 5 | "github.com/gojudge/judger/core" 6 | "github.com/gojudge/judger/judge" 7 | "io" 8 | "net/http" 9 | "runtime" 10 | ) 11 | 12 | // gather information controller 13 | type GatherController struct { 14 | core.ControllerInterface 15 | } 16 | 17 | func (this *GatherController) Tcp(data map[string]interface{}, cli *core.Client) { 18 | info := &judge.Info{} 19 | sid := data["sid"].(string) 20 | id := data["id"].(float64) 21 | information := info.Gather(sid, int(id), core.C.Get(runtime.GOOS, "buildpath")) 22 | 23 | result, _ := com.JsonEncode(map[string]interface{}{ 24 | "info": information, 25 | 26 | "time": 123456789, 27 | "sid": sid, 28 | "id": id, 29 | }) 30 | cli.Write(result) 31 | } 32 | 33 | func (this *GatherController) Http(data map[string]interface{}, w http.ResponseWriter, r *http.Request) { 34 | 35 | info := &judge.Info{} 36 | sid := data["sid"].(string) 37 | id := data["id"].(float64) 38 | information := info.Gather(sid, int(id), core.C.Get(runtime.GOOS, "buildpath")) 39 | 40 | result, _ := com.JsonEncode(map[string]interface{}{ 41 | "info": information, 42 | 43 | "time": 123456789, 44 | "sid": sid, 45 | "id": id, 46 | }) 47 | 48 | io.WriteString(w, result) 49 | } 50 | -------------------------------------------------------------------------------- /core/sqlite.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | _ "github.com/mattn/go-sqlite3" 6 | "log" 7 | ) 8 | 9 | type Sqlite struct { 10 | Filename string 11 | } 12 | 13 | func (this *Sqlite) NewSqlite(dataPath string) { 14 | orm.RegisterDataBase("default", "sqlite3", "data.db") 15 | 16 | this.createTable() 17 | } 18 | 19 | func (this *Sqlite) createTable() { 20 | o := orm.NewOrm() 21 | 22 | table1 := `CREATE TABLE [session] ( 23 | [id] INTEGER PRIMARY KEY NOT NULL, 24 | [session] VARCHAR(128) UNIQUE NOT NULL, 25 | [create_time] TIME DEFAULT CURRENT_TIMESTAMP NOT NULL 26 | )` 27 | 28 | table2 := `CREATE TABLE [task] ( 29 | [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 30 | [task_id] VARCHAR(128) UNIQUE NOT NULL, 31 | [language] VARCHAR(64) DEFAULT '''C''' NOT NULL, 32 | [type] VARCHAR(16) DEFAULT '''io''' NOT NULL, 33 | [io_data] TEXT NULL, 34 | [code] TEXT NULL, 35 | [time] TIME DEFAULT CURRENT_TIMESTAMP NOT NULL, 36 | [build_log] TEXT NULL, 37 | [build_result] VARCHAR(128) NULL, 38 | [run_result] VARCHAR(128) NULL, 39 | [debug_info] TEXT NULL 40 | )` 41 | 42 | _, err := o.Raw(table1).Exec() 43 | if err != nil { 44 | log.Println(err) 45 | } 46 | 47 | _, err = o.Raw(table2).Exec() 48 | if err != nil { 49 | log.Println(err) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/http.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/gogather/com" 5 | "io" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func HttpStart() { 11 | 12 | http.HandleFunc("/", HandleJsonRpc) 13 | 14 | err := http.ListenAndServe(":1005", nil) 15 | if err != nil { 16 | log.Println("ListenAndServe: ", err) 17 | } else { 18 | log.Println("Http Server Started!") 19 | } 20 | } 21 | 22 | func HandleJsonRpc(w http.ResponseWriter, r *http.Request) { 23 | // get request content 24 | p := make([]byte, r.ContentLength) 25 | r.Body.Read(p) 26 | 27 | content := string(p) 28 | 29 | log.Println(content) 30 | 31 | json, err := com.JsonDecode(content) 32 | 33 | if err != nil { 34 | log.Println("not json-rpc format") 35 | return 36 | } 37 | 38 | data := json.(map[string]interface{}) 39 | 40 | // get system password 41 | password := C.Get("", "password") 42 | 43 | // parse received password 44 | passwordRecv, ok := data["password"].(string) 45 | if !ok { 46 | result, _ := com.JsonEncode(map[string]interface{}{ 47 | "result": false, //bool, login result 48 | "msg": "invalid password, password must be string.", 49 | }) 50 | io.WriteString(w, result) 51 | return 52 | } 53 | 54 | // compare password 55 | if password != passwordRecv { 56 | result, _ := com.JsonEncode(map[string]interface{}{ 57 | "result": false, //bool, login failed 58 | }) 59 | io.WriteString(w, result) 60 | return 61 | } 62 | 63 | // trigger controller 64 | ctrl, exists := RouterMap[data["action"].(string)] 65 | if !exists { 66 | log.Println("not exist") 67 | return 68 | } 69 | ctrl.Http(data, w, r) 70 | } 71 | -------------------------------------------------------------------------------- /judge/gather.go: -------------------------------------------------------------------------------- 1 | package judge 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogather/com" 6 | "log" 7 | "path/filepath" 8 | "strconv" 9 | ) 10 | 11 | type Info struct { 12 | sid string 13 | id int 14 | buildLog string 15 | buildResult int 16 | runResult string 17 | buildPath string 18 | } 19 | 20 | func (this *Info) Gather(sid string, id int, buildPath string) map[string]interface{} { 21 | this.sid = sid 22 | this.id = id 23 | this.buildPath = buildPath 24 | 25 | this.buildLog = this.getLog("BUILD.LOG") 26 | 27 | if this.buildResult = this.getResult("BUILDRESULT"); this.buildResult == 0 { 28 | this.runResult = this.getLog("RUNRESULT") 29 | } else { 30 | this.runResult = "EC" 31 | } 32 | 33 | return map[string]interface{}{ 34 | "build_log": this.buildLog, 35 | "build_result": this.buildResult, 36 | "run_result": this.runResult, 37 | } 38 | } 39 | 40 | func (this *Info) getLog(file string) string { 41 | path := filepath.Join(this.buildPath, this.sid, fmt.Sprintf("%d", this.id), file) 42 | if com.PathExist(path) { 43 | content, _ := com.ReadFile(path) 44 | return content 45 | } else { 46 | return "" 47 | } 48 | } 49 | 50 | // get the result 51 | func (this *Info) getResult(file string) int { 52 | path := filepath.Join(this.buildPath, this.sid, fmt.Sprintf("%d", this.id), file) 53 | if com.PathExist(path) { 54 | content, _ := com.ReadFile(path) 55 | content = com.Strim(content) 56 | if result, err := strconv.Atoi(content); err != nil { 57 | log.Println(err) 58 | return -1 59 | } else { 60 | return result 61 | } 62 | } else { 63 | return -1 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/gen_script.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogather/com" 6 | "os" 7 | "path/filepath" 8 | "runtime" 9 | ) 10 | 11 | func GenScript() { 12 | currentPath, _ := os.Getwd() 13 | 14 | gccWin := `"%s\bin\%s.exe" %%1 -g3 -I"%s\include" -L"%s\lib" -g3 1> BUILD.LOG 2>&1 15 | echo %%ERRORLEVEL%% > BUILDRESULT` 16 | 17 | gccNix := `%s $1 1> BUILD.LOG 2>&1 18 | echo $? > BUILDRESULT` 19 | 20 | var gccScript string 21 | var gppScript string 22 | 23 | if !com.FileExist("script") { 24 | com.Mkdir("script") 25 | } 26 | 27 | if runtime.GOOS == "windows" { 28 | gccWinPath := C.Get(runtime.GOOS, "gcc_path") 29 | gccScript = fmt.Sprintf(gccWin, gccWinPath, "gcc", gccWinPath, gccWinPath) 30 | gppScript = fmt.Sprintf(gccWin, gccWinPath, "g++", gccWinPath, gccWinPath) 31 | 32 | runWin := `"` + filepath.Join(currentPath, C.Get(runtime.GOOS, "executer_path")) + `" -t=%1 -m=%2 %3` 33 | 34 | com.WriteFile(C.Get(runtime.GOOS, "compiler_c"), gccScript) 35 | com.WriteFile(C.Get(runtime.GOOS, "compiler_cpp"), gppScript) 36 | com.WriteFile(C.Get(runtime.GOOS, "run_script"), runWin) 37 | } else { 38 | gccScript = fmt.Sprintf(gccNix, "gcc") 39 | gppScript = fmt.Sprintf(gccNix, "g++") 40 | runNix := filepath.Join(currentPath, C.Get(runtime.GOOS, "executer_path")) + ` -t=$1 -m=$2 $3 -c=` + C.Get(runtime.GOOS, "executer_config") 41 | 42 | com.WriteFile(C.Get(runtime.GOOS, "compiler_c"), gccScript) 43 | com.WriteFile(C.Get(runtime.GOOS, "compiler_cpp"), gppScript) 44 | com.WriteFile(C.Get(runtime.GOOS, "run_script"), runNix) 45 | 46 | os.Chmod(C.Get(runtime.GOOS, "compiler_c"), 0755) 47 | os.Chmod(C.Get(runtime.GOOS, "compiler_cpp"), 0755) 48 | os.Chmod(C.Get(runtime.GOOS, "run_script"), 0755) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /models/task.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beego/orm" 6 | "time" 7 | ) 8 | 9 | type TaskTab struct { 10 | Id int 11 | TaskId string 12 | Language string 13 | Type string 14 | IoData string 15 | Code string 16 | Time time.Time 17 | BuildLog string 18 | BuildResult string 19 | RunResult string 20 | DebugInfo string 21 | } 22 | 23 | func (this *TaskTab) TableName() string { 24 | return "task" 25 | } 26 | 27 | // add task 28 | func (this *TaskTab) AddTask(id int, sid string, language string, ptype string, ioData string, code string) error { 29 | o := orm.NewOrm() 30 | var task TaskTab 31 | 32 | task.TaskId = fmt.Sprintf("%s:%d", sid, id) 33 | task.Language = language 34 | task.Type = ptype 35 | task.IoData = ioData 36 | task.Code = code 37 | task.Time = time.Now() 38 | task.BuildLog = "" 39 | task.BuildResult = "" 40 | task.RunResult = "TA" 41 | task.DebugInfo = "" 42 | 43 | _, err := o.Insert(&task) 44 | 45 | return err 46 | } 47 | 48 | func (this *TaskTab) GetTaskInfo(id int, sid string) (TaskTab, error) { 49 | o := orm.NewOrm() 50 | var task TaskTab 51 | 52 | task.TaskId = fmt.Sprintf("%s:%d", sid, id) 53 | err := o.Read(&task, "task") 54 | 55 | return task, err 56 | } 57 | 58 | func (this *TaskTab) UpdateTaskInfo(id int, sid string, buildLog string, buildResult string, runResult string, debugInfo string) error { 59 | o := orm.NewOrm() 60 | var task TaskTab 61 | 62 | task.TaskId = fmt.Sprintf("%s:%d", sid, id) 63 | err := o.Read(&task, "task") 64 | 65 | task.BuildLog = buildLog 66 | task.BuildResult = buildResult 67 | task.RunResult = runResult 68 | task.DebugInfo = debugInfo 69 | 70 | _, err = o.Update(&task) 71 | 72 | return err 73 | } 74 | -------------------------------------------------------------------------------- /core/init.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/gogather/com" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | "runtime" 9 | "strings" 10 | ) 11 | 12 | var DB *Sqlite 13 | var C *Config 14 | var Mode string 15 | var configFile string 16 | 17 | func Judger() { 18 | parseArg() 19 | 20 | dataPath := "data.db" 21 | 22 | if Mode == "docker" { 23 | log.Println("[mode]", "docker") 24 | 25 | if !com.FileExist("/data") { 26 | if err := com.Mkdir("/data"); err != nil { 27 | log.Println("[Warn]", "create dir /data failed") 28 | } else { 29 | log.Println("[info]", "create dir /data") 30 | } 31 | } 32 | 33 | if !com.FileExist("/data/config_docker.ini") { 34 | com.CopyFile("/data/config_docker.ini", "conf/config_docker.ini") 35 | } 36 | 37 | if !com.FileExist("/data/executer.json") { 38 | com.CopyFile("/data/executer.json", "sandbox/c/build/executer.json") 39 | } 40 | 41 | dataPath = "/data/data.db" 42 | } 43 | 44 | if configFile == "" { 45 | configFile = "conf/config.ini" 46 | } 47 | 48 | if !com.FileExist(configFile) { 49 | log.Println("[Error]", configFile, "does not exist!") 50 | os.Exit(-1) 51 | } 52 | 53 | log.Println("[config]") 54 | log.Println(configFile) 55 | 56 | C = &Config{} 57 | C.NewConfig(configFile) 58 | 59 | GenScript() 60 | 61 | log.Println("[data]") 62 | log.Println(dataPath) 63 | DB = &Sqlite{} 64 | DB.NewSqlite(dataPath) 65 | 66 | createBuildDir() 67 | 68 | go TcpStart() 69 | HttpStart() 70 | } 71 | 72 | func createBuildDir() error { 73 | var err error 74 | err = nil 75 | 76 | buildPath := filepath.Join(C.Get(runtime.GOOS, "buildpath")) 77 | if !com.PathExist(buildPath) { 78 | err = com.Mkdir(buildPath) 79 | } 80 | 81 | return err 82 | } 83 | 84 | func parseArg() { 85 | configFile = "" 86 | Mode = "" 87 | 88 | arg_num := len(os.Args) 89 | 90 | for i := 0; i < arg_num; i++ { 91 | s := os.Args[i] 92 | 93 | if s[0] == '-' { 94 | s = strings.Replace(s, "-", "", -1) 95 | arr := strings.Split(s, "=") 96 | 97 | if arr[0] == "c" { 98 | configFile = arr[1] 99 | } else if arr[0] == "mode" { 100 | Mode = arr[1] 101 | } 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /judge/native.go: -------------------------------------------------------------------------------- 1 | package judge 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "runtime" 10 | ) 11 | 12 | // run native code(compiled via c/c++) in sandbox 13 | func RunNativeInSandbox(runScript string, runPath string, time int, mem int) error { 14 | var argTime string 15 | var argMem string 16 | var binFilePath string 17 | var err error 18 | 19 | if time > 0 { 20 | argTime = fmt.Sprintf("%d", time) 21 | } else { 22 | argTime = "10" 23 | } 24 | 25 | if mem > 0 { 26 | argMem = fmt.Sprintf("%d", mem) 27 | } else { 28 | argMem = "1024" 29 | } 30 | 31 | currentPath, _ := os.Getwd() 32 | os.Chdir(runPath) 33 | 34 | if runtime.GOOS == "windows" { 35 | binFilePath = filepath.Join(runPath, "a.exe") 36 | } else { 37 | binFilePath = filepath.Join(runPath, "a.out") 38 | } 39 | 40 | runScript = filepath.Join(currentPath, runScript) 41 | 42 | log.Println(runScript, 43 | binFilePath, 44 | argTime, 45 | argMem, 46 | ) 47 | 48 | if runtime.GOOS == "windows" { 49 | err = runnerWin(runScript, 50 | binFilePath, 51 | argTime, 52 | argMem, 53 | ) 54 | } else { 55 | err = runnerNix(runScript, 56 | binFilePath, 57 | argTime, 58 | argMem, 59 | ) 60 | } 61 | 62 | os.Chdir(currentPath) 63 | 64 | return err 65 | } 66 | 67 | // call runner in windows 68 | func runnerWin(runScript string, bin string, argTime string, argMem string) error { 69 | binPath := filepath.Join(bin) 70 | cmd := exec.Command("cmd", "/K", 71 | runScript, // runner script 72 | argTime+"", // time limit 73 | argMem, // memory limit 74 | binPath, // executable name 75 | ) 76 | 77 | log.Println("[", runScript, binPath, argTime, argMem, "]") 78 | 79 | _, err := cmd.Output() 80 | if err != nil { 81 | fmt.Println("失败") 82 | fmt.Println(err) 83 | return err 84 | } 85 | 86 | return nil 87 | } 88 | 89 | // call runner in nix 90 | func runnerNix(runScript string, bin string, argTime string, argMem string) error { 91 | binPath := filepath.Join(bin) 92 | cmd := exec.Command("sh", 93 | runScript, // runner script 94 | argTime, // time limit 95 | argMem, // memory limit 96 | binPath, // executable name 97 | ) 98 | 99 | log.Println("[", runScript, binPath, argTime, argMem, "]") 100 | 101 | _, err := cmd.Output() 102 | if err != nil { 103 | fmt.Println("失败") 104 | fmt.Println(err) 105 | return err 106 | } 107 | 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | ## judger包(core目录) 2 | 3 | judger包是一个简易(tiny)的Service-Router-Controller框架 4 | 5 | ## 网络通讯 6 | 7 | ### 传输协议TCP 8 | 9 | #### 客户端 10 | 11 | "string\03" 12 | 13 | 每次发送一个字符串,字符串的结尾以ASCII码0x03结束,由于0x03是不可见字符,故串的正文部分不应该包含0x03不可见字符。 14 | 15 | 字符串的正文格式为json格式如下 16 | 17 | ##### 密码验证 18 | 19 | ```json 20 | { 21 | "action": "login", //action name 22 | "ip": "127.0.0.1", //client ip 23 | "password": "password", //password string 24 | "time": 123456789 //timestamp 25 | } 26 | ``` 27 | 28 | ##### 提交任务 29 | 30 | ```json 31 | { 32 | "action": "task_add", //action name 33 | "id": 12, //task id, task id must be unique 34 | "time": 123456789, //timestamp 35 | "language": "C", //language 36 | "code": "here is code" //code,code应该是经过html转义的 37 | } 38 | ``` 39 | 40 | ##### 查询任务状态 41 | 42 | ```json 43 | { 44 | "action": "task_status", //action name 45 | "id": 12, //task id 46 | "time": 123456789 47 | } 48 | ``` 49 | 50 | #### 服务端 51 | 52 | 服务端返回数据也是json格式 53 | 54 | ##### 密码验证 55 | 56 | 登录成功 57 | 58 | ```json 59 | { 60 | "result": true, //bool, login result 61 | "os": "linux x86", 62 | "language": { //language:compiler 63 | "C": "gcc", 64 | "C++": "g++", 65 | "Java": "javac version 1.7" 66 | }, 67 | "time": 123456789 //server time stamp 68 | } 69 | ``` 70 | 71 | 登录失败 72 | 73 | ```json 74 | { 75 | "result": false //bool, login result 76 | } 77 | ``` 78 | 79 | ##### 任务提交响应 80 | 81 | 提交成功 82 | 83 | ```json 84 | { 85 | "result": true, 86 | "message": "task in queue", 87 | "time": 123456789 88 | } 89 | ``` 90 | 91 | 提交失败 92 | 93 | ```json 94 | { 95 | "result": false, 96 | "message": "task commit failed, the reason is blablabla...", 97 | "time": 123456789 98 | } 99 | ``` 100 | 101 | ##### 任务状态查询 102 | 103 | 查询失败(通常指任务不存在) 104 | 105 | ```json 106 | { 107 | "result": false, 108 | "message": "task is not exist", 109 | "time": 123456789 110 | } 111 | ``` 112 | 113 | 队列中 114 | 115 | ```json 116 | { 117 | "result": true, 118 | "status": "waitting", //只存在waitting,success,failed三种类型 119 | "message": "task in queue", 120 | "time": 123456789 121 | } 122 | ``` 123 | 124 | 通过 125 | 126 | ```json 127 | { 128 | "result": true, 129 | "status": "success", 130 | "log": "here is compiler log and run log or any other logs", 131 | "time": 123456789 132 | } 133 | ``` 134 | 135 | 失败 136 | 137 | ```json 138 | { 139 | "result": true, 140 | "status": "failed", 141 | "log": "here is compiler log and run log or any other logs", 142 | "time": 123456789 143 | } 144 | ``` 145 | 146 | ##### 系统状态不可用 147 | 148 | ```json 149 | { 150 | "result": false, 151 | "message": "system failure", 152 | "time": 123456789 153 | } 154 | ``` 155 | 156 | #### 注意 157 | 158 | 注意,在发送数据的时候数据中不能够包含注释,否则会抛出异常,此问题不准备解决,为了节省流量发送的数据中不应该包含注释。 159 | -------------------------------------------------------------------------------- /core/config.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Unknwon/goconfig" 6 | "github.com/gogather/com" 7 | "io/ioutil" 8 | "os" 9 | "regexp" 10 | "log" 11 | ) 12 | 13 | type Config struct { 14 | jsonConfigData interface{} 15 | iniConfigData *goconfig.ConfigFile 16 | configType string 17 | configFilePath string 18 | } 19 | 20 | // load json config file 21 | func (this *Config) loadJsonConfig() error { 22 | fi, err := os.Open(this.configFilePath) 23 | if err != nil { 24 | panic(err) 25 | } 26 | defer fi.Close() 27 | fd, err := ioutil.ReadAll(fi) 28 | configString := string(fd) 29 | 30 | // kick out the comment 31 | regFilter := regexp.MustCompile(`//[\d\D][^\r]*\r`) 32 | configString = regFilter.ReplaceAllString(configString, "") 33 | this.jsonConfigData, err = com.JsonDecode(configString) 34 | if err != nil { 35 | log.Fatalln("Read config file failed. please check `conf/config.json`.") 36 | } 37 | 38 | return err 39 | } 40 | 41 | // load ini config file 42 | func (this *Config) loadIniConfig() error { 43 | var err error 44 | 45 | this.iniConfigData, err = goconfig.LoadConfigFile(this.configFilePath) 46 | if nil != err { 47 | fmt.Println(err) 48 | } 49 | 50 | return err 51 | } 52 | 53 | // get value via key for json 54 | // arg1: key level 1 55 | // arg2: key level 2 56 | func (this *Config) jsonGet(key1 string, key2 string) string { 57 | // json 58 | if key1 == "" { 59 | if value, ok := this.jsonConfigData.(map[string]interface{})[key2].(string); ok { 60 | return value 61 | } else { 62 | fmt.Println(`Cannot Get("", "` + key2 + `")`) 63 | return "" 64 | } 65 | } else { 66 | if json, ok := this.jsonConfigData.(map[string]interface{})[key1]; ok { 67 | if value, ok := json.(map[string]interface{})[key2].(string); ok { 68 | return value 69 | } else { 70 | fmt.Println(`Cannot Get("", "` + key2 + `")`) 71 | return "" 72 | } 73 | } else { 74 | fmt.Println(`Cannot Get("` + key1 + `", "~")`) 75 | return "" 76 | } 77 | } 78 | 79 | } 80 | 81 | // load config 82 | func (this *Config) NewConfig(path string) { 83 | this.configFilePath = path 84 | 85 | regFilter := regexp.MustCompile(`[\d\D][^\r\n]*\.ini$`) 86 | matched := regFilter.FindAllString(path, -1) 87 | 88 | if 0 != len(matched) { 89 | this.configType = "ini" 90 | this.loadIniConfig() 91 | } else { 92 | this.configType = "json" 93 | this.loadJsonConfig() 94 | } 95 | } 96 | 97 | // get value via key 98 | // arg1: key level 1 99 | // arg2: key level 2 100 | func (this *Config) Get(key1 string, key2 string) string { 101 | if this.configType == "ini" { 102 | // parse ini 103 | v, err := this.iniConfigData.GetValue(key1, key2) 104 | if nil != err { 105 | fmt.Println(err) 106 | } 107 | 108 | return v 109 | } else { 110 | // parse json 111 | return this.jsonGet(key1, key2) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /core/tcp.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogather/com" 6 | "io" 7 | "log" 8 | "net" 9 | "os" 10 | "regexp" 11 | ) 12 | 13 | const ( 14 | BUFF_SIZE = 10 15 | MAX_LCI = 100 16 | ) 17 | 18 | type Client struct { 19 | active bool 20 | Conn net.Conn 21 | cid int 22 | login bool 23 | } 24 | 25 | var buff = make([]byte, BUFF_SIZE) 26 | var cliTab = make(map[int]*Client) 27 | var MARK string 28 | 29 | /// close client connect from server 30 | func (this *Client) Close() { 31 | this.Conn.Close() 32 | this.active = false 33 | cliTab[this.cid] = nil 34 | } 35 | 36 | // send message to client and print in server console 37 | func (this *Client) Write(str string) { 38 | str = str + MARK 39 | this.Conn.Write([]byte(str)) 40 | log.Println(str) 41 | } 42 | 43 | // set mark for login 44 | // value: true for login, false for not login 45 | func (this *Client) Login(value bool) { 46 | this.login = value 47 | } 48 | 49 | func Parse(frame string, cli *Client) { 50 | log.Println(frame) 51 | json, err := com.JsonDecode(frame) 52 | if err != nil { 53 | log.Println(err) 54 | } else { 55 | data := json.(map[string]interface{}) 56 | 57 | actonName, ok := data["action"].(string) 58 | if !ok { 59 | cli.Write("invalid request, action name is not exist.") 60 | return 61 | } 62 | 63 | // 如果不是登录请求,并且用户处于未登录状态,禁止通行 64 | if actonName != "login" { 65 | if !cli.login { 66 | cli.Write("you have not login.") 67 | return 68 | } 69 | } 70 | 71 | RouterMap[actonName].Tcp(data, cli) 72 | } 73 | 74 | } 75 | 76 | func handleError(err error, tcpConn net.Conn) { 77 | if err != nil { 78 | fmt.Fprintf(os.Stderr, "Client error: %s\n", err.Error()) 79 | if tcpConn != nil { 80 | tcpConn.Close() 81 | } 82 | } 83 | } 84 | 85 | func handleConnection(tcpConn net.Conn, cid int) { 86 | frame := "" 87 | 88 | if tcpConn == nil { 89 | return 90 | } 91 | 92 | cli := &Client{true, tcpConn, cid, false} 93 | cliTab[cid] = cli 94 | 95 | fmt.Println("Connected! Remote address is " + tcpConn.LocalAddr().String()) 96 | tcpConn.Write([]byte("Connected! Remote address is " + tcpConn.LocalAddr().String() + "/" + MARK + "#")) 97 | for { 98 | n, err := tcpConn.Read(buff) 99 | if err == io.EOF { 100 | fmt.Printf("The RemoteAddr:%s is closed!\n", tcpConn.RemoteAddr().String()) 101 | return 102 | } 103 | 104 | // Accident exit 105 | handleError(err, tcpConn) 106 | if tcpConn != nil && err != nil { 107 | return 108 | } 109 | 110 | if n > 0 { 111 | frame = frame + string(buff[:n]) 112 | 113 | reg := regexp.MustCompile(MARK) 114 | if len(reg.FindAllString(string(buff[:n]), -1)) > 0 { 115 | // get the json 116 | frame = reg.ReplaceAllString(frame, "") 117 | // submit json task 118 | Parse(frame, cli) 119 | frame = "" 120 | // if connection is inactive[closed by server, jump out of cycle 121 | if !cli.active { 122 | return 123 | } 124 | } 125 | 126 | } 127 | } 128 | } 129 | 130 | func TcpStart() { 131 | i := 0 132 | ln, err := net.Listen("tcp", ":1004") 133 | handleError(err, nil) 134 | 135 | if len(os.Args) > 1 && os.Args[1] == "debug" { 136 | MARK = "#" 137 | } else { 138 | MARK = "\003" 139 | } 140 | 141 | for { 142 | conn, err := ln.Accept() 143 | if err != nil { 144 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 145 | continue 146 | } 147 | i += 1 148 | if i > MAX_LCI { 149 | fmt.Println("reached max client limit, server stoped.") 150 | return 151 | } 152 | go handleConnection(conn, i) 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /judge/ccpp.go: -------------------------------------------------------------------------------- 1 | package judge 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogather/com" 6 | "github.com/gojudge/judger/core" 7 | "log" 8 | "os" 9 | "os/exec" 10 | "path/filepath" 11 | "runtime" 12 | "time" 13 | ) 14 | 15 | var BuildStartTime int64 16 | var BuildProcessHaveExit bool 17 | 18 | type Compile struct { 19 | system string 20 | buildPath string 21 | userBuildPath string 22 | itemBuildPath string 23 | codeFilePath string 24 | currentPath string 25 | 26 | compiler_c string 27 | postfix_c string 28 | 29 | compiler_cpp string 30 | postfix_cpp string 31 | 32 | buildOverTime bool 33 | } 34 | 35 | func (this *Compile) NewCompile() { 36 | this.buildOverTime = false 37 | this.system = runtime.GOOS 38 | this.postfix_c = "c" 39 | this.postfix_cpp = "cpp" 40 | this.currentPath, _ = os.Getwd() 41 | 42 | this.buildPath = filepath.Join(this.currentPath, core.C.Get(runtime.GOOS, "buildpath")) 43 | this.compiler_c = filepath.Join(this.currentPath, core.C.Get(runtime.GOOS, "compiler_c")) 44 | 45 | log.Println("[current path]", this.currentPath) 46 | log.Println("[build path]", this.buildPath) 47 | log.Println("[compiler path]", this.compiler_c) 48 | } 49 | 50 | func (this *Compile) Run(code string, language string, id int, sid string) (string, error) { 51 | 52 | err := this.createDirs(id, sid) 53 | if err != nil { 54 | log.Println(err) 55 | return "", err 56 | } else { 57 | err = this.writeCode(code, id, language) 58 | if err != nil { 59 | log.Println(err) 60 | return "", err 61 | } 62 | } 63 | 64 | return this.itemBuildPath, this.gcc(id) 65 | 66 | } 67 | 68 | // 创建编译环境的目录结构 69 | func (this *Compile) createDirs(id int, sid string) error { 70 | var err error 71 | err = nil 72 | this.userBuildPath = filepath.Join(this.buildPath, sid) 73 | if !com.PathExist(this.userBuildPath) { 74 | err = com.Mkdir(this.userBuildPath) 75 | } 76 | this.itemBuildPath = filepath.Join(this.userBuildPath, fmt.Sprintf("%d", id)) 77 | if !com.PathExist(this.itemBuildPath) { 78 | err = com.Mkdir(this.itemBuildPath) 79 | } 80 | return err 81 | } 82 | 83 | // 代码写入文件 84 | func (this *Compile) writeCode(code string, id int, language string) error { 85 | lang := "" 86 | if language == "C" { 87 | lang = "c" 88 | } 89 | this.codeFilePath = filepath.Join(this.itemBuildPath, fmt.Sprintf("%d.%s", id, lang)) 90 | return com.WriteFile(this.codeFilePath, code) 91 | } 92 | 93 | // call gcc compiler in other os 94 | func (this *Compile) gcc(id int) error { 95 | os.Chdir(this.itemBuildPath) 96 | 97 | var cmd *exec.Cmd 98 | 99 | log.Println("cmd", "/K", 100 | this.compiler_c, 101 | this.codeFilePath, 102 | this.itemBuildPath, 103 | ) 104 | 105 | if runtime.GOOS == "windows" { 106 | cmd = exec.Command("cmd", "/K", 107 | this.compiler_c, 108 | this.codeFilePath, 109 | this.itemBuildPath, 110 | ) 111 | } else { 112 | cmd = exec.Command("sh", 113 | this.compiler_c, 114 | this.codeFilePath, 115 | this.itemBuildPath, 116 | ) 117 | } 118 | 119 | err := cmd.Start() 120 | if err != nil { 121 | log.Println("Start Failed") 122 | log.Println(err) 123 | } 124 | 125 | stn := time.Now() 126 | BuildStartTime = stn.UnixNano() 127 | go checkTimer(cmd, this, id) 128 | BuildProcessHaveExit = false 129 | 130 | err = cmd.Wait() 131 | BuildProcessHaveExit = true 132 | 133 | if err != nil { 134 | log.Println("Wait Failed") 135 | log.Println(err) 136 | } 137 | 138 | os.Chdir(this.currentPath) 139 | 140 | return err 141 | } 142 | 143 | func checkTimer(cmd *exec.Cmd, comp *Compile, id int) { 144 | for { 145 | // if building process hava exit normally, exit timer 146 | if BuildProcessHaveExit { 147 | log.Println("Building Process Exit Normally.") 148 | return 149 | } 150 | 151 | stn := time.Now() 152 | now := stn.UnixNano() 153 | // over 10s 154 | if now-BuildStartTime > 10*1000000000 { 155 | comp.buildOverTime = true 156 | log.Println("Building Out of Time, Terminated!") 157 | cmd.Process.Kill() 158 | 159 | systemTag := com.SubString(runtime.GOOS, 0, 5) 160 | if systemTag == "linux" { 161 | // ps -ef|grep cc1|grep 5.c|awk '{print $2}'|xargs kill -9 162 | cleanScript := fmt.Sprintf("ps -ef|grep cc1|grep %d.c|awk '{print $2}'|xargs kill -9", id) 163 | cleanCmd := exec.Command("sh", 164 | "-c", 165 | cleanScript, 166 | ) 167 | err := cleanCmd.Run() 168 | if err != nil { 169 | log.Println("clean orphan failed") 170 | } 171 | } 172 | return 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/gogather/com" 7 | "html" 8 | "io" 9 | "log" 10 | "net" 11 | "regexp" 12 | "time" 13 | ) 14 | 15 | type JClient struct { 16 | ip string 17 | port int 18 | conn net.Conn 19 | connected bool 20 | mark string 21 | debug bool 22 | login bool 23 | sid string 24 | } 25 | 26 | func New(ip string, port int, password string) (*JClient, error) { 27 | J := &JClient{} 28 | err := J.Start(ip, port, password) 29 | if err != nil { 30 | J.connected = false 31 | } else { 32 | J.connected = true 33 | } 34 | return J, err 35 | } 36 | 37 | func (this *JClient) SetDebug(flag bool) { 38 | this.debug = flag 39 | } 40 | 41 | // start the session 42 | func (this *JClient) Start(ip string, port int, password string) error { 43 | // not login, first time 44 | this.login = false 45 | 46 | // default # to get the real sep 47 | this.mark = "#" 48 | addr := fmt.Sprintf("%s:%d", ip, port) 49 | conn, err := net.Dial("tcp", addr) 50 | if err != nil { 51 | if conn != nil { 52 | conn.Close() 53 | } 54 | 55 | log.Println("connect judge server failed in port:", port) 56 | 57 | return err 58 | } else { 59 | this.conn = conn 60 | this.connected = true 61 | content, err := this.read() 62 | if err != nil { 63 | return err 64 | } 65 | 66 | // get seperater mark 67 | reg := regexp.MustCompile(`/[\d\D]+$`) 68 | if arr := reg.FindAllString(content, -1); len(arr) > 0 { 69 | this.mark = com.SubString(arr[0], 1, 1) 70 | } 71 | 72 | log.Println(content) 73 | } 74 | 75 | // login 76 | loginRequest := map[string]interface{}{ 77 | "action": "login", 78 | "password": password, 79 | } 80 | 81 | response, err := this.Request(loginRequest) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | result, ok := response["result"].(bool) 87 | if !result || !ok { 88 | return errors.New("login failed.") 89 | } 90 | 91 | sid, ok := response["sid"].(string) 92 | if ok { 93 | this.sid = sid 94 | } else { 95 | this.sid = "" 96 | } 97 | 98 | this.login = true 99 | 100 | return err 101 | } 102 | 103 | // send request 104 | func (this *JClient) Request(msg map[string]interface{}) (map[string]interface{}, error) { 105 | msgStr, err := com.JsonEncode(msg) 106 | 107 | if err != nil { 108 | return nil, err 109 | } 110 | 111 | if this.conn == nil { 112 | log.Println("Connection Not Exist") 113 | return nil, errors.New("Connection Not Exist") 114 | } 115 | 116 | _, err = this.conn.Write([]byte(msgStr + this.mark)) 117 | if err != nil { 118 | log.Println("[Write Error]", err) 119 | this.conn.Close() 120 | return nil, err 121 | } 122 | 123 | content, err := this.read() 124 | 125 | if err != nil { 126 | return nil, err 127 | } 128 | 129 | // kick sep char 130 | reg := regexp.MustCompile(this.mark) 131 | content = reg.ReplaceAllString(content, "") 132 | 133 | if this.debug { 134 | log.Println("[judger/send:%s]\n%s\n", time.Now(), msgStr) 135 | log.Println("[judger/recv:%s]\n%s\n", time.Now(), content) 136 | } 137 | 138 | resp, err := com.JsonDecode(content) 139 | 140 | return resp.(map[string]interface{}), err 141 | } 142 | 143 | // read message from socket 144 | func (this *JClient) read() (string, error) { 145 | var buff [10]byte 146 | frame := "" 147 | 148 | for { 149 | n, err := this.conn.Read(buff[0:]) 150 | if err != nil { 151 | if err == io.EOF { 152 | return "", err 153 | } 154 | } 155 | 156 | if n > 0 { 157 | frame = frame + string(buff[:n]) 158 | 159 | reg := regexp.MustCompile(this.mark) 160 | if len(reg.FindAllString(string(buff[:n]), -1)) > 0 { 161 | break 162 | } 163 | 164 | } 165 | } 166 | 167 | return frame, nil 168 | } 169 | 170 | // add task 171 | func (this *JClient) AddTask(id int64, language string, code string) (map[string]interface{}, error) { 172 | if !this.login { 173 | return nil, errors.New("login first") 174 | } 175 | 176 | req := map[string]interface{}{ 177 | "action": "task_add", 178 | "id": id, 179 | "sid": this.sid, 180 | "time": time.Now().Nanosecond(), 181 | "language": language, 182 | "code": html.EscapeString(code), 183 | } 184 | 185 | return this.Request(req) 186 | } 187 | 188 | // get task status 189 | func (this *JClient) GetStatus(id int64) (map[string]interface{}, error) { 190 | if !this.login { 191 | return nil, errors.New("login first") 192 | } 193 | 194 | req := map[string]interface{}{ 195 | "action": "task_info", 196 | "sid": this.sid, 197 | "id": id, 198 | } 199 | 200 | return this.Request(req) 201 | } 202 | 203 | // ping 204 | func (this *JClient) Ping() error { 205 | if !this.login { 206 | return errors.New("login first") 207 | } 208 | 209 | req := map[string]interface{}{ 210 | "action": "ping", 211 | } 212 | 213 | resp, err := this.Request(req) 214 | if err != nil { 215 | return err 216 | } 217 | 218 | if result, ok := resp["result"].(bool); !ok || !result { 219 | return errors.New("ping failed.") 220 | } else { 221 | return nil 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /controller/judge.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/gogather/com" 5 | "github.com/gojudge/judger/core" 6 | "github.com/gojudge/judger/judge" 7 | "github.com/gojudge/judger/models" 8 | "io" 9 | "net/http" 10 | "runtime" 11 | ) 12 | 13 | // login controller 14 | type LoginController struct { 15 | core.ControllerInterface 16 | } 17 | 18 | func (this *LoginController) Tcp(data map[string]interface{}, cli *core.Client) { 19 | sess := &models.SessionTab{} 20 | password := core.C.Get("", "password") 21 | 22 | passwordRecv, ok := data["password"].(string) 23 | if !ok { 24 | result, _ := com.JsonEncode(map[string]interface{}{ 25 | "result": false, //bool, login result 26 | "msg": "invalid password, password must be string.", 27 | }) 28 | cli.Write(result) 29 | return 30 | } 31 | if password != passwordRecv { 32 | result, _ := com.JsonEncode(map[string]interface{}{ 33 | "result": false, //bool, login result 34 | "msg": "wrong password.", 35 | }) 36 | cli.Write(result) 37 | cli.Close() 38 | return 39 | } 40 | 41 | sid, ok := data["sid"] 42 | if ok { 43 | sidString, ok := sid.(string) 44 | if !ok { 45 | result, _ := com.JsonEncode(map[string]interface{}{ 46 | "result": false, //bool, login result 47 | "msg": "invalid sid, sid must be a string.", 48 | }) 49 | cli.Write(result) 50 | return 51 | } 52 | 53 | s, err := sess.GetSession(sidString) 54 | if err == nil && s.Session == sidString { 55 | // login success 56 | cli.Login(true) 57 | result, _ := com.JsonEncode(map[string]interface{}{ 58 | "result": true, //bool, login result 59 | "sid": sid, 60 | "os": runtime.GOOS + " " + runtime.GOARCH, 61 | "language": map[string]interface{}{ //language:compiler 62 | "C": "gcc", 63 | "C++": "g++", 64 | "Java": "javac version 1.7", 65 | }, 66 | "time": 123456789, //server time stamp 67 | }) 68 | cli.Write(result) 69 | } else { 70 | result, _ := com.JsonEncode(map[string]interface{}{ 71 | "result": false, //bool, login result 72 | "msg": "invalid sid, please login without sid.", 73 | }) 74 | cli.Write(result) 75 | } 76 | } else { 77 | sid, err := sess.CreateSession() 78 | if err != nil { 79 | result, _ := com.JsonEncode(map[string]interface{}{ 80 | "result": false, //bool, login result 81 | "msg": "create session failed. please contact the admin.", 82 | }) 83 | cli.Write(result) 84 | } else { 85 | cli.Login(true) 86 | result, _ := com.JsonEncode(map[string]interface{}{ 87 | "result": true, //bool, login result 88 | "sid": sid, 89 | "os": runtime.GOOS + " " + runtime.GOARCH, 90 | "language": map[string]interface{}{ //language:compiler 91 | "C": "gcc", 92 | "C++": "g++", 93 | "Java": "javac version 1.7", 94 | }, 95 | "time": 123456789, //server time stamp 96 | }) 97 | cli.Write(result) 98 | } 99 | } 100 | 101 | } 102 | 103 | func (this *LoginController) Http(data map[string]interface{}, w http.ResponseWriter, r *http.Request) { 104 | var sid string 105 | sess := &models.SessionTab{} 106 | 107 | sidObj, ok := data["sid"] 108 | if !ok { 109 | sid, _ = sess.CreateSession() 110 | } else { 111 | sid, ok = sidObj.(string) 112 | if !ok { 113 | result, _ := com.JsonEncode(map[string]interface{}{ 114 | "result": false, //bool, login result 115 | "msg": "invalid sid, sid must be a string.", 116 | }) 117 | io.WriteString(w, result) 118 | return 119 | } else { 120 | s, err := sess.GetSession(sid) 121 | if err != nil { 122 | result, _ := com.JsonEncode(map[string]interface{}{ 123 | "result": false, //bool, login result 124 | "msg": "invalid sid, login failed.", 125 | }) 126 | io.WriteString(w, result) 127 | return 128 | } 129 | 130 | if s.Session == sid { 131 | 132 | } else { 133 | result, _ := com.JsonEncode(map[string]interface{}{ 134 | "result": false, //bool, login result 135 | "msg": "invalid sid, please login without sid.", 136 | }) 137 | io.WriteString(w, result) 138 | return 139 | } 140 | } 141 | } 142 | 143 | // login success 144 | result, _ := com.JsonEncode(map[string]interface{}{ 145 | "result": true, //bool, login result 146 | "sid": sid, 147 | "os": runtime.GOOS + " " + runtime.GOARCH, 148 | "language": map[string]interface{}{ //language:compiler 149 | "C": "gcc", 150 | "C++": "g++", 151 | "Java": "javac version 1.7", 152 | }, 153 | "time": 123456789, //server time stamp 154 | }) 155 | io.WriteString(w, result) 156 | 157 | } 158 | 159 | // add task controller 160 | type TaskAddController struct { 161 | core.ControllerInterface 162 | } 163 | 164 | func (this *TaskAddController) Tcp(data map[string]interface{}, cli *core.Client) { 165 | judge.AddTask(data) 166 | 167 | result, _ := com.JsonEncode(map[string]interface{}{ 168 | "result": true, //bool, login result 169 | "msg": "task added", 170 | }) 171 | cli.Write(result) 172 | } 173 | 174 | func (this *TaskAddController) Http(data map[string]interface{}, w http.ResponseWriter, r *http.Request) { 175 | judge.AddTask(data) 176 | 177 | result, _ := com.JsonEncode(map[string]interface{}{ 178 | "result": true, //bool, login result 179 | "msg": "task added", 180 | }) 181 | io.WriteString(w, result) 182 | } 183 | -------------------------------------------------------------------------------- /installer.nsi: -------------------------------------------------------------------------------- 1 | ; 该脚本使用 易量安装(az.eliang.com) 向导生成 2 | ; 安装程序初始定义常量 3 | !define PRODUCT_NAME "Goj-Judger" 4 | !define PRODUCT_VERSION "1.0" 5 | !define PRODUCT_PUBLISHER "duguying" 6 | !define PRODUCT_WEB_SITE "http://oj.duguying.net" 7 | !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\judger.exe" 8 | !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" 9 | !define PRODUCT_UNINST_ROOT_KEY "HKLM" 10 | 11 | SetCompressor lzma 12 | 13 | ; 提升安装程序权限(vista,win7,win8) 14 | RequestExecutionLevel admin 15 | 16 | ; ------ MUI 现代界面定义 ------ 17 | !include "MUI2.nsh" 18 | 19 | ; MUI 预定义常量 20 | !define MUI_ABORTWARNING 21 | !define MUI_HEADERIMAGE 22 | !define MUI_HEADERIMAGE_BITMAP "etc\header\install.bmp" 23 | !define MUI_HEADERIMAGE_UNBITMAP "etc\header\uninstall.bmp" 24 | !define MUI_ICON "etc\icon\install.ico" 25 | !define MUI_UNICON "etc\icon\uninstall.ico" 26 | !define MUI_WELCOMEFINISHPAGE_BITMAP "etc\wizard\install.bmp" 27 | !define MUI_UNWELCOMEFINISHPAGE_BITMAP "etc\wizard\uninstall.bmp" 28 | 29 | ; 欢迎页面 30 | !insertmacro MUI_PAGE_WELCOME 31 | ; 许可协议页面 32 | !insertmacro MUI_PAGE_LICENSE "LICENSE" 33 | ; 安装目录选择页面 34 | !insertmacro MUI_PAGE_DIRECTORY 35 | ; 安装过程页面 36 | !insertmacro MUI_PAGE_INSTFILES 37 | ; 安装完成页面 38 | !define MUI_FINISHPAGE_RUN "$INSTDIR\judger.exe" 39 | !insertmacro MUI_PAGE_FINISH 40 | 41 | ; 安装卸载过程页面 42 | !insertmacro MUI_UNPAGE_WELCOME 43 | !insertmacro MUI_UNPAGE_INSTFILES 44 | !insertmacro MUI_UNPAGE_FINISH 45 | 46 | ; 安装界面包含的语言设置 47 | !insertmacro MUI_LANGUAGE "SimpChinese" 48 | 49 | ; ------ MUI 现代界面定义结束 ------ 50 | 51 | Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" 52 | OutFile "setup.exe" 53 | ;ELiangID 统计编号 /* 安装统计项名称:【Goj-Judger】 */ 54 | InstallDir "$PROGRAMFILES\Goj-Judger" 55 | InstallDirRegKey HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" 56 | ShowInstDetails show 57 | ShowUninstDetails show 58 | BrandingText "Goj-Golang based Online Judge" 59 | 60 | ;安装包版本号格式必须为x.x.x.x的4组整数,每组整数范围0~65535,如:2.0.1.2 61 | ;若使用易量统计,版本号将用于区分不同版本的安装情况,此时建议用户务必填写正确的版本号 62 | ;!define INSTALL_VERSION "2.0.1.2" 63 | 64 | ;VIProductVersion "${INSTALL_VERSION}" 65 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "ProductName" "Goj-Judger" 66 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "Comments" "Goj-Judger(duguying)" 67 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "CompanyName" "duguying" 68 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "LegalCopyright" "duguying(http://duguying.net)" 69 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "FileDescription" "Goj-Judger" 70 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "ProductVersion" "${INSTALL_VERSION}" 71 | ;VIAddVersionKey /LANG=${LANG_SimpChinese} "FileVersion" "${INSTALL_VERSION}" 72 | 73 | Section "MainSection" SEC01 74 | SetOutPath "$INSTDIR" 75 | SetOverwrite ifnewer 76 | 77 | File "/oname=judger.exe" "judger.exe" 78 | 79 | SetOutPath "$INSTDIR\bin" 80 | File "/oname=executer.exe" "sandbox\c\build\executer.exe" 81 | File "/oname=executer.json" "sandbox\c\build\executer.json" 82 | 83 | SetOutPath "$INSTDIR\conf" 84 | File "/oname=config.ini" "conf\config.ini" 85 | 86 | CreateDirectory "$SMPROGRAMS\Goj-Judger" 87 | CreateShortCut "$SMPROGRAMS\Goj-Judger\Goj-Judger.lnk" "$INSTDIR\judger.exe" 88 | CreateShortCut "$DESKTOP\Goj-Judger.lnk" "$INSTDIR\judger.exe" 89 | SectionEnd 90 | 91 | Section -AdditionalIcons 92 | WriteINIStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" 93 | CreateShortCut "$SMPROGRAMS\Goj-Judger\访问Goj-Judger主页.lnk" "$INSTDIR\${PRODUCT_NAME}.url" 94 | CreateShortCut "$SMPROGRAMS\Goj-Judger\卸载Goj-Judger.lnk" "$INSTDIR\uninst.exe" 95 | SectionEnd 96 | 97 | Section -Post 98 | WriteUninstaller "$INSTDIR\uninst.exe" 99 | WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\judger.exe" 100 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" 101 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" 102 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\judger.exe" 103 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" 104 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" 105 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" 106 | SectionEnd 107 | 108 | /****************************** 109 | * 以下是安装程序的卸载部分 * 110 | ******************************/ 111 | 112 | Section Uninstall 113 | Delete "$INSTDIR\${PRODUCT_NAME}.url" 114 | Delete "$INSTDIR\uninst.exe" 115 | Delete "$INSTDIR\judger.exe" 116 | Delete "$INSTDIR\bin\executer.exe" 117 | Delete "$INSTDIR\bin\executer.json" 118 | 119 | RMDir "$INSTDIR\bin" 120 | 121 | Delete "$INSTDIR\conf\config.ini" 122 | 123 | RMDir "$INSTDIR\conf" 124 | 125 | Delete "$SMPROGRAMS\Goj-Judger\访问Goj-Judger主页.lnk" 126 | Delete "$SMPROGRAMS\Goj-Judger\卸载Goj-Judger.lnk" 127 | Delete "$SMPROGRAMS\Goj-Judger\Goj-Judger.lnk" 128 | Delete "$DESKTOP\Goj-Judger.lnk" 129 | 130 | RMDir "$SMPROGRAMS\Goj-Judger" 131 | 132 | RMDir "$INSTDIR" 133 | 134 | DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" 135 | DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" 136 | SectionEnd 137 | 138 | /* 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题. */ 139 | 140 | Function un.onInit 141 | FunctionEnd 142 | 143 | Function un.onUninstSuccess 144 | FunctionEnd 145 | --------------------------------------------------------------------------------