Skip to content

Commit

Permalink
feat: much better poller + change status with api (#9)
Browse files Browse the repository at this point in the history
* feat: much better poller + change status with api

* chore: go.mod update + remove poll_batch_size

* fix: ejudge poll size config
  • Loading branch information
Gornak40 authored May 13, 2024
1 parent 0f831e8 commit a28a6e9
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 89 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ SQLITE_PATH = <PATH>
[server]
GIN_SECRET = <SECRET>
JWT_SECRET = <SECRET>
POLL_BATCH_SIZE = 50
POLL_MAX_RUNS = 1000
POLL_DELAY_SECONDS = 10
REVIEW_LIMIT = 3
```
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type DBConfig struct {
type ServerConfig struct {
GinSecret string `ini:"GIN_SECRET"`
JWTSecret string `ini:"JWT_SECRET"`
PollBatchSize int64 `ini:"POLL_BATCH_SIZE"`
PollMaxRuns int64 `ini:"POLL_MAX_RUNS"`
PollDelaySeconds int64 `ini:"POLL_DELAY_SECONDS"`
ReviewLimit int64 `ini:"REVIEW_LIMIT"`
}
Expand Down
2 changes: 1 addition & 1 deletion controller/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (s *Server) AdminPOST(c *gin.Context) {
session.Set("jwt", form.JWT)
_ = session.Save()

_ = alerts.Add(session, alerts.Alert{ // TODO: add expiration time
_ = alerts.Add(session, alerts.Alert{
Message: "JWT is valid",
Type: alerts.TypeSuccess,
})
Expand Down
4 changes: 2 additions & 2 deletions controller/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ func (s *Server) IndexPOST(c *gin.Context) {
}

func (s *Server) reviewValid(user string, contestID uint, problem string) error {
filter := fmt.Sprintf("login == '%s' && prob == '%s' && (status == OK || status == PR)", user, problem)
runs, err := s.ej.GetContestRuns(contestID, filter)
filter := fmt.Sprintf("login == '%s' && prob == '%s' && status == OK", user, problem)
runs, err := s.ej.GetContestRuns(contestID, filter, 1)
if err != nil {
return err
}
Expand Down
75 changes: 62 additions & 13 deletions controller/poller.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package controller

import (
"fmt"

"github.com/Gornak40/crosspawn/models"
"github.com/Gornak40/crosspawn/pkg/ejudge"
"github.com/sirupsen/logrus"
)

Expand All @@ -23,25 +22,75 @@ func (s *Server) Poll() error {
return nil
}

func (s *Server) pollContest(dbContest *models.Contest) error {
from := dbContest.MaxRunID
to := from + uint(s.cfg.PollBatchSize)
filter := fmt.Sprintf("status == PR && %d <= id && id < %d", from, to)
func statusFromRating(rating int) ejudge.RunStatus {
if rating > 0 { // TODO: think about it
return ejudge.RunStatusOK
}

runs, err := s.ej.GetContestRuns(dbContest.EjudgeID, filter)
return ejudge.RunStatusRJ
}

func runStatusFromDB(dbStatus *models.Run) *ejudge.EjStatusChange {
return &ejudge.EjStatusChange{
RunID: dbStatus.EjudgeID,
ContestID: dbStatus.EjudgeContestID,
Status: statusFromRating(dbStatus.Rating),
}
}

func (s *Server) pollContest(dbContest *models.Contest) error {
runs, err := s.ej.GetContestRuns(dbContest.EjudgeID, "status == PR", int(s.cfg.PollMaxRuns))
if err != nil {
return err
}
logrus.WithField("count", len(runs.Runs)).Info("ejudge runs received")
runsMapa := make(map[uint]struct{})
for _, run := range runs.Runs {
runsMapa[run.RunID] = struct{}{}
}

var dbRuns []models.Run
quRun := models.Run{EjudgeContestID: dbContest.EjudgeID}
if err := s.db.Where(&quRun).Find(&dbRuns).Error; err != nil {
return err
}

// change status of runs
oldMapa := make(map[uint]struct{})
for _, dbRun := range dbRuns {
if _, ok := runsMapa[dbRun.EjudgeID]; !ok {
logrus.WithField("runID", dbRun.EjudgeID).Warn("run is lost in ejudge")
if err := s.db.Delete(&dbRun).Error; err != nil { //nolint:gosec // G601: Implicit memory aliasing in for loop.
logrus.WithError(err).Error("failed to delete run")
}

continue
}
if dbRun.ReviewCount >= uint(s.cfg.ReviewLimit) {
status := runStatusFromDB(&dbRun) //nolint:gosec // G601: Implicit memory aliasing in for loop.
if err := s.ej.ChangeRunStatus(status); err != nil {
logrus.WithError(err).Error("failed to change run status")
}
logrus.WithField("runID", dbRun.EjudgeID).Info("run review done")
if err := s.db.Delete(&dbRun).Error; err != nil { //nolint:gosec // G601: Implicit memory aliasing in for loop.
logrus.WithError(err).Error("failed to delete run")
}
}
oldMapa[dbRun.EjudgeID] = struct{}{}
}

// save new runs
// TODO: fix saving deleted runs
for _, run := range runs.Runs {
logrus.Info(run) // TODO: move to debug
if _, ok := oldMapa[run.RunID]; ok {
continue
}
dbRun := models.NewRunFromEj(&run) //nolint:gosec // G601: Implicit memory aliasing in for loop.
if err := s.db.Create(dbRun).Error; err != nil {
logrus.WithError(err).WithFields(logrus.Fields{"contestID": run.ContestID, "runID": run.RunID}).
Error("failed to save run")
logrus.WithField("run", run).Info("saving new run")
if err := s.db.Save(&dbRun).Error; err != nil {
logrus.WithError(err).Error("failed to save run")
}
}
dbContest.MaxRunID = min(to, runs.TotalRuns)

return s.db.Save(dbContest).Error
return nil
}
34 changes: 18 additions & 16 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@ module github.com/Gornak40/crosspawn
go 1.22.2

require (
github.com/gin-contrib/sessions v1.0.0
github.com/gin-gonic/gin v1.9.1
github.com/gin-contrib/sessions v1.0.1
github.com/gin-gonic/gin v1.10.0
github.com/go-zoox/ini v1.0.4
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/sirupsen/logrus v1.9.3
gorm.io/driver/sqlite v1.5.5
gorm.io/gorm v1.25.9
gorm.io/gorm v1.25.10
)

require (
github.com/bytedance/sonic v1.11.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.19.0 // indirect
github.com/go-zoox/core-utils v1.0.4 // indirect
github.com/go-zoox/tag v1.0.6 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-zoox/core-utils v1.4.7 // indirect
github.com/go-zoox/tag v1.3.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
Expand All @@ -36,14 +37,15 @@ require (
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit a28a6e9

Please sign in to comment.