Skip to content

Commit

Permalink
Adjust code structure (#21)
Browse files Browse the repository at this point in the history
* Adjust code structure

* Squashed commit of the following:

commit 4cc24fe
Author: slhmy <[email protected]>
Date:   Wed Sep 13 22:26:58 2023 +0800

    Perf

commit 75f9073
Author: slhmy <[email protected]>
Date:   Wed Sep 13 22:14:38 2023 +0800

    Project refactor

commit d132b9f
Author: slhmy <[email protected]>
Date:   Wed Sep 13 11:28:30 2023 +0000

    Perf code structure

* Resolve conflicts

* Adjust project structure

* Remove outdated part of README.md

* Make code more real world

* Refactor and support login

* Perf according to new structure
  • Loading branch information
slhmy authored Sep 16, 2023
1 parent 3a589d3 commit e2681ca
Show file tree
Hide file tree
Showing 42 changed files with 814 additions and 334 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# vendor/

*.ini
!packages/config/ini/example.ini
!packages/config/ini/test.ini
!package/config/ini/example.ini
!package/config/ini/test.ini

bin/
25 changes: 1 addition & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,6 @@
# oj-lab-services

This is a collection of services for OJ-lab systems.

Each service is supposed to run either separately or in a batch,
so that the deployment of the online-judge system can be more flexible.

## Services

To understand the philosophy of our design,
you can simply think an online-judge system consists of three main parts:
- user
- problem
- judge

If every request is trusted
(and thanks to the usage of JWT authentication, this is now a solved problem),
each of the above parts can be considered as a single service.

So separating them can make the build of functionality clearer than ever before.

## Model migration

There is a migration script in every service directory.

You will need to run the migration script before you can use the service.
Currently the backend server for OJ Lab.

## Development

Expand Down
13 changes: 9 additions & 4 deletions application/migrate_db/main.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package main

import (
"github.com/OJ-lab/oj-lab-services/packages/core"
"github.com/OJ-lab/oj-lab-services/packages/mapper"
"github.com/OJ-lab/oj-lab-services/packages/model"
"github.com/OJ-lab/oj-lab-services/core/agent/gorm"
"github.com/OJ-lab/oj-lab-services/service/mapper"
"github.com/OJ-lab/oj-lab-services/service/model"
"github.com/sirupsen/logrus"
)

func main() {
db := core.GetDefaultDB()
db := gorm.GetDefaultDB()
err := db.AutoMigrate(&model.User{}, &model.Problem{})
if err != nil {
panic("failed to migrate database")
Expand All @@ -20,5 +20,10 @@ func main() {
Description: `Write a program that prints "Hello! %s" to the standard output (stdout).`,
})

mapper.CreateUser(model.User{
Account: "admin",
Password: func() *string { s := "admin"; return &s }(),
})

logrus.Info("migrate tables success")
}
50 changes: 25 additions & 25 deletions application/server/handler/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package handler
import (
"net/http"

"github.com/OJ-lab/oj-lab-services/packages/agent/judger"
"github.com/OJ-lab/oj-lab-services/packages/mapper"
"github.com/OJ-lab/oj-lab-services/core/agent/judger"
"github.com/OJ-lab/oj-lab-services/service"
"github.com/OJ-lab/oj-lab-services/service/mapper"
"github.com/gin-gonic/gin"
)

Expand All @@ -15,60 +15,60 @@ func SetupProblemRoute(r *gin.Engine) {
g.GET("/greet", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, this is problem service")
})
g.GET("/:slug", GetProblemInfo)
g.PUT("/:slug/package", PutProblemPackage)
g.POST("/:slug/judge", Judge)
g.GET("/:slug", getProblemInfo)
g.PUT("/:slug/package", putProblemPackage)
g.POST("/:slug/judge", judge)
}
}

