diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-08-08 21:17:13 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-08-08 21:17:13 +0900 |
| commit | a100dc8ba76aaeda2229940c1743c33cc0ef84b5 (patch) | |
| tree | e2e48d8d92e2601d65e3ce7d794d8727026c14e0 /backend | |
| parent | bb62b6ff19d9f8008458d1c0ad0b8b76090f091e (diff) | |
| parent | 3b13a61123becc63823ab0c0941aaff2048b020e (diff) | |
| download | iosdc-japan-2025-albatross-a100dc8ba76aaeda2229940c1743c33cc0ef84b5.tar.gz iosdc-japan-2025-albatross-a100dc8ba76aaeda2229940c1743c33cc0ef84b5.tar.zst iosdc-japan-2025-albatross-a100dc8ba76aaeda2229940c1743c33cc0ef84b5.zip | |
Merge branch 'feat/code-hash'
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/api/handler_wrapper.go | 28 | ||||
| -rw-r--r-- | backend/db/models.go | 1 | ||||
| -rw-r--r-- | backend/db/query.sql.go | 6 | ||||
| -rw-r--r-- | backend/game/hub.go | 15 | ||||
| -rw-r--r-- | backend/query.sql | 4 | ||||
| -rw-r--r-- | backend/schema.sql | 1 | ||||
| -rw-r--r-- | backend/taskqueue/processor.go | 15 | ||||
| -rw-r--r-- | backend/taskqueue/queue.go | 12 | ||||
| -rw-r--r-- | backend/taskqueue/tasks.go | 69 |
9 files changed, 91 insertions, 60 deletions
diff --git a/backend/api/handler_wrapper.go b/backend/api/handler_wrapper.go index 69b9baa..9f524e9 100644 --- a/backend/api/handler_wrapper.go +++ b/backend/api/handler_wrapper.go @@ -11,15 +11,15 @@ import ( "github.com/nsfisis/iosdc-japan-2024-albatross/backend/db" ) -var _ StrictServerInterface = (*ApiHandlerWrapper)(nil) +var _ StrictServerInterface = (*HandlerWrapper)(nil) -type ApiHandlerWrapper struct { - innerHandler Handler +type HandlerWrapper struct { + impl Handler } -func NewHandler(queries *db.Queries, hubs GameHubsInterface) *ApiHandlerWrapper { - return &ApiHandlerWrapper{ - innerHandler: Handler{ +func NewHandler(queries *db.Queries, hubs GameHubsInterface) *HandlerWrapper { + return &HandlerWrapper{ + impl: Handler{ q: queries, hubs: hubs, }, @@ -39,7 +39,7 @@ func parseJWTClaimsFromAuthorizationHeader(authorization string) (*auth.JWTClaim return claims, nil } -func (h *ApiHandlerWrapper) GetGame(ctx context.Context, request GetGameRequestObject) (GetGameResponseObject, error) { +func (h *HandlerWrapper) GetGame(ctx context.Context, request GetGameRequestObject) (GetGameResponseObject, error) { user, err := parseJWTClaimsFromAuthorizationHeader(request.Params.Authorization) if err != nil { return GetGame401JSONResponse{ @@ -48,10 +48,10 @@ func (h *ApiHandlerWrapper) GetGame(ctx context.Context, request GetGameRequestO }, }, nil } - return h.innerHandler.GetGame(ctx, request, user) + return h.impl.GetGame(ctx, request, user) } -func (h *ApiHandlerWrapper) GetGames(ctx context.Context, request GetGamesRequestObject) (GetGamesResponseObject, error) { +func (h *HandlerWrapper) GetGames(ctx context.Context, request GetGamesRequestObject) (GetGamesResponseObject, error) { user, err := parseJWTClaimsFromAuthorizationHeader(request.Params.Authorization) if err != nil { return GetGames401JSONResponse{ @@ -60,10 +60,10 @@ func (h *ApiHandlerWrapper) GetGames(ctx context.Context, request GetGamesReques }, }, nil } - return h.innerHandler.GetGames(ctx, request, user) + return h.impl.GetGames(ctx, request, user) } -func (h *ApiHandlerWrapper) GetToken(ctx context.Context, request GetTokenRequestObject) (GetTokenResponseObject, error) { +func (h *HandlerWrapper) GetToken(ctx context.Context, request GetTokenRequestObject) (GetTokenResponseObject, error) { user, err := parseJWTClaimsFromAuthorizationHeader(request.Params.Authorization) if err != nil { return GetToken401JSONResponse{ @@ -72,9 +72,9 @@ func (h *ApiHandlerWrapper) GetToken(ctx context.Context, request GetTokenReques }, }, nil } - return h.innerHandler.GetToken(ctx, request, user) + return h.impl.GetToken(ctx, request, user) } -func (h *ApiHandlerWrapper) PostLogin(ctx context.Context, request PostLoginRequestObject) (PostLoginResponseObject, error) { - return h.innerHandler.PostLogin(ctx, request) +func (h *HandlerWrapper) PostLogin(ctx context.Context, request PostLoginRequestObject) (PostLoginResponseObject, error) { + return h.impl.PostLogin(ctx, request) } diff --git a/backend/db/models.go b/backend/db/models.go index d4cf98b..5bca7b7 100644 --- a/backend/db/models.go +++ b/backend/db/models.go @@ -36,6 +36,7 @@ type Submission struct { UserID int32 Code string CodeSize int32 + CodeHash string CreatedAt pgtype.Timestamp } diff --git a/backend/db/query.sql.go b/backend/db/query.sql.go index 5475067..dc87602 100644 --- a/backend/db/query.sql.go +++ b/backend/db/query.sql.go @@ -34,8 +34,8 @@ func (q *Queries) AggregateTestcaseResults(ctx context.Context, submissionID int } const createSubmission = `-- name: CreateSubmission :one -INSERT INTO submissions (game_id, user_id, code, code_size) -VALUES ($1, $2, $3, $4) +INSERT INTO submissions (game_id, user_id, code, code_size, code_hash) +VALUES ($1, $2, $3, $4, $5) RETURNING submission_id ` @@ -44,6 +44,7 @@ type CreateSubmissionParams struct { UserID int32 Code string CodeSize int32 + CodeHash string } func (q *Queries) CreateSubmission(ctx context.Context, arg CreateSubmissionParams) (int32, error) { @@ -52,6 +53,7 @@ func (q *Queries) CreateSubmission(ctx context.Context, arg CreateSubmissionPara arg.UserID, arg.Code, arg.CodeSize, + arg.CodeHash, ) var submission_id int32 err := row.Scan(&submission_id) diff --git a/backend/game/hub.go b/backend/game/hub.go index ac71152..aa1b9f2 100644 --- a/backend/game/hub.go +++ b/backend/game/hub.go @@ -2,7 +2,9 @@ package game import ( "context" + "crypto/md5" "errors" + "fmt" "log" "strings" "time" @@ -163,11 +165,13 @@ func (hub *gameHub) run() { log.Printf("submit: %v", message.message) code := msg.Data.Code codeSize := len(code) // TODO: exclude whitespaces. + codeHash := calcHash(code) if err := hub.taskQueue.EnqueueTaskCreateSubmissionRecord( hub.game.gameID, message.client.playerID, code, codeSize, + taskqueue.MD5HexHash(codeHash), ); err != nil { // TODO: notify failure to player log.Fatalf("failed to enqueue task: %v", err) @@ -329,7 +333,8 @@ func (hub *gameHub) processTaskResultCreateSubmissionRecord( if err := hub.taskQueue.EnqueueTaskCompileSwiftToWasm( taskResult.TaskPayload.GameID(), taskResult.TaskPayload.UserID(), - taskResult.TaskPayload.Code(), + taskResult.TaskPayload.Code, + taskResult.TaskPayload.CodeHash(), taskResult.SubmissionID, ); err != nil { return &codeSubmissionError{ @@ -371,7 +376,7 @@ func (hub *gameHub) processTaskResultCompileSwiftToWasm( if err := hub.taskQueue.EnqueueTaskCompileWasmToNativeExecutable( taskResult.TaskPayload.GameID(), taskResult.TaskPayload.UserID(), - taskResult.TaskPayload.Code(), + taskResult.TaskPayload.CodeHash(), taskResult.TaskPayload.SubmissionID, ); err != nil { return &codeSubmissionError{ @@ -429,7 +434,7 @@ func (hub *gameHub) processTaskResultCompileWasmToNativeExecutable( if err := hub.taskQueue.EnqueueTaskRunTestcase( taskResult.TaskPayload.GameID(), taskResult.TaskPayload.UserID(), - taskResult.TaskPayload.Code(), + taskResult.TaskPayload.CodeHash(), taskResult.TaskPayload.SubmissionID, int(testcase.TestcaseID), testcase.Stdin, @@ -644,3 +649,7 @@ func isTestcaseResultCorrect(expectedStdout, actualStdout string) bool { actualStdout = strings.TrimSpace(actualStdout) return actualStdout == expectedStdout } + +func calcHash(code string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(code))) +} diff --git a/backend/query.sql b/backend/query.sql index e767746..f0e4034 100644 --- a/backend/query.sql +++ b/backend/query.sql @@ -59,8 +59,8 @@ SET WHERE game_id = $1; -- name: CreateSubmission :one -INSERT INTO submissions (game_id, user_id, code, code_size) -VALUES ($1, $2, $3, $4) +INSERT INTO submissions (game_id, user_id, code, code_size, code_hash) +VALUES ($1, $2, $3, $4, $5) RETURNING submission_id; -- name: ListTestcasesByGameID :many diff --git a/backend/schema.sql b/backend/schema.sql index 74d1202..64642bc 100644 --- a/backend/schema.sql +++ b/backend/schema.sql @@ -59,6 +59,7 @@ CREATE TABLE submissions ( user_id INT NOT NULL, code TEXT NOT NULL, code_size INT NOT NULL, + code_hash CHAR(32) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW(), CONSTRAINT fk_game_id FOREIGN KEY(game_id) REFERENCES games(game_id), CONSTRAINT fk_user_id FOREIGN KEY(user_id) REFERENCES users(user_id) diff --git a/backend/taskqueue/processor.go b/backend/taskqueue/processor.go index 149ab67..5678cc8 100644 --- a/backend/taskqueue/processor.go +++ b/backend/taskqueue/processor.go @@ -29,8 +29,9 @@ func (p *processor) doProcessTaskCreateSubmissionRecord( submissionID, err := p.q.CreateSubmission(ctx, db.CreateSubmissionParams{ GameID: int32(payload.GameID()), UserID: int32(payload.UserID()), - Code: payload.Code(), + Code: payload.Code, CodeSize: int32(payload.CodeSize), + CodeHash: string(payload.CodeHash()), }) if err != nil { return nil, err @@ -49,6 +50,7 @@ func (p *processor) doProcessTaskCompileSwiftToWasm( type swiftcRequestData struct { MaxDuration int `json:"max_duration_ms"` Code string `json:"code"` + CodeHash string `json:"code_hash"` } type swiftcResponseData struct { Status string `json:"status"` @@ -57,7 +59,8 @@ func (p *processor) doProcessTaskCompileSwiftToWasm( } reqData := swiftcRequestData{ MaxDuration: 5000, - Code: payload.Code(), + Code: payload.Code, + CodeHash: string(payload.CodeHash()), } reqJSON, err := json.Marshal(reqData) if err != nil { @@ -99,7 +102,7 @@ func (p *processor) doProcessTaskCompileWasmToNativeExecutable( ) (*TaskResultCompileWasmToNativeExecutable, error) { type wasmcRequestData struct { MaxDuration int `json:"max_duration_ms"` - Code string `json:"code"` + CodeHash string `json:"code_hash"` } type wasmcResponseData struct { Status string `json:"status"` @@ -108,7 +111,7 @@ func (p *processor) doProcessTaskCompileWasmToNativeExecutable( } reqData := wasmcRequestData{ MaxDuration: 5000, - Code: payload.Code(), + CodeHash: string(payload.CodeHash()), } reqJSON, err := json.Marshal(reqData) if err != nil { @@ -150,7 +153,7 @@ func (p *processor) doProcessTaskRunTestcase( ) (*TaskResultRunTestcase, error) { type testrunRequestData struct { MaxDuration int `json:"max_duration_ms"` - Code string `json:"code"` + CodeHash string `json:"code_hash"` Stdin string `json:"stdin"` } type testrunResponseData struct { @@ -160,7 +163,7 @@ func (p *processor) doProcessTaskRunTestcase( } reqData := testrunRequestData{ MaxDuration: 5000, - Code: payload.Code(), + CodeHash: string(payload.CodeHash()), Stdin: payload.Stdin, } reqJSON, err := json.Marshal(reqData) diff --git a/backend/taskqueue/queue.go b/backend/taskqueue/queue.go index 515a406..30fe265 100644 --- a/backend/taskqueue/queue.go +++ b/backend/taskqueue/queue.go @@ -25,12 +25,14 @@ func (q *Queue) EnqueueTaskCreateSubmissionRecord( userID int, code string, codeSize int, + codeHash MD5HexHash, ) error { task, err := newTaskCreateSubmissionRecord( gameID, userID, code, codeSize, + codeHash, ) if err != nil { return err @@ -43,12 +45,14 @@ func (q *Queue) EnqueueTaskCompileSwiftToWasm( gameID int, userID int, code string, + codeHash MD5HexHash, submissionID int, ) error { task, err := newTaskCompileSwiftToWasm( gameID, userID, code, + codeHash, submissionID, ) if err != nil { @@ -61,13 +65,13 @@ func (q *Queue) EnqueueTaskCompileSwiftToWasm( func (q *Queue) EnqueueTaskCompileWasmToNativeExecutable( gameID int, userID int, - code string, + codeHash MD5HexHash, submissionID int, ) error { task, err := newTaskCompileWasmToNativeExecutable( gameID, userID, - code, + codeHash, submissionID, ) if err != nil { @@ -80,7 +84,7 @@ func (q *Queue) EnqueueTaskCompileWasmToNativeExecutable( func (q *Queue) EnqueueTaskRunTestcase( gameID int, userID int, - code string, + codeHash MD5HexHash, submissionID int, testcaseID int, stdin string, @@ -89,7 +93,7 @@ func (q *Queue) EnqueueTaskRunTestcase( task, err := newTaskRunTestcase( gameID, userID, - code, + codeHash, submissionID, testcaseID, stdin, diff --git a/backend/taskqueue/tasks.go b/backend/taskqueue/tasks.go index cbe83b1..d5f2993 100644 --- a/backend/taskqueue/tasks.go +++ b/backend/taskqueue/tasks.go @@ -8,6 +8,9 @@ import ( type TaskType string +// MD5 hash in hexadecimal format +type MD5HexHash string + const ( TaskTypeCreateSubmissionRecord TaskType = "create_submission_record" TaskTypeCompileSwiftToWasm TaskType = "compile_swift_to_wasm" @@ -16,13 +19,14 @@ const ( ) type TaskPayloadBase struct { - GameID int - UserID int - Code string + GameID int + UserID int + CodeHash MD5HexHash } type TaskPayloadCreateSubmissionRecord struct { TaskPayloadBase + Code string CodeSize int } @@ -31,13 +35,15 @@ func newTaskCreateSubmissionRecord( userID int, code string, codeSize int, + codeHash MD5HexHash, ) (*asynq.Task, error) { payload, err := json.Marshal(TaskPayloadCreateSubmissionRecord{ TaskPayloadBase: TaskPayloadBase{ - GameID: gameID, - UserID: userID, - Code: code, + GameID: gameID, + UserID: userID, + CodeHash: codeHash, }, + Code: code, CodeSize: codeSize, }) if err != nil { @@ -46,28 +52,31 @@ func newTaskCreateSubmissionRecord( return asynq.NewTask(string(TaskTypeCreateSubmissionRecord), payload), nil } -func (t *TaskPayloadCreateSubmissionRecord) GameID() int { return t.TaskPayloadBase.GameID } -func (t *TaskPayloadCreateSubmissionRecord) UserID() int { return t.TaskPayloadBase.UserID } -func (t *TaskPayloadCreateSubmissionRecord) Code() string { return t.TaskPayloadBase.Code } +func (t *TaskPayloadCreateSubmissionRecord) GameID() int { return t.TaskPayloadBase.GameID } +func (t *TaskPayloadCreateSubmissionRecord) UserID() int { return t.TaskPayloadBase.UserID } +func (t *TaskPayloadCreateSubmissionRecord) CodeHash() MD5HexHash { return t.TaskPayloadBase.CodeHash } type TaskPayloadCompileSwiftToWasm struct { TaskPayloadBase SubmissionID int + Code string } func newTaskCompileSwiftToWasm( gameID int, userID int, code string, + codeHash MD5HexHash, submissionID int, ) (*asynq.Task, error) { payload, err := json.Marshal(TaskPayloadCompileSwiftToWasm{ TaskPayloadBase: TaskPayloadBase{ - GameID: gameID, - UserID: userID, - Code: code, + GameID: gameID, + UserID: userID, + CodeHash: codeHash, }, SubmissionID: submissionID, + Code: code, }) if err != nil { return nil, err @@ -75,9 +84,9 @@ func newTaskCompileSwiftToWasm( return asynq.NewTask(string(TaskTypeCompileSwiftToWasm), payload), nil } -func (t *TaskPayloadCompileSwiftToWasm) GameID() int { return t.TaskPayloadBase.GameID } -func (t *TaskPayloadCompileSwiftToWasm) UserID() int { return t.TaskPayloadBase.UserID } -func (t *TaskPayloadCompileSwiftToWasm) Code() string { return t.TaskPayloadBase.Code } +func (t *TaskPayloadCompileSwiftToWasm) GameID() int { return t.TaskPayloadBase.GameID } +func (t *TaskPayloadCompileSwiftToWasm) UserID() int { return t.TaskPayloadBase.UserID } +func (t *TaskPayloadCompileSwiftToWasm) CodeHash() MD5HexHash { return t.TaskPayloadBase.CodeHash } type TaskPayloadCompileWasmToNativeExecutable struct { TaskPayloadBase @@ -87,14 +96,14 @@ type TaskPayloadCompileWasmToNativeExecutable struct { func newTaskCompileWasmToNativeExecutable( gameID int, userID int, - code string, + codeHash MD5HexHash, submissionID int, ) (*asynq.Task, error) { payload, err := json.Marshal(TaskPayloadCompileWasmToNativeExecutable{ TaskPayloadBase: TaskPayloadBase{ - GameID: gameID, - UserID: userID, - Code: code, + GameID: gameID, + UserID: userID, + CodeHash: codeHash, }, SubmissionID: submissionID, }) @@ -104,9 +113,11 @@ func newTaskCompileWasmToNativeExecutable( return asynq.NewTask(string(TaskTypeCompileWasmToNativeExecutable), payload), nil } -func (t *TaskPayloadCompileWasmToNativeExecutable) GameID() int { return t.TaskPayloadBase.GameID } -func (t *TaskPayloadCompileWasmToNativeExecutable) UserID() int { return t.TaskPayloadBase.UserID } -func (t *TaskPayloadCompileWasmToNativeExecutable) Code() string { return t.TaskPayloadBase.Code } +func (t *TaskPayloadCompileWasmToNativeExecutable) GameID() int { return t.TaskPayloadBase.GameID } +func (t *TaskPayloadCompileWasmToNativeExecutable) UserID() int { return t.TaskPayloadBase.UserID } +func (t *TaskPayloadCompileWasmToNativeExecutable) CodeHash() MD5HexHash { + return t.TaskPayloadBase.CodeHash +} type TaskPayloadRunTestcase struct { TaskPayloadBase @@ -119,7 +130,7 @@ type TaskPayloadRunTestcase struct { func newTaskRunTestcase( gameID int, userID int, - code string, + codeHash MD5HexHash, submissionID int, testcaseID int, stdin string, @@ -127,9 +138,9 @@ func newTaskRunTestcase( ) (*asynq.Task, error) { payload, err := json.Marshal(TaskPayloadRunTestcase{ TaskPayloadBase: TaskPayloadBase{ - GameID: gameID, - UserID: userID, - Code: code, + GameID: gameID, + UserID: userID, + CodeHash: codeHash, }, SubmissionID: submissionID, TestcaseID: testcaseID, @@ -142,9 +153,9 @@ func newTaskRunTestcase( return asynq.NewTask(string(TaskTypeRunTestcase), payload), nil } -func (t *TaskPayloadRunTestcase) GameID() int { return t.TaskPayloadBase.GameID } -func (t *TaskPayloadRunTestcase) UserID() int { return t.TaskPayloadBase.UserID } -func (t *TaskPayloadRunTestcase) Code() string { return t.TaskPayloadBase.Code } +func (t *TaskPayloadRunTestcase) GameID() int { return t.TaskPayloadBase.GameID } +func (t *TaskPayloadRunTestcase) UserID() int { return t.TaskPayloadBase.UserID } +func (t *TaskPayloadRunTestcase) CodeHash() MD5HexHash { return t.TaskPayloadBase.CodeHash } type TaskResult interface { Type() TaskType |
