feat: another big update
1. add consumer 2. add createVersion 3. add upload 4. fix runner 5. add rejudge Co-authored-by: cxy004 <cxy004@qq.com> Co-authored-by: wzt <w.zhongtao@qq.com>
This commit is contained in:
parent
d42ee0ce54
commit
26a81652b3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
### Project
|
### Project
|
||||||
|
/tmp
|
||||||
/server
|
/server
|
||||||
/runner
|
/runner
|
||||||
my.secrets
|
my.secrets
|
||||||
|
@ -21,6 +21,13 @@ Database:
|
|||||||
MaxIdleConns: 60
|
MaxIdleConns: 60
|
||||||
ConnMaxLifetime: 60
|
ConnMaxLifetime: 60
|
||||||
|
|
||||||
|
Storage:
|
||||||
|
Endpoint: '127.0.0.1:9000'
|
||||||
|
UseSSL: false
|
||||||
|
AccessKey: 'EHd5Zj56QrTivhFI'
|
||||||
|
SecretKey: 'FUHy4RW1mn0Kbr5pibDZ6R2F9116FZKY'
|
||||||
|
Bucket: 'woj'
|
||||||
|
|
||||||
Metrics:
|
Metrics:
|
||||||
Namespace: 'OJ'
|
Namespace: 'OJ'
|
||||||
Subsystem: 'server'
|
Subsystem: 'server'
|
||||||
|
13
go.mod
13
go.mod
@ -11,13 +11,14 @@ require (
|
|||||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||||
github.com/hibiken/asynq v0.23.0
|
github.com/hibiken/asynq v0.23.0
|
||||||
github.com/jackc/pgtype v1.11.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/prometheus/client_golang v1.13.0
|
||||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
|
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
|
||||||
github.com/swaggo/gin-swagger v1.5.3
|
github.com/swaggo/gin-swagger v1.5.3
|
||||||
github.com/swaggo/swag v1.8.5
|
github.com/swaggo/swag v1.8.5
|
||||||
github.com/urfave/cli/v2 v2.14.1
|
github.com/urfave/cli/v2 v2.14.1
|
||||||
go.uber.org/zap v1.23.0
|
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
|
golang.org/x/text v0.3.7
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/driver/postgres v1.3.9
|
gorm.io/driver/postgres v1.3.9
|
||||||
@ -33,6 +34,7 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.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/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/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // 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/jinzhu/now v1.1.4 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // 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/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.6 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // 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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1 // 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/common v0.37.0 // indirect
|
||||||
github.com/prometheus/procfs v0.8.0 // indirect
|
github.com/prometheus/procfs v0.8.0 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // 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/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/spf13/cast v1.5.0 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/multierr 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/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // 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
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
28
go.sum
28
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/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 h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
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.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.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
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.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
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/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.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.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=
|
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/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 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
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-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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
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 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
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.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.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||||
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.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
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.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/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/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=
|
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-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-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-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-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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
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-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-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-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-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-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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-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-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-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 h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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=
|
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
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/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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
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=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
36
internal/api/consumer/handler.go
Normal file
36
internal/api/consumer/handler.go
Normal file
@ -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
|
||||||
|
}
|
40
internal/api/consumer/problemUpdate.go
Normal file
40
internal/api/consumer/problemUpdate.go
Normal file
@ -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
|
||||||
|
}
|
37
internal/api/consumer/submitUpdate.go
Normal file
37
internal/api/consumer/submitUpdate.go
Normal file
@ -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
|
||||||
|
}
|
67
internal/api/problem/createVersion.go
Normal file
67
internal/api/problem/createVersion.go
Normal file
@ -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)
|
||||||
|
}
|
@ -37,9 +37,11 @@ func (h *handler) Details(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pv, status := h.problemService.QueryLatestVersion(req.Pid)
|
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,
|
"problem": p,
|
||||||
"context": pv.Context,
|
"context": pv.Context.Get(),
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package problem
|
|||||||
import (
|
import (
|
||||||
"github.com/WHUPRJ/woj-server/internal/global"
|
"github.com/WHUPRJ/woj-server/internal/global"
|
||||||
"github.com/WHUPRJ/woj-server/internal/service/problem"
|
"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"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
@ -13,12 +15,15 @@ type Handler interface {
|
|||||||
Details(c *gin.Context)
|
Details(c *gin.Context)
|
||||||
Search(c *gin.Context)
|
Search(c *gin.Context)
|
||||||
Update(c *gin.Context)
|
Update(c *gin.Context)
|
||||||
|
Upload(c *gin.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
jwtService global.JwtService
|
jwtService global.JwtService
|
||||||
problemService problem.Service
|
problemService problem.Service
|
||||||
|
taskService task.Service
|
||||||
|
storageService storage.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
||||||
@ -26,9 +31,13 @@ func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
|||||||
log: g.Log,
|
log: g.Log,
|
||||||
jwtService: g.Jwt,
|
jwtService: g.Jwt,
|
||||||
problemService: problem.NewService(g),
|
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("/search", app.Search)
|
||||||
|
group.POST("/details", app.jwtService.Handler(false), app.Details)
|
||||||
group.POST("/update", app.jwtService.Handler(true), app.Update)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,12 @@ func (h *handler) Search(c *gin.Context) {
|
|||||||
// TODO: pagination
|
// TODO: pagination
|
||||||
if req.Search == "" {
|
if req.Search == "" {
|
||||||
// TODO: query without LIKE
|
// TODO: query without LIKE
|
||||||
problem, status := h.problemService.QueryFuzz(req.Search, true, true)
|
problems, status := h.problemService.QueryFuzz(req.Search, true, true)
|
||||||
e.Pong(c, status, problem)
|
e.Pong(c, status, problems)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
problem, status := h.problemService.QueryFuzz(req.Search, true, true)
|
problems, status := h.problemService.QueryFuzz(req.Search, true, true)
|
||||||
e.Pong(c, status, problem)
|
e.Pong(c, status, problems)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
internal/api/problem/upload.go
Normal file
44
internal/api/problem/upload.go
Normal file
@ -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,
|
||||||
|
})
|
||||||
|
}
|
@ -4,14 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/WHUPRJ/woj-server/internal/e"
|
||||||
"github.com/WHUPRJ/woj-server/internal/model"
|
"github.com/WHUPRJ/woj-server/internal/model"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) Build(_ context.Context, t *asynq.Task) error {
|
func (h *handler) Build(_ context.Context, t *asynq.Task) error {
|
||||||
// TODO: configure timeout with context
|
|
||||||
|
|
||||||
var p model.ProblemBuildPayload
|
var p model.ProblemBuildPayload
|
||||||
if err := json.Unmarshal(t.Payload(), &p); err != nil {
|
if err := json.Unmarshal(t.Payload(), &p); err != nil {
|
||||||
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
|
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))
|
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, status := h.runnerService.NewProblem(p.ProblemVersionID, url, true)
|
||||||
config.Languages[i].Type = ""
|
if status != e.Success {
|
||||||
config.Languages[i].Script = ""
|
return e.InternalError, "{}"
|
||||||
config.Languages[i].Cmp = ""
|
}
|
||||||
}
|
|
||||||
|
|
||||||
b, _ := json.Marshal(config)
|
for i := range config.Languages {
|
||||||
h.taskService.ProblemUpdate(status, p.ProblemVersionID, string(b))
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/WHUPRJ/woj-server/internal/e"
|
"github.com/WHUPRJ/woj-server/internal/e"
|
||||||
"github.com/WHUPRJ/woj-server/internal/global"
|
"github.com/WHUPRJ/woj-server/internal/global"
|
||||||
"github.com/WHUPRJ/woj-server/internal/service/runner"
|
"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/WHUPRJ/woj-server/internal/service/task"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -19,16 +20,18 @@ type Handler interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
runnerService runner.Service
|
runnerService runner.Service
|
||||||
taskService task.Service
|
taskService task.Service
|
||||||
|
storageService storage.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRunner(g *global.Global) (Handler, error) {
|
func NewRunner(g *global.Global) (Handler, error) {
|
||||||
hnd := &handler{
|
hnd := &handler{
|
||||||
log: g.Log,
|
log: g.Log,
|
||||||
runnerService: runner.NewService(g),
|
runnerService: runner.NewService(g),
|
||||||
taskService: task.NewService(g),
|
taskService: task.NewService(g),
|
||||||
|
storageService: storage.NewService(g),
|
||||||
}
|
}
|
||||||
|
|
||||||
status := hnd.runnerService.EnsureDeps(false)
|
status := hnd.runnerService.EnsureDeps(false)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
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)
|
user := utils.RandomString(16)
|
||||||
h.log.Info("judge", zap.Any("payload", p), zap.String("user", user))
|
h.log.Info("judge", zap.Any("payload", p), zap.String("user", user))
|
||||||
|
|
||||||
// common
|
status, point, ctx := func() (e.Status, int32, runner.JudgeStatus) {
|
||||||
systemError := runner.JudgeStatus{Message: "System Error"}
|
systemError := runner.JudgeStatus{Message: "System Error"}
|
||||||
|
|
||||||
// write code
|
// 1. write user code
|
||||||
userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language))
|
userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language))
|
||||||
if !utils.FileTouch(userCode) {
|
if !utils.FileTouch(userCode) {
|
||||||
h.log.Info("Touch file failed", zap.String("userCode", userCode))
|
return e.InternalError, 0, systemError
|
||||||
h.taskService.SubmitUpdate(e.InternalError, p.ProblemVersionId, 0, systemError)
|
}
|
||||||
return nil
|
err := utils.FileWrite(userCode, []byte(p.Submission.Code))
|
||||||
}
|
if err != nil {
|
||||||
err := utils.FileWrite(userCode, []byte(p.Submission.Code))
|
return e.InternalError, 0, systemError
|
||||||
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
|
|
||||||
}
|
}
|
||||||
} else if status != e.Success {
|
|
||||||
h.taskService.SubmitUpdate(status, p.Submission.ID, 0, result)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// config
|
// 2. check problem
|
||||||
config, err := h.runnerService.ParseConfig(p.ProblemVersionId, true)
|
if !h.runnerService.ProblemExists(p.ProblemVersionID) {
|
||||||
if err != nil {
|
url, status := h.storageService.Get(p.StorageKey, time.Second*60*5)
|
||||||
h.log.Info("parse config failed", zap.Error(err), zap.Uint("pvid", p.ProblemVersionId))
|
if status != e.Success {
|
||||||
h.taskService.SubmitUpdate(e.InternalError, p.ProblemVersionId, 0, systemError)
|
return e.InternalError, 0, systemError
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// run
|
_, status = h.runnerService.NewProblem(p.ProblemVersionID, url, false)
|
||||||
var points int32
|
if status != e.Success {
|
||||||
result, points, status = h.runnerService.RunAndJudge(p.ProblemVersionId, user, p.Submission.Language, &config)
|
return e.InternalError, 0, systemError
|
||||||
h.taskService.SubmitUpdate(status, p.Submission.ID, points, result)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type queryRequest struct {
|
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) {
|
func (h *handler) Query(c *gin.Context) {
|
||||||
req := new(queryRequest)
|
req := new(queryRequest)
|
||||||
|
|
||||||
@ -20,5 +28,4 @@ func (h *handler) Query(c *gin.Context) {
|
|||||||
status, eStatus := h.statusService.Query(req.SubmissionID, true)
|
status, eStatus := h.statusService.Query(req.SubmissionID, true)
|
||||||
|
|
||||||
e.Pong(c, eStatus, status)
|
e.Pong(c, eStatus, status)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type queryByVersionRequest struct {
|
type queryByVersionRequest struct {
|
||||||
ProblemVersionID uint `form:"pvid"`
|
ProblemVersionID uint `form:"pvid" binding:"required"`
|
||||||
Offset int `form:"offset"`
|
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) {
|
func (h *handler) QueryByProblemVersion(c *gin.Context) {
|
||||||
|
|
||||||
claim, exist := c.Get("claim")
|
claim, exist := c.Get("claim")
|
||||||
@ -26,7 +36,7 @@ func (h *handler) QueryByProblemVersion(c *gin.Context) {
|
|||||||
req := new(queryByVersionRequest)
|
req := new(queryByVersionRequest)
|
||||||
|
|
||||||
if err := c.ShouldBind(req); err != nil {
|
if err := c.ShouldBind(req); err != nil {
|
||||||
e.Pong(c, e.InvalidParameter, nil)
|
e.Pong(c, e.InvalidParameter, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,5 +48,4 @@ func (h *handler) QueryByProblemVersion(c *gin.Context) {
|
|||||||
statuses, eStatus := h.statusService.QueryByVersion(req.ProblemVersionID, req.Offset, req.Limit)
|
statuses, eStatus := h.statusService.QueryByVersion(req.ProblemVersionID, req.Offset, req.Limit)
|
||||||
|
|
||||||
e.Pong(c, eStatus, statuses)
|
e.Pong(c, eStatus, statuses)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package submission
|
|||||||
import (
|
import (
|
||||||
"github.com/WHUPRJ/woj-server/internal/e"
|
"github.com/WHUPRJ/woj-server/internal/e"
|
||||||
"github.com/WHUPRJ/woj-server/internal/global"
|
"github.com/WHUPRJ/woj-server/internal/global"
|
||||||
|
"github.com/WHUPRJ/woj-server/internal/model"
|
||||||
"github.com/WHUPRJ/woj-server/internal/service/submission"
|
"github.com/WHUPRJ/woj-server/internal/service/submission"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -10,7 +11,7 @@ import (
|
|||||||
type createRequest struct {
|
type createRequest struct {
|
||||||
Pid uint `form:"pid" binding:"required"`
|
Pid uint `form:"pid" binding:"required"`
|
||||||
Language string `form:"language" binding:"required"`
|
Language string `form:"language" binding:"required"`
|
||||||
Code string `form:"statement" binding:"required"`
|
Code string `form:"code" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
@ -33,6 +34,7 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
|
|
||||||
uid := claim.(*global.Claim).UID
|
uid := claim.(*global.Claim).UID
|
||||||
|
|
||||||
|
role := claim.(*global.Claim).Role
|
||||||
req := new(createRequest)
|
req := new(createRequest)
|
||||||
|
|
||||||
if err := c.ShouldBind(req); err != nil {
|
if err := c.ShouldBind(req); err != nil {
|
||||||
@ -40,6 +42,12 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// guest can not submit
|
||||||
|
if role < model.RoleGeneral {
|
||||||
|
e.Pong(c, e.UserUnauthorized, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
createData := &submission.CreateData{
|
createData := &submission.CreateData{
|
||||||
ProblemID: req.Pid,
|
ProblemID: req.Pid,
|
||||||
UserID: uid,
|
UserID: uid,
|
||||||
@ -58,7 +66,12 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
return
|
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)
|
e.Pong(c, status, nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ var _ Handler = (*handler)(nil)
|
|||||||
type Handler interface {
|
type Handler interface {
|
||||||
Create(c *gin.Context)
|
Create(c *gin.Context)
|
||||||
Query(c *gin.Context)
|
Query(c *gin.Context)
|
||||||
|
Rejudge(c *gin.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
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("/create", app.jwtService.Handler(true), app.Create)
|
||||||
group.POST("/query", app.Query)
|
group.POST("/query", app.Query)
|
||||||
|
group.POST("/rejudge", app.jwtService.Handler(true), app.Rejudge)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ type queryRequest struct {
|
|||||||
Pid uint `form:"pid"`
|
Pid uint `form:"pid"`
|
||||||
Uid uint `form:"uid"`
|
Uid uint `form:"uid"`
|
||||||
Offset int `form:"offset"`
|
Offset int `form:"offset"`
|
||||||
Limit int `form:"limit"`
|
Limit int `form:"limit" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type queryResponse struct {
|
type queryResponse struct {
|
||||||
@ -23,10 +23,10 @@ type queryResponse struct {
|
|||||||
// @Description Query submissions
|
// @Description Query submissions
|
||||||
// @Accept application/x-www-form-urlencoded
|
// @Accept application/x-www-form-urlencoded
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param pid formData uint false "problem id"
|
// @Param pid formData uint true "problem id"
|
||||||
// @Param uid formData uint false "user id"
|
// @Param uid formData uint true "user id"
|
||||||
// @Param offset formData int false "start position"
|
// @Param offset formData int true "start position"
|
||||||
// @Param limit formData int false "limit number of records"
|
// @Param limit formData int true "limit number of records"
|
||||||
// @Response 200 {object} e.Response "queryResponse"
|
// @Response 200 {object} e.Response "queryResponse"
|
||||||
// @Router /v1/submission/query [post]
|
// @Router /v1/submission/query [post]
|
||||||
|
|
||||||
@ -67,7 +67,5 @@ func (h *handler) Query(c *gin.Context) {
|
|||||||
response = append(response, newResponse)
|
response = append(response, newResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Pong(c, status, submissions)
|
e.Pong(c, status, response)
|
||||||
return
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
63
internal/api/submission/rejudge.go
Normal file
63
internal/api/submission/rejudge.go
Normal file
@ -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)
|
||||||
|
}
|
@ -55,5 +55,4 @@ func (h *handler) Create(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
token, status := h.jwtService.SignClaim(claim)
|
token, status := h.jwtService.SignClaim(claim)
|
||||||
e.Pong(c, status, token)
|
e.Pong(c, status, token)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,4 @@ func (h *handler) Logout(c *gin.Context) {
|
|||||||
|
|
||||||
_, status := h.userService.IncrVersion(claim.(*global.Claim).UID)
|
_, status := h.userService.IncrVersion(claim.(*global.Claim).UID)
|
||||||
e.Pong(c, status, nil)
|
e.Pong(c, status, nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ func (h *handler) Profile(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user, status := h.userService.Profile(req.UID)
|
user, status := h.userService.Profile(req.UID)
|
||||||
|
|
||||||
|
// TODO: >= admin can see is_enable
|
||||||
|
|
||||||
e.Pong(c, status, user)
|
e.Pong(c, status, user)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/WHUPRJ/woj-server/internal/api/consumer"
|
||||||
"github.com/WHUPRJ/woj-server/internal/global"
|
"github.com/WHUPRJ/woj-server/internal/global"
|
||||||
"github.com/WHUPRJ/woj-server/internal/model"
|
"github.com/WHUPRJ/woj-server/internal/model"
|
||||||
"github.com/WHUPRJ/woj-server/internal/repo/postgresql"
|
"github.com/WHUPRJ/woj-server/internal/repo/postgresql"
|
||||||
@ -52,9 +53,11 @@ func RunServer(g *global.Global) error {
|
|||||||
|
|
||||||
// Create Queue
|
// Create Queue
|
||||||
queueMux := asynq.NewServeMux()
|
queueMux := asynq.NewServeMux()
|
||||||
// TODO: fill
|
{
|
||||||
queueMux.HandleFunc(model.TypeProblemUpdate, func(ctx context.Context, t *asynq.Task) error { return nil })
|
handler := consumer.NewConsumer(g)
|
||||||
queueMux.HandleFunc(model.TypeSubmitUpdate, func(ctx context.Context, t *asynq.Task) error { return nil })
|
queueMux.HandleFunc(model.TypeProblemUpdate, handler.ProblemUpdate)
|
||||||
|
queueMux.HandleFunc(model.TypeSubmitUpdate, handler.SubmitUpdate)
|
||||||
|
}
|
||||||
queueSrv := asynq.NewServer(
|
queueSrv := asynq.NewServer(
|
||||||
asynq.RedisClientOpt{
|
asynq.RedisClientOpt{
|
||||||
Addr: g.Conf.Redis.Address,
|
Addr: g.Conf.Redis.Address,
|
||||||
|
@ -37,6 +37,7 @@ const (
|
|||||||
ProblemNotAvailable
|
ProblemNotAvailable
|
||||||
ProblemVersionNotFound
|
ProblemVersionNotFound
|
||||||
ProblemVersionNotAvailable
|
ProblemVersionNotAvailable
|
||||||
|
SubmissionNotFound
|
||||||
StatusNotFound
|
StatusNotFound
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,6 +59,11 @@ const (
|
|||||||
RunnerJudgeFailed
|
RunnerJudgeFailed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StorageUploadFailed Status = 800 + iota
|
||||||
|
StorageGetFailed
|
||||||
|
)
|
||||||
|
|
||||||
var msgText = map[Status]string{
|
var msgText = map[Status]string{
|
||||||
Success: "Success",
|
Success: "Success",
|
||||||
Unknown: "Unknown error",
|
Unknown: "Unknown error",
|
||||||
@ -88,6 +94,8 @@ var msgText = map[Status]string{
|
|||||||
ProblemVersionNotFound: "Problem Version Not Found",
|
ProblemVersionNotFound: "Problem Version Not Found",
|
||||||
ProblemVersionNotAvailable: "Problem Version Not Available",
|
ProblemVersionNotAvailable: "Problem Version Not Available",
|
||||||
|
|
||||||
|
SubmissionNotFound: "Submission Not Found",
|
||||||
|
|
||||||
StatusNotFound: "Status Not Found",
|
StatusNotFound: "Status Not Found",
|
||||||
|
|
||||||
TaskEnqueueFailed: "Task Enqueue Failed",
|
TaskEnqueueFailed: "Task Enqueue Failed",
|
||||||
@ -103,4 +111,7 @@ var msgText = map[Status]string{
|
|||||||
RunnerUserCompileFailed: "Runner User Compile Failed",
|
RunnerUserCompileFailed: "Runner User Compile Failed",
|
||||||
RunnerRunFailed: "Runner Run Failed",
|
RunnerRunFailed: "Runner Run Failed",
|
||||||
RunnerJudgeFailed: "Runner Judge Failed",
|
RunnerJudgeFailed: "Runner Judge Failed",
|
||||||
|
|
||||||
|
StorageUploadFailed: "Storage Upload Failed",
|
||||||
|
StorageGetFailed: "Storage Get Failed",
|
||||||
}
|
}
|
||||||
|
@ -24,3 +24,12 @@ func Pong(c *gin.Context, status Status, body interface{}) {
|
|||||||
c.Set("err", status)
|
c.Set("err", status)
|
||||||
c.JSON(http.StatusOK, Wrap(status, body))
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,6 +26,14 @@ type ConfigDatabase struct {
|
|||||||
ConnMaxLifetime int `yaml:"ConnMaxLifetime"`
|
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 {
|
type ConfigMetrics struct {
|
||||||
Namespace string `yaml:"Namespace"`
|
Namespace string `yaml:"Namespace"`
|
||||||
Subsystem string `yaml:"Subsystem"`
|
Subsystem string `yaml:"Subsystem"`
|
||||||
@ -35,6 +43,7 @@ type Config struct {
|
|||||||
WebServer ConfigWebServer `yaml:"WebServer"`
|
WebServer ConfigWebServer `yaml:"WebServer"`
|
||||||
Redis ConfigRedis `yaml:"Redis"`
|
Redis ConfigRedis `yaml:"Redis"`
|
||||||
Database ConfigDatabase `yaml:"Database"`
|
Database ConfigDatabase `yaml:"Database"`
|
||||||
|
Storage ConfigStorage `yaml:"Storage"`
|
||||||
Metrics ConfigMetrics `yaml:"Metrics"`
|
Metrics ConfigMetrics `yaml:"Metrics"`
|
||||||
Development bool `yaml:"Development"`
|
Development bool `yaml:"Development"`
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ const (
|
|||||||
|
|
||||||
type ProblemBuildPayload struct {
|
type ProblemBuildPayload struct {
|
||||||
ProblemVersionID uint
|
ProblemVersionID uint
|
||||||
ProblemFile string
|
StorageKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProblemUpdatePayload struct {
|
type ProblemUpdatePayload struct {
|
||||||
@ -28,14 +28,15 @@ type ProblemUpdatePayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SubmitJudgePayload struct {
|
type SubmitJudgePayload struct {
|
||||||
ProblemVersionId uint
|
ProblemVersionID uint
|
||||||
StorageKey string
|
StorageKey string
|
||||||
Submission Submission
|
Submission Submission
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubmitUpdatePayload struct {
|
type SubmitUpdatePayload struct {
|
||||||
Status e.Status
|
Status e.Status
|
||||||
Sid uint
|
SubmissionID uint
|
||||||
Point int32
|
ProblemVersionID uint
|
||||||
Context string
|
Point int32
|
||||||
|
Context string
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,9 @@ func (r *Repo) migrateDatabase() {
|
|||||||
|
|
||||||
_ = r.db.AutoMigrate(&model.User{})
|
_ = r.db.AutoMigrate(&model.User{})
|
||||||
_ = r.db.AutoMigrate(&model.Problem{})
|
_ = r.db.AutoMigrate(&model.Problem{})
|
||||||
|
_ = r.db.AutoMigrate(&model.ProblemVersion{})
|
||||||
_ = r.db.AutoMigrate(&model.Submission{})
|
_ = r.db.AutoMigrate(&model.Submission{})
|
||||||
|
_ = r.db.AutoMigrate(&model.Status{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAlive deprecated
|
// checkAlive deprecated
|
||||||
|
@ -3,6 +3,7 @@ package problem
|
|||||||
import (
|
import (
|
||||||
"github.com/WHUPRJ/woj-server/internal/e"
|
"github.com/WHUPRJ/woj-server/internal/e"
|
||||||
"github.com/WHUPRJ/woj-server/internal/model"
|
"github.com/WHUPRJ/woj-server/internal/model"
|
||||||
|
"github.com/jackc/pgtype"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ type CreateVersionData struct {
|
|||||||
func (s *service) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) {
|
func (s *service) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) {
|
||||||
problemVersion := &model.ProblemVersion{
|
problemVersion := &model.ProblemVersion{
|
||||||
ProblemID: data.ProblemID,
|
ProblemID: data.ProblemID,
|
||||||
|
Context: pgtype.JSON{Status: pgtype.Null},
|
||||||
StorageKey: data.StorageKey,
|
StorageKey: data.StorageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ type Service interface {
|
|||||||
QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status)
|
QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status)
|
||||||
|
|
||||||
CreateVersion(data *CreateVersionData) (*model.ProblemVersion, 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)
|
QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status)
|
||||||
QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status)
|
QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status)
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) UpdateVersion(problemVersion *model.ProblemVersion) (*model.ProblemVersion, e.Status) {
|
func (s *service) UpdateVersion(pvid uint, values interface{}) e.Status {
|
||||||
err := s.db.Save(problemVersion).Error
|
err := s.db.Model(&model.ProblemVersion{}).Where("id = ?", pvid).Updates(values).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("pvid", pvid), zap.Any("values", values))
|
||||||
return nil, e.DatabaseError
|
return e.DatabaseError
|
||||||
}
|
}
|
||||||
|
|
||||||
return problemVersion, e.Success
|
return e.Success
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Prefix = "./resource/runner"
|
Prefix = "./resource/runner"
|
||||||
ProblemDir = "./problems/"
|
ProblemDir = "./problem/"
|
||||||
ScriptsDir = "./scripts/"
|
ScriptsDir = "./scripts/"
|
||||||
UserDir = "./users/"
|
UserDir = "./user/"
|
||||||
TmpDir = "./tmp/"
|
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 {
|
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))
|
s.log.Info("problem not exists", zap.Uint("version", version))
|
||||||
return e.RunnerProblemNotExist
|
return e.RunnerProblemNotExist
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ func (s *service) checkAndExecute(version uint, user string, lang string, script
|
|||||||
return e.RunnerUserNotExist
|
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 {
|
if err != nil {
|
||||||
s.log.Info("execute failed",
|
s.log.Info("execute failed",
|
||||||
@ -64,12 +64,12 @@ func (s *service) checkAndExecute(version uint, user string, lang string, script
|
|||||||
return e.Success
|
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))
|
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", version))
|
||||||
return utils.FileExist(problemPath)
|
return utils.FileExist(problemPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) userExists(user string, file string) bool {
|
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)
|
return utils.FileExist(userPath)
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) Compile(version uint, user string, lang string) (JudgeStatus, e.Status) {
|
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)
|
_ = os.Remove(target)
|
||||||
status := s.checkAndExecute(version, user, lang, "problem_compile.sh", e.RunnerUserCompileFailed)
|
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, err := utils.FileRead(log)
|
||||||
msg = utils.If(err == nil, msg, nil).([]byte)
|
msg = utils.If(err == nil, msg, nil).([]byte)
|
||||||
msgText := string(msg)
|
msgText := string(msg)
|
||||||
|
|
||||||
if utils.FileExist(target) {
|
if !utils.FileExist(target) || utils.FileEmpty(target) {
|
||||||
return JudgeStatus{}, e.Success
|
|
||||||
} else {
|
|
||||||
return JudgeStatus{
|
return JudgeStatus{
|
||||||
Message: "compile failed",
|
Message: "compile failed",
|
||||||
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
||||||
utils.If(status == e.Success, e.RunnerUserCompileFailed, status).(e.Status)
|
utils.If(status == e.Success, e.RunnerUserCompileFailed, status).(e.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return JudgeStatus{}, e.Success
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func (s *service) download(version uint, url string) e.Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) prebuild(version uint, force bool) e.Status {
|
func (s *service) prebuild(version uint, force bool) e.Status {
|
||||||
if !s.problemExists(version) {
|
if !s.ProblemExists(version) {
|
||||||
return e.RunnerProblemNotExist
|
return e.RunnerProblemNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,17 @@ func (s *service) prebuild(version uint, force bool) e.Status {
|
|||||||
return e.Success
|
return e.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) NewProblem(version uint, url string) (Config, e.Status) {
|
func (s *service) NewProblem(version uint, url string, force bool) (Config, e.Status) {
|
||||||
status := s.download(version, url)
|
if force {
|
||||||
if status != e.Success {
|
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", version))
|
||||||
return Config{}, status
|
_ = 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)
|
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
|
return Config{}, e.RunnerProblemParseFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
status = s.prebuild(version, true)
|
status := s.prebuild(version, true)
|
||||||
if status != e.Success {
|
if status != e.Success {
|
||||||
return Config{}, status
|
return Config{}, status
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ type Service interface {
|
|||||||
// EnsureDeps build docker images
|
// EnsureDeps build docker images
|
||||||
EnsureDeps(force bool) e.Status
|
EnsureDeps(force bool) e.Status
|
||||||
// NewProblem = Download + Parse + Prebuild
|
// 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 compile user submission
|
||||||
Compile(version uint, user string, lang string) (JudgeStatus, e.Status)
|
Compile(version uint, user string, lang string) (JudgeStatus, e.Status)
|
||||||
@ -21,6 +21,8 @@ type Service interface {
|
|||||||
|
|
||||||
// ParseConfig parse config file
|
// ParseConfig parse config file
|
||||||
ParseConfig(version uint, skipCheck bool) (Config, error)
|
ParseConfig(version uint, skipCheck bool) (Config, error)
|
||||||
|
// ProblemExists check if problem exists
|
||||||
|
ProblemExists(version uint) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
@ -202,7 +202,7 @@ func (s *service) checkResults(user string, config *Config) (JudgeStatus, int32)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var results []TaskStatus
|
var results []TaskStatus
|
||||||
dir := filepath.Join(UserDir, fmt.Sprintf("%s", user))
|
dir := filepath.Join(UserDir, user)
|
||||||
var sum int32 = 0
|
var sum int32 = 0
|
||||||
|
|
||||||
for i := 1; i <= len(config.Tasks); i++ {
|
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).
|
result.getInfoText(info).
|
||||||
getInfo().
|
getInfo().
|
||||||
checkExit().
|
|
||||||
checkTime(config).
|
checkTime(config).
|
||||||
checkMemory(config).
|
checkMemory(config).
|
||||||
|
checkExit().
|
||||||
getJudgeText(judge).
|
getJudgeText(judge).
|
||||||
getJudge().
|
getJudge().
|
||||||
checkJudge(&pts)
|
checkJudge(&pts)
|
||||||
|
|
||||||
sum += result.Points
|
sum += result.Points
|
||||||
|
results = append(results, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
return JudgeStatus{Message: "", Tasks: results}, sum
|
return JudgeStatus{Message: "", Tasks: results}, sum
|
||||||
|
@ -10,17 +10,20 @@ import (
|
|||||||
type CreateData struct {
|
type CreateData struct {
|
||||||
SubmissionID uint
|
SubmissionID uint
|
||||||
ProblemVersionID uint
|
ProblemVersionID uint
|
||||||
Context pgtype.JSON
|
Context string
|
||||||
Point int32
|
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{
|
status := &model.Status{
|
||||||
SubmissionID: data.SubmissionID,
|
SubmissionID: data.SubmissionID,
|
||||||
ProblemVersionID: data.ProblemVersionID,
|
ProblemVersionID: data.ProblemVersionID,
|
||||||
Context: data.Context,
|
Context: pgtype.JSON{
|
||||||
Point: data.Point,
|
Bytes: []byte(data.Context),
|
||||||
IsEnabled: true,
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Point: data.Point,
|
||||||
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.db.Create(status).Error
|
err := s.db.Create(status).Error
|
||||||
|
@ -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")
|
|
||||||
}
|
|
@ -11,10 +11,9 @@ import (
|
|||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
type Service interface {
|
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)
|
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)
|
||||||
Rejudge(statusID uint) ([]*model.Status, e.Status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
30
internal/service/storage/get.go
Normal file
30
internal/service/storage/get.go
Normal file
@ -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
|
||||||
|
}
|
41
internal/service/storage/service.go
Normal file
41
internal/service/storage/service.go
Normal file
@ -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,
|
||||||
|
}
|
||||||
|
}
|
28
internal/service/storage/upload.go
Normal file
28
internal/service/storage/upload.go
Normal file
@ -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
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package submission
|
package submission
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/WHUPRJ/woj-server/internal/e"
|
"github.com/WHUPRJ/woj-server/internal/e"
|
||||||
"github.com/WHUPRJ/woj-server/internal/model"
|
"github.com/WHUPRJ/woj-server/internal/model"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
"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
|
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
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ var _ Service = (*service)(nil)
|
|||||||
type Service interface {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
@ -15,8 +15,6 @@ func (s *service) submit(typename string, payload []byte, queue string) (*asynq.
|
|||||||
return nil, e.TaskEnqueueFailed
|
return nil, e.TaskEnqueueFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
s.log.Debug("Successfully enqueued task", zap.Any("info", info))
|
|
||||||
|
|
||||||
return info, e.Success
|
return info, e.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,16 +7,13 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) ProblemBuild(pvId uint, file string) (string, e.Status) {
|
func (s *service) ProblemBuild(data *model.ProblemBuildPayload) (string, e.Status) {
|
||||||
payload, err := json.Marshal(model.ProblemBuildPayload{
|
payload, err := json.Marshal(data)
|
||||||
ProblemVersionID: pvId,
|
|
||||||
ProblemFile: file,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("json marshal error",
|
s.log.Warn("json marshal error",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.Any("ProblemVersionID", pvId),
|
zap.Any("data", data),
|
||||||
zap.String("ProblemFile", file))
|
)
|
||||||
return "", e.InternalError
|
return "", e.InternalError
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,18 +22,13 @@ func (s *service) ProblemBuild(pvId uint, file string) (string, e.Status) {
|
|||||||
return info.ID, status
|
return info.ID, status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) ProblemUpdate(status e.Status, pvId uint, ctx string) (string, e.Status) {
|
func (s *service) ProblemUpdate(data *model.ProblemUpdatePayload) (string, e.Status) {
|
||||||
payload, err := json.Marshal(model.ProblemUpdatePayload{
|
payload, err := json.Marshal(data)
|
||||||
Status: status,
|
|
||||||
ProblemVersionID: pvId,
|
|
||||||
Context: ctx,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("json marshal error",
|
s.log.Warn("json marshal error",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.Any("Status", status),
|
zap.Any("data", data),
|
||||||
zap.Any("ProblemVersionID", pvId),
|
)
|
||||||
zap.Any("Context", ctx))
|
|
||||||
return "", e.InternalError
|
return "", e.InternalError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
var _ Service = (*service)(nil)
|
var _ Service = (*service)(nil)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
ProblemBuild(pvId uint, file string) (string, e.Status)
|
ProblemBuild(data *model.ProblemBuildPayload) (string, e.Status)
|
||||||
ProblemUpdate(status e.Status, pvId uint, ctx string) (string, e.Status)
|
ProblemUpdate(data *model.ProblemUpdatePayload) (string, e.Status)
|
||||||
SubmitJudge(pvid uint, storageKey string, submission model.Submission) (string, e.Status)
|
SubmitJudge(data *model.SubmitJudgePayload) (string, e.Status)
|
||||||
SubmitUpdate(status e.Status, sid uint, point int32, 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)
|
||||||
}
|
}
|
||||||
|
@ -8,15 +8,13 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *service) SubmitJudge(pvid uint, storageKey string, submission model.Submission) (string, e.Status) {
|
func (s *service) SubmitJudge(data *model.SubmitJudgePayload) (string, e.Status) {
|
||||||
payload, err := json.Marshal(
|
payload, err := json.Marshal(data)
|
||||||
model.SubmitJudgePayload{
|
|
||||||
ProblemVersionId: pvid,
|
|
||||||
StorageKey: storageKey,
|
|
||||||
Submission: submission,
|
|
||||||
})
|
|
||||||
if err != nil {
|
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
|
return "", e.InternalError
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ func (s *service) SubmitJudge(pvid uint, storageKey string, submission model.Sub
|
|||||||
return info.ID, status
|
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)
|
ctxText, err := json.Marshal(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("json marshal error",
|
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
|
return "", e.InternalError
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, err := json.Marshal(model.SubmitUpdatePayload{
|
data.Context = string(ctxText)
|
||||||
Status: status,
|
payload, err := json.Marshal(data)
|
||||||
Sid: sid,
|
|
||||||
Point: point,
|
|
||||||
Context: string(ctxText),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("json marshal error",
|
s.log.Warn("json marshal error",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.Any("Status", status),
|
zap.Any("data", data),
|
||||||
zap.Int32("Point", point),
|
zap.Any("Context", ctx),
|
||||||
zap.Any("Context", ctx))
|
)
|
||||||
return "", e.InternalError
|
return "", e.InternalError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,14 @@ func FileExist(filePath string) bool {
|
|||||||
return If(err == nil || os.IsExist(err), true, false).(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 {
|
func FileTouch(filePath string) bool {
|
||||||
base := filepath.Dir(filePath)
|
base := filepath.Dir(filePath)
|
||||||
_ = os.MkdirAll(base, 0755)
|
_ = os.MkdirAll(base, 0755)
|
||||||
|
@ -31,7 +31,7 @@ log_info "NProcLimit: $Info_Limit_NProc"
|
|||||||
|
|
||||||
# launcher will add 2 more seconds
|
# launcher will add 2 more seconds
|
||||||
# here add 3 more seconds
|
# here add 3 more seconds
|
||||||
TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 3))
|
TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 4))
|
||||||
log_info "Timeout: $TIMEOUT"
|
log_info "Timeout: $TIMEOUT"
|
||||||
|
|
||||||
for test_num in $(seq "$Info_Num"); do
|
for test_num in $(seq "$Info_Num"); do
|
||||||
|
Loading…
Reference in New Issue
Block a user