From 26a81652b387671b7e3c8b38fc4232a96a8a3eaa Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sun, 23 Oct 2022 17:29:35 +0800 Subject: [PATCH] feat: another big update 1. add consumer 2. add createVersion 3. add upload 4. fix runner 5. add rejudge Co-authored-by: cxy004 Co-authored-by: wzt --- .gitignore | 1 + config.yaml | 7 ++ go.mod | 13 +++- go.sum | 28 +++++++- internal/api/consumer/handler.go | 36 ++++++++++ internal/api/consumer/problemUpdate.go | 40 +++++++++++ internal/api/consumer/submitUpdate.go | 37 ++++++++++ internal/api/problem/createVersion.go | 67 +++++++++++++++++ internal/api/problem/details.go | 8 ++- internal/api/problem/handler.go | 11 ++- internal/api/problem/search.go | 8 +-- internal/api/problem/upload.go | 44 ++++++++++++ internal/api/runner/build.go | 36 +++++++--- internal/api/runner/handler.go | 15 ++-- internal/api/runner/judge.go | 88 ++++++++++++----------- internal/api/status/query.go | 11 ++- internal/api/status/queryByVersion.go | 17 +++-- internal/api/submission/create.go | 19 ++++- internal/api/submission/handler.go | 2 + internal/api/submission/query.go | 14 ++-- internal/api/submission/rejudge.go | 63 ++++++++++++++++ internal/api/user/create.go | 1 - internal/api/user/logout.go | 1 - internal/api/user/profile.go | 4 +- internal/app/server/server.go | 9 ++- internal/e/code.go | 11 +++ internal/e/resp.go | 9 +++ internal/global/config.go | 9 +++ internal/model/Task.go | 13 ++-- internal/repo/postgresql/postgresql.go | 2 + internal/service/problem/createVersion.go | 2 + internal/service/problem/service.go | 2 +- internal/service/problem/updateVersion.go | 10 +-- internal/service/runner/common.go | 12 ++-- internal/service/runner/compile.go | 10 +-- internal/service/runner/newProblem.go | 19 +++-- internal/service/runner/service.go | 4 +- internal/service/runner/status.go | 5 +- internal/service/status/create.go | 13 ++-- internal/service/status/rejudge.go | 11 --- internal/service/status/service.go | 3 +- internal/service/storage/get.go | 30 ++++++++ internal/service/storage/service.go | 41 +++++++++++ internal/service/storage/upload.go | 28 ++++++++ internal/service/submission/query.go | 24 +++++++ internal/service/submission/service.go | 1 + internal/service/task/common.go | 2 - internal/service/task/problem.go | 24 +++---- internal/service/task/service.go | 8 +-- internal/service/task/submit.go | 30 ++++---- pkg/utils/file.go | 8 +++ resource/runner/scripts/problem_run.sh | 2 +- 52 files changed, 729 insertions(+), 184 deletions(-) create mode 100644 internal/api/consumer/handler.go create mode 100644 internal/api/consumer/problemUpdate.go create mode 100644 internal/api/consumer/submitUpdate.go create mode 100644 internal/api/problem/createVersion.go create mode 100644 internal/api/problem/upload.go create mode 100644 internal/api/submission/rejudge.go delete mode 100644 internal/service/status/rejudge.go create mode 100644 internal/service/storage/get.go create mode 100644 internal/service/storage/service.go create mode 100644 internal/service/storage/upload.go diff --git a/.gitignore b/.gitignore index 75afa1a..8826357 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ ### Project +/tmp /server /runner my.secrets diff --git a/config.yaml b/config.yaml index 7ff81ec..206536b 100644 --- a/config.yaml +++ b/config.yaml @@ -21,6 +21,13 @@ Database: MaxIdleConns: 60 ConnMaxLifetime: 60 +Storage: + Endpoint: '127.0.0.1:9000' + UseSSL: false + AccessKey: 'EHd5Zj56QrTivhFI' + SecretKey: 'FUHy4RW1mn0Kbr5pibDZ6R2F9116FZKY' + Bucket: 'woj' + Metrics: Namespace: 'OJ' Subsystem: 'server' diff --git a/go.mod b/go.mod index f3d872a..b42a8c2 100644 --- a/go.mod +++ b/go.mod @@ -11,13 +11,14 @@ require ( github.com/golang-jwt/jwt/v4 v4.4.2 github.com/hibiken/asynq v0.23.0 github.com/jackc/pgtype v1.11.0 + github.com/minio/minio-go/v7 v7.0.42 github.com/prometheus/client_golang v1.13.0 github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a github.com/swaggo/gin-swagger v1.5.3 github.com/swaggo/swag v1.8.5 github.com/urfave/cli/v2 v2.14.1 go.uber.org/zap v1.23.0 - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 + golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa golang.org/x/text v0.3.7 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/postgres v1.3.9 @@ -33,6 +34,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect @@ -55,10 +57,14 @@ require ( github.com/jinzhu/now v1.1.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/cpuid/v2 v2.1.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/sha256-simd v1.0.0 // 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.0.1 // indirect @@ -66,16 +72,19 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rs/xid v1.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/ugorji/go/codec v1.2.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.7.0 // indirect - golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect golang.org/x/tools v0.1.10 // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index d858d78..28e388a 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -271,6 +273,12 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= +github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -305,6 +313,12 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.42 h1:fP56plNR/Tkw/+Xczw9NL5TGxe5gJDvgd8LidNR3BEI= +github.com/minio/minio-go/v7 v7.0.42/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -371,6 +385,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -385,6 +401,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -467,8 +485,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -541,8 +560,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -616,6 +636,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -781,6 +803,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= +gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/api/consumer/handler.go b/internal/api/consumer/handler.go new file mode 100644 index 0000000..3c8b840 --- /dev/null +++ b/internal/api/consumer/handler.go @@ -0,0 +1,36 @@ +package consumer + +import ( + "context" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/WHUPRJ/woj-server/internal/service/problem" + "github.com/WHUPRJ/woj-server/internal/service/status" + "github.com/WHUPRJ/woj-server/internal/service/task" + "github.com/hibiken/asynq" + "go.uber.org/zap" +) + +var _ Handler = (*handler)(nil) + +type Handler interface { + ProblemUpdate(_ context.Context, t *asynq.Task) error + SubmitUpdate(_ context.Context, t *asynq.Task) error +} + +type handler struct { + log *zap.Logger + problemService problem.Service + statusService status.Service + taskService task.Service +} + +func NewConsumer(g *global.Global) Handler { + hnd := &handler{ + log: g.Log, + problemService: problem.NewService(g), + statusService: status.NewService(g), + taskService: task.NewService(g), + } + + return hnd +} diff --git a/internal/api/consumer/problemUpdate.go b/internal/api/consumer/problemUpdate.go new file mode 100644 index 0000000..d5187d0 --- /dev/null +++ b/internal/api/consumer/problemUpdate.go @@ -0,0 +1,40 @@ +package consumer + +import ( + "context" + "encoding/json" + "fmt" + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/model" + "github.com/hibiken/asynq" + "github.com/jackc/pgtype" + "go.uber.org/zap" +) + +func (h *handler) ProblemUpdate(_ context.Context, t *asynq.Task) error { + p := new(model.ProblemUpdatePayload) + if err := json.Unmarshal(t.Payload(), &p); err != nil { + return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry) + } + + if p.Status != e.Success { + h.log.Warn("RunnerError", zap.Any("payload", p)) + return nil + } + + status := h.problemService.UpdateVersion( + p.ProblemVersionID, + map[string]interface{}{ + "Context": pgtype.JSON{ + Bytes: []byte(p.Context), + Status: pgtype.Present, + }, + "IsEnabled": true, + }, + ) + + if status != e.Success { + return fmt.Errorf(status.String()) + } + return nil +} diff --git a/internal/api/consumer/submitUpdate.go b/internal/api/consumer/submitUpdate.go new file mode 100644 index 0000000..8b9c64b --- /dev/null +++ b/internal/api/consumer/submitUpdate.go @@ -0,0 +1,37 @@ +package consumer + +import ( + "context" + "encoding/json" + "fmt" + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/model" + "github.com/WHUPRJ/woj-server/internal/service/status" + "github.com/hibiken/asynq" + "go.uber.org/zap" +) + +func (h *handler) SubmitUpdate(_ context.Context, t *asynq.Task) error { + p := new(model.SubmitUpdatePayload) + if err := json.Unmarshal(t.Payload(), &p); err != nil { + return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry) + } + + if p.Status != e.Success { + h.log.Warn("RunnerError", zap.Any("payload", p)) + return nil + } + + createData := &status.CreateData{ + SubmissionID: p.SubmissionID, + ProblemVersionID: p.ProblemVersionID, + Context: p.Context, + Point: p.Point, + } + _, eStatus := h.statusService.Create(createData) + + if eStatus != e.Success { + return fmt.Errorf(eStatus.String()) + } + return nil +} diff --git a/internal/api/problem/createVersion.go b/internal/api/problem/createVersion.go new file mode 100644 index 0000000..2456abc --- /dev/null +++ b/internal/api/problem/createVersion.go @@ -0,0 +1,67 @@ +package problem + +import ( + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/WHUPRJ/woj-server/internal/model" + "github.com/WHUPRJ/woj-server/internal/service/problem" + "github.com/gin-gonic/gin" +) + +type createVersionRequest struct { + ProblemID uint `form:"pid" binding:"required"` + StorageKey string `form:"storage_key" binding:"required"` +} + +// CreateVersion +// @Summary create a problem version +// @Description create a problem version +// @Accept application/x-www-form-urlencoded +// @Produce json +// @Param pid formData int true "problem id" +// @Param storage_key formData string true "storage key" +// @Response 200 {object} e.Response "" +// @Security Authentication +// @Router /v1/problem/create_version [post] +func (h *handler) CreateVersion(c *gin.Context) { + claim, exist := c.Get("claim") + if !exist { + e.Pong(c, e.UserUnauthenticated, nil) + return + } + + // uid := claim.(*global.Claim).UID + + role := claim.(*global.Claim).Role + req := new(createVersionRequest) + + if err := c.ShouldBind(req); err != nil { + e.Pong(c, e.InvalidParameter, err.Error()) + return + } + + // guest can not submit + if role < model.RoleAdmin { + e.Pong(c, e.UserUnauthorized, nil) + return + } + + // TODO: check pid exist + + createVersionData := &problem.CreateVersionData{ + ProblemID: req.ProblemID, + StorageKey: req.StorageKey, + } + pv, status := h.problemService.CreateVersion(createVersionData) + if status != e.Success { + e.Pong(c, status, nil) + return + } + + payload := &model.ProblemBuildPayload{ + ProblemVersionID: pv.ID, + StorageKey: pv.StorageKey, + } + _, status = h.taskService.ProblemBuild(payload) + e.Pong(c, status, nil) +} diff --git a/internal/api/problem/details.go b/internal/api/problem/details.go index f9c42b3..3df21e6 100644 --- a/internal/api/problem/details.go +++ b/internal/api/problem/details.go @@ -37,9 +37,11 @@ func (h *handler) Details(c *gin.Context) { } pv, status := h.problemService.QueryLatestVersion(req.Pid) - e.Pong(c, status, gin.H{ + if status != e.Success { + e.Pong(c, status, nil) + } + e.Pong(c, e.Success, gin.H{ "problem": p, - "context": pv.Context, + "context": pv.Context.Get(), }) - return } diff --git a/internal/api/problem/handler.go b/internal/api/problem/handler.go index 4e3a9a2..53bdda2 100644 --- a/internal/api/problem/handler.go +++ b/internal/api/problem/handler.go @@ -3,6 +3,8 @@ package problem import ( "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/service/problem" + "github.com/WHUPRJ/woj-server/internal/service/storage" + "github.com/WHUPRJ/woj-server/internal/service/task" "github.com/gin-gonic/gin" "go.uber.org/zap" ) @@ -13,12 +15,15 @@ type Handler interface { Details(c *gin.Context) Search(c *gin.Context) Update(c *gin.Context) + Upload(c *gin.Context) } type handler struct { log *zap.Logger jwtService global.JwtService problemService problem.Service + taskService task.Service + storageService storage.Service } func RouteRegister(g *global.Global, group *gin.RouterGroup) { @@ -26,9 +31,13 @@ func RouteRegister(g *global.Global, group *gin.RouterGroup) { log: g.Log, jwtService: g.Jwt, problemService: problem.NewService(g), + taskService: task.NewService(g), + storageService: storage.NewService(g), } - group.POST("/details", app.jwtService.Handler(false), app.Details) group.POST("/search", app.Search) + group.POST("/details", app.jwtService.Handler(false), app.Details) group.POST("/update", app.jwtService.Handler(true), app.Update) + group.POST("/upload", app.jwtService.Handler(true), app.Upload) + group.POST("/create_version", app.jwtService.Handler(true), app.CreateVersion) } diff --git a/internal/api/problem/search.go b/internal/api/problem/search.go index 4384647..9baeab1 100644 --- a/internal/api/problem/search.go +++ b/internal/api/problem/search.go @@ -28,12 +28,12 @@ func (h *handler) Search(c *gin.Context) { // TODO: pagination if req.Search == "" { // TODO: query without LIKE - problem, status := h.problemService.QueryFuzz(req.Search, true, true) - e.Pong(c, status, problem) + problems, status := h.problemService.QueryFuzz(req.Search, true, true) + e.Pong(c, status, problems) return } else { - problem, status := h.problemService.QueryFuzz(req.Search, true, true) - e.Pong(c, status, problem) + problems, status := h.problemService.QueryFuzz(req.Search, true, true) + e.Pong(c, status, problems) return } } diff --git a/internal/api/problem/upload.go b/internal/api/problem/upload.go new file mode 100644 index 0000000..a83edc3 --- /dev/null +++ b/internal/api/problem/upload.go @@ -0,0 +1,44 @@ +package problem + +import ( + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/WHUPRJ/woj-server/internal/model" + "github.com/WHUPRJ/woj-server/pkg/utils" + "github.com/gin-gonic/gin" + "time" +) + +// Upload +// @Summary get upload url +// @Description get upload url +// @Produce json +// @Response 200 {object} e.Response "upload url and key" +// @Security Authentication +// @Router /v1/problem/upload [post] +func (h *handler) Upload(c *gin.Context) { + claim, exist := c.Get("claim") + if !exist { + e.Pong(c, e.UserUnauthenticated, nil) + return + } + + role := claim.(*global.Claim).Role + if role < model.RoleAdmin { + e.Pong(c, e.UserUnauthorized, nil) + return + } + + key := utils.RandomString(16) + url, status := h.storageService.Upload(key, time.Second*60*60) + + if status != e.Success { + e.Pong(c, status, nil) + return + } + + e.Pong(c, e.Success, gin.H{ + "key": key, + "url": url, + }) +} diff --git a/internal/api/runner/build.go b/internal/api/runner/build.go index 1f7f74a..58d9463 100644 --- a/internal/api/runner/build.go +++ b/internal/api/runner/build.go @@ -4,14 +4,14 @@ import ( "context" "encoding/json" "fmt" + "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/model" "github.com/hibiken/asynq" "go.uber.org/zap" + "time" ) func (h *handler) Build(_ context.Context, t *asynq.Task) error { - // TODO: configure timeout with context - var p model.ProblemBuildPayload if err := json.Unmarshal(t.Payload(), &p); err != nil { return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry) @@ -19,16 +19,32 @@ func (h *handler) Build(_ context.Context, t *asynq.Task) error { h.log.Info("build", zap.Any("payload", p)) - config, status := h.runnerService.NewProblem(p.ProblemVersionID, p.ProblemFile) + status, ctx := func() (e.Status, string) { + url, status := h.storageService.Get(p.StorageKey, time.Second*60*5) + if status != e.Success { + return e.InternalError, "{}" + } - for i := range config.Languages { - config.Languages[i].Type = "" - config.Languages[i].Script = "" - config.Languages[i].Cmp = "" - } + config, status := h.runnerService.NewProblem(p.ProblemVersionID, url, true) + if status != e.Success { + return e.InternalError, "{}" + } - b, _ := json.Marshal(config) - h.taskService.ProblemUpdate(status, p.ProblemVersionID, string(b)) + for i := range config.Languages { + config.Languages[i].Type = "" + config.Languages[i].Script = "" + config.Languages[i].Cmp = "" + } + + b, _ := json.Marshal(config) + return e.Success, string(b) + }() + + h.taskService.ProblemUpdate(&model.ProblemUpdatePayload{ + Status: status, + ProblemVersionID: p.ProblemVersionID, + Context: ctx, + }) return nil } diff --git a/internal/api/runner/handler.go b/internal/api/runner/handler.go index d8ddbff..ad89428 100644 --- a/internal/api/runner/handler.go +++ b/internal/api/runner/handler.go @@ -6,6 +6,7 @@ import ( "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/service/runner" + "github.com/WHUPRJ/woj-server/internal/service/storage" "github.com/WHUPRJ/woj-server/internal/service/task" "github.com/hibiken/asynq" "go.uber.org/zap" @@ -19,16 +20,18 @@ type Handler interface { } type handler struct { - log *zap.Logger - runnerService runner.Service - taskService task.Service + log *zap.Logger + runnerService runner.Service + taskService task.Service + storageService storage.Service } func NewRunner(g *global.Global) (Handler, error) { hnd := &handler{ - log: g.Log, - runnerService: runner.NewService(g), - taskService: task.NewService(g), + log: g.Log, + runnerService: runner.NewService(g), + taskService: task.NewService(g), + storageService: storage.NewService(g), } status := hnd.runnerService.EnsureDeps(false) diff --git a/internal/api/runner/judge.go b/internal/api/runner/judge.go index 594af4d..1a8e563 100644 --- a/internal/api/runner/judge.go +++ b/internal/api/runner/judge.go @@ -11,6 +11,7 @@ import ( "github.com/hibiken/asynq" "go.uber.org/zap" "path/filepath" + "time" ) func (h *handler) Judge(_ context.Context, t *asynq.Task) error { @@ -22,52 +23,55 @@ func (h *handler) Judge(_ context.Context, t *asynq.Task) error { user := utils.RandomString(16) h.log.Info("judge", zap.Any("payload", p), zap.String("user", user)) - // common - systemError := runner.JudgeStatus{Message: "System Error"} + status, point, ctx := func() (e.Status, int32, runner.JudgeStatus) { + systemError := runner.JudgeStatus{Message: "System Error"} - // write code - userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language)) - if !utils.FileTouch(userCode) { - h.log.Info("Touch file failed", zap.String("userCode", userCode)) - h.taskService.SubmitUpdate(e.InternalError, p.ProblemVersionId, 0, systemError) - return nil - } - err := utils.FileWrite(userCode, []byte(p.Submission.Code)) - if err != nil { - h.log.Info("Write file failed", zap.String("code", p.Submission.Code)) - h.taskService.SubmitUpdate(e.InternalError, p.ProblemVersionId, 0, systemError) - return nil - } - - // compile - result, status := h.runnerService.Compile(p.ProblemVersionId, user, p.Submission.Language) - if status == e.RunnerProblemNotExist { - _, status := h.runnerService.NewProblem(p.ProblemVersionId, p.StorageKey) - if status != e.Success { - h.log.Warn("download problem failed", - zap.Any("status", status), - zap.Uint("pvid", p.ProblemVersionId), - zap.String("storageKey", p.StorageKey)) - h.taskService.SubmitUpdate(status, p.ProblemVersionId, 0, systemError) - return nil + // 1. write user code + userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language)) + if !utils.FileTouch(userCode) { + return e.InternalError, 0, systemError + } + err := utils.FileWrite(userCode, []byte(p.Submission.Code)) + if err != nil { + return e.InternalError, 0, systemError } - } else if status != e.Success { - h.taskService.SubmitUpdate(status, p.Submission.ID, 0, result) - return nil - } - // config - config, err := h.runnerService.ParseConfig(p.ProblemVersionId, true) - if err != nil { - h.log.Info("parse config failed", zap.Error(err), zap.Uint("pvid", p.ProblemVersionId)) - h.taskService.SubmitUpdate(e.InternalError, p.ProblemVersionId, 0, systemError) - return nil - } + // 2. check problem + if !h.runnerService.ProblemExists(p.ProblemVersionID) { + url, status := h.storageService.Get(p.StorageKey, time.Second*60*5) + if status != e.Success { + return e.InternalError, 0, systemError + } - // run - var points int32 - result, points, status = h.runnerService.RunAndJudge(p.ProblemVersionId, user, p.Submission.Language, &config) - h.taskService.SubmitUpdate(status, p.Submission.ID, points, result) + _, status = h.runnerService.NewProblem(p.ProblemVersionID, url, false) + if status != e.Success { + return e.InternalError, 0, systemError + } + } + + // 3. compile + compileResult, status := h.runnerService.Compile(p.ProblemVersionID, user, p.Submission.Language) + if status != e.Success { + return e.Success, 0, compileResult + } + + // 4. config + config, err := h.runnerService.ParseConfig(p.ProblemVersionID, true) + if err != nil { + return e.InternalError, 0, systemError + } + + // 5. run and judge + result, point, status := h.runnerService.RunAndJudge(p.ProblemVersionID, user, p.Submission.Language, &config) + return utils.If(status != e.Success, e.InternalError, e.Success).(e.Status), point, result + }() + + h.taskService.SubmitUpdate(&model.SubmitUpdatePayload{ + Status: status, + SubmissionID: p.Submission.ID, + ProblemVersionID: p.ProblemVersionID, + Point: point, + }, ctx) return nil } diff --git a/internal/api/status/query.go b/internal/api/status/query.go index 54b353d..13faf0f 100644 --- a/internal/api/status/query.go +++ b/internal/api/status/query.go @@ -6,9 +6,17 @@ import ( ) type queryRequest struct { - SubmissionID uint `form:"sid"` + SubmissionID uint `form:"sid" binding:"required"` } +// Query +// @Summary query submissions by via submission id +// @Description query submissions by via submission id +// @Accept application/x-www-form-urlencoded +// @Produce json +// @Param sid formData uint true "submission id" +// @Response 200 {object} e.Response "model.status" +// @Router /v1/status/query [post] func (h *handler) Query(c *gin.Context) { req := new(queryRequest) @@ -20,5 +28,4 @@ func (h *handler) Query(c *gin.Context) { status, eStatus := h.statusService.Query(req.SubmissionID, true) e.Pong(c, eStatus, status) - return } diff --git a/internal/api/status/queryByVersion.go b/internal/api/status/queryByVersion.go index d7e1728..3a738c0 100644 --- a/internal/api/status/queryByVersion.go +++ b/internal/api/status/queryByVersion.go @@ -8,11 +8,21 @@ import ( ) type queryByVersionRequest struct { - ProblemVersionID uint `form:"pvid"` + ProblemVersionID uint `form:"pvid" binding:"required"` Offset int `form:"offset"` - Limit int `form:"limit"` + Limit int `form:"limit" binding:"required"` } +// QueryByProblemVersion +// @Summary query submissions by problem version (admin only) +// @Description query submissions by problem version (admin only) +// @Accept application/x-www-form-urlencoded +// @Produce json +// @Param pvid formData uint true "problem version id" +// @Param offset formData int true "start position" +// @Param limit formData int true "limit number of records" +// @Response 200 {object} e.Response "[]*model.status" +// @Router /v1/status/query/problem_version [post] func (h *handler) QueryByProblemVersion(c *gin.Context) { claim, exist := c.Get("claim") @@ -26,7 +36,7 @@ func (h *handler) QueryByProblemVersion(c *gin.Context) { req := new(queryByVersionRequest) if err := c.ShouldBind(req); err != nil { - e.Pong(c, e.InvalidParameter, nil) + e.Pong(c, e.InvalidParameter, err.Error()) return } @@ -38,5 +48,4 @@ func (h *handler) QueryByProblemVersion(c *gin.Context) { statuses, eStatus := h.statusService.QueryByVersion(req.ProblemVersionID, req.Offset, req.Limit) e.Pong(c, eStatus, statuses) - return } diff --git a/internal/api/submission/create.go b/internal/api/submission/create.go index a49fea4..5743285 100644 --- a/internal/api/submission/create.go +++ b/internal/api/submission/create.go @@ -3,6 +3,7 @@ package submission import ( "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/global" + "github.com/WHUPRJ/woj-server/internal/model" "github.com/WHUPRJ/woj-server/internal/service/submission" "github.com/gin-gonic/gin" ) @@ -10,7 +11,7 @@ import ( type createRequest struct { Pid uint `form:"pid" binding:"required"` Language string `form:"language" binding:"required"` - Code string `form:"statement" binding:"required"` + Code string `form:"code" binding:"required"` } // Create @@ -33,6 +34,7 @@ func (h *handler) Create(c *gin.Context) { uid := claim.(*global.Claim).UID + role := claim.(*global.Claim).Role req := new(createRequest) if err := c.ShouldBind(req); err != nil { @@ -40,6 +42,12 @@ func (h *handler) Create(c *gin.Context) { return } + // guest can not submit + if role < model.RoleGeneral { + e.Pong(c, e.UserUnauthorized, nil) + return + } + createData := &submission.CreateData{ ProblemID: req.Pid, UserID: uid, @@ -58,7 +66,12 @@ func (h *handler) Create(c *gin.Context) { return } - _, status = h.taskService.SubmitJudge(pv.ID, pv.StorageKey, *s) + payload := &model.SubmitJudgePayload{ + ProblemVersionID: pv.ID, + StorageKey: pv.StorageKey, + Submission: *s, + } + _, status = h.taskService.SubmitJudge(payload) + e.Pong(c, status, nil) - return } diff --git a/internal/api/submission/handler.go b/internal/api/submission/handler.go index 9a0c9c3..a23aff5 100644 --- a/internal/api/submission/handler.go +++ b/internal/api/submission/handler.go @@ -15,6 +15,7 @@ var _ Handler = (*handler)(nil) type Handler interface { Create(c *gin.Context) Query(c *gin.Context) + Rejudge(c *gin.Context) } type handler struct { @@ -38,4 +39,5 @@ func RouteRegister(g *global.Global, group *gin.RouterGroup) { group.POST("/create", app.jwtService.Handler(true), app.Create) group.POST("/query", app.Query) + group.POST("/rejudge", app.jwtService.Handler(true), app.Rejudge) } diff --git a/internal/api/submission/query.go b/internal/api/submission/query.go index 7259fdf..e3e6126 100644 --- a/internal/api/submission/query.go +++ b/internal/api/submission/query.go @@ -10,7 +10,7 @@ type queryRequest struct { Pid uint `form:"pid"` Uid uint `form:"uid"` Offset int `form:"offset"` - Limit int `form:"limit"` + Limit int `form:"limit" binding:"required"` } type queryResponse struct { @@ -23,10 +23,10 @@ type queryResponse struct { // @Description Query submissions // @Accept application/x-www-form-urlencoded // @Produce json -// @Param pid formData uint false "problem id" -// @Param uid formData uint false "user id" -// @Param offset formData int false "start position" -// @Param limit formData int false "limit number of records" +// @Param pid formData uint true "problem id" +// @Param uid formData uint true "user id" +// @Param offset formData int true "start position" +// @Param limit formData int true "limit number of records" // @Response 200 {object} e.Response "queryResponse" // @Router /v1/submission/query [post] @@ -67,7 +67,5 @@ func (h *handler) Query(c *gin.Context) { response = append(response, newResponse) } - e.Pong(c, status, submissions) - return - + e.Pong(c, status, response) } diff --git a/internal/api/submission/rejudge.go b/internal/api/submission/rejudge.go new file mode 100644 index 0000000..7d87250 --- /dev/null +++ b/internal/api/submission/rejudge.go @@ -0,0 +1,63 @@ +package submission + +import ( + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/WHUPRJ/woj-server/internal/model" + "github.com/gin-gonic/gin" +) + +type rejudgeRequest struct { + Sid uint `form:"sid" binding:"required"` +} + +// Rejudge +// @Summary rejudge a submission +// @Description rejudge a submission +// @Accept application/x-www-form-urlencoded +// @Produce json +// @Param sid formData int true "submission id" +// @Response 200 {object} e.Response "" +// @Security Authentication +// @Router /v1/submission/rejudge [post] +func (h *handler) Rejudge(c *gin.Context) { + claim, exist := c.Get("claim") + if !exist { + e.Pong(c, e.UserUnauthenticated, nil) + return + } + + role := claim.(*global.Claim).Role + req := new(rejudgeRequest) + + if err := c.ShouldBind(req); err != nil { + e.Pong(c, e.InvalidParameter, err.Error()) + return + } + + // only admin can rejudge + if role < model.RoleAdmin { + e.Pong(c, e.UserUnauthorized, nil) + return + } + + s, status := h.submissionService.QueryBySid(req.Sid, false) + if status != e.Success { + e.Pong(c, status, nil) + return + } + + pv, status := h.problemService.QueryLatestVersion(s.ProblemID) + if status != e.Success { + e.Pong(c, status, nil) + return + } + + _, status = h.taskService.SubmitJudge(&model.SubmitJudgePayload{ + ProblemVersionID: pv.ID, + StorageKey: pv.StorageKey, + Submission: *s, + }) + + e.Pong(c, status, nil) +} diff --git a/internal/api/user/create.go b/internal/api/user/create.go index f8c8fb0..ba224e1 100644 --- a/internal/api/user/create.go +++ b/internal/api/user/create.go @@ -55,5 +55,4 @@ func (h *handler) Create(c *gin.Context) { } token, status := h.jwtService.SignClaim(claim) e.Pong(c, status, token) - return } diff --git a/internal/api/user/logout.go b/internal/api/user/logout.go index c2554ec..f9a288c 100644 --- a/internal/api/user/logout.go +++ b/internal/api/user/logout.go @@ -23,5 +23,4 @@ func (h *handler) Logout(c *gin.Context) { _, status := h.userService.IncrVersion(claim.(*global.Claim).UID) e.Pong(c, status, nil) - return } diff --git a/internal/api/user/profile.go b/internal/api/user/profile.go index 072ed3a..bc23f9e 100644 --- a/internal/api/user/profile.go +++ b/internal/api/user/profile.go @@ -47,6 +47,8 @@ func (h *handler) Profile(c *gin.Context) { } user, status := h.userService.Profile(req.UID) + + // TODO: >= admin can see is_enable + e.Pong(c, status, user) - return } diff --git a/internal/app/server/server.go b/internal/app/server/server.go index ed7d4a9..c46b94a 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "fmt" + "github.com/WHUPRJ/woj-server/internal/api/consumer" "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/model" "github.com/WHUPRJ/woj-server/internal/repo/postgresql" @@ -52,9 +53,11 @@ func RunServer(g *global.Global) error { // Create Queue queueMux := asynq.NewServeMux() - // TODO: fill - queueMux.HandleFunc(model.TypeProblemUpdate, func(ctx context.Context, t *asynq.Task) error { return nil }) - queueMux.HandleFunc(model.TypeSubmitUpdate, func(ctx context.Context, t *asynq.Task) error { return nil }) + { + handler := consumer.NewConsumer(g) + queueMux.HandleFunc(model.TypeProblemUpdate, handler.ProblemUpdate) + queueMux.HandleFunc(model.TypeSubmitUpdate, handler.SubmitUpdate) + } queueSrv := asynq.NewServer( asynq.RedisClientOpt{ Addr: g.Conf.Redis.Address, diff --git a/internal/e/code.go b/internal/e/code.go index 9161c73..df0f552 100644 --- a/internal/e/code.go +++ b/internal/e/code.go @@ -37,6 +37,7 @@ const ( ProblemNotAvailable ProblemVersionNotFound ProblemVersionNotAvailable + SubmissionNotFound StatusNotFound ) @@ -58,6 +59,11 @@ const ( RunnerJudgeFailed ) +const ( + StorageUploadFailed Status = 800 + iota + StorageGetFailed +) + var msgText = map[Status]string{ Success: "Success", Unknown: "Unknown error", @@ -88,6 +94,8 @@ var msgText = map[Status]string{ ProblemVersionNotFound: "Problem Version Not Found", ProblemVersionNotAvailable: "Problem Version Not Available", + SubmissionNotFound: "Submission Not Found", + StatusNotFound: "Status Not Found", TaskEnqueueFailed: "Task Enqueue Failed", @@ -103,4 +111,7 @@ var msgText = map[Status]string{ RunnerUserCompileFailed: "Runner User Compile Failed", RunnerRunFailed: "Runner Run Failed", RunnerJudgeFailed: "Runner Judge Failed", + + StorageUploadFailed: "Storage Upload Failed", + StorageGetFailed: "Storage Get Failed", } diff --git a/internal/e/resp.go b/internal/e/resp.go index b3a8e4c..4ea2ae5 100644 --- a/internal/e/resp.go +++ b/internal/e/resp.go @@ -24,3 +24,12 @@ func Pong(c *gin.Context, status Status, body interface{}) { c.Set("err", status) c.JSON(http.StatusOK, Wrap(status, body)) } + +type Endpoint func(*gin.Context) (Status, interface{}) + +func PongWrapper(handler Endpoint) func(*gin.Context) { + return func(c *gin.Context) { + status, body := handler(c) + Pong(c, status, body) + } +} diff --git a/internal/global/config.go b/internal/global/config.go index e478dee..0eaaa19 100644 --- a/internal/global/config.go +++ b/internal/global/config.go @@ -26,6 +26,14 @@ type ConfigDatabase struct { ConnMaxLifetime int `yaml:"ConnMaxLifetime"` } +type ConfigStorage struct { + Endpoint string `yaml:"Endpoint"` + UseSSL bool `yaml:"UseSSL"` + AccessKey string `yaml:"AccessKey"` + SecretKey string `yaml:"SecretKey"` + Bucket string `yaml:"Bucket"` +} + type ConfigMetrics struct { Namespace string `yaml:"Namespace"` Subsystem string `yaml:"Subsystem"` @@ -35,6 +43,7 @@ type Config struct { WebServer ConfigWebServer `yaml:"WebServer"` Redis ConfigRedis `yaml:"Redis"` Database ConfigDatabase `yaml:"Database"` + Storage ConfigStorage `yaml:"Storage"` Metrics ConfigMetrics `yaml:"Metrics"` Development bool `yaml:"Development"` } diff --git a/internal/model/Task.go b/internal/model/Task.go index ad2096a..fc8a529 100644 --- a/internal/model/Task.go +++ b/internal/model/Task.go @@ -18,7 +18,7 @@ const ( type ProblemBuildPayload struct { ProblemVersionID uint - ProblemFile string + StorageKey string } type ProblemUpdatePayload struct { @@ -28,14 +28,15 @@ type ProblemUpdatePayload struct { } type SubmitJudgePayload struct { - ProblemVersionId uint + ProblemVersionID uint StorageKey string Submission Submission } type SubmitUpdatePayload struct { - Status e.Status - Sid uint - Point int32 - Context string + Status e.Status + SubmissionID uint + ProblemVersionID uint + Point int32 + Context string } diff --git a/internal/repo/postgresql/postgresql.go b/internal/repo/postgresql/postgresql.go index 15b0226..4a5ae90 100644 --- a/internal/repo/postgresql/postgresql.go +++ b/internal/repo/postgresql/postgresql.go @@ -83,7 +83,9 @@ func (r *Repo) migrateDatabase() { _ = 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 diff --git a/internal/service/problem/createVersion.go b/internal/service/problem/createVersion.go index f355c6a..b63a9d0 100644 --- a/internal/service/problem/createVersion.go +++ b/internal/service/problem/createVersion.go @@ -3,6 +3,7 @@ package problem import ( "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/model" + "github.com/jackc/pgtype" "go.uber.org/zap" ) @@ -14,6 +15,7 @@ type CreateVersionData struct { func (s *service) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) { problemVersion := &model.ProblemVersion{ ProblemID: data.ProblemID, + Context: pgtype.JSON{Status: pgtype.Null}, StorageKey: data.StorageKey, } diff --git a/internal/service/problem/service.go b/internal/service/problem/service.go index 8e6df02..0dd05af 100644 --- a/internal/service/problem/service.go +++ b/internal/service/problem/service.go @@ -17,7 +17,7 @@ type Service interface { QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) - UpdateVersion(problemVersion *model.ProblemVersion) (*model.ProblemVersion, e.Status) + UpdateVersion(pvid uint, values interface{}) e.Status QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status) QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status) } diff --git a/internal/service/problem/updateVersion.go b/internal/service/problem/updateVersion.go index c5e360c..de8230c 100644 --- a/internal/service/problem/updateVersion.go +++ b/internal/service/problem/updateVersion.go @@ -6,12 +6,12 @@ import ( "go.uber.org/zap" ) -func (s *service) UpdateVersion(problemVersion *model.ProblemVersion) (*model.ProblemVersion, e.Status) { - err := s.db.Save(problemVersion).Error +func (s *service) UpdateVersion(pvid uint, values interface{}) e.Status { + err := s.db.Model(&model.ProblemVersion{}).Where("id = ?", pvid).Updates(values).Error if err != nil { - s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problemVersion", problemVersion)) - return nil, e.DatabaseError + s.log.Warn("DatabaseError", zap.Error(err), zap.Any("pvid", pvid), zap.Any("values", values)) + return e.DatabaseError } - return problemVersion, e.Success + return e.Success } diff --git a/internal/service/runner/common.go b/internal/service/runner/common.go index 01260c7..24eba47 100644 --- a/internal/service/runner/common.go +++ b/internal/service/runner/common.go @@ -13,9 +13,9 @@ import ( var ( Prefix = "./resource/runner" - ProblemDir = "./problems/" + ProblemDir = "./problem/" ScriptsDir = "./scripts/" - UserDir = "./users/" + UserDir = "./user/" TmpDir = "./tmp/" ) @@ -40,7 +40,7 @@ func (s *service) execute(script string, args ...string) error { } func (s *service) checkAndExecute(version uint, user string, lang string, script string, fail e.Status) e.Status { - if !s.problemExists(version) { + if !s.ProblemExists(version) { s.log.Info("problem not exists", zap.Uint("version", version)) return e.RunnerProblemNotExist } @@ -50,7 +50,7 @@ func (s *service) checkAndExecute(version uint, user string, lang string, script return e.RunnerUserNotExist } - err := s.execute(script, fmt.Sprintf("%d", version), fmt.Sprintf("%s", user), lang) + err := s.execute(script, fmt.Sprintf("%d", version), user, lang) if err != nil { s.log.Info("execute failed", @@ -64,12 +64,12 @@ func (s *service) checkAndExecute(version uint, user string, lang string, script return e.Success } -func (s *service) problemExists(version uint) bool { +func (s *service) ProblemExists(version uint) bool { problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", version)) return utils.FileExist(problemPath) } func (s *service) userExists(user string, file string) bool { - userPath := filepath.Join(UserDir, fmt.Sprintf("%s", user), file) + userPath := filepath.Join(UserDir, user, file) return utils.FileExist(userPath) } diff --git a/internal/service/runner/compile.go b/internal/service/runner/compile.go index 2b0b270..62ad6c0 100644 --- a/internal/service/runner/compile.go +++ b/internal/service/runner/compile.go @@ -9,22 +9,22 @@ import ( ) func (s *service) Compile(version uint, user string, lang string) (JudgeStatus, e.Status) { - target := filepath.Join(UserDir, fmt.Sprintf("%s", user), fmt.Sprintf("%s.out", user)) + target := filepath.Join(UserDir, user, fmt.Sprintf("%s.out", user)) _ = os.Remove(target) status := s.checkAndExecute(version, user, lang, "problem_compile.sh", e.RunnerUserCompileFailed) - log := filepath.Join(UserDir, fmt.Sprintf("%s.compile.log", user)) + log := filepath.Join(UserDir, user, fmt.Sprintf("%s.compile.log", user)) msg, err := utils.FileRead(log) msg = utils.If(err == nil, msg, nil).([]byte) msgText := string(msg) - if utils.FileExist(target) { - return JudgeStatus{}, e.Success - } else { + if !utils.FileExist(target) || utils.FileEmpty(target) { return JudgeStatus{ Message: "compile failed", Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}}, utils.If(status == e.Success, e.RunnerUserCompileFailed, status).(e.Status) } + + return JudgeStatus{}, e.Success } diff --git a/internal/service/runner/newProblem.go b/internal/service/runner/newProblem.go index 6c9c91a..79f969f 100644 --- a/internal/service/runner/newProblem.go +++ b/internal/service/runner/newProblem.go @@ -31,7 +31,7 @@ func (s *service) download(version uint, url string) e.Status { } func (s *service) prebuild(version uint, force bool) e.Status { - if !s.problemExists(version) { + if !s.ProblemExists(version) { return e.RunnerProblemNotExist } @@ -52,10 +52,17 @@ func (s *service) prebuild(version uint, force bool) e.Status { return e.Success } -func (s *service) NewProblem(version uint, url string) (Config, e.Status) { - status := s.download(version, url) - if status != e.Success { - return Config{}, status +func (s *service) NewProblem(version uint, url string, force bool) (Config, e.Status) { + if force { + problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", version)) + _ = os.RemoveAll(problemPath) + } + + if !s.ProblemExists(version) { + status := s.download(version, url) + if status != e.Success { + return Config{}, status + } } cfg, err := s.ParseConfig(version, false) @@ -63,7 +70,7 @@ func (s *service) NewProblem(version uint, url string) (Config, e.Status) { return Config{}, e.RunnerProblemParseFailed } - status = s.prebuild(version, true) + status := s.prebuild(version, true) if status != e.Success { return Config{}, status } diff --git a/internal/service/runner/service.go b/internal/service/runner/service.go index b4fd57b..d9322ac 100644 --- a/internal/service/runner/service.go +++ b/internal/service/runner/service.go @@ -12,7 +12,7 @@ type Service interface { // EnsureDeps build docker images EnsureDeps(force bool) e.Status // NewProblem = Download + Parse + Prebuild - NewProblem(version uint, url string) (Config, e.Status) + NewProblem(version uint, url string, force bool) (Config, e.Status) // Compile compile user submission Compile(version uint, user string, lang string) (JudgeStatus, e.Status) @@ -21,6 +21,8 @@ type Service interface { // ParseConfig parse config file ParseConfig(version uint, skipCheck bool) (Config, error) + // ProblemExists check if problem exists + ProblemExists(version uint) bool } type service struct { diff --git a/internal/service/runner/status.go b/internal/service/runner/status.go index 8c9ddbe..6336b95 100644 --- a/internal/service/runner/status.go +++ b/internal/service/runner/status.go @@ -202,7 +202,7 @@ func (s *service) checkResults(user string, config *Config) (JudgeStatus, int32) } var results []TaskStatus - dir := filepath.Join(UserDir, fmt.Sprintf("%s", user)) + dir := filepath.Join(UserDir, user) var sum int32 = 0 for i := 1; i <= len(config.Tasks); i++ { @@ -213,14 +213,15 @@ func (s *service) checkResults(user string, config *Config) (JudgeStatus, int32) result.getInfoText(info). getInfo(). - checkExit(). checkTime(config). checkMemory(config). + checkExit(). getJudgeText(judge). getJudge(). checkJudge(&pts) sum += result.Points + results = append(results, result) } return JudgeStatus{Message: "", Tasks: results}, sum diff --git a/internal/service/status/create.go b/internal/service/status/create.go index ad8093f..4c863d6 100644 --- a/internal/service/status/create.go +++ b/internal/service/status/create.go @@ -10,17 +10,20 @@ import ( type CreateData struct { SubmissionID uint ProblemVersionID uint - Context pgtype.JSON + Context string Point int32 } -func (s service) Create(data *model.Status) (*model.Status, e.Status) { +func (s service) Create(data *CreateData) (*model.Status, e.Status) { status := &model.Status{ SubmissionID: data.SubmissionID, ProblemVersionID: data.ProblemVersionID, - Context: data.Context, - Point: data.Point, - IsEnabled: true, + Context: pgtype.JSON{ + Bytes: []byte(data.Context), + Status: pgtype.Present, + }, + Point: data.Point, + IsEnabled: true, } err := s.db.Create(status).Error diff --git a/internal/service/status/rejudge.go b/internal/service/status/rejudge.go deleted file mode 100644 index 919b0db..0000000 --- a/internal/service/status/rejudge.go +++ /dev/null @@ -1,11 +0,0 @@ -package status - -import ( - "github.com/WHUPRJ/woj-server/internal/e" - "github.com/WHUPRJ/woj-server/internal/model" -) - -func (s service) Rejudge(statusID uint) ([]*model.Status, e.Status) { - //TODO implement me - panic("implement me") -} diff --git a/internal/service/status/service.go b/internal/service/status/service.go index 221b83f..70a95b8 100644 --- a/internal/service/status/service.go +++ b/internal/service/status/service.go @@ -11,10 +11,9 @@ import ( var _ Service = (*service)(nil) type Service interface { - Create(*model.Status) (*model.Status, e.Status) + Create(data *CreateData) (*model.Status, e.Status) Query(sid uint, associations bool) (*model.Status, e.Status) QueryByVersion(pvid uint, offset int, limit int) ([]*model.Status, e.Status) - Rejudge(statusID uint) ([]*model.Status, e.Status) } type service struct { diff --git a/internal/service/storage/get.go b/internal/service/storage/get.go new file mode 100644 index 0000000..c65f3cd --- /dev/null +++ b/internal/service/storage/get.go @@ -0,0 +1,30 @@ +package storage + +import ( + "context" + "github.com/WHUPRJ/woj-server/internal/e" + "go.uber.org/zap" + "net/url" + "time" +) + +func (s *service) Get(objectName string, expiry time.Duration) (string, e.Status) { + preSignedURL, err := s.client.PresignedGetObject( + context.Background(), + s.bucket, + objectName, + expiry, + url.Values{}, + ) + + if err != nil { + s.log.Warn("failed to generate pre-signed get url", + zap.Error(err), + zap.String("objectName", objectName), + zap.Duration("expiry", expiry), + ) + return "", e.StorageGetFailed + } + + return preSignedURL.String(), e.Success +} diff --git a/internal/service/storage/service.go b/internal/service/storage/service.go new file mode 100644 index 0000000..633b336 --- /dev/null +++ b/internal/service/storage/service.go @@ -0,0 +1,41 @@ +package storage + +import ( + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "go.uber.org/zap" + "time" +) + +var _ Service = (*service)(nil) + +type Service interface { + Upload(objectName string, expiry time.Duration) (string, e.Status) + Get(objectName string, expiry time.Duration) (string, e.Status) +} + +type service struct { + log *zap.Logger + client *minio.Client + bucket string +} + +func NewService(g *global.Global) Service { + minioClient, err := minio.New(g.Conf.Storage.Endpoint, &minio.Options{ + 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, + } +} diff --git a/internal/service/storage/upload.go b/internal/service/storage/upload.go new file mode 100644 index 0000000..69e7627 --- /dev/null +++ b/internal/service/storage/upload.go @@ -0,0 +1,28 @@ +package storage + +import ( + "context" + "github.com/WHUPRJ/woj-server/internal/e" + "go.uber.org/zap" + "time" +) + +func (s *service) Upload(objectName string, expiry time.Duration) (string, e.Status) { + preSignedURL, err := s.client.PresignedPutObject( + context.Background(), + s.bucket, + objectName, + expiry, + ) + + if err != nil { + s.log.Warn("failed to generate pre-signed upload url", + zap.Error(err), + zap.String("objectName", objectName), + zap.Duration("expiry", expiry), + ) + return "", e.StorageUploadFailed + } + + return preSignedURL.String(), e.Success +} diff --git a/internal/service/submission/query.go b/internal/service/submission/query.go index 1a3838b..7dc6e7f 100644 --- a/internal/service/submission/query.go +++ b/internal/service/submission/query.go @@ -1,9 +1,11 @@ package submission import ( + "errors" "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/model" "go.uber.org/zap" + "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -31,3 +33,25 @@ func (s *service) Query(pid uint, uid uint, offset int, limit int) ([]*model.Sub } return submissions, e.Success } + +func (s *service) QueryBySid(sid uint, associations bool) (*model.Submission, e.Status) { + submission := new(model.Submission) + + query := s.db + if associations { + query = query.Preload(clause.Associations) + } + + err := query.First(&submission, sid).Error + + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, e.SubmissionNotFound + } + + if err != nil { + s.log.Warn("DatabaseError", zap.Error(err), zap.Any("sid", sid)) + return nil, e.DatabaseError + } + + return submission, e.Success +} diff --git a/internal/service/submission/service.go b/internal/service/submission/service.go index 4c8de37..b5e8095 100644 --- a/internal/service/submission/service.go +++ b/internal/service/submission/service.go @@ -13,6 +13,7 @@ var _ Service = (*service)(nil) type Service interface { Create(data *CreateData) (*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) } type service struct { diff --git a/internal/service/task/common.go b/internal/service/task/common.go index b626d6b..e88844c 100644 --- a/internal/service/task/common.go +++ b/internal/service/task/common.go @@ -15,8 +15,6 @@ func (s *service) submit(typename string, payload []byte, queue string) (*asynq. return nil, e.TaskEnqueueFailed } - s.log.Debug("Successfully enqueued task", zap.Any("info", info)) - return info, e.Success } diff --git a/internal/service/task/problem.go b/internal/service/task/problem.go index 818934a..327b003 100644 --- a/internal/service/task/problem.go +++ b/internal/service/task/problem.go @@ -7,16 +7,13 @@ import ( "go.uber.org/zap" ) -func (s *service) ProblemBuild(pvId uint, file string) (string, e.Status) { - payload, err := json.Marshal(model.ProblemBuildPayload{ - ProblemVersionID: pvId, - ProblemFile: file, - }) +func (s *service) ProblemBuild(data *model.ProblemBuildPayload) (string, e.Status) { + payload, err := json.Marshal(data) if err != nil { s.log.Warn("json marshal error", zap.Error(err), - zap.Any("ProblemVersionID", pvId), - zap.String("ProblemFile", file)) + zap.Any("data", data), + ) return "", e.InternalError } @@ -25,18 +22,13 @@ func (s *service) ProblemBuild(pvId uint, file string) (string, e.Status) { return info.ID, status } -func (s *service) ProblemUpdate(status e.Status, pvId uint, ctx string) (string, e.Status) { - payload, err := json.Marshal(model.ProblemUpdatePayload{ - Status: status, - ProblemVersionID: pvId, - Context: ctx, - }) +func (s *service) ProblemUpdate(data *model.ProblemUpdatePayload) (string, e.Status) { + payload, err := json.Marshal(data) if err != nil { s.log.Warn("json marshal error", zap.Error(err), - zap.Any("Status", status), - zap.Any("ProblemVersionID", pvId), - zap.Any("Context", ctx)) + zap.Any("data", data), + ) return "", e.InternalError } diff --git a/internal/service/task/service.go b/internal/service/task/service.go index af64354..f1931bd 100644 --- a/internal/service/task/service.go +++ b/internal/service/task/service.go @@ -12,10 +12,10 @@ import ( var _ Service = (*service)(nil) type Service interface { - ProblemBuild(pvId uint, file string) (string, e.Status) - ProblemUpdate(status e.Status, pvId uint, ctx string) (string, e.Status) - SubmitJudge(pvid uint, storageKey string, submission model.Submission) (string, e.Status) - SubmitUpdate(status e.Status, sid uint, point int32, ctx runner.JudgeStatus) (string, e.Status) + ProblemBuild(data *model.ProblemBuildPayload) (string, e.Status) + ProblemUpdate(data *model.ProblemUpdatePayload) (string, e.Status) + SubmitJudge(data *model.SubmitJudgePayload) (string, e.Status) + SubmitUpdate(data *model.SubmitUpdatePayload, ctx runner.JudgeStatus) (string, e.Status) GetTaskInfo(string, string) (*asynq.TaskInfo, e.Status) } diff --git a/internal/service/task/submit.go b/internal/service/task/submit.go index 4c3e0e7..c588c6b 100644 --- a/internal/service/task/submit.go +++ b/internal/service/task/submit.go @@ -8,15 +8,13 @@ import ( "go.uber.org/zap" ) -func (s *service) SubmitJudge(pvid uint, storageKey string, submission model.Submission) (string, e.Status) { - payload, err := json.Marshal( - model.SubmitJudgePayload{ - ProblemVersionId: pvid, - StorageKey: storageKey, - Submission: submission, - }) +func (s *service) SubmitJudge(data *model.SubmitJudgePayload) (string, e.Status) { + payload, err := json.Marshal(data) if err != nil { - s.log.Warn("json marshal error", zap.Error(err), zap.Any("Submission", submission)) + s.log.Warn("json marshal error", + zap.Error(err), + zap.Any("data", data), + ) return "", e.InternalError } @@ -25,7 +23,7 @@ func (s *service) SubmitJudge(pvid uint, storageKey string, submission model.Sub return info.ID, status } -func (s *service) SubmitUpdate(status e.Status, sid uint, point int32, ctx runner.JudgeStatus) (string, e.Status) { +func (s *service) SubmitUpdate(data *model.SubmitUpdatePayload, ctx runner.JudgeStatus) (string, e.Status) { ctxText, err := json.Marshal(ctx) if err != nil { s.log.Warn("json marshal error", @@ -34,18 +32,14 @@ func (s *service) SubmitUpdate(status e.Status, sid uint, point int32, ctx runne return "", e.InternalError } - payload, err := json.Marshal(model.SubmitUpdatePayload{ - Status: status, - Sid: sid, - Point: point, - Context: string(ctxText), - }) + data.Context = string(ctxText) + payload, err := json.Marshal(data) if err != nil { s.log.Warn("json marshal error", zap.Error(err), - zap.Any("Status", status), - zap.Int32("Point", point), - zap.Any("Context", ctx)) + zap.Any("data", data), + zap.Any("Context", ctx), + ) return "", e.InternalError } diff --git a/pkg/utils/file.go b/pkg/utils/file.go index 5857aac..9ae7939 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -23,6 +23,14 @@ func FileExist(filePath string) bool { return If(err == nil || os.IsExist(err), true, false).(bool) } +func FileEmpty(filePath string) bool { + stat, err := os.Stat(filePath) + if err != nil { + return true + } + return stat.Size() == 0 +} + func FileTouch(filePath string) bool { base := filepath.Dir(filePath) _ = os.MkdirAll(base, 0755) diff --git a/resource/runner/scripts/problem_run.sh b/resource/runner/scripts/problem_run.sh index 8168fd4..3fb4ae3 100755 --- a/resource/runner/scripts/problem_run.sh +++ b/resource/runner/scripts/problem_run.sh @@ -31,7 +31,7 @@ log_info "NProcLimit: $Info_Limit_NProc" # launcher will add 2 more seconds # here add 3 more seconds -TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 3)) +TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 4)) log_info "Timeout: $TIMEOUT" for test_num in $(seq "$Info_Num"); do