func GetProblemInfo(ctx *gin.Context) {
slug := ctx.Param("slug")
func getProblemInfo(ginCtx *gin.Context) {
slug := ginCtx.Param("slug")

problemInfo, err := service.GetProblemInfo(slug)
problemInfo, err := service.GetProblemInfo(ginCtx, slug)
if err != nil {
ctx.Error(err)
ginCtx.Error(err)
return
}

ctx.JSON(200, gin.H{
ginCtx.JSON(200, gin.H{
"slug": problemInfo.Slug,
"title": problemInfo.Title,
"description": problemInfo.Description,
"tags": mapper.GetTagsList(*problemInfo),
})
}

func PutProblemPackage(ctx *gin.Context) {
slug := ctx.Param("slug")
file, err := ctx.FormFile("file")
func putProblemPackage(ginCtx *gin.Context) {
slug := ginCtx.Param("slug")
file, err := ginCtx.FormFile("file")
if err != nil {
ctx.Error(err)
ginCtx.Error(err)
return
}
zipFile := "/tmp/" + slug + ".zip"
if err := ctx.SaveUploadedFile(file, zipFile); err != nil {
ctx.Error(err)
if err := ginCtx.SaveUploadedFile(file, zipFile); err != nil {
ginCtx.Error(err)
return
}

service.PutProblemPackage(slug, zipFile)
service.PutProblemPackage(ginCtx, slug, zipFile)

ctx.Done()
ginCtx.Done()
}

func Judge(ctx *gin.Context) {
slug := ctx.Param("slug")
func judge(ginCtx *gin.Context) {
slug := ginCtx.Param("slug")
judgeRequest := judger.JudgeRequest{}
if err := ctx.ShouldBindJSON(&judgeRequest); err != nil {
ctx.Error(err)
if err := ginCtx.ShouldBindJSON(&judgeRequest); err != nil {
ginCtx.Error(err)
return
}

body, err := service.Judge(slug, judgeRequest)
body, err := service.Judge(ginCtx, slug, judgeRequest)
if err != nil {
ctx.Error(err)
ginCtx.Error(err)
return
}

ctx.JSON(200, body)
ginCtx.JSON(200, body)
}
66 changes: 64 additions & 2 deletions application/server/handler/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,76 @@ package handler
import (
"net/http"

"github.com/OJ-lab/oj-lab-services/core"
"github.com/OJ-lab/oj-lab-services/core/middleware"
"github.com/OJ-lab/oj-lab-services/service"
"github.com/gin-gonic/gin"
)

func SetupUserRouter(r *gin.Engine) {
g := r.Group("/api/v1/user")
{
g.GET("/health", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, this is user service")
g.GET("/health", func(ginCtx *gin.Context) {
ginCtx.String(http.StatusOK, "Hello, this is user service")
})
g.POST("/login", login)
g.GET("/me", middleware.HandleRequireLogin, me)
g.GET("/check-exist", checkUserExist)
}
}

type loginBody struct {
Account string `json:"account"`
Password string `json:"password"`
}

func login(ginCtx *gin.Context) {
body := &loginBody{}
err := ginCtx.BindJSON(body)
if err != nil {
core.NewInvalidParamError("body", "invalid body").AppendToGin(ginCtx)
return
}

lsId, svcErr := service.StartLoginSession(ginCtx, body.Account, body.Password)
if svcErr != nil {
svcErr.AppendToGin(ginCtx)
return
}
middleware.SetLoginSessionCookie(ginCtx, *lsId)

ginCtx.String(http.StatusOK, "")
}

func me(ginCtx *gin.Context) {
ls := middleware.GetLoginSession(ginCtx)
if ls == nil {
core.NewUnauthorizedError("not logined").AppendToGin(ginCtx)
return
}
user, svcErr := service.GetUser(ginCtx, ls.Account)
if svcErr != nil {
svcErr.AppendToGin(ginCtx)
return
}

ginCtx.JSON(http.StatusOK, user)
}

func checkUserExist(ginCtx *gin.Context) {
account := ginCtx.Query("account")
if account == "" {
core.NewInvalidParamError("account", "account cannot be empty").AppendToGin(ginCtx)
return
}

exist, err := service.CheckUserExist(ginCtx, account)
if err != nil {
ginCtx.Error(err)
return
}

ginCtx.JSON(http.StatusOK, gin.H{
"exist": exist,
})
}
5 changes: 3 additions & 2 deletions application/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package main

import (
"github.com/OJ-lab/oj-lab-services/application/server/handler"
"github.com/OJ-lab/oj-lab-services/packages/core"
"github.com/OJ-lab/oj-lab-services/core"
"github.com/OJ-lab/oj-lab-services/core/middleware"
"github.com/gin-gonic/gin"
)

Expand All @@ -23,7 +24,7 @@ func init() {

func main() {
r := gin.Default()
r.Use(core.HandleError)
r.Use(middleware.HandleError)
gin.SetMode(serviceMode)
handler.SetupUserRouter(r)
handler.SetupProblemRoute(r)
Expand Down
2 changes: 1 addition & 1 deletion config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ endpoint = "localhost:9000"
accessKeyID = "minio-root-user"
secretAccessKey = "minio-root-password"
useSSL = false
bucketName = "oj-lab-problem-packages"
bucketName = "oj-lab-problem-package"
5 changes: 3 additions & 2 deletions packages/core/database.go → core/agent/gorm/database.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core
package gorm

import (
"github.com/OJ-lab/oj-lab-services/core"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
Expand All @@ -12,7 +13,7 @@ var db *gorm.DB
var dsn string

func init() {
dsn = AppConfig.GetString(dsnProp)
dsn = core.AppConfig.GetString(dsnProp)
if dsn == "" {
panic("database dsn is not set")
}
Expand Down
6 changes: 3 additions & 3 deletions packages/agent/judger/judge.go → core/agent/judger/judge.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"
"net/url"

"github.com/OJ-lab/oj-lab-services/packages/core"
"github.com/OJ-lab/oj-lab-services/core"
)

const JUDGER_HOST_PROP = "judger.host"
Expand All @@ -23,8 +23,8 @@ type JudgeRequest struct {
SrcLanguage string `json:"src_language"`
}

func PostJudgeSync(packageSlug string, judgeRequest JudgeRequest) ([]map[string]interface{}, error) {
url, err := url.JoinPath(judgerHost, JUDGER_JUDGE_PATH, packageSlug)
func PostJudgeSync(packagelug string, judgeRequest JudgeRequest) ([]map[string]interface{}, error) {
url, err := url.JoinPath(judgerHost, JUDGER_JUDGE_PATH, packagelug)
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"log"

"github.com/OJ-lab/oj-lab-services/packages/core"
"github.com/OJ-lab/oj-lab-services/core"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
Expand Down
53 changes: 53 additions & 0 deletions core/agent/minio/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package minio

import (
"context"
"io/fs"
"path/filepath"
"strings"

"github.com/minio/minio-go/v7"
)

func PutLocalObjects(ctx context.Context, rootName, localPath string) error {
minioClient := GetMinioClient()
bucketName := GetBucketName()

// Remove old
objectsCh := minioClient.ListObjects(ctx, bucketName, minio.ListObjectsOptions{
Prefix: rootName,
Recursive: true,
})
for objInfo := range objectsCh {
if objInfo.Err != nil {
return objInfo.Err
}

err := minioClient.RemoveObject(ctx, bucketName, objInfo.Key, minio.RemoveObjectOptions{})
if err != nil {
return err
}
}

filepath.Walk(localPath, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

objectName := filepath.Join(rootName, strings.Replace(path, localPath, "", 1))
_, err = minioClient.FPutObject(ctx, bucketName,
objectName, path,
minio.PutObjectOptions{})
if err != nil {
return err
}

return nil
})

return nil
}
14 changes: 14 additions & 0 deletions core/agent/redis/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package redis

import "github.com/redis/go-redis/v9"

var redisClient *redis.Client

func GetDefaultRedisClient() *redis.Client {
if redisClient == nil {
redisClient = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
}
return redisClient
}
Loading

0 comments on commit e2681ca

Please sign in to comment.