From 5964fa404909550a2dd42a75633fef223fdb05fb Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 12 Aug 2024 01:23:54 +0900 Subject: feat: do not show preliminary score --- backend/api/generated.go | 58 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'backend/api/generated.go') diff --git a/backend/api/generated.go b/backend/api/generated.go index ac536c0..dd85f04 100644 --- a/backend/api/generated.go +++ b/backend/api/generated.go @@ -213,8 +213,7 @@ type GameWatcherMessageS2CSubmit struct { // GameWatcherMessageS2CSubmitPayload defines model for GameWatcherMessageS2CSubmitPayload. type GameWatcherMessageS2CSubmitPayload struct { - PlayerID int `json:"player_id"` - PreliminaryScore int `json:"preliminary_score"` + PlayerID int `json:"player_id"` } // GameWatcherMessageS2CSubmitResult defines model for GameWatcherMessageS2CSubmitResult. @@ -226,6 +225,7 @@ type GameWatcherMessageS2CSubmitResult struct { // GameWatcherMessageS2CSubmitResultPayload defines model for GameWatcherMessageS2CSubmitResultPayload. type GameWatcherMessageS2CSubmitResultPayload struct { PlayerID int `json:"player_id"` + Score nullable.Nullable[int] `json:"score"` Status GameWatcherMessageS2CSubmitResultPayloadStatus `json:"status"` } @@ -1108,33 +1108,33 @@ func (sh *strictHandler) GetToken(ctx echo.Context, params GetTokenParams) error // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "n5IHiANszAUWYJ7n+V8BAAD//+IyXiP0JAAA", } // GetSwagger returns the content of the embedded swagger specification file -- cgit v1.2.3-70-g09d2 From b3d91170662accdd48cdfc42ca2180521b096669 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 12 Aug 2024 01:56:57 +0900 Subject: refactor: rename verification_steps for consistant naming --- backend/api/generated.go | 84 ++++++++++++------------- backend/api/handler.go | 10 +-- frontend/app/.server/api/schema.d.ts | 4 +- frontend/app/components/GolfWatchApp.client.tsx | 4 +- openapi/api-server.yaml | 8 +-- 5 files changed, 55 insertions(+), 55 deletions(-) (limited to 'backend/api/generated.go') diff --git a/backend/api/generated.go b/backend/api/generated.go index dd85f04..f3be897 100644 --- a/backend/api/generated.go +++ b/backend/api/generated.go @@ -72,17 +72,23 @@ type Error struct { Message string `json:"message"` } +// ExecStep defines model for ExecStep. +type ExecStep struct { + Label string `json:"label"` + TestcaseID nullable.Nullable[int] `json:"testcase_id"` +} + // Game defines model for Game. type Game struct { - DisplayName string `json:"display_name"` - DurationSeconds int `json:"duration_seconds"` - GameID int `json:"game_id"` - GameType GameGameType `json:"game_type"` - Players []User `json:"players"` - Problem Problem `json:"problem"` - StartedAt *int `json:"started_at,omitempty"` - State GameState `json:"state"` - VerificationSteps []VerificationStep `json:"verification_steps"` + DisplayName string `json:"display_name"` + DurationSeconds int `json:"duration_seconds"` + ExecSteps []ExecStep `json:"exec_steps"` + GameID int `json:"game_id"` + GameType GameGameType `json:"game_type"` + Players []User `json:"players"` + Problem Problem `json:"problem"` + StartedAt *int `json:"started_at,omitempty"` + State GameState `json:"state"` } // GameGameType defines model for Game.GameType. @@ -248,12 +254,6 @@ type User struct { Username string `json:"username"` } -// VerificationStep defines model for VerificationStep. -type VerificationStep struct { - Label string `json:"label"` - TestcaseID nullable.Nullable[int] `json:"testcase_id"` -} - // HeaderAuthorization defines model for header_authorization. type HeaderAuthorization = string @@ -1108,33 +1108,33 @@ func (sh *strictHandler) GetToken(ctx echo.Context, params GetTokenParams) error // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "n5IHiANszAUWYJ7n+V8BAAD//+IyXiP0JAAA", + "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", + "/UzJPYQeNuY8CzBN0/TfAAAA//9NY96x1CQAAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/api/handler.go b/backend/api/handler.go index 4150ba6..7ef77e5 100644 --- a/backend/api/handler.go +++ b/backend/api/handler.go @@ -146,12 +146,12 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } - verificationSteps := make([]VerificationStep, len(testcaseIDs)+1) - verificationSteps[0] = VerificationStep{ + execSteps := make([]ExecStep, len(testcaseIDs)+1) + execSteps[0] = ExecStep{ Label: "Compile", } for i, testcaseID := range testcaseIDs { - verificationSteps[i+1] = VerificationStep{ + execSteps[i+1] = ExecStep{ TestcaseID: nullable.NewNullableWithValue(int(testcaseID)), Label: fmt.Sprintf("Testcase %d", i+1), } @@ -168,8 +168,8 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use Title: row.Title, Description: row.Description, }, - Players: players, - VerificationSteps: verificationSteps, + Players: players, + ExecSteps: execSteps, } return GetGame200JSONResponse{ Game: game, diff --git a/frontend/app/.server/api/schema.d.ts b/frontend/app/.server/api/schema.d.ts index 157a96f..5b37081 100644 --- a/frontend/app/.server/api/schema.d.ts +++ b/frontend/app/.server/api/schema.d.ts @@ -113,9 +113,9 @@ export interface components { started_at?: number; problem: components["schemas"]["Problem"]; players: components["schemas"]["User"][]; - verification_steps: components["schemas"]["VerificationStep"][]; + exec_steps: components["schemas"]["ExecStep"][]; }; - VerificationStep: { + ExecStep: { /** @example 1 */ testcase_id: number | null; /** @example Test case 1 */ diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx index 7041572..481b997 100644 --- a/frontend/app/components/GolfWatchApp.client.tsx +++ b/frontend/app/components/GolfWatchApp.client.tsx @@ -127,7 +127,7 @@ export default function GolfWatchApp({ ...prev, submitResult: { status: "running", - execResults: game.verification_steps.map((r) => ({ + execResults: game.exec_steps.map((r) => ({ testcase_id: r.testcase_id, status: "running", label: r.label, @@ -217,7 +217,7 @@ export default function GolfWatchApp({ } } }, [ - game.verification_steps, + game.exec_steps, game.started_at, lastJsonMessage, readyState, diff --git a/openapi/api-server.yaml b/openapi/api-server.yaml index 38e07d7..d13d738 100644 --- a/openapi/api-server.yaml +++ b/openapi/api-server.yaml @@ -218,10 +218,10 @@ components: type: array items: $ref: '#/components/schemas/User' - verification_steps: + exec_steps: type: array items: - $ref: '#/components/schemas/VerificationStep' + $ref: '#/components/schemas/ExecStep' required: - game_id - game_type @@ -230,8 +230,8 @@ components: - duration_seconds - problem - players - - verification_steps - VerificationStep: + - exec_steps + ExecStep: type: object properties: testcase_id: -- cgit v1.2.3-70-g09d2 From 8cbb00ae115545a5803f6d08283985ca089d7e41 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 12 Aug 2024 02:11:30 +0900 Subject: feat: add `submitresult` message --- backend/api/generated.go | 125 ++++++++++++----- backend/api/handler.go | 3 +- backend/game/hub.go | 150 +++++++++++++-------- backend/game/message.go | 11 +- frontend/app/.server/api/schema.d.ts | 22 ++- frontend/app/components/GolfPlayApp.client.tsx | 82 +++++++++-- .../components/GolfPlayApps/GolfPlayAppGaming.tsx | 13 +- frontend/app/components/GolfWatchApp.client.tsx | 8 +- openapi/api-server.yaml | 42 +++++- 9 files changed, 328 insertions(+), 128 deletions(-) (limited to 'backend/api/generated.go') diff --git a/backend/api/generated.go b/backend/api/generated.go index f3be897..7991f97 100644 --- a/backend/api/generated.go +++ b/backend/api/generated.go @@ -40,13 +40,23 @@ const ( // Defines values for GamePlayerMessageS2CExecResultPayloadStatus. const ( GamePlayerMessageS2CExecResultPayloadStatusCompileError GamePlayerMessageS2CExecResultPayloadStatus = "compile_error" - GamePlayerMessageS2CExecResultPayloadStatusFailure GamePlayerMessageS2CExecResultPayloadStatus = "failure" GamePlayerMessageS2CExecResultPayloadStatusInternalError GamePlayerMessageS2CExecResultPayloadStatus = "internal_error" + GamePlayerMessageS2CExecResultPayloadStatusRuntimeError GamePlayerMessageS2CExecResultPayloadStatus = "runtime_error" GamePlayerMessageS2CExecResultPayloadStatusSuccess GamePlayerMessageS2CExecResultPayloadStatus = "success" GamePlayerMessageS2CExecResultPayloadStatusTimeout GamePlayerMessageS2CExecResultPayloadStatus = "timeout" GamePlayerMessageS2CExecResultPayloadStatusWrongAnswer GamePlayerMessageS2CExecResultPayloadStatus = "wrong_answer" ) +// Defines values for GamePlayerMessageS2CSubmitResultPayloadStatus. +const ( + GamePlayerMessageS2CSubmitResultPayloadStatusCompileError GamePlayerMessageS2CSubmitResultPayloadStatus = "compile_error" + GamePlayerMessageS2CSubmitResultPayloadStatusInternalError GamePlayerMessageS2CSubmitResultPayloadStatus = "internal_error" + GamePlayerMessageS2CSubmitResultPayloadStatusRuntimeError GamePlayerMessageS2CSubmitResultPayloadStatus = "runtime_error" + GamePlayerMessageS2CSubmitResultPayloadStatusSuccess GamePlayerMessageS2CSubmitResultPayloadStatus = "success" + GamePlayerMessageS2CSubmitResultPayloadStatusTimeout GamePlayerMessageS2CSubmitResultPayloadStatus = "timeout" + GamePlayerMessageS2CSubmitResultPayloadStatusWrongAnswer GamePlayerMessageS2CSubmitResultPayloadStatus = "wrong_answer" +) + // Defines values for GameWatcherMessageS2CExecResultPayloadStatus. const ( GameWatcherMessageS2CExecResultPayloadStatusCompileError GameWatcherMessageS2CExecResultPayloadStatus = "compile_error" @@ -59,12 +69,12 @@ const ( // Defines values for GameWatcherMessageS2CSubmitResultPayloadStatus. const ( - CompileError GameWatcherMessageS2CSubmitResultPayloadStatus = "compile_error" - InternalError GameWatcherMessageS2CSubmitResultPayloadStatus = "internal_error" - RuntimeError GameWatcherMessageS2CSubmitResultPayloadStatus = "runtime_error" - Success GameWatcherMessageS2CSubmitResultPayloadStatus = "success" - Timeout GameWatcherMessageS2CSubmitResultPayloadStatus = "timeout" - WrongAnswer GameWatcherMessageS2CSubmitResultPayloadStatus = "wrong_answer" + GameWatcherMessageS2CSubmitResultPayloadStatusCompileError GameWatcherMessageS2CSubmitResultPayloadStatus = "compile_error" + GameWatcherMessageS2CSubmitResultPayloadStatusInternalError GameWatcherMessageS2CSubmitResultPayloadStatus = "internal_error" + GameWatcherMessageS2CSubmitResultPayloadStatusRuntimeError GameWatcherMessageS2CSubmitResultPayloadStatus = "runtime_error" + GameWatcherMessageS2CSubmitResultPayloadStatusSuccess GameWatcherMessageS2CSubmitResultPayloadStatus = "success" + GameWatcherMessageS2CSubmitResultPayloadStatusTimeout GameWatcherMessageS2CSubmitResultPayloadStatus = "timeout" + GameWatcherMessageS2CSubmitResultPayloadStatusWrongAnswer GameWatcherMessageS2CSubmitResultPayloadStatus = "wrong_answer" ) // Error defines model for Error. @@ -142,8 +152,10 @@ type GamePlayerMessageS2CExecResult struct { // GamePlayerMessageS2CExecResultPayload defines model for GamePlayerMessageS2CExecResultPayload. type GamePlayerMessageS2CExecResultPayload struct { - Score nullable.Nullable[int] `json:"score"` - Status GamePlayerMessageS2CExecResultPayloadStatus `json:"status"` + Status GamePlayerMessageS2CExecResultPayloadStatus `json:"status"` + Stderr string `json:"stderr"` + Stdout string `json:"stdout"` + TestcaseID nullable.Nullable[int] `json:"testcase_id"` } // GamePlayerMessageS2CExecResultPayloadStatus defines model for GamePlayerMessageS2CExecResultPayload.Status. @@ -160,6 +172,21 @@ type GamePlayerMessageS2CStartPayload struct { StartAt int `json:"start_at"` } +// GamePlayerMessageS2CSubmitResult defines model for GamePlayerMessageS2CSubmitResult. +type GamePlayerMessageS2CSubmitResult struct { + Data GamePlayerMessageS2CSubmitResultPayload `json:"data"` + Type string `json:"type"` +} + +// GamePlayerMessageS2CSubmitResultPayload defines model for GamePlayerMessageS2CSubmitResultPayload. +type GamePlayerMessageS2CSubmitResultPayload struct { + Score nullable.Nullable[int] `json:"score"` + Status GamePlayerMessageS2CSubmitResultPayloadStatus `json:"status"` +} + +// GamePlayerMessageS2CSubmitResultPayloadStatus defines model for GamePlayerMessageS2CSubmitResultPayload.Status. +type GamePlayerMessageS2CSubmitResultPayloadStatus string + // GameWatcherMessage defines model for GameWatcherMessage. type GameWatcherMessage struct { union json.RawMessage @@ -473,6 +500,32 @@ func (t *GamePlayerMessageS2C) MergeGamePlayerMessageS2CExecResult(v GamePlayerM return err } +// AsGamePlayerMessageS2CSubmitResult returns the union data inside the GamePlayerMessageS2C as a GamePlayerMessageS2CSubmitResult +func (t GamePlayerMessageS2C) AsGamePlayerMessageS2CSubmitResult() (GamePlayerMessageS2CSubmitResult, error) { + var body GamePlayerMessageS2CSubmitResult + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromGamePlayerMessageS2CSubmitResult overwrites any union data inside the GamePlayerMessageS2C as the provided GamePlayerMessageS2CSubmitResult +func (t *GamePlayerMessageS2C) FromGamePlayerMessageS2CSubmitResult(v GamePlayerMessageS2CSubmitResult) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeGamePlayerMessageS2CSubmitResult performs a merge with any union data inside the GamePlayerMessageS2C, using the provided GamePlayerMessageS2CSubmitResult +func (t *GamePlayerMessageS2C) MergeGamePlayerMessageS2CSubmitResult(v GamePlayerMessageS2CSubmitResult) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + func (t GamePlayerMessageS2C) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() return b, err @@ -1108,33 +1161,33 @@ func (sh *strictHandler) GetToken(ctx echo.Context, params GetTokenParams) error // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "/UzJPYQeNuY8CzBN0/TfAAAA//9NY96x1CQAAA==", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/api/handler.go b/backend/api/handler.go index 7ef77e5..eca6006 100644 --- a/backend/api/handler.go +++ b/backend/api/handler.go @@ -148,7 +148,8 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use } execSteps := make([]ExecStep, len(testcaseIDs)+1) execSteps[0] = ExecStep{ - Label: "Compile", + TestcaseID: nullable.NewNullNullable[int](), + Label: "Compile", } for i, testcaseID := range testcaseIDs { execSteps[i+1] = ExecStep{ diff --git a/backend/game/hub.go b/backend/game/hub.go index 670b05f..490b79e 100644 --- a/backend/game/hub.go +++ b/backend/game/hub.go @@ -137,6 +137,15 @@ func (hub *gameHub) run() { } } +func (hub *gameHub) sendToPlayer(playerID int, msg playerMessageS2C) { + for player := range hub.players { + if player.playerID == playerID { + player.s2cMessages <- msg + return + } + } +} + func (hub *gameHub) broadcastToWatchers(msg watcherMessageS2C) { for watcher := range hub.watchers { watcher.s2cMessages <- msg @@ -159,18 +168,12 @@ func (hub *gameHub) processTaskResults() { case *taskqueue.TaskResultCreateSubmissionRecord: err := hub.processTaskResultCreateSubmissionRecord(taskResult) if err != nil { - for player := range hub.players { - if player.playerID != taskResult.TaskPayload.UserID() { - continue - } - player.s2cMessages <- &playerMessageS2CExecResult{ - Type: playerMessageTypeS2CExecResult, - Data: playerMessageS2CExecResultPayload{ - Score: nil, - Status: api.GamePlayerMessageS2CExecResultPayloadStatus(err.Status), - }, - } - } + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CSubmitResult{ + Type: playerMessageTypeS2CSubmitResult, + Data: playerMessageS2CSubmitResultPayload{ + Status: api.GamePlayerMessageS2CSubmitResultPayloadStatus(err.Status), + }, + }) hub.broadcastToWatchers(&watcherMessageS2CSubmitResult{ Type: watcherMessageTypeS2CSubmitResult, Data: watcherMessageS2CSubmitResultPayload{ @@ -182,18 +185,20 @@ func (hub *gameHub) processTaskResults() { case *taskqueue.TaskResultCompileSwiftToWasm: err := hub.processTaskResultCompileSwiftToWasm(taskResult) if err != nil { - for player := range hub.players { - if player.playerID != taskResult.TaskPayload.UserID() { - continue - } - player.s2cMessages <- &playerMessageS2CExecResult{ - Type: playerMessageTypeS2CExecResult, - Data: playerMessageS2CExecResultPayload{ - Score: nil, - Status: api.GamePlayerMessageS2CExecResultPayloadStatus(err.Status), - }, - } - } + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + Status: api.GamePlayerMessageS2CExecResultPayloadStatus(err.Status), + Stdout: err.Stdout, + Stderr: err.Stderr, + }, + }) + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CSubmitResult{ + Type: playerMessageTypeS2CSubmitResult, + Data: playerMessageS2CSubmitResultPayload{ + Status: api.GamePlayerMessageS2CSubmitResultPayloadStatus(err.Status), + }, + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -214,18 +219,20 @@ func (hub *gameHub) processTaskResults() { case *taskqueue.TaskResultCompileWasmToNativeExecutable: err := hub.processTaskResultCompileWasmToNativeExecutable(taskResult) if err != nil { - for player := range hub.players { - if player.playerID != taskResult.TaskPayload.UserID() { - continue - } - player.s2cMessages <- &playerMessageS2CExecResult{ - Type: playerMessageTypeS2CExecResult, - Data: playerMessageS2CExecResultPayload{ - Score: nil, - Status: api.GamePlayerMessageS2CExecResultPayloadStatus(err.Status), - }, - } - } + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + Status: api.GamePlayerMessageS2CExecResultPayloadStatus(err.Status), + Stdout: err.Stdout, + Stderr: err.Stderr, + }, + }) + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CSubmitResult{ + Type: playerMessageTypeS2CSubmitResult, + Data: playerMessageS2CSubmitResultPayload{ + Status: api.GamePlayerMessageS2CSubmitResultPayloadStatus(err.Status), + }, + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -243,6 +250,15 @@ func (hub *gameHub) processTaskResults() { }, }) } else { + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + Status: api.GamePlayerMessageS2CExecResultPayloadStatus("success"), + // TODO: inherit the command stdout/stderr. + Stdout: "Successfully compiled", + Stderr: "", + }, + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -268,18 +284,22 @@ func (hub *gameHub) processTaskResults() { Stderr: "", }) if err != nil { - for player := range hub.players { - if player.playerID != taskResult.TaskPayload.UserID() { - continue - } - player.s2cMessages <- &playerMessageS2CExecResult{ - Type: playerMessageTypeS2CExecResult, - Data: playerMessageS2CExecResultPayload{ - Score: nil, - Status: api.GamePlayerMessageS2CExecResultPayloadStatus("internal_error"), - }, - } - } + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + TestcaseID: nullable.NewNullableWithValue(int(taskResult.TaskPayload.TestcaseID)), + Status: api.GamePlayerMessageS2CExecResultPayloadStatus("internal_error"), + // TODO: inherit the command stdout/stderr? + Stdout: "", + Stderr: "internal error", + }, + }) + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CSubmitResult{ + Type: playerMessageTypeS2CSubmitResult, + Data: playerMessageS2CSubmitResultPayload{ + Status: api.GamePlayerMessageS2CSubmitResultPayloadStatus("internal_error"), + }, + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -300,19 +320,16 @@ func (hub *gameHub) processTaskResults() { }) continue } - for player := range hub.players { - if player.playerID != taskResult.TaskPayload.UserID() { - continue - } - player.s2cMessages <- &playerMessageS2CExecResult{ + if err1 != nil { + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ Type: playerMessageTypeS2CExecResult, Data: playerMessageS2CExecResultPayload{ - Score: nil, - Status: api.GamePlayerMessageS2CExecResultPayloadStatus(aggregatedStatus), + TestcaseID: nullable.NewNullableWithValue(int(taskResult.TaskPayload.TestcaseID)), + Status: api.GamePlayerMessageS2CExecResultPayloadStatus(aggregatedStatus), + Stdout: err1.Stdout, + Stderr: err1.Stderr, }, - } - } - if err1 != nil { + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -324,6 +341,16 @@ func (hub *gameHub) processTaskResults() { }, }) } else { + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + TestcaseID: nullable.NewNullableWithValue(int(taskResult.TaskPayload.TestcaseID)), + Status: api.GamePlayerMessageS2CExecResultPayloadStatus("success"), + // TODO: inherit the command stdout/stderr? + Stdout: "Testcase passed", + Stderr: "", + }, + }) hub.broadcastToWatchers(&watcherMessageS2CExecResult{ Type: watcherMessageTypeS2CExecResult, Data: watcherMessageS2CExecResultPayload{ @@ -344,6 +371,13 @@ func (hub *gameHub) processTaskResults() { score = nullable.NewNullableWithValue(int(codeSize)) } } + hub.sendToPlayer(taskResult.TaskPayload.UserID(), &playerMessageS2CSubmitResult{ + Type: playerMessageTypeS2CSubmitResult, + Data: playerMessageS2CSubmitResultPayload{ + Status: api.GamePlayerMessageS2CSubmitResultPayloadStatus(aggregatedStatus), + Score: score, + }, + }) hub.broadcastToWatchers(&watcherMessageS2CSubmitResult{ Type: watcherMessageTypeS2CSubmitResult, Data: watcherMessageS2CSubmitResultPayload{ diff --git a/backend/game/message.go b/backend/game/message.go index 4877ac4..b535c1d 100644 --- a/backend/game/message.go +++ b/backend/game/message.go @@ -8,10 +8,11 @@ import ( ) const ( - playerMessageTypeS2CStart = "player:s2c:start" - playerMessageTypeS2CExecResult = "player:s2c:execresult" - playerMessageTypeC2SCode = "player:c2s:code" - playerMessageTypeC2SSubmit = "player:c2s:submit" + playerMessageTypeS2CStart = "player:s2c:start" + playerMessageTypeS2CExecResult = "player:s2c:execresult" + playerMessageTypeS2CSubmitResult = "player:s2c:submitresult" + playerMessageTypeC2SCode = "player:c2s:code" + playerMessageTypeC2SSubmit = "player:c2s:submit" ) type playerMessageC2SWithClient struct { @@ -24,6 +25,8 @@ type playerMessageS2CStart = api.GamePlayerMessageS2CStart type playerMessageS2CStartPayload = api.GamePlayerMessageS2CStartPayload type playerMessageS2CExecResult = api.GamePlayerMessageS2CExecResult type playerMessageS2CExecResultPayload = api.GamePlayerMessageS2CExecResultPayload +type playerMessageS2CSubmitResult = api.GamePlayerMessageS2CSubmitResult +type playerMessageS2CSubmitResultPayload = api.GamePlayerMessageS2CSubmitResultPayload type playerMessageC2S = interface{} type playerMessageC2SCode = api.GamePlayerMessageC2SCode diff --git a/frontend/app/.server/api/schema.d.ts b/frontend/app/.server/api/schema.d.ts index 5b37081..7fd612e 100644 --- a/frontend/app/.server/api/schema.d.ts +++ b/frontend/app/.server/api/schema.d.ts @@ -130,7 +130,7 @@ export interface components { description: string; }; GamePlayerMessage: components["schemas"]["GamePlayerMessageS2C"] | components["schemas"]["GamePlayerMessageC2S"]; - GamePlayerMessageS2C: components["schemas"]["GamePlayerMessageS2CStart"] | components["schemas"]["GamePlayerMessageS2CExecResult"]; + GamePlayerMessageS2C: components["schemas"]["GamePlayerMessageS2CStart"] | components["schemas"]["GamePlayerMessageS2CExecResult"] | components["schemas"]["GamePlayerMessageS2CSubmitResult"]; GamePlayerMessageS2CStart: { /** @constant */ type: "player:s2c:start"; @@ -146,11 +146,29 @@ export interface components { data: components["schemas"]["GamePlayerMessageS2CExecResultPayload"]; }; GamePlayerMessageS2CExecResultPayload: { + /** @example 1 */ + testcase_id: number | null; /** * @example success * @enum {string} */ - status: "success" | "failure" | "timeout" | "internal_error" | "compile_error" | "wrong_answer"; + status: "success" | "wrong_answer" | "timeout" | "runtime_error" | "internal_error" | "compile_error"; + /** @example Hello, world! */ + stdout: string; + /** @example */ + stderr: string; + }; + GamePlayerMessageS2CSubmitResult: { + /** @constant */ + type: "player:s2c:submitresult"; + data: components["schemas"]["GamePlayerMessageS2CSubmitResultPayload"]; + }; + GamePlayerMessageS2CSubmitResultPayload: { + /** + * @example success + * @enum {string} + */ + status: "success" | "wrong_answer" | "timeout" | "runtime_error" | "internal_error" | "compile_error"; /** @example 100 */ score: number | null; }; diff --git a/frontend/app/components/GolfPlayApp.client.tsx b/frontend/app/components/GolfPlayApp.client.tsx index ef3a229..dbc8c1b 100644 --- a/frontend/app/components/GolfPlayApp.client.tsx +++ b/frontend/app/components/GolfPlayApp.client.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import type { components } from "../.server/api/schema"; import useWebSocket, { ReadyState } from "../hooks/useWebSocket"; +import type { PlayerInfo } from "../models/PlayerInfo"; import GolfPlayAppConnecting from "./GolfPlayApps/GolfPlayAppConnecting"; import GolfPlayAppFinished from "./GolfPlayApps/GolfPlayAppFinished"; import GolfPlayAppGaming from "./GolfPlayApps/GolfPlayAppGaming"; @@ -73,9 +74,21 @@ export default function GolfPlayApp({ } }, [gameState, startedAt, game.duration_seconds]); - const [currentScore, setCurrentScore] = useState(null); - - const [lastExecStatus, setLastExecStatus] = useState(null); + const [playerInfo, setPlayerInfo] = useState>({ + displayName: player.display_name, + iconPath: player.icon_path ?? null, + score: null, + submitResult: { + status: "waiting_submission", + execResults: game.exec_steps.map((r) => ({ + testcase_id: r.testcase_id, + status: "waiting_submission", + label: r.label, + stdout: "", + stderr: "", + })), + }, + }); const onCodeChange = useDebouncedCallback((code: string) => { console.log("player:c2s:code"); @@ -94,6 +107,18 @@ export default function GolfPlayApp({ type: "player:c2s:submit", data: { code }, }); + setPlayerInfo((prev) => ({ + ...prev, + submitResult: { + status: "running", + execResults: prev.submitResult.execResults.map((r) => ({ + ...r, + status: "running", + stdout: "", + stderr: "", + })), + }, + })); }, 1000); if (readyState === ReadyState.UNINSTANTIATED) { @@ -123,14 +148,46 @@ export default function GolfPlayApp({ setGameState("starting"); } } else if (lastJsonMessage.type === "player:s2c:execresult") { + const { testcase_id, status, stdout, stderr } = lastJsonMessage.data; + setPlayerInfo((prev) => { + const ret = { ...prev }; + ret.submitResult = { + ...prev.submitResult, + execResults: prev.submitResult.execResults.map((r) => + r.testcase_id === testcase_id && r.status === "running" + ? { + ...r, + status, + stdout, + stderr, + } + : r, + ), + }; + return ret; + }); + } else if (lastJsonMessage.type === "player:s2c:submitresult") { const { status, score } = lastJsonMessage.data; - if ( - score !== null && - (currentScore === null || score < currentScore) - ) { - setCurrentScore(score); - } - setLastExecStatus(status); + setPlayerInfo((prev) => { + const ret = { ...prev }; + ret.submitResult = { + ...prev.submitResult, + status, + }; + if (status === "success") { + if (score) { + if (ret.score === null || score < ret.score) { + ret.score = score; + } + } + } else { + ret.submitResult.execResults = prev.submitResult.execResults.map( + (r) => + r.status === "running" ? { ...r, status: "canceled" } : r, + ); + } + return ret; + }); } } else { if (game.started_at) { @@ -165,7 +222,6 @@ export default function GolfPlayApp({ lastJsonMessage, readyState, gameState, - currentScore, ]); if (gameState === "connecting") { @@ -178,13 +234,11 @@ export default function GolfPlayApp({ return ( ); } else if (gameState === "finished") { diff --git a/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx index 03acf5a..08490a6 100644 --- a/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx +++ b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx @@ -1,28 +1,25 @@ import { Link } from "@remix-run/react"; import React, { useRef } from "react"; import SubmitButton from "../../components/SubmitButton"; +import type { PlayerInfo } from "../../models/PlayerInfo"; import BorderedContainer from "../BorderedContainer"; type Props = { gameDisplayName: string; - playerDisplayName: string; + playerInfo: Omit; problemTitle: string; problemDescription: string; onCodeChange: (code: string) => void; onCodeSubmit: (code: string) => void; - currentScore: number | null; - lastExecStatus: string | null; }; export default function GolfPlayAppGaming({ gameDisplayName, - playerDisplayName, + playerInfo, problemTitle, problemDescription, onCodeChange, onCodeSubmit, - currentScore, - lastExecStatus, }: Props) { const textareaRef = useRef(null); @@ -45,7 +42,7 @@ export default function GolfPlayAppGaming({
- {playerDisplayName} + {playerInfo.displayName}
@@ -69,7 +66,7 @@ export default function GolfPlayAppGaming({ 提出
- Score: {currentScore ?? "-"} ({lastExecStatus ?? "-"}) + Score: {playerInfo.score ?? "-"}
diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx index 7f582c9..9d3f752 100644 --- a/frontend/app/components/GolfWatchApp.client.tsx +++ b/frontend/app/components/GolfWatchApp.client.tsx @@ -161,8 +161,8 @@ export default function GolfWatchApp({ setter((prev) => { const ret = { ...prev }; ret.submitResult = { - ...ret.submitResult, - execResults: ret.submitResult.execResults.map((r) => + ...prev.submitResult, + execResults: prev.submitResult.execResults.map((r) => r.testcase_id === testcase_id && r.status === "running" ? { ...r, @@ -182,7 +182,7 @@ export default function GolfWatchApp({ setter((prev) => { const ret = { ...prev }; ret.submitResult = { - ...ret.submitResult, + ...prev.submitResult, status, }; if (status === "success") { @@ -192,7 +192,7 @@ export default function GolfWatchApp({ } } } else { - ret.submitResult.execResults = ret.submitResult.execResults.map( + ret.submitResult.execResults = prev.submitResult.execResults.map( (r) => r.status === "running" ? { ...r, status: "canceled" } : r, ); diff --git a/openapi/api-server.yaml b/openapi/api-server.yaml index d13d738..036d8d6 100644 --- a/openapi/api-server.yaml +++ b/openapi/api-server.yaml @@ -268,6 +268,7 @@ components: oneOf: - $ref: '#/components/schemas/GamePlayerMessageS2CStart' - $ref: '#/components/schemas/GamePlayerMessageS2CExecResult' + - $ref: '#/components/schemas/GamePlayerMessageS2CSubmitResult' GamePlayerMessageS2CStart: type: object properties: @@ -301,16 +302,55 @@ components: GamePlayerMessageS2CExecResultPayload: type: object properties: + testcase_id: + type: integer + nullable: true + example: 1 status: type: string example: "success" enum: - success - - failure + - wrong_answer - timeout + - runtime_error - internal_error - compile_error + stdout: + type: string + example: "Hello, world!" + stderr: + type: string + example: "" + required: + - testcase_id + - status + - stdout + - stderr + GamePlayerMessageS2CSubmitResult: + type: object + properties: + type: + type: string + const: "player:s2c:submitresult" + data: + $ref: '#/components/schemas/GamePlayerMessageS2CSubmitResultPayload' + required: + - type + - data + GamePlayerMessageS2CSubmitResultPayload: + type: object + properties: + status: + type: string + example: "success" + enum: + - success - wrong_answer + - timeout + - runtime_error + - internal_error + - compile_error score: type: integer nullable: true -- cgit v1.2.3-70-g09d2 From b37d6f213c2f3b19631e5067f39a7106859faaed Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 12 Aug 2024 05:54:37 +0900 Subject: feat: show left time in play page --- backend/admin/handler.go | 20 +++---- backend/api/generated.go | 61 +++++++++++----------- backend/api/handler.go | 8 +-- backend/game/hub.go | 4 +- frontend/app/components/GolfPlayApp.client.tsx | 11 ++-- .../components/GolfPlayApps/GolfPlayAppGaming.tsx | 19 +++++-- frontend/app/components/GolfWatchApp.client.tsx | 14 ++--- .../GolfWatchApps/GolfWatchAppGaming.tsx | 16 +++--- openapi/api-server.yaml | 3 ++ 9 files changed, 90 insertions(+), 66 deletions(-) (limited to 'backend/api/generated.go') diff --git a/backend/admin/handler.go b/backend/admin/handler.go index 5398107..41eacd4 100644 --- a/backend/admin/handler.go +++ b/backend/admin/handler.go @@ -229,16 +229,6 @@ func (h *Handler) postGameEdit(c echo.Context) error { } } - { - // TODO: - if state != row.State && state == "starting" { - err := h.hubs.StartGame(int(gameID)) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - } - } - err = h.q.UpdateGame(c.Request().Context(), db.UpdateGameParams{ GameID: int32(gameID), GameType: gameType, @@ -252,5 +242,15 @@ func (h *Handler) postGameEdit(c echo.Context) error { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } + { + // TODO: + if state != row.State && state == "starting" { + err := h.hubs.StartGame(int(gameID)) + if err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + } + } + return c.Redirect(http.StatusSeeOther, c.Request().URL.Path) } diff --git a/backend/api/generated.go b/backend/api/generated.go index 7991f97..7eb5940 100644 --- a/backend/api/generated.go +++ b/backend/api/generated.go @@ -97,7 +97,7 @@ type Game struct { GameType GameGameType `json:"game_type"` Players []User `json:"players"` Problem Problem `json:"problem"` - StartedAt *int `json:"started_at,omitempty"` + StartedAt *int64 `json:"started_at,omitempty"` State GameState `json:"state"` } @@ -169,7 +169,7 @@ type GamePlayerMessageS2CStart struct { // GamePlayerMessageS2CStartPayload defines model for GamePlayerMessageS2CStartPayload. type GamePlayerMessageS2CStartPayload struct { - StartAt int `json:"start_at"` + StartAt int64 `json:"start_at"` } // GamePlayerMessageS2CSubmitResult defines model for GamePlayerMessageS2CSubmitResult. @@ -235,7 +235,7 @@ type GameWatcherMessageS2CStart struct { // GameWatcherMessageS2CStartPayload defines model for GameWatcherMessageS2CStartPayload. type GameWatcherMessageS2CStartPayload struct { - StartAt int `json:"start_at"` + StartAt int64 `json:"start_at"` } // GameWatcherMessageS2CSubmit defines model for GameWatcherMessageS2CSubmit. @@ -1161,33 +1161,34 @@ func (sh *strictHandler) GetToken(ctx echo.Context, params GetTokenParams) error // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "AA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/api/handler.go b/backend/api/handler.go index eca6006..a0ecd4c 100644 --- a/backend/api/handler.go +++ b/backend/api/handler.go @@ -84,9 +84,9 @@ func (h *Handler) GetGames(ctx context.Context, _ GetGamesRequestObject, user *a } games := make([]Game, len(gameRows)) for i, row := range gameRows { - var startedAt *int + var startedAt *int64 if row.StartedAt.Valid { - startedAtTimestamp := int(row.StartedAt.Time.Unix()) + startedAtTimestamp := row.StartedAt.Time.Unix() startedAt = &startedAtTimestamp } games[i] = Game{ @@ -123,9 +123,9 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use } return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } - var startedAt *int + var startedAt *int64 if row.StartedAt.Valid { - startedAtTimestamp := int(row.StartedAt.Time.Unix()) + startedAtTimestamp := row.StartedAt.Time.Unix() startedAt = &startedAtTimestamp } playerRows, err := h.q.ListGamePlayers(ctx, int32(gameID)) diff --git a/backend/game/hub.go b/backend/game/hub.go index e08ed4a..7c06e05 100644 --- a/backend/game/hub.go +++ b/backend/game/hub.go @@ -509,14 +509,14 @@ func (hub *gameHub) startGame() error { player.s2cMessages <- &playerMessageS2CStart{ Type: playerMessageTypeS2CStart, Data: playerMessageS2CStartPayload{ - StartAt: int(startAt.Unix()), + StartAt: startAt.Unix(), }, } } hub.broadcastToWatchers(&watcherMessageS2CStart{ Type: watcherMessageTypeS2CStart, Data: watcherMessageS2CStartPayload{ - StartAt: int(startAt.Unix()), + StartAt: startAt.Unix(), }, }) err := hub.q.UpdateGameStartedAt(hub.ctx, db.UpdateGameStartedAtParams{ diff --git a/frontend/app/components/GolfPlayApp.client.tsx b/frontend/app/components/GolfPlayApp.client.tsx index dbc8c1b..d527e07 100644 --- a/frontend/app/components/GolfPlayApp.client.tsx +++ b/frontend/app/components/GolfPlayApp.client.tsx @@ -43,16 +43,17 @@ export default function GolfPlayApp({ const [leftTimeSeconds, setLeftTimeSeconds] = useState(null); useEffect(() => { - if (gameState === "starting" && startedAt !== null) { + if ( + (gameState === "starting" || gameState === "gaming") && + startedAt !== null + ) { const timer1 = setInterval(() => { setLeftTimeSeconds((prev) => { if (prev === null) { return null; } if (prev <= 1) { - clearInterval(timer1); setGameState("gaming"); - return 0; } return prev - 1; }); @@ -196,7 +197,7 @@ export default function GolfPlayApp({ // The game has already started. if (gameState !== "gaming" && gameState !== "finished") { setStartedAt(game.started_at); - setLeftTimeSeconds(0); + setLeftTimeSeconds(game.started_at - nowSec); setGameState("gaming"); } } else { @@ -234,6 +235,8 @@ export default function GolfPlayApp({ return ( ; problemTitle: string; problemDescription: string; @@ -19,6 +21,8 @@ type Props = { export default function GolfPlayAppGaming({ gameDisplayName, + gameDurationSeconds, + leftTimeSeconds, playerInfo, problemTitle, problemDescription, @@ -37,12 +41,19 @@ export default function GolfPlayAppGaming({ } }; + const leftTime = (() => { + const k = gameDurationSeconds + leftTimeSeconds; + const m = Math.floor(k / 60); + const s = k % 60; + return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; + })(); + return (
{gameDisplayName}
-
03:21
+
{leftTime}
diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx index 9d3f752..b2f3b69 100644 --- a/frontend/app/components/GolfWatchApp.client.tsx +++ b/frontend/app/components/GolfWatchApp.client.tsx @@ -39,16 +39,17 @@ export default function GolfWatchApp({ const [leftTimeSeconds, setLeftTimeSeconds] = useState(null); useEffect(() => { - if (gameState === "starting" && startedAt !== null) { + if ( + (gameState === "starting" || gameState === "gaming") && + startedAt !== null + ) { const timer1 = setInterval(() => { setLeftTimeSeconds((prev) => { if (prev === null) { return null; } if (prev <= 1) { - clearInterval(timer1); setGameState("gaming"); - return 0; } return prev - 1; }); @@ -207,7 +208,7 @@ export default function GolfWatchApp({ // The game has already started. if (gameState !== "gaming" && gameState !== "finished") { setStartedAt(game.started_at); - setLeftTimeSeconds(0); + setLeftTimeSeconds(game.started_at - nowSec); setGameState("gaming"); } } else { @@ -245,10 +246,11 @@ export default function GolfWatchApp({ } else if (gameState === "gaming") { return ( ); } else if (gameState === "finished") { diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx index 2a852e0..f9647b3 100644 --- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx +++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx @@ -3,23 +3,27 @@ import ExecStatusIndicatorIcon from "../ExecStatusIndicatorIcon"; import SubmitStatusLabel from "../SubmitStatusLabel"; type Props = { - problem: string; + gameDurationSeconds: number; + leftTimeSeconds: number; playerInfoA: PlayerInfo; playerInfoB: PlayerInfo; - leftTimeSeconds: number; + problem: string; }; export default function GolfWatchAppGaming({ - problem, + gameDurationSeconds, + leftTimeSeconds, playerInfoA, playerInfoB, - leftTimeSeconds, + problem, }: Props) { const leftTime = (() => { - const m = Math.floor(leftTimeSeconds / 60); - const s = leftTimeSeconds % 60; + const k = gameDurationSeconds + leftTimeSeconds; + const m = Math.floor(k / 60); + const s = k % 60; return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; })(); + const scoreRatio = (() => { const scoreA = playerInfoA.score ?? 0; const scoreB = playerInfoB.score ?? 0; diff --git a/openapi/api-server.yaml b/openapi/api-server.yaml index 036d8d6..94083d3 100644 --- a/openapi/api-server.yaml +++ b/openapi/api-server.yaml @@ -212,6 +212,7 @@ components: started_at: type: integer example: 946684800 + x-go-type: int64 problem: $ref: '#/components/schemas/Problem' players: @@ -286,6 +287,7 @@ components: start_at: type: integer example: 946684800 + x-go-type: int64 required: - start_at GamePlayerMessageS2CExecResult: @@ -428,6 +430,7 @@ components: start_at: type: integer example: 946684800 + x-go-type: int64 required: - start_at GameWatcherMessageS2CCode: -- cgit v1.2.3-70-g09d2