diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 95a5723..0f4a861 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,13 +1,13 @@ { - "recommendations": [ - "golang.go", - // I don't like this extension for it requires purechase for pro, - // need to find another elegant way for operating & debug with redis - // "cweijan.vscode-redis-client", - "ms-azuretools.vscode-docker", - "ms-vscode.makefile-tools", - "tamasfe.even-better-toml", - "pkief.material-icon-theme", - "ckolkman.vscode-postgres" - ], -} \ No newline at end of file + "recommendations": [ + "golang.go", + // I don't like this extension for it requires purechase for pro, + // need to find another elegant way for operating & debug with redis + // "cweijan.vscode-redis-client", + "ms-azuretools.vscode-docker", + "ms-vscode.makefile-tools", + "tamasfe.even-better-toml", + "pkief.material-icon-theme", + "ckolkman.vscode-postgres" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 86343c5..298c840 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,9 @@ { - "material-icon-theme.folders.associations": { - "application": "core", - "mapper": "database", - "migration": "import", - "user-service": "server", - } -} \ No newline at end of file + "material-icon-theme.folders.associations": { + "application": "core", + "mapper": "database", + "migration": "import", + "user-service": "server", + "postman": "api" + } +} diff --git a/config/development.toml b/config/development.toml index f71b0f3..715caaa 100644 --- a/config/development.toml +++ b/config/development.toml @@ -12,4 +12,7 @@ duration = "24h" auth_on = true port = ":8080" cookie.age = "24h" -mode = "debug" \ No newline at end of file +mode = "debug" + +[judger] +host = "http://localhost:8000" \ No newline at end of file diff --git a/migration/migrate_db.go b/migration/migrate_db.go index 9a18b05..54305e5 100644 --- a/migration/migrate_db.go +++ b/migration/migrate_db.go @@ -12,5 +12,5 @@ func main() { if err != nil { panic("failed to migrate database") } - logrus.Info("migrate user table success") + logrus.Info("migrate tables success") } diff --git a/packages/application/error.go b/packages/application/error.go index 3c0b286..34180cb 100644 --- a/packages/application/error.go +++ b/packages/application/error.go @@ -5,6 +5,7 @@ import ( "runtime" "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" ) type SeviceError struct { @@ -50,14 +51,15 @@ func NewUnAuthorizedError(msg string) *SeviceError { } func HandleError(ginCtx *gin.Context) { + ginCtx.Next() + errCount := len(ginCtx.Errors) if errCount > 0 { + logrus.Errorf("Last error from GIN middleware: %+v", ginCtx.Errors[errCount-1].Err) err := WrapToServiceError(ginCtx.Errors[errCount-1].Err) ginCtx.JSON(err.Code, gin.H{ "code": err.Code, "msg": err.Msg, }) } - - ginCtx.Next() } diff --git a/postman/OJ Lab Environment.postman_environment.json b/postman/OJ Lab Environment.postman_environment.json new file mode 100644 index 0000000..46bbe43 --- /dev/null +++ b/postman/OJ Lab Environment.postman_environment.json @@ -0,0 +1,21 @@ +{ + "id": "5fdf6ce1-e53b-44eb-b273-b44be3db8bab", + "name": "OJ Lab Environment", + "values": [ + { + "key": "Judger Host", + "value": "localhost:8000", + "type": "default", + "enabled": true + }, + { + "key": "Service Host", + "value": "localhost:8080", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-09-03T02:21:12.497Z", + "_postman_exported_using": "Postman/10.17.4" +} \ No newline at end of file diff --git a/postman/OJ Lab Services.postman_collection.json b/postman/OJ Lab Services.postman_collection.json new file mode 100644 index 0000000..d39f0af --- /dev/null +++ b/postman/OJ Lab Services.postman_collection.json @@ -0,0 +1,40 @@ +{ + "info": { + "_postman_id": "2625a326-8284-4665-b0fc-16199486095d", + "name": "OJ Lab Services", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "12985580" + }, + "item": [ + { + "name": "localhost:8000/api/v1/judge/hello-world Copy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"src\": \"#include \\n\\nusing namespace std;\\n\\nint main() {\\n string s;\\n cin >> s;\\n cout << \\\"Hello! \\\" << s << endl;\\n}\\n\",\r\n \"src_language\": \"Cpp\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{Service Host}}/api/v1/problem/hello-world/judge", + "host": [ + "{{Service Host}}" + ], + "path": [ + "api", + "v1", + "problem", + "hello-world", + "judge" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/service/application.go b/service/application.go index 3c563f0..48bea1f 100644 --- a/service/application.go +++ b/service/application.go @@ -23,6 +23,7 @@ func init() { func main() { r := gin.Default() + r.Use(application.HandleError) gin.SetMode(serviceMode) router.SetupUserRouter(r) router.SetupProblemRoute(r) diff --git a/service/problem/judge.go b/service/problem/judge.go new file mode 100644 index 0000000..36bf98a --- /dev/null +++ b/service/problem/judge.go @@ -0,0 +1,68 @@ +package problem + +import ( + "bytes" + "encoding/json" + "net/http" + "net/url" + + "github.com/OJ-lab/oj-lab-services/packages/application" + "github.com/gin-gonic/gin" +) + +const JUDGER_HOST_PROP = "judger.host" +const JUDGER_JUDGE_PATH = "/api/v1/judge" + +var judgerHost string + +func init() { + judgerHost = application.AppConfig.GetString(JUDGER_HOST_PROP) +} + +type JudgeRequest struct { + Src string `json:"src"` + SrcLanguage string `json:"src_language"` +} + +func Judge(ctx *gin.Context) { + packageSlug := ctx.Param("slug") + + judgeRequest := JudgeRequest{} + if err := ctx.ShouldBindJSON(&judgeRequest); err != nil { + ctx.Error(err) + return + } + + url, err := url.JoinPath(judgerHost, JUDGER_JUDGE_PATH, packageSlug) + if err != nil { + ctx.Error(err) + return + } + payloadBytes, err := json.Marshal(judgeRequest) + if err != nil { + ctx.Error(err) + return + } + client := &http.Client{} + innerRequest, err := http.NewRequest("POST", url, bytes.NewReader(payloadBytes)) + if err != nil { + ctx.Error(err) + return + } + innerRequest.Header.Set("Content-Type", "application/json") + innerRequest.Header.Set("Accept", "application/json") + innerResponse, err := client.Do(innerRequest) + if err != nil { + ctx.Error(err) + return + } + defer innerResponse.Body.Close() + + innerBody := []map[string]interface{}{} + if err := json.NewDecoder(innerResponse.Body).Decode(&innerBody); err != nil { + ctx.Error(err) + return + } + + ctx.JSON(innerResponse.StatusCode, innerBody) +} diff --git a/service/router/setup.go b/service/router/setup.go index 196a06c..8dde615 100644 --- a/service/router/setup.go +++ b/service/router/setup.go @@ -23,5 +23,6 @@ func SetupProblemRoute(r *gin.Engine) { c.String(http.StatusOK, "Hello, this is problem service") }) g.GET("/:slug", problem.GetProblemInfo) + g.POST("/:slug/judge", problem.Judge) } }