feat: refactor to use DI
This commit is contained in:
parent
eca749e2c6
commit
a0c36c1606
32
.github/workflows/docker-image.yml
vendored
32
.github/workflows/docker-image.yml
vendored
@ -1,32 +0,0 @@
|
|||||||
name: Docker Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master", "develop" ]
|
|
||||||
tags: [ "v*" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "master", "develop" ]
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Server Meta
|
|
||||||
id: server_meta
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: panpaul/woj-server
|
|
||||||
- name: Build and Push the Server Image
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.server_meta.outputs.tags }}
|
|
||||||
file: ./Dockerfile.server
|
|
||||||
labels: ${{ steps.server_meta.outputs.labels }}
|
|
29
.github/workflows/golangci-lint.yml
vendored
29
.github/workflows/golangci-lint.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master", "develop" ]
|
|
||||||
tags: [ "v*" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "master", "develop" ]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
golangci:
|
|
||||||
name: lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: 1.19
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Generate Swagger Docs
|
|
||||||
run: make swagger
|
|
||||||
- name: golangci-lint
|
|
||||||
uses: golangci/golangci-lint-action@v3
|
|
||||||
with:
|
|
||||||
version: latest
|
|
||||||
only-new-issues: true
|
|
@ -1,11 +0,0 @@
|
|||||||
FROM golang:latest AS builder
|
|
||||||
WORKDIR /builder
|
|
||||||
COPY . /builder
|
|
||||||
RUN make runner
|
|
||||||
|
|
||||||
FROM alpine:latest
|
|
||||||
WORKDIR /app
|
|
||||||
RUN apk --no-cache add tzdata ca-certificates libc6-compat
|
|
||||||
COPY --from=builder /builder/server /app
|
|
||||||
COPY --from=builder /builder/resource/runner /app/resource/runner
|
|
||||||
ENTRYPOINT ["/app/runner"]
|
|
@ -1,12 +0,0 @@
|
|||||||
FROM golang:latest AS builder
|
|
||||||
WORKDIR /builder
|
|
||||||
COPY . /builder
|
|
||||||
RUN make server
|
|
||||||
|
|
||||||
FROM alpine:latest
|
|
||||||
WORKDIR /app
|
|
||||||
RUN apk --no-cache add tzdata ca-certificates libc6-compat
|
|
||||||
COPY --from=builder /builder/server /app
|
|
||||||
COPY --from=builder /builder/resource/frontend /app/resource/frontend
|
|
||||||
EXPOSE 8000
|
|
||||||
ENTRYPOINT ["/app/server"]
|
|
17
Makefile
17
Makefile
@ -1,36 +1,31 @@
|
|||||||
GO := go
|
GO := go
|
||||||
|
|
||||||
LDFLAGS += -X cmd.BuildTime=$(shell date -u '+%Y-%m-%d-%I-%M-%S')
|
LDFLAGS += -X cmd.BuildTime=$(shell date -u '+%Y-%m-%d-%I-%M-%S')
|
||||||
LDFLAGS += -X cmd.Version=$(shell cat VERSION)+$(shell git rev-parse HEAD)
|
LDFLAGS += -X cmd.Version=$(shell cat VERSION)+$(shell git rev-parse --short HEAD)
|
||||||
LDFLAGS += -s -w
|
LDFLAGS += -s -w
|
||||||
|
|
||||||
GOBUILD := $(GO) build -ldflags '$(LDFLAGS)'
|
GOBUILD := $(GO) build -ldflags '$(LDFLAGS)'
|
||||||
GOBIN := $(shell go env GOPATH)/bin
|
GOBIN := $(shell go env GOPATH)/bin
|
||||||
|
|
||||||
.PHONY: all server runner build clean dep swagger fmt
|
.PHONY: all build clean dep swagger fmt
|
||||||
|
|
||||||
default: all
|
default: all
|
||||||
|
|
||||||
all: clean build
|
all: clean build
|
||||||
|
|
||||||
server: swagger dep
|
build: swagger dep
|
||||||
$(GOBUILD) -o server ./cmd/server
|
$(GOBUILD) -o woj ./cmd/woj
|
||||||
|
|
||||||
runner: swagger dep
|
|
||||||
$(GOBUILD) -o runner ./cmd/runner
|
|
||||||
|
|
||||||
build: runner server
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f runner
|
rm -f runner
|
||||||
rm -f server
|
rm -f server
|
||||||
|
|
||||||
dep:
|
dep:
|
||||||
go mod tidy && go mod download
|
go mod download
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
$(GOBIN)/swag init -g internal/router/api.go -o internal/router/docs
|
$(GOBIN)/swag init -g internal/web/router/api.go -o internal/web/router/docs
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,15 +59,3 @@ func getBuildTime() time.Time {
|
|||||||
}
|
}
|
||||||
return build
|
return build
|
||||||
}
|
}
|
||||||
|
|
||||||
func CommonSetup(c *cli.Context) *global.Global {
|
|
||||||
rand.Seed(time.Now().Unix())
|
|
||||||
|
|
||||||
g := new(global.Global)
|
|
||||||
g.SetupConfig(c.String("config"))
|
|
||||||
g.SetupZap()
|
|
||||||
|
|
||||||
g.Log.Info("starting...")
|
|
||||||
|
|
||||||
return g
|
|
||||||
}
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/cmd"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/app/runner"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
a := cmd.App
|
|
||||||
a.Usage = "woj-runner"
|
|
||||||
a.Commands = []*cli.Command{
|
|
||||||
{
|
|
||||||
Name: "run",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Usage: "start the runner",
|
|
||||||
Action: run,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := a.Run(os.Args)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(c *cli.Context) error {
|
|
||||||
g := cmd.CommonSetup(c)
|
|
||||||
defer func() { _ = g.Log.Sync() }()
|
|
||||||
|
|
||||||
return runner.RunRunner(g)
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/cmd"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/app/server"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
a := cmd.App
|
|
||||||
a.Usage = "woj-server"
|
|
||||||
a.Commands = []*cli.Command{
|
|
||||||
{
|
|
||||||
Name: "run",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Usage: "start the server",
|
|
||||||
Action: run,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := a.Run(os.Args)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(c *cli.Context) error {
|
|
||||||
g := cmd.CommonSetup(c)
|
|
||||||
defer func() { _ = g.Log.Sync() }()
|
|
||||||
|
|
||||||
return server.RunServer(g)
|
|
||||||
}
|
|
104
cmd/woj/woj.go
Normal file
104
cmd/woj/woj.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.0x7f.app/WOJ/woj-server/cmd"
|
||||||
|
appRunner "git.0x7f.app/WOJ/woj-server/internal/app/runner"
|
||||||
|
appServer "git.0x7f.app/WOJ/woj-server/internal/app/server"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/cache"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/runner"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/storage"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/jwt"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/metrics"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/router"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
slog "log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := cmd.App
|
||||||
|
a.Usage = "woj-server"
|
||||||
|
a.Commands = []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "web",
|
||||||
|
Aliases: []string{"w"},
|
||||||
|
Usage: "start web api server",
|
||||||
|
Action: runServer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "runner",
|
||||||
|
Aliases: []string{"r"},
|
||||||
|
Usage: "start runner",
|
||||||
|
Action: runRunner,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareServices(c *cli.Context) *do.Injector {
|
||||||
|
injector := do.New()
|
||||||
|
|
||||||
|
// cli context
|
||||||
|
do.ProvideValue(injector, c)
|
||||||
|
|
||||||
|
{ // basic services
|
||||||
|
do.Provide(injector, config.NewService)
|
||||||
|
do.Provide(injector, log.NewService)
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // repo services
|
||||||
|
do.Provide(injector, db.NewService)
|
||||||
|
do.Provide(injector, cache.NewService)
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // web helper services
|
||||||
|
do.Provide(injector, metrics.NewService)
|
||||||
|
do.Provide(injector, jwt.NewService)
|
||||||
|
do.Provide(injector, router.NewService)
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // core services
|
||||||
|
do.Provide(injector, problem.NewService)
|
||||||
|
do.Provide(injector, runner.NewService)
|
||||||
|
do.Provide(injector, status.NewService)
|
||||||
|
do.Provide(injector, storage.NewService)
|
||||||
|
do.Provide(injector, submission.NewService)
|
||||||
|
do.Provide(injector, task.NewService)
|
||||||
|
do.Provide(injector, user.NewService)
|
||||||
|
}
|
||||||
|
|
||||||
|
return injector
|
||||||
|
}
|
||||||
|
|
||||||
|
func runServer(c *cli.Context) error {
|
||||||
|
injector := prepareServices(c)
|
||||||
|
|
||||||
|
logger := do.MustInvoke[log.Service](injector)
|
||||||
|
defer func() { _ = logger.GetRawLogger().Sync() }()
|
||||||
|
logger.GetRawLogger().Info("starting...")
|
||||||
|
|
||||||
|
return appServer.RunServer(injector)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runRunner(c *cli.Context) error {
|
||||||
|
injector := prepareServices(c)
|
||||||
|
|
||||||
|
logger := do.MustInvoke[log.Service](injector)
|
||||||
|
defer func() { _ = logger.GetRawLogger().Sync() }()
|
||||||
|
logger.GetRawLogger().Info("starting...")
|
||||||
|
|
||||||
|
return appRunner.RunRunner(injector)
|
||||||
|
}
|
8
go.mod
8
go.mod
@ -1,18 +1,19 @@
|
|||||||
module git.0x7f.app/WOJ/woj-server
|
module git.0x7f.app/WOJ/woj-server
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/cors v1.4.0
|
github.com/gin-contrib/cors v1.4.0
|
||||||
github.com/gin-contrib/pprof v1.4.0
|
github.com/gin-contrib/pprof v1.4.0
|
||||||
github.com/gin-contrib/zap v0.1.0
|
github.com/gin-contrib/zap v0.1.0
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/hibiken/asynq v0.24.1
|
github.com/hibiken/asynq v0.24.1
|
||||||
github.com/jackc/pgtype v1.14.0
|
github.com/jackc/pgtype v1.14.0
|
||||||
github.com/minio/minio-go/v7 v7.0.60
|
github.com/minio/minio-go/v7 v7.0.60
|
||||||
github.com/prometheus/client_golang v1.16.0
|
github.com/prometheus/client_golang v1.16.0
|
||||||
|
github.com/redis/go-redis/v9 v9.0.5
|
||||||
|
github.com/samber/do v1.6.0
|
||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.0
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
github.com/swaggo/swag v1.16.1
|
github.com/swaggo/swag v1.16.1
|
||||||
@ -37,7 +38,7 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/spec v0.20.9 // indirect
|
github.com/go-openapi/spec v0.20.9 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // indirect
|
github.com/go-openapi/swag v0.22.4 // indirect
|
||||||
@ -70,7 +71,6 @@ require (
|
|||||||
github.com/prometheus/client_model v0.4.0 // indirect
|
github.com/prometheus/client_model v0.4.0 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/common v0.44.0 // indirect
|
||||||
github.com/prometheus/procfs v0.11.0 // indirect
|
github.com/prometheus/procfs v0.11.0 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.0.5 // indirect
|
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/rs/xid v1.5.0 // indirect
|
github.com/rs/xid v1.5.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -33,7 +33,6 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
|
|||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||||
@ -55,8 +54,9 @@ github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
|||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
|
||||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
@ -78,8 +78,6 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
|
|||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
@ -216,9 +214,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
|
||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
@ -251,6 +246,8 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
|
|||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/samber/do v1.6.0 h1:Jy/N++BXINDB6lAx5wBlbpHlUdl0FKpLWgGEV9YWqaU=
|
||||||
|
github.com/samber/do v1.6.0/go.mod h1:DWqBvumy8dyb2vEnYZE7D7zaVEB64J45B0NjTlY/M4k=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
@ -439,7 +436,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
@ -2,11 +2,12 @@ package consumer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,12 +25,12 @@ type handler struct {
|
|||||||
taskService task.Service
|
taskService task.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsumer(g *global.Global) Handler {
|
func NewConsumer(i *do.Injector) Handler {
|
||||||
hnd := &handler{
|
hnd := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.consumer"),
|
||||||
problemService: problem.NewService(g),
|
problemService: do.MustInvoke[problem.Service](i),
|
||||||
statusService: status.NewService(g),
|
statusService: do.MustInvoke[status.Service](i),
|
||||||
taskService: task.NewService(g),
|
taskService: do.MustInvoke[task.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
return hnd
|
return hnd
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package debug
|
package debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +17,9 @@ type handler struct {
|
|||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||||
app := &handler{g.Log}
|
app := &handler{}
|
||||||
group.GET("/random", app.randomString)
|
app.log = do.MustInvoke[log.Service](i).GetLogger("api.debug")
|
||||||
|
|
||||||
|
rg.GET("/random", app.randomString)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package problem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -30,9 +29,9 @@ func (h *handler) CreateVersion(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// uid := claim.(*global.Claim).UID
|
// uid := claim.(*model.Claim).UID
|
||||||
|
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
req := new(createVersionRequest)
|
req := new(createVersionRequest)
|
||||||
|
|
||||||
if err := c.ShouldBind(req); err != nil {
|
if err := c.ShouldBind(req); err != nil {
|
||||||
|
@ -2,7 +2,6 @@ package problem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -28,7 +27,7 @@ func (h *handler) Details(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
claim, exist := c.Get("claim")
|
claim, exist := c.Get("claim")
|
||||||
shouldEnable := !exist || claim.(*global.Claim).Role < model.RoleAdmin
|
shouldEnable := !exist || claim.(*model.Claim).Role < model.RoleAdmin
|
||||||
|
|
||||||
p, status := h.problemService.Query(req.Pid, true, shouldEnable)
|
p, status := h.problemService.Query(req.Pid, true, shouldEnable)
|
||||||
if status != e.Success {
|
if status != e.Success {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package problem
|
package problem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/storage"
|
"git.0x7f.app/WOJ/woj-server/internal/service/storage"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/jwt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,24 +22,24 @@ type Handler interface {
|
|||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
jwtService global.JwtService
|
jwtService jwt.Service
|
||||||
problemService problem.Service
|
problemService problem.Service
|
||||||
taskService task.Service
|
taskService task.Service
|
||||||
storageService storage.Service
|
storageService storage.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||||
app := &handler{
|
app := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.problem"),
|
||||||
jwtService: g.Jwt,
|
jwtService: do.MustInvoke[jwt.Service](i),
|
||||||
problemService: problem.NewService(g),
|
problemService: do.MustInvoke[problem.Service](i),
|
||||||
taskService: task.NewService(g),
|
taskService: do.MustInvoke[task.Service](i),
|
||||||
storageService: storage.NewService(g),
|
storageService: do.MustInvoke[storage.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
group.POST("/search", app.Search)
|
rg.POST("/search", app.Search)
|
||||||
group.POST("/details", app.jwtService.Handler(false), app.Details)
|
rg.POST("/details", app.jwtService.Handler(false), app.Details)
|
||||||
group.POST("/update", app.jwtService.Handler(true), app.Update)
|
rg.POST("/update", app.jwtService.Handler(true), app.Update)
|
||||||
group.POST("/upload", app.jwtService.Handler(true), app.Upload)
|
rg.POST("/upload", app.jwtService.Handler(true), app.Upload)
|
||||||
group.POST("/create_version", app.jwtService.Handler(true), app.CreateVersion)
|
rg.POST("/create_version", app.jwtService.Handler(true), app.CreateVersion)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package problem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -34,8 +33,8 @@ func (h *handler) Update(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := claim.(*global.Claim).UID
|
uid := claim.(*model.Claim).UID
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
if role < model.RoleAdmin {
|
if role < model.RoleAdmin {
|
||||||
e.Pong(c, e.UserUnauthorized, nil)
|
e.Pong(c, e.UserUnauthorized, nil)
|
||||||
return
|
return
|
||||||
|
@ -2,7 +2,6 @@ package problem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -23,7 +22,7 @@ func (h *handler) Upload(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
if role < model.RoleAdmin {
|
if role < model.RoleAdmin {
|
||||||
e.Pong(c, e.UserUnauthorized, nil)
|
e.Pong(c, e.UserUnauthorized, nil)
|
||||||
return
|
return
|
||||||
|
@ -4,11 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/runner"
|
"git.0x7f.app/WOJ/woj-server/internal/service/runner"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/storage"
|
"git.0x7f.app/WOJ/woj-server/internal/service/storage"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,17 +27,17 @@ type handler struct {
|
|||||||
storageService storage.Service
|
storageService storage.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRunner(g *global.Global) (Handler, error) {
|
func NewRunner(i *do.Injector) (Handler, error) {
|
||||||
hnd := &handler{
|
hnd := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.runner"),
|
||||||
runnerService: runner.NewService(g),
|
runnerService: do.MustInvoke[runner.Service](i),
|
||||||
taskService: task.NewService(g),
|
taskService: do.MustInvoke[task.Service](i),
|
||||||
storageService: storage.NewService(g),
|
storageService: do.MustInvoke[storage.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
status := hnd.runnerService.EnsureDeps(false)
|
status := hnd.runnerService.EnsureDeps(false)
|
||||||
if status != e.Success {
|
if status != e.Success {
|
||||||
g.Log.Error("failed to ensure runner dependencies", zap.String("status", status.String()))
|
hnd.log.Error("failed to ensure runner dependencies", zap.String("status", status.String()))
|
||||||
return nil, errors.New("failed to ensure dependencies")
|
return nil, errors.New("failed to ensure dependencies")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package status
|
package status
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/jwt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,16 +19,16 @@ type Handler interface {
|
|||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
statusService status.Service
|
statusService status.Service
|
||||||
jwtService global.JwtService
|
jwtService jwt.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||||
app := &handler{
|
app := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.status"),
|
||||||
statusService: status.NewService(g),
|
statusService: do.MustInvoke[status.Service](i),
|
||||||
jwtService: g.Jwt,
|
jwtService: do.MustInvoke[jwt.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
group.POST("/query", app.Query)
|
rg.POST("/query", app.Query)
|
||||||
group.POST("/query/problem_version", app.jwtService.Handler(true), app.QueryByProblemVersion)
|
rg.POST("/query/problem_version", app.jwtService.Handler(true), app.QueryByProblemVersion)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package status
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -31,7 +30,7 @@ func (h *handler) QueryByProblemVersion(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
|
|
||||||
req := new(queryByVersionRequest)
|
req := new(queryByVersionRequest)
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package submission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -32,9 +31,9 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := claim.(*global.Claim).UID
|
uid := claim.(*model.Claim).UID
|
||||||
|
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
req := new(createRequest)
|
req := new(createRequest)
|
||||||
|
|
||||||
if err := c.ShouldBind(req); err != nil {
|
if err := c.ShouldBind(req); err != nil {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package submission
|
package submission
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
"git.0x7f.app/WOJ/woj-server/internal/service/problem"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
"git.0x7f.app/WOJ/woj-server/internal/service/status"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
"git.0x7f.app/WOJ/woj-server/internal/service/submission"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
"git.0x7f.app/WOJ/woj-server/internal/service/task"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/jwt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,24 +22,24 @@ type Handler interface {
|
|||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
jwtService global.JwtService
|
jwtService jwt.Service
|
||||||
problemService problem.Service
|
problemService problem.Service
|
||||||
statusService status.Service
|
statusService status.Service
|
||||||
submissionService submission.Service
|
submissionService submission.Service
|
||||||
taskService task.Service
|
taskService task.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||||
app := &handler{
|
app := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.submission"),
|
||||||
jwtService: g.Jwt,
|
jwtService: do.MustInvoke[jwt.Service](i),
|
||||||
problemService: problem.NewService(g),
|
problemService: do.MustInvoke[problem.Service](i),
|
||||||
statusService: status.NewService(g),
|
statusService: do.MustInvoke[status.Service](i),
|
||||||
submissionService: submission.NewService(g),
|
submissionService: do.MustInvoke[submission.Service](i),
|
||||||
taskService: task.NewService(g),
|
taskService: do.MustInvoke[task.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
group.POST("/create", app.jwtService.Handler(true), app.Create)
|
rg.POST("/create", app.jwtService.Handler(true), app.Create)
|
||||||
group.POST("/query", app.Query)
|
rg.POST("/query", app.Query)
|
||||||
group.POST("/rejudge", app.jwtService.Handler(true), app.Rejudge)
|
rg.POST("/rejudge", app.jwtService.Handler(true), app.Rejudge)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package submission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -27,7 +26,7 @@ func (h *handler) Rejudge(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
req := new(rejudgeRequest)
|
req := new(rejudgeRequest)
|
||||||
|
|
||||||
if err := c.ShouldBind(req); err != nil {
|
if err := c.ShouldBind(req); err != nil {
|
||||||
|
@ -2,7 +2,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -48,7 +48,7 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
claim := &global.Claim{
|
claim := &model.Claim{
|
||||||
UID: u.ID,
|
UID: u.ID,
|
||||||
Role: u.Role,
|
Role: u.Role,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/jwt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,19 +20,19 @@ type Handler interface {
|
|||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
jwtService global.JwtService
|
jwtService jwt.Service
|
||||||
userService user.Service
|
userService user.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(rg *gin.RouterGroup, i *do.Injector) {
|
||||||
app := &handler{
|
app := &handler{
|
||||||
log: g.Log,
|
log: do.MustInvoke[log.Service](i).GetLogger("api.user"),
|
||||||
jwtService: g.Jwt,
|
jwtService: do.MustInvoke[jwt.Service](i),
|
||||||
userService: user.NewService(g),
|
userService: do.MustInvoke[user.Service](i),
|
||||||
}
|
}
|
||||||
|
|
||||||
group.POST("/create", app.Create)
|
rg.POST("/create", app.Create)
|
||||||
group.POST("/login", app.Login)
|
rg.POST("/login", app.Login)
|
||||||
group.POST("/logout", app.jwtService.Handler(true), app.Logout)
|
rg.POST("/logout", app.jwtService.Handler(true), app.Logout)
|
||||||
group.POST("/profile", app.jwtService.Handler(true), app.Profile)
|
rg.POST("/profile", app.jwtService.Handler(true), app.Profile)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
"git.0x7f.app/WOJ/woj-server/internal/service/user"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -46,7 +46,7 @@ func (h *handler) Login(c *gin.Context) {
|
|||||||
e.Pong(c, status, nil)
|
e.Pong(c, status, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
claim := &global.Claim{
|
claim := &model.Claim{
|
||||||
UID: u.ID,
|
UID: u.ID,
|
||||||
Role: u.Role,
|
Role: u.Role,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
@ -2,7 +2,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,6 +21,6 @@ func (h *handler) Logout(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, status := h.userService.IncrVersion(claim.(*global.Claim).UID)
|
_, status := h.userService.IncrVersion(claim.(*model.Claim).UID)
|
||||||
e.Pong(c, status, nil)
|
e.Pong(c, status, nil)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -29,8 +28,8 @@ func (h *handler) Profile(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := claim.(*global.Claim).UID
|
uid := claim.(*model.Claim).UID
|
||||||
role := claim.(*global.Claim).Role
|
role := claim.(*model.Claim).Role
|
||||||
|
|
||||||
req := new(profileRequest)
|
req := new(profileRequest)
|
||||||
|
|
||||||
|
@ -2,17 +2,22 @@ package runner
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/api/runner"
|
"git.0x7f.app/WOJ/woj-server/internal/api/runner"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/zapasynq"
|
"git.0x7f.app/WOJ/woj-server/pkg/zapasynq"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunRunner(g *global.Global) error {
|
func RunRunner(i *do.Injector) error {
|
||||||
hnd, err := runner.NewRunner(g)
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
rlog := do.MustInvoke[log.Service](i).GetLogger("app.runner")
|
||||||
|
|
||||||
|
hnd, err := runner.NewRunner(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -23,19 +28,19 @@ func RunRunner(g *global.Global) error {
|
|||||||
|
|
||||||
srv := asynq.NewServer(
|
srv := asynq.NewServer(
|
||||||
asynq.RedisClientOpt{
|
asynq.RedisClientOpt{
|
||||||
Addr: g.Conf.Redis.Address,
|
Addr: conf.Redis.Address,
|
||||||
Password: g.Conf.Redis.Password,
|
Password: conf.Redis.Password,
|
||||||
DB: g.Conf.Redis.QueueDb,
|
DB: conf.Redis.QueueDb,
|
||||||
},
|
},
|
||||||
asynq.Config{
|
asynq.Config{
|
||||||
Concurrency: utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1),
|
Concurrency: utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1),
|
||||||
Logger: zapasynq.New(g.Log),
|
Logger: zapasynq.New(rlog),
|
||||||
Queues: map[string]int{model.QueueRunner: 1},
|
Queues: map[string]int{model.QueueRunner: 1},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := srv.Run(mux); err != nil {
|
if err := srv.Run(mux); err != nil {
|
||||||
g.Log.Warn("could not run server", zap.Error(err))
|
rlog.Warn("could not run server", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,15 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/api/consumer"
|
"git.0x7f.app/WOJ/woj-server/internal/api/consumer"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/repo/postgresql"
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/repo/redis"
|
"git.0x7f.app/WOJ/woj-server/internal/web/router"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/router"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/jwt"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/zapasynq"
|
"git.0x7f.app/WOJ/woj-server/pkg/zapasynq"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -22,23 +22,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunServer(g *global.Global) error {
|
func RunServer(i *do.Injector) error { // Prepare Router
|
||||||
// Setup Database
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
g.Db = new(postgresql.Repo)
|
slog := do.MustInvoke[log.Service](i).GetLogger("app.server")
|
||||||
g.Db.Setup(g)
|
|
||||||
|
|
||||||
// Setup Redis
|
routers := do.MustInvoke[router.Service](i).GetRouter()
|
||||||
g.Redis = new(redis.Repo)
|
|
||||||
g.Redis.Setup(g)
|
|
||||||
|
|
||||||
// Setup JWT
|
|
||||||
g.Jwt = jwt.NewJwtService(g)
|
|
||||||
|
|
||||||
// Prepare Router
|
|
||||||
routers := router.InitRouters(g)
|
|
||||||
|
|
||||||
// Create Server
|
// Create Server
|
||||||
addr := fmt.Sprintf("%s:%d", g.Conf.WebServer.Address, g.Conf.WebServer.Port)
|
addr := fmt.Sprintf("%s:%d", conf.WebServer.Address, conf.WebServer.Port)
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
Handler: routers,
|
Handler: routers,
|
||||||
@ -47,56 +38,56 @@ func RunServer(g *global.Global) error {
|
|||||||
// Run Server
|
// Run Server
|
||||||
go func() {
|
go func() {
|
||||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
g.Log.Fatal("ListenAndServe Failed", zap.Error(err))
|
slog.Fatal("ListenAndServe Failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create Queue
|
// Create Queue
|
||||||
queueMux := asynq.NewServeMux()
|
queueMux := asynq.NewServeMux()
|
||||||
{
|
{
|
||||||
handler := consumer.NewConsumer(g)
|
handler := consumer.NewConsumer(i)
|
||||||
queueMux.HandleFunc(model.TypeProblemUpdate, handler.ProblemUpdate)
|
queueMux.HandleFunc(model.TypeProblemUpdate, handler.ProblemUpdate)
|
||||||
queueMux.HandleFunc(model.TypeSubmitUpdate, handler.SubmitUpdate)
|
queueMux.HandleFunc(model.TypeSubmitUpdate, handler.SubmitUpdate)
|
||||||
}
|
}
|
||||||
queueSrv := asynq.NewServer(
|
queueSrv := asynq.NewServer(
|
||||||
asynq.RedisClientOpt{
|
asynq.RedisClientOpt{
|
||||||
Addr: g.Conf.Redis.Address,
|
Addr: conf.Redis.Address,
|
||||||
Password: g.Conf.Redis.Password,
|
Password: conf.Redis.Password,
|
||||||
DB: g.Conf.Redis.QueueDb,
|
DB: conf.Redis.QueueDb,
|
||||||
},
|
},
|
||||||
asynq.Config{
|
asynq.Config{
|
||||||
Concurrency: utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1),
|
Concurrency: utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1),
|
||||||
Logger: zapasynq.New(g.Log),
|
Logger: zapasynq.New(slog),
|
||||||
Queues: map[string]int{model.QueueServer: 1},
|
Queues: map[string]int{model.QueueServer: 1},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Run Queue
|
// Run Queue
|
||||||
if err := queueSrv.Start(queueMux); err != nil {
|
if err := queueSrv.Start(queueMux); err != nil {
|
||||||
g.Log.Fatal("queueSrv.Start Failed", zap.Error(err))
|
slog.Fatal("queueSrv.Start Failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle SIGINT and SIGTERM.
|
// Handle SIGINT and SIGTERM.
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
<-quit
|
<-quit
|
||||||
g.Log.Info("Shutting down server ...")
|
slog.Info("Shutting down server ...")
|
||||||
|
|
||||||
// Graceful Shutdown Server
|
// Graceful Shutdown Server
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
err := server.Shutdown(ctx)
|
err := server.Shutdown(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log.Warn("Server Shutdown Failed", zap.Error(err))
|
slog.Warn("Server Shutdown Failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graceful Shutdown Queue
|
// Graceful Shutdown Queue
|
||||||
queueSrv.Shutdown()
|
queueSrv.Shutdown()
|
||||||
|
|
||||||
// Graceful Shutdown Database
|
// Graceful Shutdown Database
|
||||||
err = g.Db.Close()
|
err = do.MustInvoke[db.Service](i).Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log.Warn("Database Close Failed", zap.Error(err))
|
slog.Warn("Database Close Failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
package global
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/pkg/metrics"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Global struct {
|
|
||||||
Log *zap.Logger
|
|
||||||
Conf *Config
|
|
||||||
Stat *metrics.Metrics
|
|
||||||
Db Repo
|
|
||||||
Redis Repo
|
|
||||||
Jwt JwtService
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package global
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Claim struct {
|
|
||||||
UID uint `json:"id"`
|
|
||||||
Role model.Role `json:"role"`
|
|
||||||
Version int64 `json:"version"`
|
|
||||||
jwt.RegisteredClaims
|
|
||||||
}
|
|
||||||
|
|
||||||
type JwtService interface {
|
|
||||||
ParseToken(tokenText string) (*Claim, e.Status)
|
|
||||||
SignClaim(claim *Claim) (string, e.Status)
|
|
||||||
Validate(claim *Claim) bool
|
|
||||||
|
|
||||||
Handler(forced bool) gin.HandlerFunc
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package global
|
|
||||||
|
|
||||||
type Repo interface {
|
|
||||||
Setup(*Global)
|
|
||||||
Get() interface{}
|
|
||||||
Close() error
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package global
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (g *Global) SetupZap() {
|
|
||||||
cfg := zap.Config{
|
|
||||||
Level: zap.NewAtomicLevelAt(
|
|
||||||
utils.If(g.Conf.Development, zapcore.DebugLevel, zapcore.InfoLevel),
|
|
||||||
),
|
|
||||||
Development: g.Conf.Development,
|
|
||||||
Encoding: "console", // or json
|
|
||||||
EncoderConfig: zap.NewDevelopmentEncoderConfig(),
|
|
||||||
OutputPaths: []string{"stdout"},
|
|
||||||
ErrorOutputPaths: []string{"stderr"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
g.Log, err = cfg.Build()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to setup Zap: %s\n", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Global) SetupConfig(configFile string) {
|
|
||||||
data, err := utils.FileRead(configFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to setup config: %s\n", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = yaml.Unmarshal(data, &g.Conf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to setup config: %s\n", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
48
internal/misc/config/conf.go
Normal file
48
internal/misc/config/conf.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
GetConfig() *model.Config
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
cliCtx := do.MustInvoke[*cli.Context](i)
|
||||||
|
|
||||||
|
data, err := utils.FileRead(cliCtx.String("config"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to setup config: %s\n", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
srv := &service{}
|
||||||
|
err = yaml.Unmarshal(data, &srv.conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to setup config: %s\n", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
conf model.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetConfig() *model.Config {
|
||||||
|
return &s.conf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return nil
|
||||||
|
}
|
67
internal/misc/log/zap.go
Normal file
67
internal/misc/log/zap.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
GetRawLogger() *zap.Logger
|
||||||
|
GetLogger(domain string) *zap.Logger
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
srv.confService = do.MustInvoke[config.Service](i)
|
||||||
|
|
||||||
|
c := srv.confService.GetConfig()
|
||||||
|
cfg := zap.Config{
|
||||||
|
Level: zap.NewAtomicLevelAt(utils.If(
|
||||||
|
c.Development,
|
||||||
|
zapcore.DebugLevel,
|
||||||
|
zapcore.InfoLevel,
|
||||||
|
)),
|
||||||
|
Development: c.Development,
|
||||||
|
Encoding: "console", // or json
|
||||||
|
EncoderConfig: utils.If(
|
||||||
|
c.Development,
|
||||||
|
zap.NewDevelopmentEncoderConfig(),
|
||||||
|
zap.NewProductionEncoderConfig(),
|
||||||
|
),
|
||||||
|
OutputPaths: []string{"stdout"},
|
||||||
|
ErrorOutputPaths: []string{"stderr"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
srv.logger, err = cfg.Build()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to setup Zap: %s\n", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
confService config.Service
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetRawLogger() *zap.Logger {
|
||||||
|
return s.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetLogger(domain string) *zap.Logger {
|
||||||
|
return s.logger.Named(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package global
|
package model
|
||||||
|
|
||||||
type ConfigWebServer struct {
|
type ConfigWebServer struct {
|
||||||
Address string `yaml:"Address"`
|
Address string `yaml:"Address"`
|
12
internal/model/jwt.go
Normal file
12
internal/model/jwt.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Claim struct {
|
||||||
|
UID uint `json:"id"`
|
||||||
|
Role Role `json:"role"`
|
||||||
|
Version int64 `json:"version"`
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
package global
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EndpointInfo struct {
|
type EndpointInfo struct {
|
||||||
Version string
|
Version string
|
||||||
Path string
|
Path string
|
||||||
Register func(g *Global, group *gin.RouterGroup)
|
Register func(rg *gin.RouterGroup, i *do.Injector)
|
||||||
}
|
}
|
59
internal/repo/cache/redis.go
vendored
Normal file
59
internal/repo/cache/redis.go
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Get() *redis.Client
|
||||||
|
Close() error
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
srv.log = do.MustInvoke[log.Service](i).GetLogger("redis")
|
||||||
|
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
srv.setup(conf.Redis.Address, conf.Redis.Password, conf.Redis.Db)
|
||||||
|
return srv, srv.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
log *zap.Logger
|
||||||
|
client *redis.Client
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Get() *redis.Client {
|
||||||
|
return s.client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Close() error {
|
||||||
|
return s.client.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) setup(addr string, password string, db int) {
|
||||||
|
s.client = redis.NewClient(&redis.Options{
|
||||||
|
Addr: addr,
|
||||||
|
Password: password,
|
||||||
|
DB: db,
|
||||||
|
})
|
||||||
|
|
||||||
|
_, s.err = s.client.Ping(context.Background()).Result()
|
||||||
|
if s.err != nil {
|
||||||
|
s.log.Error("Redis ping failed", zap.Error(s.err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
139
internal/repo/db/pg.go
Normal file
139
internal/repo/db/pg.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
"moul.io/zapgorm2"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Get() *gorm.DB
|
||||||
|
Close() error
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
srv.log = do.MustInvoke[log.Service](i).GetLogger("postgresql")
|
||||||
|
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
srv.setup(conf)
|
||||||
|
return srv, srv.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
log *zap.Logger
|
||||||
|
db *gorm.DB
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Get() *gorm.DB {
|
||||||
|
return s.db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Close() error {
|
||||||
|
var db *sql.DB
|
||||||
|
db, s.err = s.db.DB()
|
||||||
|
if s.err != nil {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.err = db.Close()
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) setup(conf *model.Config) {
|
||||||
|
s.log.Info("Connecting to database...")
|
||||||
|
|
||||||
|
logger := zapgorm2.New(s.log)
|
||||||
|
logger.IgnoreRecordNotFoundError = true
|
||||||
|
|
||||||
|
dsn := fmt.Sprintf(
|
||||||
|
// TODO: timezone as config
|
||||||
|
"user=%s password=%s dbname=%s host=%s port=%d sslmode=disable TimeZone=Asia/Shanghai",
|
||||||
|
conf.Database.User,
|
||||||
|
conf.Database.Password,
|
||||||
|
conf.Database.Database,
|
||||||
|
conf.Database.Host,
|
||||||
|
conf.Database.Port,
|
||||||
|
)
|
||||||
|
|
||||||
|
s.db, s.err = gorm.Open(
|
||||||
|
postgres.Open(dsn),
|
||||||
|
&gorm.Config{
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
SingularTable: true,
|
||||||
|
TablePrefix: conf.Database.Prefix,
|
||||||
|
},
|
||||||
|
PrepareStmt: true,
|
||||||
|
Logger: logger,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if s.err != nil {
|
||||||
|
s.log.Error("Failed to connect to database", zap.Error(s.err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var db *sql.DB
|
||||||
|
db, s.err = s.checkAlive(3)
|
||||||
|
if s.err != nil {
|
||||||
|
s.log.Error("Database is not alive", zap.Error(s.err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SetMaxOpenConns(conf.Database.MaxOpenConns)
|
||||||
|
db.SetMaxIdleConns(conf.Database.MaxIdleConns)
|
||||||
|
db.SetConnMaxLifetime(time.Duration(conf.Database.ConnMaxLifetime) * time.Minute)
|
||||||
|
|
||||||
|
s.migrateDatabase()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) migrateDatabase() {
|
||||||
|
s.log.Info("Auto Migrating database...")
|
||||||
|
|
||||||
|
_ = s.db.AutoMigrate(&model.User{})
|
||||||
|
_ = s.db.AutoMigrate(&model.Problem{})
|
||||||
|
_ = s.db.AutoMigrate(&model.ProblemVersion{})
|
||||||
|
_ = s.db.AutoMigrate(&model.Submission{})
|
||||||
|
_ = s.db.AutoMigrate(&model.Status{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) checkAlive(retry int) (*sql.DB, error) {
|
||||||
|
if retry <= 0 {
|
||||||
|
return nil, errors.New("all retries are used up. failed to connect to database")
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := s.db.DB()
|
||||||
|
if err != nil {
|
||||||
|
s.log.Warn("failed to get sql.DB instance", zap.Error(err))
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
return s.checkAlive(retry - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Ping()
|
||||||
|
if err != nil {
|
||||||
|
s.log.Warn("failed to ping database", zap.Error(err))
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
return s.checkAlive(retry - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Info("database connect established")
|
||||||
|
return db, nil
|
||||||
|
}
|
@ -1,113 +0,0 @@
|
|||||||
package postgresql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/driver/postgres"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"gorm.io/gorm/schema"
|
|
||||||
"moul.io/zapgorm2"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ global.Repo = (*Repo)(nil)
|
|
||||||
|
|
||||||
type Repo struct {
|
|
||||||
db *gorm.DB
|
|
||||||
log *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Get() interface{} {
|
|
||||||
return r.db
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Close() error {
|
|
||||||
db, err := r.db.DB()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Setup(g *global.Global) {
|
|
||||||
r.log = g.Log
|
|
||||||
|
|
||||||
r.log.Info("Connecting to database...")
|
|
||||||
|
|
||||||
logger := zapgorm2.New(r.log)
|
|
||||||
logger.IgnoreRecordNotFoundError = true
|
|
||||||
|
|
||||||
dsn := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=disable TimeZone=Asia/Shanghai",
|
|
||||||
g.Conf.Database.User,
|
|
||||||
g.Conf.Database.Password,
|
|
||||||
g.Conf.Database.Database,
|
|
||||||
g.Conf.Database.Host,
|
|
||||||
g.Conf.Database.Port)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
r.db, err = gorm.Open(
|
|
||||||
postgres.Open(dsn),
|
|
||||||
&gorm.Config{
|
|
||||||
NamingStrategy: schema.NamingStrategy{
|
|
||||||
SingularTable: true,
|
|
||||||
TablePrefix: g.Conf.Database.Prefix,
|
|
||||||
},
|
|
||||||
PrepareStmt: true,
|
|
||||||
Logger: logger,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
r.log.Fatal("Failed to connect to database", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := r.checkAlive(3)
|
|
||||||
if err != nil {
|
|
||||||
r.log.Fatal("Database is not alive", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db.SetMaxOpenConns(g.Conf.Database.MaxOpenConns)
|
|
||||||
db.SetMaxIdleConns(g.Conf.Database.MaxIdleConns)
|
|
||||||
db.SetConnMaxLifetime(time.Duration(g.Conf.Database.ConnMaxLifetime) * time.Minute)
|
|
||||||
|
|
||||||
r.migrateDatabase()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) migrateDatabase() {
|
|
||||||
r.log.Info("Auto Migrating database...")
|
|
||||||
|
|
||||||
_ = r.db.AutoMigrate(&model.User{})
|
|
||||||
_ = r.db.AutoMigrate(&model.Problem{})
|
|
||||||
_ = r.db.AutoMigrate(&model.ProblemVersion{})
|
|
||||||
_ = r.db.AutoMigrate(&model.Submission{})
|
|
||||||
_ = r.db.AutoMigrate(&model.Status{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkAlive deprecated
|
|
||||||
func (r *Repo) checkAlive(retry int) (*sql.DB, error) {
|
|
||||||
if retry <= 0 {
|
|
||||||
return nil, errors.New("all retries are used up. failed to connect to database")
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := r.db.DB()
|
|
||||||
if err != nil {
|
|
||||||
r.log.Warn("failed to get sql.DB instance", zap.Error(err))
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
return r.checkAlive(retry - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = db.Ping()
|
|
||||||
if err != nil {
|
|
||||||
r.log.Warn("failed to ping database", zap.Error(err))
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
return r.checkAlive(retry - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
r.log.Info("database connect established")
|
|
||||||
return db, nil
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package redis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ global.Repo = (*Repo)(nil)
|
|
||||||
|
|
||||||
type Repo struct {
|
|
||||||
client *redis.Client
|
|
||||||
log *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Setup(g *global.Global) {
|
|
||||||
r.log = g.Log
|
|
||||||
|
|
||||||
r.client = redis.NewClient(&redis.Options{
|
|
||||||
Addr: g.Conf.Redis.Address,
|
|
||||||
Password: g.Conf.Redis.Password,
|
|
||||||
DB: g.Conf.Redis.Db,
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := r.client.Ping(context.Background()).Result()
|
|
||||||
if err != nil {
|
|
||||||
r.log.Fatal("Redis ping failed", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Get() interface{} {
|
|
||||||
return r.client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) Close() error {
|
|
||||||
return r.client.Close()
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package jwt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ global.JwtService = (*service)(nil)
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
log *zap.Logger
|
|
||||||
redis *redis.Client
|
|
||||||
SigningKey []byte
|
|
||||||
ExpireHour int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJwtService(g *global.Global) global.JwtService {
|
|
||||||
return &service{
|
|
||||||
log: g.Log,
|
|
||||||
redis: g.Redis.Get().(*redis.Client),
|
|
||||||
SigningKey: []byte(g.Conf.WebServer.JwtSigningKey),
|
|
||||||
ExpireHour: g.Conf.WebServer.JwtExpireHour,
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ func (s *service) Create(data *CreateData) (*model.Problem, e.Status) {
|
|||||||
IsEnabled: data.IsEnabled,
|
IsEnabled: data.IsEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Create(problem).Error
|
err := s.db.Get().Create(problem).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problem", problem))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problem", problem))
|
||||||
return nil, e.DatabaseError
|
return nil, e.DatabaseError
|
||||||
|
@ -19,7 +19,7 @@ func (s *service) CreateVersion(data *CreateVersionData) (*model.ProblemVersion,
|
|||||||
StorageKey: data.StorageKey,
|
StorageKey: data.StorageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Create(problemVersion).Error
|
err := s.db.Get().Create(problemVersion).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problemVersion", problemVersion))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problemVersion", problemVersion))
|
||||||
return nil, e.DatabaseError
|
return nil, e.DatabaseError
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
func (s *service) Query(pid uint, associations bool, shouldEnable bool) (*model.Problem, e.Status) {
|
func (s *service) Query(pid uint, associations bool, shouldEnable bool) (*model.Problem, e.Status) {
|
||||||
problem := new(model.Problem)
|
problem := new(model.Problem)
|
||||||
|
|
||||||
query := s.db
|
query := s.db.Get()
|
||||||
if associations {
|
if associations {
|
||||||
query = query.Preload(clause.Associations)
|
query = query.Preload(clause.Associations)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
func (s *service) QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status) {
|
func (s *service) QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status) {
|
||||||
problems := make([]*model.Problem, 0)
|
problems := make([]*model.Problem, 0)
|
||||||
|
|
||||||
query := s.db
|
query := s.db.Get()
|
||||||
if associations {
|
if associations {
|
||||||
query = query.Preload(clause.Associations)
|
query = query.Preload(clause.Associations)
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ func (s *service) QueryFuzz(search string, associations bool, shouldEnable bool)
|
|||||||
query = query.Where("is_enabled = true")
|
query = query.Where("is_enabled = true")
|
||||||
}
|
}
|
||||||
query = query.
|
query = query.
|
||||||
Where(s.db.Where("title LIKE ?", "%"+search+"%").
|
Where(s.db.Get().Where("title LIKE ?", "%"+search+"%").
|
||||||
Or("statement LIKE ?", "%"+search+"%"))
|
Or("statement LIKE ?", "%"+search+"%"))
|
||||||
err := query.Find(&problems).Error
|
err := query.Find(&problems).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -14,7 +14,7 @@ func (s *service) QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status)
|
|||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.
|
err := s.db.Get().
|
||||||
Where(problemVersion).
|
Where(problemVersion).
|
||||||
Last(&problemVersion).Error
|
Last(&problemVersion).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func (s *service) QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status) {
|
func (s *service) QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status) {
|
||||||
problemVersion := new(model.ProblemVersion)
|
problemVersion := new(model.ProblemVersion)
|
||||||
|
|
||||||
err := s.db.First(&problemVersion, pvid).Error
|
err := s.db.Get().First(&problemVersion, pvid).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, e.ProblemVersionNotFound
|
return nil, e.ProblemVersionNotFound
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,11 @@ package problem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
@ -20,16 +21,22 @@ type Service interface {
|
|||||||
UpdateVersion(pvid uint, values interface{}) e.Status
|
UpdateVersion(pvid uint, values interface{}) e.Status
|
||||||
QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status)
|
QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status)
|
||||||
QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status)
|
QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("problem"),
|
||||||
|
db: do.MustInvoke[db.Service](i),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
db *gorm.DB
|
db db.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
return &service{
|
return nil
|
||||||
log: g.Log,
|
|
||||||
db: g.Db.Get().(*gorm.DB),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) Update(problem *model.Problem) (*model.Problem, e.Status) {
|
func (s *service) Update(problem *model.Problem) (*model.Problem, e.Status) {
|
||||||
err := s.db.Save(problem).Error
|
err := s.db.Get().Save(problem).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problem", problem))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problem", problem))
|
||||||
return nil, e.DatabaseError
|
return nil, e.DatabaseError
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) UpdateVersion(pvid uint, values interface{}) e.Status {
|
func (s *service) UpdateVersion(pvid uint, values interface{}) e.Status {
|
||||||
err := s.db.Model(&model.ProblemVersion{}).Where("id = ?", pvid).Updates(values).Error
|
err := s.db.Get().Model(&model.ProblemVersion{}).Where("id = ?", pvid).Updates(values).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("pvid", pvid), zap.Any("values", values))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("pvid", pvid), zap.Any("values", values))
|
||||||
return e.DatabaseError
|
return e.DatabaseError
|
||||||
|
@ -2,7 +2,9 @@ package runner
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +25,15 @@ type Service interface {
|
|||||||
ParseConfig(version uint, skipCheck bool) (Config, error)
|
ParseConfig(version uint, skipCheck bool) (Config, error)
|
||||||
// ProblemExists check if problem exists
|
// ProblemExists check if problem exists
|
||||||
ProblemExists(version uint) bool
|
ProblemExists(version uint) bool
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("runner"),
|
||||||
|
verbose: do.MustInvoke[config.Service](i).GetConfig().Development,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
@ -30,9 +41,6 @@ type service struct {
|
|||||||
verbose bool
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
return &service{
|
return nil
|
||||||
log: g.Log,
|
|
||||||
verbose: g.Conf.Development,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ type CreateData struct {
|
|||||||
Point int32
|
Point int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s service) Create(data *CreateData) (*model.Status, e.Status) {
|
func (s *service) Create(data *CreateData) (*model.Status, e.Status) {
|
||||||
status := &model.Status{
|
status := &model.Status{
|
||||||
SubmissionID: data.SubmissionID,
|
SubmissionID: data.SubmissionID,
|
||||||
ProblemVersionID: data.ProblemVersionID,
|
ProblemVersionID: data.ProblemVersionID,
|
||||||
@ -26,7 +26,7 @@ func (s service) Create(data *CreateData) (*model.Status, e.Status) {
|
|||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Create(status).Error
|
err := s.db.Get().Create(status).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("status", status))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("status", status))
|
||||||
return nil, e.DatabaseError
|
return nil, e.DatabaseError
|
||||||
|
@ -9,14 +9,14 @@ import (
|
|||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s service) Query(sid uint, associations bool) (*model.Status, e.Status) {
|
func (s *service) Query(sid uint, associations bool) (*model.Status, e.Status) {
|
||||||
|
|
||||||
status := &model.Status{
|
status := &model.Status{
|
||||||
SubmissionID: sid,
|
SubmissionID: sid,
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
query := s.db
|
query := s.db.Get()
|
||||||
if associations {
|
if associations {
|
||||||
query = query.Preload(clause.Associations)
|
query = query.Preload(clause.Associations)
|
||||||
}
|
}
|
||||||
@ -36,14 +36,14 @@ func (s service) Query(sid uint, associations bool) (*model.Status, e.Status) {
|
|||||||
return status, e.Success
|
return status, e.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s service) QueryByVersion(pvid uint, offset int, limit int) ([]*model.Status, e.Status) {
|
func (s *service) QueryByVersion(pvid uint, offset int, limit int) ([]*model.Status, e.Status) {
|
||||||
var statuses []*model.Status
|
var statuses []*model.Status
|
||||||
status := &model.Status{
|
status := &model.Status{
|
||||||
ProblemVersionID: pvid,
|
ProblemVersionID: pvid,
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Preload(clause.Associations).
|
err := s.db.Get().Preload(clause.Associations).
|
||||||
Where(status).
|
Where(status).
|
||||||
Limit(limit).
|
Limit(limit).
|
||||||
Offset(offset).
|
Offset(offset).
|
||||||
|
@ -2,10 +2,11 @@ package status
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
@ -14,16 +15,22 @@ type Service interface {
|
|||||||
Create(data *CreateData) (*model.Status, e.Status)
|
Create(data *CreateData) (*model.Status, e.Status)
|
||||||
Query(sid uint, associations bool) (*model.Status, e.Status)
|
Query(sid uint, associations bool) (*model.Status, e.Status)
|
||||||
QueryByVersion(pvid uint, offset int, limit int) ([]*model.Status, e.Status)
|
QueryByVersion(pvid uint, offset int, limit int) ([]*model.Status, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("status"),
|
||||||
|
db: do.MustInvoke[db.Service](i),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
db *gorm.DB
|
db db.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
return &service{
|
return nil
|
||||||
log: g.Log,
|
|
||||||
db: g.Db.Get().(*gorm.DB),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ package storage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"github.com/minio/minio-go/v7"
|
"github.com/minio/minio-go/v7"
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -14,6 +16,33 @@ var _ Service = (*service)(nil)
|
|||||||
type Service interface {
|
type Service interface {
|
||||||
Upload(objectName string, expiry time.Duration) (string, e.Status)
|
Upload(objectName string, expiry time.Duration) (string, e.Status)
|
||||||
Get(objectName string, expiry time.Duration) (string, e.Status)
|
Get(objectName string, expiry time.Duration) (string, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
|
||||||
|
srv := &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("storage"),
|
||||||
|
bucket: conf.Storage.Bucket,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
srv.client, err = minio.New(
|
||||||
|
conf.Storage.Endpoint,
|
||||||
|
&minio.Options{
|
||||||
|
Creds: credentials.NewStaticV4(conf.Storage.AccessKey, conf.Storage.SecretKey, ""),
|
||||||
|
Secure: conf.Storage.UseSSL,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
srv.log.Error("failed to create minio client", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
@ -22,20 +51,6 @@ type service struct {
|
|||||||
bucket string
|
bucket string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
minioClient, err := minio.New(g.Conf.Storage.Endpoint, &minio.Options{
|
return nil
|
||||||
Creds: credentials.NewStaticV4(g.Conf.Storage.AccessKey, g.Conf.Storage.SecretKey, ""),
|
|
||||||
Secure: g.Conf.Storage.UseSSL,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
g.Log.Fatal("failed to create minio client", zap.Error(err))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &service{
|
|
||||||
log: g.Log,
|
|
||||||
client: minioClient,
|
|
||||||
bucket: g.Conf.Storage.Bucket,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ func (s *service) Create(data *CreateData) (*model.Submission, e.Status) {
|
|||||||
Code: data.Code,
|
Code: data.Code,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Create(submission).Error
|
err := s.db.Get().Create(submission).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("submission", submission))
|
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("submission", submission))
|
||||||
return nil, e.DatabaseError
|
return nil, e.DatabaseError
|
||||||
|
@ -17,7 +17,7 @@ func (s *service) Query(pid uint, uid uint, offset int, limit int) ([]*model.Sub
|
|||||||
UserID: uid,
|
UserID: uid,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Preload(clause.Associations).
|
err := s.db.Get().Preload(clause.Associations).
|
||||||
Where(submission).
|
Where(submission).
|
||||||
Limit(limit).
|
Limit(limit).
|
||||||
Offset(offset).
|
Offset(offset).
|
||||||
@ -37,7 +37,7 @@ func (s *service) Query(pid uint, uid uint, offset int, limit int) ([]*model.Sub
|
|||||||
func (s *service) QueryBySid(sid uint, associations bool) (*model.Submission, e.Status) {
|
func (s *service) QueryBySid(sid uint, associations bool) (*model.Submission, e.Status) {
|
||||||
submission := new(model.Submission)
|
submission := new(model.Submission)
|
||||||
|
|
||||||
query := s.db
|
query := s.db.Get()
|
||||||
if associations {
|
if associations {
|
||||||
query = query.Preload(clause.Associations)
|
query = query.Preload(clause.Associations)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,11 @@ package submission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
@ -14,16 +15,22 @@ type Service interface {
|
|||||||
Create(data *CreateData) (*model.Submission, e.Status)
|
Create(data *CreateData) (*model.Submission, e.Status)
|
||||||
Query(pid uint, uid uint, offset int, limit int) ([]*model.Submission, e.Status)
|
Query(pid uint, uid uint, offset int, limit int) ([]*model.Submission, e.Status)
|
||||||
QueryBySid(sid uint, associations bool) (*model.Submission, e.Status)
|
QueryBySid(sid uint, associations bool) (*model.Submission, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("submission"),
|
||||||
|
db: do.MustInvoke[db.Service](i),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
db *gorm.DB
|
db db.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
return &service{
|
return nil
|
||||||
log: g.Log,
|
|
||||||
db: g.Db.Get().(*gorm.DB),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package task
|
package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/service/runner"
|
"git.0x7f.app/WOJ/woj-server/internal/service/runner"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,6 +21,24 @@ type Service interface {
|
|||||||
SubmitUpdate(data *model.SubmitUpdatePayload, ctx runner.JudgeStatus) (string, e.Status)
|
SubmitUpdate(data *model.SubmitUpdatePayload, ctx runner.JudgeStatus) (string, e.Status)
|
||||||
|
|
||||||
GetTaskInfo(string, string) (*asynq.TaskInfo, e.Status)
|
GetTaskInfo(string, string) (*asynq.TaskInfo, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
|
||||||
|
redisOpt := asynq.RedisClientOpt{
|
||||||
|
Addr: conf.Redis.Address,
|
||||||
|
Password: conf.Redis.Password,
|
||||||
|
DB: conf.Redis.QueueDb,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("task"),
|
||||||
|
queue: asynq.NewClient(redisOpt),
|
||||||
|
inspector: asynq.NewInspector(redisOpt),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
@ -26,15 +47,13 @@ type service struct {
|
|||||||
inspector *asynq.Inspector
|
inspector *asynq.Inspector
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
redisOpt := asynq.RedisClientOpt{
|
servers, err := s.inspector.Servers()
|
||||||
Addr: g.Conf.Redis.Address,
|
if err != nil {
|
||||||
Password: g.Conf.Redis.Password,
|
return err
|
||||||
DB: g.Conf.Redis.QueueDb,
|
|
||||||
}
|
}
|
||||||
return &service{
|
if len(servers) == 0 {
|
||||||
log: g.Log,
|
return errors.New("no asynq server found")
|
||||||
queue: asynq.NewClient(redisOpt),
|
|
||||||
inspector: asynq.NewInspector(redisOpt),
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func (s *service) Create(data *CreateData) (*model.User, e.Status) {
|
|||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.db.Create(user).Error
|
err = s.db.Get().Create(user).Error
|
||||||
if err != nil && strings.Contains(err.Error(), "duplicate key") {
|
if err != nil && strings.Contains(err.Error(), "duplicate key") {
|
||||||
return nil, e.UserDuplicated
|
return nil, e.UserDuplicated
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ type LoginData struct {
|
|||||||
func (s *service) Login(data *LoginData) (*model.User, e.Status) {
|
func (s *service) Login(data *LoginData) (*model.User, e.Status) {
|
||||||
user := &model.User{UserName: data.UserName}
|
user := &model.User{UserName: data.UserName}
|
||||||
|
|
||||||
err := s.db.Where(user).First(&user).Error
|
err := s.db.Get().Where(user).First(&user).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, e.UserNotFound
|
return nil, e.UserNotFound
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func (s *service) Profile(uid uint) (*model.User, e.Status) {
|
func (s *service) Profile(uid uint) (*model.User, e.Status) {
|
||||||
user := new(model.User)
|
user := new(model.User)
|
||||||
|
|
||||||
err := s.db.First(&user, uid).Error
|
err := s.db.Get().First(&user, uid).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, e.UserNotFound
|
return nil, e.UserNotFound
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/model"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/go-redis/redis/v8"
|
"git.0x7f.app/WOJ/woj-server/internal/repo/cache"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/db"
|
||||||
|
"github.com/samber/do"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
@ -16,18 +17,24 @@ type Service interface {
|
|||||||
Login(data *LoginData) (*model.User, e.Status)
|
Login(data *LoginData) (*model.User, e.Status)
|
||||||
IncrVersion(uid uint) (int64, e.Status)
|
IncrVersion(uid uint) (int64, e.Status)
|
||||||
Profile(uid uint) (*model.User, e.Status)
|
Profile(uid uint) (*model.User, e.Status)
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
return &service{
|
||||||
|
log: do.MustInvoke[log.Service](i).GetLogger("user"),
|
||||||
|
db: do.MustInvoke[db.Service](i),
|
||||||
|
cache: do.MustInvoke[cache.Service](i),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
db *gorm.DB
|
db db.Service
|
||||||
redis *redis.Client
|
cache cache.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(g *global.Global) Service {
|
func (s *service) HealthCheck() error {
|
||||||
return &service{
|
return nil
|
||||||
log: g.Log,
|
|
||||||
db: g.Db.Get().(*gorm.DB),
|
|
||||||
redis: g.Redis.Get().(*redis.Client),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) IncrVersion(uid uint) (int64, e.Status) {
|
func (s *service) IncrVersion(uid uint) (int64, e.Status) {
|
||||||
version, err := s.redis.Incr(context.Background(), fmt.Sprintf("Version:%d", uid)).Result()
|
version, err := s.cache.Get().Incr(context.Background(), fmt.Sprintf("Version:%d", uid)).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("RedisError", zap.Error(err), zap.Any("uid", uid))
|
s.log.Warn("RedisError", zap.Error(err), zap.Any("uid", uid))
|
||||||
return -1, e.RedisError
|
return -1, e.RedisError
|
||||||
|
@ -2,14 +2,14 @@ package jwt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) Handler(forced bool) gin.HandlerFunc {
|
func (s *service) Handler(forced bool) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
claim, status := func() (*global.Claim, e.Status) {
|
claim, status := func() (*model.Claim, e.Status) {
|
||||||
const tokenPrefix = "bearer "
|
const tokenPrefix = "bearer "
|
||||||
tokenHeader := c.GetHeader("Authorization")
|
tokenHeader := c.GetHeader("Authorization")
|
||||||
if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), tokenPrefix) {
|
if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), tokenPrefix) {
|
50
internal/web/jwt/service.go
Normal file
50
internal/web/jwt/service.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/repo/cache"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
ParseToken(tokenText string) (*model.Claim, e.Status)
|
||||||
|
SignClaim(claim *model.Claim) (string, e.Status)
|
||||||
|
Validate(claim *model.Claim) bool
|
||||||
|
|
||||||
|
Handler(forced bool) gin.HandlerFunc
|
||||||
|
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
srv.log = do.MustInvoke[log.Service](i).GetLogger("jwt")
|
||||||
|
srv.cacheService = do.MustInvoke[cache.Service](i) // .Get().(*redis.Client)
|
||||||
|
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
srv.SigningKey = []byte(conf.WebServer.JwtSigningKey)
|
||||||
|
srv.ExpireHour = conf.WebServer.JwtExpireHour
|
||||||
|
|
||||||
|
return srv, srv.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
cacheService cache.Service
|
||||||
|
log *zap.Logger
|
||||||
|
|
||||||
|
SigningKey []byte
|
||||||
|
ExpireHour int
|
||||||
|
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return s.err
|
||||||
|
}
|
@ -4,21 +4,21 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) ParseToken(tokenText string) (*global.Claim, e.Status) {
|
func (s *service) ParseToken(tokenText string) (*model.Claim, e.Status) {
|
||||||
if tokenText == "" {
|
if tokenText == "" {
|
||||||
return nil, e.TokenEmpty
|
return nil, e.TokenEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := jwt.ParseWithClaims(
|
token, err := jwt.ParseWithClaims(
|
||||||
tokenText,
|
tokenText,
|
||||||
new(global.Claim),
|
new(model.Claim),
|
||||||
func(token *jwt.Token) (interface{}, error) {
|
func(token *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
@ -41,20 +41,19 @@ func (s *service) ParseToken(tokenText string) (*global.Claim, e.Status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if token.Valid {
|
if token.Valid {
|
||||||
c := token.Claims.(*global.Claim)
|
c := token.Claims.(*model.Claim)
|
||||||
return c, e.Success
|
return c, e.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, e.TokenInvalid
|
return nil, e.TokenInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) SignClaim(claim *global.Claim) (string, e.Status) {
|
func (s *service) SignClaim(claim *model.Claim) (string, e.Status) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
claim.IssuedAt = jwt.NewNumericDate(now)
|
claim.IssuedAt = jwt.NewNumericDate(now)
|
||||||
claim.ExpiresAt = jwt.NewNumericDate(now.Add(time.Duration(s.ExpireHour) * time.Hour))
|
claim.ExpiresAt = jwt.NewNumericDate(now.Add(time.Duration(s.ExpireHour) * time.Hour))
|
||||||
claim.ID = utils.RandomString(16)
|
claim.ID = utils.RandomString(16)
|
||||||
// TODO: use per-user claim.Version to tracker invalidation
|
|
||||||
claim.NotBefore = jwt.NewNumericDate(time.Now())
|
claim.NotBefore = jwt.NewNumericDate(time.Now())
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, claim)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS512, claim)
|
||||||
@ -66,10 +65,10 @@ func (s *service) SignClaim(claim *global.Claim) (string, e.Status) {
|
|||||||
return ss, e.Success
|
return ss, e.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Validate(claim *global.Claim) bool {
|
func (s *service) Validate(claim *model.Claim) bool {
|
||||||
curVersion, err := s.redis.Get(context.Background(), fmt.Sprintf("Version:%d", claim.UID)).Int64()
|
curVersion, err := s.cacheService.Get().Get(context.Background(), fmt.Sprintf("Version:%d", claim.UID)).Int64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Debug("redis.Get error", zap.Error(err))
|
s.log.Debug("cache.Get error", zap.Error(err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return curVersion == claim.Version
|
return curVersion == claim.Version
|
@ -9,16 +9,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *Metrics) SetLogPaths(paths []string) {
|
func (s *service) SetLogPaths(paths []string) {
|
||||||
m.logPaths = paths
|
s.logPaths = paths
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metrics) Handler() gin.HandlerFunc {
|
func (s *service) Handler() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
url := c.Request.URL.String()
|
url := c.Request.URL.String()
|
||||||
method := c.Request.Method
|
method := c.Request.Method
|
||||||
|
|
||||||
if !utils.Contains(m.logPaths, func(path string) bool { return strings.HasPrefix(url, path) }) {
|
if !utils.Contains(s.logPaths, func(path string) bool { return strings.HasPrefix(url, path) }) {
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -38,6 +38,6 @@ func (m *Metrics) Handler() gin.HandlerFunc {
|
|||||||
success = false
|
success = false
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Record(method, url, success, status, err, elapsed)
|
s.Record(method, url, success, status, err, elapsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,11 +2,32 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/e"
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/pkg/cast"
|
"git.0x7f.app/WOJ/woj-server/internal/pkg/cast"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/samber/do"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metrics struct {
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Record(method, url string, success bool, httpCode int, errCode e.Status, elapsed float64)
|
||||||
|
SetLogPaths(paths []string)
|
||||||
|
Handler() gin.HandlerFunc
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
srv.setup(conf.Metrics.Namespace, conf.Metrics.Subsystem)
|
||||||
|
|
||||||
|
return srv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
namespace string
|
namespace string
|
||||||
subsystem string
|
subsystem string
|
||||||
|
|
||||||
@ -16,11 +37,15 @@ type Metrics struct {
|
|||||||
logPaths []string
|
logPaths []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metrics) Setup(namespace string, subsystem string) {
|
func (s *service) HealthCheck() error {
|
||||||
m.namespace = namespace
|
return nil
|
||||||
m.subsystem = subsystem
|
}
|
||||||
|
|
||||||
m.counter = prometheus.NewCounterVec(
|
func (s *service) setup(namespace string, subsystem string) {
|
||||||
|
s.namespace = namespace
|
||||||
|
s.subsystem = subsystem
|
||||||
|
|
||||||
|
s.counter = prometheus.NewCounterVec(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: subsystem,
|
Subsystem: subsystem,
|
||||||
@ -30,7 +55,7 @@ func (m *Metrics) Setup(namespace string, subsystem string) {
|
|||||||
[]string{"method", "url"},
|
[]string{"method", "url"},
|
||||||
)
|
)
|
||||||
|
|
||||||
m.hist = prometheus.NewHistogramVec(
|
s.hist = prometheus.NewHistogramVec(
|
||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: subsystem,
|
Subsystem: subsystem,
|
||||||
@ -41,16 +66,16 @@ func (m *Metrics) Setup(namespace string, subsystem string) {
|
|||||||
[]string{"method", "url", "success", "http_code", "err_code"},
|
[]string{"method", "url", "success", "http_code", "err_code"},
|
||||||
)
|
)
|
||||||
|
|
||||||
prometheus.MustRegister(m.counter, m.hist)
|
prometheus.MustRegister(s.counter, s.hist)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metrics) Record(method, url string, success bool, httpCode int, errCode e.Status, elapsed float64) {
|
func (s *service) Record(method, url string, success bool, httpCode int, errCode e.Status, elapsed float64) {
|
||||||
m.counter.With(prometheus.Labels{
|
s.counter.With(prometheus.Labels{
|
||||||
"method": method,
|
"method": method,
|
||||||
"url": url,
|
"url": url,
|
||||||
}).Inc()
|
}).Inc()
|
||||||
|
|
||||||
m.hist.With(prometheus.Labels{
|
s.hist.With(prometheus.Labels{
|
||||||
"method": method,
|
"method": method,
|
||||||
"url": url,
|
"url": url,
|
||||||
"success": cast.ToString(success),
|
"success": cast.ToString(success),
|
@ -6,8 +6,9 @@ import (
|
|||||||
"git.0x7f.app/WOJ/woj-server/internal/api/status"
|
"git.0x7f.app/WOJ/woj-server/internal/api/status"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/api/submission"
|
"git.0x7f.app/WOJ/woj-server/internal/api/submission"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/api/user"
|
"git.0x7f.app/WOJ/woj-server/internal/api/user"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/samber/do"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title OJ Server API Documentation
|
// @title OJ Server API Documentation
|
||||||
@ -16,14 +17,14 @@ import (
|
|||||||
// @securityDefinitions.apikey Authentication
|
// @securityDefinitions.apikey Authentication
|
||||||
// @in header
|
// @in header
|
||||||
// @name Authorization
|
// @name Authorization
|
||||||
func setupApi(g *global.Global, root *gin.RouterGroup) {
|
func (s *service) setupApi(root *gin.RouterGroup, injector *do.Injector) {
|
||||||
for _, v := range endpoints {
|
for _, v := range endpoints {
|
||||||
group := root.Group(v.Version).Group(v.Path)
|
group := root.Group(v.Version).Group(v.Path)
|
||||||
v.Register(g, group)
|
v.Register(group, injector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var endpoints = []global.EndpointInfo{
|
var endpoints = []model.EndpointInfo{
|
||||||
{Version: "", Path: "/debug", Register: debug.RouteRegister},
|
{Version: "", Path: "/debug", Register: debug.RouteRegister},
|
||||||
{Version: "/v1", Path: "/user", Register: user.RouteRegister},
|
{Version: "/v1", Path: "/user", Register: user.RouteRegister},
|
||||||
{Version: "/v1", Path: "/problem", Register: problem.RouteRegister},
|
{Version: "/v1", Path: "/problem", Register: problem.RouteRegister},
|
@ -1,37 +1,74 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/global"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/config"
|
||||||
"git.0x7f.app/WOJ/woj-server/internal/pkg/metrics"
|
"git.0x7f.app/WOJ/woj-server/internal/misc/log"
|
||||||
_ "git.0x7f.app/WOJ/woj-server/internal/router/docs"
|
"git.0x7f.app/WOJ/woj-server/internal/model"
|
||||||
|
"git.0x7f.app/WOJ/woj-server/internal/web/metrics"
|
||||||
|
_ "git.0x7f.app/WOJ/woj-server/internal/web/router/docs"
|
||||||
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-contrib/pprof"
|
"github.com/gin-contrib/pprof"
|
||||||
ginZap "github.com/gin-contrib/zap"
|
ginZap "github.com/gin-contrib/zap"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/samber/do"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
"github.com/swaggo/gin-swagger"
|
"github.com/swaggo/gin-swagger"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRouters(g *global.Global) *gin.Engine {
|
var _ Service = (*service)(nil)
|
||||||
gin.SetMode(utils.If(g.Conf.Development, gin.DebugMode, gin.ReleaseMode))
|
|
||||||
|
type Service interface {
|
||||||
|
GetRouter() *gin.Engine
|
||||||
|
HealthCheck() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(i *do.Injector) (Service, error) {
|
||||||
|
srv := &service{}
|
||||||
|
srv.metric = do.MustInvoke[metrics.Service](i)
|
||||||
|
srv.logger = do.MustInvoke[log.Service](i)
|
||||||
|
|
||||||
|
conf := do.MustInvoke[config.Service](i).GetConfig()
|
||||||
|
srv.initRouters(conf, i)
|
||||||
|
|
||||||
|
return srv, srv.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
metric metrics.Service
|
||||||
|
logger log.Service
|
||||||
|
engine *gin.Engine
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetRouter() *gin.Engine {
|
||||||
|
return s.engine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) HealthCheck() error {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) initRouters(conf *model.Config, injector *do.Injector) *gin.Engine {
|
||||||
|
gin.SetMode(utils.If(conf.Development, gin.DebugMode, gin.ReleaseMode))
|
||||||
|
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
r.MaxMultipartMemory = 8 << 20
|
r.MaxMultipartMemory = 8 << 20
|
||||||
|
|
||||||
// Logger middleware and debug
|
// Logger middleware and debug
|
||||||
if g.Conf.Development {
|
if conf.Development {
|
||||||
// Gin's default logger is pretty enough
|
// Gin's default logger is pretty enough
|
||||||
r.Use(gin.Logger())
|
r.Use(gin.Logger())
|
||||||
r.Use(gin.Recovery())
|
r.Use(gin.Recovery())
|
||||||
// add prof
|
// add prof
|
||||||
pprof.Register(r)
|
pprof.Register(r)
|
||||||
} else {
|
} else {
|
||||||
r.Use(ginZap.Ginzap(g.Log, time.RFC3339, false))
|
ginLog := s.logger.GetLogger("gin")
|
||||||
r.Use(ginZap.RecoveryWithZap(g.Log, true))
|
r.Use(ginZap.Ginzap(ginLog, time.RFC3339, false))
|
||||||
|
r.Use(ginZap.RecoveryWithZap(ginLog, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CORS middleware
|
// CORS middleware
|
||||||
@ -43,10 +80,8 @@ func InitRouters(g *global.Global) *gin.Engine {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Prometheus middleware
|
// Prometheus middleware
|
||||||
g.Stat = new(metrics.Metrics)
|
s.metric.SetLogPaths([]string{"/api"})
|
||||||
g.Stat.Setup(g.Conf.Metrics.Namespace, g.Conf.Metrics.Subsystem)
|
r.Use(s.metric.Handler())
|
||||||
g.Stat.SetLogPaths([]string{"/api"})
|
|
||||||
r.Use(g.Stat.Handler())
|
|
||||||
|
|
||||||
// metrics
|
// metrics
|
||||||
r.GET("/metrics", gin.WrapH(promhttp.Handler()))
|
r.GET("/metrics", gin.WrapH(promhttp.Handler()))
|
||||||
@ -68,7 +103,7 @@ func InitRouters(g *global.Global) *gin.Engine {
|
|||||||
|
|
||||||
// api
|
// api
|
||||||
api := r.Group("/api/")
|
api := r.Group("/api/")
|
||||||
setupApi(g, api)
|
s.setupApi(api, injector)
|
||||||
|
|
||||||
// static files
|
// static files
|
||||||
r.Static("/static", "./resource/frontend/static")
|
r.Static("/static", "./resource/frontend/static")
|
1
internal/web/web.go
Normal file
1
internal/web/web.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package web
|
Loading…
Reference in New Issue
Block a user