From 6f2b63511c4f19c8a2f38d562038dd09b017591b Mon Sep 17 00:00:00 2001 From: Fedorov Vladimir Date: Sun, 11 Oct 2026 13:26:38 +0700 Subject: [PATCH] up --- api/main.proto | 37 + cmd/evening_detective_server/main.go | 15 +- .../main.swagger.json | 97 +++ docs/GAME_PACKAGE.md | 49 +- internal/app/game_results_package.go | 153 ++++ internal/app/game_results_package_errors.go | 33 + internal/app/game_results_package_mapper.go | 14 + internal/app/game_results_package_test.go | 63 ++ internal/app/server.go | 79 ++- .../game_export_service/export_test.go | 2 +- .../game_export_service/return_test.go | 73 +- .../game_results_package_service/apply.go | 28 +- .../apply_test.go | 10 +- .../flow_apply_test.go | 6 +- proto/main.pb.go | 659 +++++++++++------- proto/main.pb.gw.go | 162 +++++ proto/main_grpc.pb.go | 78 +++ 17 files changed, 1254 insertions(+), 304 deletions(-) create mode 100644 internal/app/game_results_package.go create mode 100644 internal/app/game_results_package_errors.go create mode 100644 internal/app/game_results_package_mapper.go create mode 100644 internal/app/game_results_package_test.go diff --git a/api/main.proto b/api/main.proto index f573f36..babdabd 100644 --- a/api/main.proto +++ b/api/main.proto @@ -634,6 +634,30 @@ service EveningDetectiveServer { }; } + // Dedicated HTTP handlers stream ZIPs; gRPC retains its message size limit. + rpc DownloadGameResultsPackage(GameResultsPackageReq) returns (google.api.HttpBody) { + option (google.api.http) = {get: "/api/games/{ID}/results-package/download"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Игры"; + summary : "Скачать свежий ZIP результатов завершённой venue-игры"; + produces: "application/zip"; + }; + } + + rpc ApplyGameResultsPackage(ApplyGameResultsPackageReq) returns (GameResultsPackageRsp) { + option (google.api.http) = { + post: "/api/games/{ID}/results-package/apply" + body: "package" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Игры"; + summary : "Применить ZIP результатов на исходной prod-игре"; + description: "HTTP принимает сырой ZIP до 1 ГиБ, включая поток без Content-Length. Ошибки: 400 неверный пакет/игра, 413 размер, 409 конфликт, 503 временный отказ."; + consumes : "application/zip"; + produces : "application/json"; + }; + } + rpc StartGameExport(StartGameExportReq) returns (GameExportRsp) { option (google.api.http) = { post: "/api/games/{ID}/export" @@ -2345,3 +2369,16 @@ message DeleteTaskReq { message TaskRsp { DeveloperTask task = 1; } message DeleteTaskRsp {} + +message GameResultsPackageReq { int32 ID = 1; } + +message ApplyGameResultsPackageReq { + int32 ID = 1; + google.api.HttpBody package = 2; +} + +message GameResultsPackageRsp { + int32 gameID = 1; + string packageID = 2; + string appliedAt = 3; +} diff --git a/cmd/evening_detective_server/main.go b/cmd/evening_detective_server/main.go index deb3541..dc5258c 100644 --- a/cmd/evening_detective_server/main.go +++ b/cmd/evening_detective_server/main.go @@ -19,6 +19,8 @@ import ( "evening_detective_server/internal/repos/game_exports_repo" "evening_detective_server/internal/repos/game_imports_repo" "evening_detective_server/internal/repos/game_map_repo" + "evening_detective_server/internal/repos/game_results_repo" + "evening_detective_server/internal/repos/game_returns_repo" "evening_detective_server/internal/repos/game_reviews_repo" "evening_detective_server/internal/repos/game_screen_plans_repo" "evening_detective_server/internal/repos/games_repo" @@ -37,6 +39,7 @@ import ( "evening_detective_server/internal/services/game_export_service" "evening_detective_server/internal/services/game_import_service" "evening_detective_server/internal/services/game_package_service" + "evening_detective_server/internal/services/game_results_package_service" "evening_detective_server/internal/services/game_review_service" "evening_detective_server/internal/services/game_service" "evening_detective_server/internal/services/gameplay_service" @@ -85,7 +88,11 @@ const grpcMsgLimit = 257 << 20 func main() { _ = godotenv.Load() - venueMode := os.Getenv("APP_MODE") == "venue" + mode := "prod" + if os.Getenv("APP_MODE") == "venue" { + mode = "venue" + } + venueMode := mode == "venue" dbpool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL")) if err != nil { @@ -165,6 +172,8 @@ func main() { if !venueMode { go gameExportService.Run(context.Background()) } + gameResultsService := game_results_package_service.NewGameResultsPackageService(game_results_repo.NewGameResultsRepo(dbpool), mode) + gameResultsApplyService := game_results_package_service.NewGameResultsApplyService(game_returns_repo.NewGameReturnsRepo(dbpool), exportStorage, mode, os.Getenv("APP_BASE_URL")) scenariosRepo := scenarios_repo.NewScenariosRepo(dbpool) cleaner := cleaner.NewCleaner() scenarioService := scenarios_service.NewScenarioService( @@ -276,6 +285,8 @@ func main() { taskService, gameExportService, gameImportService, + gameResultsService, + gameResultsApplyService, ), ) @@ -335,6 +346,8 @@ func main() { } mainMux := http.NewServeMux() + mainMux.Handle("GET /api/games/{id}/results-package/download", app.GameResultsDownloadHandler(processorJWT, gameResultsService)) + mainMux.Handle("POST /api/games/{id}/results-package/apply", app.GameResultsApplyHandler(processorJWT, gameResultsApplyService)) mainMux.Handle("POST /api/games/import", app.GameImportHandler(processorJWT, gameImportService)) mainMux.Handle("GET /api/games/{id}/export/download", app.GameExportDownloadHandler(processorJWT, gameExportService)) if !venueMode { diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index 93faa20..7efff95 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -813,6 +813,88 @@ ] } }, + "/api/games/{ID}/results-package/apply": { + "post": { + "summary": "Применить ZIP результатов на исходной prod-игре", + "description": "HTTP принимает сырой ZIP до 1 ГиБ, включая поток без Content-Length. Ошибки: 400 неверный пакет/игра, 413 размер, 409 конфликт, 503 временный отказ.", + "operationId": "EveningDetectiveServer_ApplyGameResultsPackage", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/evening_detective_serverGameResultsPackageRsp" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "ID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "package", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/apiHttpBody" + } + } + ], + "tags": [ + "Игры" + ], + "consumes": [ + "application/zip" + ], + "produces": [ + "application/json" + ] + } + }, + "/api/games/{ID}/results-package/download": { + "get": { + "summary": "Скачать свежий ZIP результатов завершённой venue-игры", + "operationId": "EveningDetectiveServer_DownloadGameResultsPackage", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/apiHttpBody" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "ID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "tags": [ + "Игры" + ], + "produces": [ + "application/zip" + ] + } + }, "/api/games/{ID}/start": { "put": { "summary": "Начать игру", @@ -4748,6 +4830,21 @@ } } }, + "evening_detective_serverGameResultsPackageRsp": { + "type": "object", + "properties": { + "gameID": { + "type": "integer", + "format": "int32" + }, + "packageID": { + "type": "string" + }, + "appliedAt": { + "type": "string" + } + } + }, "evening_detective_serverGameReview": { "type": "object", "properties": { diff --git a/docs/GAME_PACKAGE.md b/docs/GAME_PACKAGE.md index a4bde10..ae4b336 100644 --- a/docs/GAME_PACKAGE.md +++ b/docs/GAME_PACKAGE.md @@ -350,7 +350,7 @@ RustFS и создать `.continue` в течение минуты. Buc ## Пакет результатов, версия 1 (ED-029, этап 9) Это отдельный контракт: ZIP содержит ровно `manifest.json` и `results.json`, -без сценария и файлов. Серверное применение реализовано этапом 10; API/UI остаются этапом 11. +без сценария и файлов. Серверное применение реализовано этапом 10; API/UI описаны в этапе 11. `game_results_package_service.NewGameResultsPackageService(repo, mode).Prepare(ctx, gameID, output)` доступен только в `venue`, для существующей игры из готового @@ -441,10 +441,10 @@ workspace. Стенд проверяет оба формата, свежую о ## Применение результатов онлайн (ED-029, этап 10) `game_results_package_service.NewGameResultsApplyService(repo, privateStorage, -mode, sourceServer).Apply(ctx, input io.ReaderAt, size, initiatorID)` доступен -только при `mode="prod"`. Это серверный сервис без нового API/UI и развёртывания. -Возвращается закрытая запись реестра; будущий transport должен выдавать только -публичный результат операции. +mode, sourceServer).Apply(ctx, expectedGameID, input io.Reader, initiatorID)` доступен +только при `mode="prod"`. Положительный `expectedGameID` и совпадение с manifest +проверяются до поиска повтора и изменений. Возвращается закрытая запись реестра; +transport выдаёт только `gameID`, `packageID`, `appliedAt`. Входные байты один раз сохраняются в приватный временный файл и проверяются кодеком этапа 9; SHA-256 всего ZIP связывает повтор с этими же байтами. @@ -518,3 +518,42 @@ Sequence-значения PostgreSQL не откатываются: больши Перед поддержкой площадок с такими разрывами требуется расширить типы ID. ZIP на 1 ГиБ, 100 клиентов и Wi-Fi этим этапом не проверяются. До завершения этапа 11 и контрольного прогона используются только тестовые игры. + + +## Интерфейс возврата (ED-029, этап 11) + +Организатор, администратор и разработчик используют два endpoint-а с Bearer JWT: + +- `GET /api/games/{ID}/results-package/download` — только venue, завершённая + импортированная игра. Каждый запрос готовит свежий ZIP в приватном временном + файле, целиком проверяет подготовку и затем выдаёт `application/zip` с + `Content-Disposition`, `Content-Length`, `Cache-Control: no-store`. Очереди + и сохранённого пакета нет; файл удаляется при успехе, ошибке и отмене. +- `POST /api/games/{ID}/results-package/apply` — только prod, сырое тело + `application/zip` до 1 ГиБ, в том числе без `Content-Length`. Сервис один раз + сохраняет ограниченный поток с SHA-256 в файл 0600 и проверяет ZIP. Ответ: + `{ "gameID": 1, "packageID": "…", "appliedAt": "…" }`; закрытый реестр + не раскрывается. Повтор выдаёт исходное время применения. + +Неверный пакет/игра — HTTP 400, превышение размера — 413, конфликт — 409, +временный отказ — 503. Прочие ошибки и авторизация следуют правилам приложения; +внутренние причины логируются на транспортной границе. Protobuf/OpenAPI описывают +операции; HTTP использует отдельные бинарные handlers, gRPC ограничен текущим +размером сообщений. Таймаут бинарных HTTP-операций — 30 минут. + +В настройках завершённой venue-игры есть «Скачать результаты». В настройках +prod-игры блок «Возврат результатов с площадки» доступен и после исчезновения +офлайн-отметки. Форма проверяет один непустой `.zip` до 1 ГиБ и предупреждает +о замене команд, билетов, результатов и сценария, потере онлайн-правок и +сохранении оформления/музыки. Бинарный клиент обновляет авторизацию. Во время +запроса повтор заблокирован; любой принятый ZIP получает сообщение «Результаты +приняты». После успеха страница пересоздаётся и перечитывает данные; старые +ответы, формы, модальные окна и черновики редакторов удаляются. + +Конфигурации nginx и reproxy допускают ZIP 1 ГиБ и долгие операции; работающие +серверы не обновляются. У reproxy лимит/таймауты общие для его маршрутов. +Контрольный тест: `python3 tests/venue/flow.py --apply --browser` — оба формата, +реальные PostgreSQL/RustFS, API и Firefox, свежий ZIP кнопкой, применение через +страницу prod, исправленный балл, перезапись онлайн-ответа, исходные ссылки и +билеты, сохранение оформления, снятие офлайн-отметки, повтор после перезапуска. +ZIP остаётся неподписанным; нагрузка, Wi-Fi и фактический ZIP 1 ГиБ не проверяются. diff --git a/internal/app/game_results_package.go b/internal/app/game_results_package.go new file mode 100644 index 0000000..16f0898 --- /dev/null +++ b/internal/app/game_results_package.go @@ -0,0 +1,153 @@ +package app + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "io" + "log" + "net/http" + "os" + "strconv" + "strings" + "time" + + "evening_detective_server/internal/modules/processor_jwt" + results "evening_detective_server/internal/services/game_results_package_service" + "evening_detective_server/proto" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (s *server) DownloadGameResultsPackage(ctx context.Context, req *proto.GameResultsPackageReq) (*httpbody.HttpBody, error) { + claims, err := claimsFromContext(ctx) + if err != nil { + return nil, err + } + if !canExportGame(claims) { + return nil, status.Error(codes.PermissionDenied, "permission denied") + } + if req.GetID() <= 0 { + return nil, status.Error(codes.InvalidArgument, "Некорректный идентификатор игры") + } + var output bytes.Buffer + if err := s.gameResultsService.Prepare(ctx, int(req.GetID()), &output); err != nil { + return nil, gameResultsErrorStatus(err) + } + return &httpbody.HttpBody{ContentType: "application/zip", Data: output.Bytes()}, nil +} + +func (s *server) ApplyGameResultsPackage(ctx context.Context, req *proto.ApplyGameResultsPackageReq) (*proto.GameResultsPackageRsp, error) { + claims, err := claimsFromContext(ctx) + if err != nil { + return nil, err + } + if !canExportGame(claims) { + return nil, status.Error(codes.PermissionDenied, "permission denied") + } + if !isZIP(req.GetPackage().GetContentType()) { + return nil, status.Error(codes.InvalidArgument, "Требуется application/zip") + } + result, err := s.gameResultsApplyService.Apply(ctx, int(req.GetID()), bytes.NewReader(req.GetPackage().GetData()), claims.UserID) + if err != nil { + return nil, gameResultsErrorStatus(err) + } + return mapGameResultsPackage(result.GameID, result.PackageID, result.AppliedAt), nil +} + +// GameResultsDownloadHandler stages a fresh ZIP before sending headers. +func GameResultsDownloadHandler(jwt processor_jwt.IProcessorJWT, service *results.GameResultsPackageService) http.Handler { + return gameResultsHandler(jwt, func(w http.ResponseWriter, r *http.Request, id, actor int) error { + file, err := os.CreateTemp("", "game-results-download-*.zip") + if err != nil { + return err + } + defer func() { _ = file.Close(); _ = os.Remove(file.Name()) }() + if err := service.Prepare(r.Context(), id, file); err != nil { + return err + } + info, err := file.Stat() + if err != nil { + return err + } + if _, err := file.Seek(0, io.SeekStart); err != nil { + return err + } + w.Header().Set("Content-Type", "application/zip") + w.Header().Set("Content-Disposition", `attachment; filename="game-results-`+strconv.Itoa(id)+`.zip"`) + w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10)) + if _, err := io.Copy(w, file); err != nil && r.Context().Err() == nil { + log.Printf("game results download: %v", err) + } + return nil + }) +} + +// GameResultsApplyHandler accepts ZIP streams without Content-Length. +func GameResultsApplyHandler(jwt processor_jwt.IProcessorJWT, service *results.GameResultsApplyService) http.Handler { + return gameResultsHandler(jwt, func(w http.ResponseWriter, r *http.Request, id, actor int) error { + if !isZIP(r.Header.Get("Content-Type")) { + return status.Error(codes.InvalidArgument, "Требуется application/zip") + } + if r.ContentLength > 1<<30 { + return results.ErrLimitExceeded + } + result, err := service.Apply(r.Context(), id, r.Body, actor) + if err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(mapGameResultsPackage(result.GameID, result.PackageID, result.AppliedAt)); err != nil { + log.Printf("game results response: %v", err) + } + return nil + }) +} + +func gameResultsHandler(jwt processor_jwt.IProcessorJWT, action func(http.ResponseWriter, *http.Request, int, int) error) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-store") + w.Header().Set("X-Content-Type-Options", "nosniff") + err := func() error { + token, ok := strings.CutPrefix(r.Header.Get("Authorization"), "Bearer ") + if !ok || token == "" { + return status.Error(codes.Unauthenticated, "Требуется авторизация") + } + claims, err := jwt.GetClaims(token) + if err != nil { + return status.Error(codes.Unauthenticated, "Недействительный токен") + } + if !canExportGame(claims) { + return status.Error(codes.PermissionDenied, "permission denied") + } + id, err := strconv.ParseInt(r.PathValue("id"), 10, 32) + if err != nil || id <= 0 { + return status.Error(codes.InvalidArgument, "Некорректный идентификатор игры") + } + controller := http.NewResponseController(w) + if err := controller.SetReadDeadline(time.Now().Add(30 * time.Minute)); err != nil && !errors.Is(err, http.ErrNotSupported) { + return err + } + if err := controller.SetWriteDeadline(time.Now().Add(30 * time.Minute)); err != nil && !errors.Is(err, http.ErrNotSupported) { + return err + } + return action(w, r, int(id), claims.UserID) + }() + if err == nil { + return + } + if status.Code(err) == codes.Unknown { + err = gameResultsErrorStatus(err) + } + code := runtime.HTTPStatusFromCode(status.Code(err)) + if status.Code(err) == codes.ResourceExhausted { + code = http.StatusRequestEntityTooLarge + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(map[string]string{"error": status.Convert(err).Message()}) + }) +} diff --git a/internal/app/game_results_package_errors.go b/internal/app/game_results_package_errors.go new file mode 100644 index 0000000..2f5cf20 --- /dev/null +++ b/internal/app/game_results_package_errors.go @@ -0,0 +1,33 @@ +package app + +import ( + "context" + "errors" + results "evening_detective_server/internal/services/game_results_package_service" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "log" + "os" +) + +func gameResultsErrorStatus(err error) error { + switch { + case errors.Is(err, results.ErrInvalidPackage), errors.Is(err, results.ErrUnsupportedVersion), errors.Is(err, results.ErrSourceMismatch), errors.Is(err, results.ErrScenarioChanged): + return status.Error(codes.InvalidArgument, "Некорректный пакет результатов или игра") + case errors.Is(err, results.ErrLimitExceeded): + return status.Error(codes.ResourceExhausted, "Пакет результатов превышает допустимый размер") + case errors.Is(err, results.ErrReturnConflict): + return status.Error(codes.Aborted, "Конфликт пакета результатов") + case errors.Is(err, results.ErrReturnRetry): + return status.Error(codes.Unavailable, "Повторите загрузку позже") + case errors.Is(err, results.ErrNotAvailable), errors.Is(err, results.ErrReturnNotAvailable): + return status.Error(codes.FailedPrecondition, err.Error()) + case errors.Is(err, context.Canceled): + return status.Error(codes.Canceled, "Операция отменена") + case errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): + return status.Error(codes.Unavailable, "Время операции истекло; повторите позже") + default: + log.Printf("game results package: %v (cause: %v)", err, errors.Unwrap(err)) + return status.Error(codes.Internal, "Не удалось обработать результаты") + } +} diff --git a/internal/app/game_results_package_mapper.go b/internal/app/game_results_package_mapper.go new file mode 100644 index 0000000..82735a1 --- /dev/null +++ b/internal/app/game_results_package_mapper.go @@ -0,0 +1,14 @@ +package app + +import ( + "evening_detective_server/proto" + "time" +) + +func mapGameResultsPackage(gameID int, packageID string, appliedAt time.Time) *proto.GameResultsPackageRsp { + return &proto.GameResultsPackageRsp{ + GameID: int32(gameID), + PackageID: packageID, + AppliedAt: appliedAt.UTC().Format(time.RFC3339Nano), + } +} diff --git a/internal/app/game_results_package_test.go b/internal/app/game_results_package_test.go new file mode 100644 index 0000000..cac8351 --- /dev/null +++ b/internal/app/game_results_package_test.go @@ -0,0 +1,63 @@ +package app + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" + + "evening_detective_server/internal/modules/processor_jwt" + results "evening_detective_server/internal/services/game_results_package_service" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestResultsSafeErrors(t *testing.T) { + for _, tc := range []struct { + err error + code codes.Code + }{ + {results.ErrInvalidPackage, codes.InvalidArgument}, + {results.ErrUnsupportedVersion, codes.InvalidArgument}, + {results.ErrSourceMismatch, codes.InvalidArgument}, + {results.ErrScenarioChanged, codes.InvalidArgument}, + {results.ErrLimitExceeded, codes.ResourceExhausted}, + {results.ErrReturnConflict, codes.Aborted}, + {results.ErrReturnRetry, codes.Unavailable}, + {results.ErrNotAvailable, codes.FailedPrecondition}, + {results.ErrReturnNotAvailable, codes.FailedPrecondition}, + {context.Canceled, codes.Canceled}, + {context.DeadlineExceeded, codes.Unavailable}, + {errors.New("private SQL and file path"), codes.Internal}, + } { + err := gameResultsErrorStatus(tc.err) + if status.Code(err) != tc.code || strings.Contains(err.Error(), "private SQL") { + t.Fatal(err) + } + } +} + +func TestResultsDownloadFailureDoesNotSendZIPOrLeakFile(t *testing.T) { + dir := t.TempDir() + t.Setenv("TMPDIR", dir) + jwt := processor_jwt.NewProcessor("results-test-secret") + token, err := jwt.GenerateAccessToken(1, "test@test.invalid", []string{"organizer"}) + if err != nil { + t.Fatal(err) + } + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.SetPathValue("id", "1") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + GameResultsDownloadHandler(jwt, results.NewGameResultsPackageService(nil, "prod")).ServeHTTP(w, req) + if w.Code != 400 || w.Header().Get("Content-Type") != "application/json" || w.Header().Get("Content-Disposition") != "" { + t.Fatal(w) + } + files, err := os.ReadDir(dir) + if err != nil || len(files) != 0 { + t.Fatal("temporary file leaked", err) + } +} diff --git a/internal/app/server.go b/internal/app/server.go index 5f54318..888dcd8 100644 --- a/internal/app/server.go +++ b/internal/app/server.go @@ -5,6 +5,7 @@ import ( "evening_detective_server/internal/services/file_service" "evening_detective_server/internal/services/game_export_service" "evening_detective_server/internal/services/game_import_service" + "evening_detective_server/internal/services/game_results_package_service" "evening_detective_server/internal/services/game_review_service" "evening_detective_server/internal/services/game_service" "evening_detective_server/internal/services/gameplay_service" @@ -25,24 +26,26 @@ import ( type server struct { proto.UnsafeEveningDetectiveServerServer - usersService *users_service.UsersService - uiService *ui_service.UIService - taskService *task_service.TaskService - fileService *file_service.FileService - scenarioService *scenarios_service.ScenarioService - gameExportService *game_export_service.GameExportService - gameImportService *game_import_service.GameImportService - gameService *game_service.GameService - gameplayService *gameplay_service.GameplayService - answerService *answer_service.AnswerService - reviewService *game_review_service.GameReviewService - teamService *team_service.TeamService - ticketService *ticket_service.TicketService - participationService *participation_service.ParticipationService - screenService *screen_service.ScreenService - playlistService *playlist_service.Service - screenPlanService *screen_plan_service.ScreenPlanService - mapService *map_service.MapService + usersService *users_service.UsersService + uiService *ui_service.UIService + taskService *task_service.TaskService + fileService *file_service.FileService + scenarioService *scenarios_service.ScenarioService + gameExportService *game_export_service.GameExportService + gameImportService *game_import_service.GameImportService + gameResultsService *game_results_package_service.GameResultsPackageService + gameResultsApplyService *game_results_package_service.GameResultsApplyService + gameService *game_service.GameService + gameplayService *gameplay_service.GameplayService + answerService *answer_service.AnswerService + reviewService *game_review_service.GameReviewService + teamService *team_service.TeamService + ticketService *ticket_service.TicketService + participationService *participation_service.ParticipationService + screenService *screen_service.ScreenService + playlistService *playlist_service.Service + screenPlanService *screen_plan_service.ScreenPlanService + mapService *map_service.MapService } // NewServer creates the application server. @@ -65,25 +68,29 @@ func NewServer( taskService *task_service.TaskService, gameExportService *game_export_service.GameExportService, gameImportService *game_import_service.GameImportService, + gameResultsService *game_results_package_service.GameResultsPackageService, + gameResultsApplyService *game_results_package_service.GameResultsApplyService, ) proto.EveningDetectiveServerServer { return &server{ - gameImportService: gameImportService, - taskService: taskService, - gameExportService: gameExportService, - usersService: usersService, - uiService: uiService, - fileService: fileService, - scenarioService: scenarioService, - gameService: gameService, - gameplayService: gameplayService, - answerService: answerService, - reviewService: reviewService, - teamService: teamService, - ticketService: ticketService, - participationService: participationService, - screenService: screenService, - playlistService: playlistService, - screenPlanService: screenPlanService, - mapService: mapService, + gameImportService: gameImportService, + gameResultsService: gameResultsService, + gameResultsApplyService: gameResultsApplyService, + taskService: taskService, + gameExportService: gameExportService, + usersService: usersService, + uiService: uiService, + fileService: fileService, + scenarioService: scenarioService, + gameService: gameService, + gameplayService: gameplayService, + answerService: answerService, + reviewService: reviewService, + teamService: teamService, + ticketService: ticketService, + participationService: participationService, + screenService: screenService, + playlistService: playlistService, + screenPlanService: screenPlanService, + mapService: mapService, } } diff --git a/internal/services/game_export_service/export_test.go b/internal/services/game_export_service/export_test.go index 62bc42e..edacd62 100644 --- a/internal/services/game_export_service/export_test.go +++ b/internal/services/game_export_service/export_test.go @@ -377,7 +377,7 @@ func verifyExportedGameReads(t *testing.T, f serviceFixture, worker *game_export games := game_service.NewGameService(f.games, f.teams, f.scenarios, nil, "", actions_repo.NewActionsRepo(f.pool), applications_repo.NewApplicationsRepo(f.pool)) mapRepo := game_map_repo.NewGameMapRepo(f.pool) server := app.NewServer(nil, nil, nil, nil, games, nil, nil, nil, nil, nil, nil, - screen_service.NewScreenService(screen_sessions_repo.NewScreenSessionsRepo(f.pool)), nil, nil, map_service.NewMapService(mapRepo), nil, worker, nil) + screen_service.NewScreenService(screen_sessions_repo.NewScreenSessionsRepo(f.pool)), nil, nil, map_service.NewMapService(mapRepo), nil, worker, nil, nil, nil) ctx := processor_jwt.ContextWithClaims(context.Background(), &processor_jwt.JWTClaims{UserID: f.userID, Roles: []string{"organizer"}}) game, err := server.GetGame(ctx, &proto.GetGameReq{ID: int32(f.gameID)}) check(t, err) diff --git a/internal/services/game_export_service/return_test.go b/internal/services/game_export_service/return_test.go index 44ae23e..749c9ff 100644 --- a/internal/services/game_export_service/return_test.go +++ b/internal/services/game_export_service/return_test.go @@ -9,6 +9,12 @@ import ( "encoding/json" "errors" "fmt" + "net/http" + "net/http/httptest" + "strings" + + "evening_detective_server/internal/app" + "evening_detective_server/internal/modules/processor_jwt" "github.com/jackc/pgx/v5" "os" "reflect" @@ -101,7 +107,7 @@ func (f returnFixture) pack(t *testing.T) []byte { } func (f returnFixture) apply(raw []byte) (*game_returns_repo.Return, error) { service := results.NewGameResultsApplyService(game_returns_repo.NewGameReturnsRepo(f.pool), f.storage, "prod", "https://game.example") - r, err := service.Apply(context.Background(), bytes.NewReader(raw), int64(len(raw)), f.userID) + r, err := service.Apply(context.Background(), f.gameID, bytes.NewReader(raw), f.userID) if err != nil { return nil, fmt.Errorf("%w (cause: %v)", err, errors.Unwrap(err)) } @@ -506,3 +512,68 @@ func TestReturnOverwritesOnlineEditsAndIsolatesScenario(t *testing.T) { }) } } + +func TestReturnHTTPRealService(t *testing.T) { + f := newReturnFixture(t, "online") + raw := f.pack(t) + service := results.NewGameResultsApplyService(game_returns_repo.NewGameReturnsRepo(f.pool), f.storage, "prod", "https://game.example") + jwt := processor_jwt.NewProcessor("results-test-secret") + temp := t.TempDir() + t.Setenv("TMPDIR", temp) + for _, tc := range []struct { + name, role, mime string + id int + body []byte + size int64 + want int + }{ + {"wrong game before apply", "organizer", "application/zip", f.gameID + 1, raw, -1, 400}, + {"chunked apply", "organizer", "application/zip", f.gameID, raw, -1, 200}, + {"wrong game after apply", "organizer", "application/zip", f.gameID + 1, raw, -1, 400}, + {"admin repeat", "admin", "application/zip", f.gameID, raw, -1, 200}, + {"developer repeat", "developer", "application/zip", f.gameID, raw, -1, 200}, + {"author", "author", "application/zip", f.gameID, raw, -1, 403}, + {"missing auth", "", "application/zip", f.gameID, raw, -1, 401}, + {"invalid route", "organizer", "application/zip", 0, raw, -1, 400}, + {"MIME", "organizer", "application/json", f.gameID, raw, -1, 400}, + {"size", "organizer", "application/zip", f.gameID, raw, 1<<30 + 1, 413}, + {"invalid ZIP", "organizer", "application/zip", f.gameID, []byte("invalid"), -1, 400}, + } { + t.Run(tc.name, func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(tc.body)) + req.ContentLength = tc.size + req.SetPathValue("id", fmt.Sprint(tc.id)) + req.Header.Set("Content-Type", tc.mime) + if tc.role != "" { + token, err := jwt.GenerateAccessToken(f.userID, "test@test.invalid", []string{tc.role}) + check(t, err) + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + app.GameResultsApplyHandler(jwt, service).ServeHTTP(w, req) + if w.Code != tc.want { + t.Fatalf("HTTP %d: %s", w.Code, w.Body.String()) + } + if tc.want == 200 { + var response map[string]any + check(t, json.Unmarshal(w.Body.Bytes(), &response)) + if len(response) != 3 || response["gameID"] != float64(f.gameID) || response["packageID"] == nil || response["appliedAt"] == nil { + t.Fatal("private registry exposed or bad response") + } + } else if strings.Contains(w.Body.String(), temp) { + t.Fatal("private path exposed") + } + files, err := os.ReadDir(temp) + check(t, err) + if len(files) != 0 { + t.Fatal("staging files leaked") + } + }) + } + for _, id := range []int{0, -1, f.gameID + 1} { + _, err := service.Apply(context.Background(), id, bytes.NewReader(raw), f.userID) + if !errors.Is(err, results.ErrInvalidPackage) { + t.Fatal("route mismatch bypassed repeat", err) + } + } +} diff --git a/internal/services/game_results_package_service/apply.go b/internal/services/game_results_package_service/apply.go index 65ff8c8..566bc76 100644 --- a/internal/services/game_results_package_service/apply.go +++ b/internal/services/game_results_package_service/apply.go @@ -23,7 +23,7 @@ var ( ErrReturnFailed = errors.New("не удалось применить результаты") ) -// GameResultsApplyService applies private result archives; transport is added separately. +// GameResultsApplyService applies private result archives. type GameResultsApplyService struct { repo *game_returns_repo.GameReturnsRepo storage file_storage.IStreamStorage @@ -41,17 +41,23 @@ func NewGameResultsApplyService(repo *game_returns_repo.GameReturnsRepo, storage } // Apply preserves recorded repeats, including older packages and deleted games. -func (s *GameResultsApplyService) Apply(ctx context.Context, input io.ReaderAt, size int64, initiatorID int) (*game_returns_repo.Return, error) { +func (s *GameResultsApplyService) Apply(ctx context.Context, expectedGameID int, input io.Reader, initiatorID int) (*game_returns_repo.Return, error) { if err := ctx.Err(); err != nil { return nil, err } if s.mode != "prod" || s.repo == nil || s.storage == nil { return nil, ErrReturnNotAvailable } - bundle, digest, err := readResultInput(ctx, input, size) + if expectedGameID <= 0 { + return nil, ErrInvalidPackage + } + bundle, digest, err := readResultInput(ctx, input) if err != nil { return nil, safeReturnError(ctx, err) } + if bundle.Manifest.GameID != expectedGameID { + return nil, ErrInvalidPackage + } result, err := s.apply(ctx, bundle, digest, initiatorID) if err == nil || errors.Is(err, ErrSourceMismatch) || errors.Is(err, ErrReturnConflict) || errors.Is(err, ErrReturnRetry) || errors.Is(err, ErrInvalidPackage) { return result, err @@ -281,27 +287,27 @@ func safeReturnError(ctx context.Context, err error) error { } // Stage once so the validated payload and idempotency digest always describe the same bytes. -func readResultInput(ctx context.Context, input io.ReaderAt, size int64) (*Bundle, string, error) { - if input == nil || size <= 0 { +func readResultInput(ctx context.Context, input io.Reader) (*Bundle, string, error) { + if input == nil { return nil, "", ErrInvalidPackage } - if size > game_package_service.MaxArchiveSize { - return nil, "", ErrLimitExceeded - } file, err := os.CreateTemp("", "game-return-results-*.zip") if err != nil { return nil, "", err } defer func() { _ = file.Close(); _ = os.Remove(file.Name()) }() hash := sha256.New() - n, err := io.Copy(io.MultiWriter(file, hash), &contextReader{ctx: ctx, reader: io.NewSectionReader(input, 0, size)}) + n, err := io.Copy(io.MultiWriter(file, hash), &contextReader{ctx: ctx, reader: io.LimitReader(input, game_package_service.MaxArchiveSize+1)}) if err != nil { return nil, "", err } - if n != size { + if n > game_package_service.MaxArchiveSize { + return nil, "", ErrLimitExceeded + } + if n == 0 { return nil, "", ErrInvalidPackage } - bundle, err := Unpack(ctx, file, size) + bundle, err := Unpack(ctx, file, n) if err != nil { return nil, "", err } diff --git a/internal/services/game_results_package_service/apply_test.go b/internal/services/game_results_package_service/apply_test.go index f71eadb..a84c69f 100644 --- a/internal/services/game_results_package_service/apply_test.go +++ b/internal/services/game_results_package_service/apply_test.go @@ -91,7 +91,7 @@ func TestRepeatReturnRejectsChangedBytes(t *testing.T) { func TestApplyModeAndSafeErrors(t *testing.T) { for _, mode := range []string{"venue", "", "unknown"} { t.Run(mode, func(t *testing.T) { - _, err := NewGameResultsApplyService(nil, nil, mode, "").Apply(context.Background(), nil, 0, 0) + _, err := NewGameResultsApplyService(nil, nil, mode, "").Apply(context.Background(), 1, nil, 0) if !errors.Is(err, ErrReturnNotAvailable) { t.Fatal(err) } @@ -166,12 +166,12 @@ func TestOriginalMaterialsRestoresSavedURLs(t *testing.T) { } type inspectedResultReader struct { - reader io.ReaderAt + reader io.Reader inspect func() fail error } -func (r *inspectedResultReader) ReadAt(raw []byte, offset int64) (int, error) { +func (r *inspectedResultReader) Read(raw []byte) (int, error) { if r.inspect != nil { r.inspect() r.inspect = nil @@ -179,7 +179,7 @@ func (r *inspectedResultReader) ReadAt(raw []byte, offset int64) (int, error) { if r.fail != nil { return 0, r.fail } - return r.reader.ReadAt(raw, offset) + return r.reader.Read(raw) } func TestResultStagingIsPrivateAndAlwaysRemoved(t *testing.T) { @@ -230,7 +230,7 @@ func TestResultStagingIsPrivateAndAlwaysRemoved(t *testing.T) { } }, } - bundle, digest, err := readResultInput(ctx, reader, int64(len(raw))) + bundle, digest, err := readResultInput(ctx, reader) if !errors.Is(err, tc.expected) { t.Fatal(err) } diff --git a/internal/services/game_results_package_service/flow_apply_test.go b/internal/services/game_results_package_service/flow_apply_test.go index ad296b1..db66bed 100644 --- a/internal/services/game_results_package_service/flow_apply_test.go +++ b/internal/services/game_results_package_service/flow_apply_test.go @@ -70,7 +70,7 @@ func TestProdFlowReturns(t *testing.T) { } else if err != nil { t.Fatal(err) } - applied, err := service.Apply(ctx, bytes.NewReader(raw), int64(len(raw)), 0) + applied, err := service.Apply(ctx, gameID, bytes.NewReader(raw), 0) if err != nil { t.Fatal(err) } @@ -103,14 +103,14 @@ func TestProdFlowReturns(t *testing.T) { } else if err != nil { t.Fatal(err) } - newer, err := service.Apply(ctx, bytes.NewReader(corrected), int64(len(corrected)), 0) + newer, err := service.Apply(ctx, gameID, bytes.NewReader(corrected), 0) if err != nil { t.Fatal(err) } if !newer.PreparedAt.After(applied.PreparedAt) { t.Fatal("correction did not follow original") } - repeated, err := service.Apply(ctx, bytes.NewReader(raw), int64(len(raw)), 0) + repeated, err := service.Apply(ctx, gameID, bytes.NewReader(raw), 0) if err != nil { t.Fatal(err) } diff --git a/proto/main.pb.go b/proto/main.pb.go index 4190f55..82d03b9 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -12058,6 +12058,162 @@ func (*DeleteTaskRsp) Descriptor() ([]byte, []int) { return file_main_proto_rawDescGZIP(), []int{228} } +type GameResultsPackageReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + ID int32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GameResultsPackageReq) Reset() { + *x = GameResultsPackageReq{} + mi := &file_main_proto_msgTypes[229] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GameResultsPackageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GameResultsPackageReq) ProtoMessage() {} + +func (x *GameResultsPackageReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[229] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GameResultsPackageReq.ProtoReflect.Descriptor instead. +func (*GameResultsPackageReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{229} +} + +func (x *GameResultsPackageReq) GetID() int32 { + if x != nil { + return x.ID + } + return 0 +} + +type ApplyGameResultsPackageReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + ID int32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + Package *httpbody.HttpBody `protobuf:"bytes,2,opt,name=package,proto3" json:"package,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApplyGameResultsPackageReq) Reset() { + *x = ApplyGameResultsPackageReq{} + mi := &file_main_proto_msgTypes[230] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApplyGameResultsPackageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyGameResultsPackageReq) ProtoMessage() {} + +func (x *ApplyGameResultsPackageReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[230] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyGameResultsPackageReq.ProtoReflect.Descriptor instead. +func (*ApplyGameResultsPackageReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{230} +} + +func (x *ApplyGameResultsPackageReq) GetID() int32 { + if x != nil { + return x.ID + } + return 0 +} + +func (x *ApplyGameResultsPackageReq) GetPackage() *httpbody.HttpBody { + if x != nil { + return x.Package + } + return nil +} + +type GameResultsPackageRsp struct { + state protoimpl.MessageState `protogen:"open.v1"` + GameID int32 `protobuf:"varint,1,opt,name=gameID,proto3" json:"gameID,omitempty"` + PackageID string `protobuf:"bytes,2,opt,name=packageID,proto3" json:"packageID,omitempty"` + AppliedAt string `protobuf:"bytes,3,opt,name=appliedAt,proto3" json:"appliedAt,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GameResultsPackageRsp) Reset() { + *x = GameResultsPackageRsp{} + mi := &file_main_proto_msgTypes[231] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GameResultsPackageRsp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GameResultsPackageRsp) ProtoMessage() {} + +func (x *GameResultsPackageRsp) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[231] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GameResultsPackageRsp.ProtoReflect.Descriptor instead. +func (*GameResultsPackageRsp) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{231} +} + +func (x *GameResultsPackageRsp) GetGameID() int32 { + if x != nil { + return x.GameID + } + return 0 +} + +func (x *GameResultsPackageRsp) GetPackageID() string { + if x != nil { + return x.PackageID + } + return "" +} + +func (x *GameResultsPackageRsp) GetAppliedAt() string { + if x != nil { + return x.AppliedAt + } + return "" +} + var File_main_proto protoreflect.FileDescriptor const file_main_proto_rawDesc = "" + @@ -12816,7 +12972,16 @@ const file_main_proto_rawDesc = "" + "\aversion\x18\x02 \x01(\x05R\aversion\"L\n" + "\aTaskRsp\x12A\n" + "\x04task\x18\x01 \x01(\v2-.crabs.evening_detective_server.DeveloperTaskR\x04task\"\x0f\n" + - "\rDeleteTaskRsp*\xf6\x01\n" + + "\rDeleteTaskRsp\"'\n" + + "\x15GameResultsPackageReq\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\x05R\x02ID\"\\\n" + + "\x1aApplyGameResultsPackageReq\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\x05R\x02ID\x12.\n" + + "\apackage\x18\x02 \x01(\v2\x14.google.api.HttpBodyR\apackage\"k\n" + + "\x15GameResultsPackageRsp\x12\x16\n" + + "\x06gameID\x18\x01 \x01(\x05R\x06gameID\x12\x1c\n" + + "\tpackageID\x18\x02 \x01(\tR\tpackageID\x12\x1c\n" + + "\tappliedAt\x18\x03 \x01(\tR\tappliedAt*\xf6\x01\n" + "\n" + "ScreenMode\x12\x1b\n" + "\x17SCREEN_MODE_UNSPECIFIED\x10\x00\x12\x15\n" + @@ -12852,7 +13017,7 @@ const file_main_proto_rawDesc = "" + "\x1aMUSIC_PLAYBACK_UNSPECIFIED\x10\x00\x12\x1a\n" + "\x16MUSIC_PLAYBACK_STOPPED\x10\x01\x12\x1a\n" + "\x16MUSIC_PLAYBACK_PLAYING\x10\x02\x12\x19\n" + - "\x15MUSIC_PLAYBACK_PAUSED\x10\x032\x9c\xcd\x01\n" + + "\x15MUSIC_PLAYBACK_PAUSED\x10\x032\xef\xd3\x01\n" + "\x16EveningDetectiveServer\x12\x8c\x02\n" + "\bGetTasks\x12+.crabs.evening_detective_server.GetTasksReq\x1a+.crabs.evening_detective_server.GetTasksRsp\"\xa5\x01\x92A\x8f\x01\n" + "\fЗадачи\x121Получить общую доску задач\x1aLДоступно разработчикам и администратору.\x82\xd3\xe4\x93\x02\f\x12\n" + @@ -12993,7 +13158,11 @@ const file_main_proto_rawDesc = "" + "\aGetGame\x12*.crabs.evening_detective_server.GetGameReq\x1a*.crabs.evening_detective_server.GetGameRsp\"?\x92A%\n" + "\bИгры\x12\x19Получить игру\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/games/{ID}\x12o\n" + "\n" + - "ImportGame\x12\x14.google.api.HttpBody\x1a-.crabs.evening_detective_server.GameImportRsp\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/games/import\x12\x97\x01\n" + + "ImportGame\x12\x14.google.api.HttpBody\x1a-.crabs.evening_detective_server.GameImportRsp\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/games/import\x12\x98\x02\n" + + "\x1aDownloadGameResultsPackage\x125.crabs.evening_detective_server.GameResultsPackageReq\x1a\x14.google.api.HttpBody\"\xac\x01\x92Ay\n" + + "\bИгры\x12\\Скачать свежий ZIP результатов завершённой venue-игры:\x0fapplication/zip\x82\xd3\xe4\x93\x02*\x12(/api/games/{ID}/results-package/download\x12\xb5\x04\n" + + "\x17ApplyGameResultsPackage\x12:.crabs.evening_detective_server.ApplyGameResultsPackageReq\x1a5.crabs.evening_detective_server.GameResultsPackageRsp\"\xa6\x03\x92A\xec\x02\n" + + "\bИгры\x12QПрименить ZIP результатов на исходной prod-игре\x1a\xe9\x01HTTP принимает сырой ZIP до 1 ГиБ, включая поток без Content-Length. Ошибки: 400 неверный пакет/игра, 413 размер, 409 конфликт, 503 временный отказ.2\x0fapplication/zip:\x10application/json\x82\xd3\xe4\x93\x020:\apackage\"%/api/games/{ID}/results-package/apply\x12\x97\x01\n" + "\x0fStartGameExport\x122.crabs.evening_detective_server.StartGameExportReq\x1a-.crabs.evening_detective_server.GameExportRsp\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/games/{ID}/export\x12\x90\x01\n" + "\rGetGameExport\x120.crabs.evening_detective_server.GetGameExportReq\x1a-.crabs.evening_detective_server.GameExportRsp\"\x1e\x82\xd3\xe4\x93\x02\x18\x12\x16/api/games/{ID}/export\x12\xec\x01\n" + "\x10IssueGameTickets\x123.crabs.evening_detective_server.IssueGameTicketsReq\x1a3.crabs.evening_detective_server.IssueGameTicketsRsp\"n\x92AE\n" + @@ -13143,7 +13312,7 @@ func file_main_proto_rawDescGZIP() []byte { } var file_main_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 229) +var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 232) var file_main_proto_goTypes = []any{ (ScreenMode)(0), // 0: crabs.evening_detective_server.ScreenMode (ScreenTimerState)(0), // 1: crabs.evening_detective_server.ScreenTimerState @@ -13378,12 +13547,15 @@ var file_main_proto_goTypes = []any{ (*DeleteTaskReq)(nil), // 230: crabs.evening_detective_server.DeleteTaskReq (*TaskRsp)(nil), // 231: crabs.evening_detective_server.TaskRsp (*DeleteTaskRsp)(nil), // 232: crabs.evening_detective_server.DeleteTaskRsp - (*timestamppb.Timestamp)(nil), // 233: google.protobuf.Timestamp - (*httpbody.HttpBody)(nil), // 234: google.api.HttpBody + (*GameResultsPackageReq)(nil), // 233: crabs.evening_detective_server.GameResultsPackageReq + (*ApplyGameResultsPackageReq)(nil), // 234: crabs.evening_detective_server.ApplyGameResultsPackageReq + (*GameResultsPackageRsp)(nil), // 235: crabs.evening_detective_server.GameResultsPackageRsp + (*timestamppb.Timestamp)(nil), // 236: google.protobuf.Timestamp + (*httpbody.HttpBody)(nil), // 237: google.api.HttpBody } var file_main_proto_depIdxs = []int32{ 26, // 0: crabs.evening_detective_server.GetUsersRsp.users:type_name -> crabs.evening_detective_server.User - 233, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp + 236, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp 26, // 2: crabs.evening_detective_server.GetUserByIDRsp.user:type_name -> crabs.evening_detective_server.User 26, // 3: crabs.evening_detective_server.GetMeRsp.user:type_name -> crabs.evening_detective_server.User 42, // 4: crabs.evening_detective_server.Playlist.tracks:type_name -> crabs.evening_detective_server.PlaylistTrack @@ -13396,9 +13568,9 @@ var file_main_proto_depIdxs = []int32{ 66, // 11: crabs.evening_detective_server.GetScenarioRsp.scenario:type_name -> crabs.evening_detective_server.Scenario 67, // 12: crabs.evening_detective_server.Scenario.story:type_name -> crabs.evening_detective_server.Story 26, // 13: crabs.evening_detective_server.Scenario.author:type_name -> crabs.evening_detective_server.User - 233, // 14: crabs.evening_detective_server.Scenario.updated_at:type_name -> google.protobuf.Timestamp - 233, // 15: crabs.evening_detective_server.Scenario.created_at:type_name -> google.protobuf.Timestamp - 233, // 16: crabs.evening_detective_server.Scenario.published_at:type_name -> google.protobuf.Timestamp + 236, // 14: crabs.evening_detective_server.Scenario.updated_at:type_name -> google.protobuf.Timestamp + 236, // 15: crabs.evening_detective_server.Scenario.created_at:type_name -> google.protobuf.Timestamp + 236, // 16: crabs.evening_detective_server.Scenario.published_at:type_name -> google.protobuf.Timestamp 70, // 17: crabs.evening_detective_server.Story.places:type_name -> crabs.evening_detective_server.Place 69, // 18: crabs.evening_detective_server.Story.introduction:type_name -> crabs.evening_detective_server.Introduction 74, // 19: crabs.evening_detective_server.Story.questions:type_name -> crabs.evening_detective_server.Question @@ -13415,13 +13587,13 @@ var file_main_proto_depIdxs = []int32{ 69, // 30: crabs.evening_detective_server.UpdateScenarioIntroReq.introduction:type_name -> crabs.evening_detective_server.Introduction 74, // 31: crabs.evening_detective_server.AddScenarioQuestionReq.question:type_name -> crabs.evening_detective_server.Question 74, // 32: crabs.evening_detective_server.UpdateScenarioQuestionReq.question:type_name -> crabs.evening_detective_server.Question - 233, // 33: crabs.evening_detective_server.AddGameReq.start_at:type_name -> google.protobuf.Timestamp + 236, // 33: crabs.evening_detective_server.AddGameReq.start_at:type_name -> google.protobuf.Timestamp 108, // 34: crabs.evening_detective_server.GetGamesRsp.games:type_name -> crabs.evening_detective_server.Game - 233, // 35: crabs.evening_detective_server.Game.start_at:type_name -> google.protobuf.Timestamp + 236, // 35: crabs.evening_detective_server.Game.start_at:type_name -> google.protobuf.Timestamp 66, // 36: crabs.evening_detective_server.Game.scenario:type_name -> crabs.evening_detective_server.Scenario 158, // 37: crabs.evening_detective_server.Game.teams:type_name -> crabs.evening_detective_server.Team - 233, // 38: crabs.evening_detective_server.Game.started_at:type_name -> google.protobuf.Timestamp - 233, // 39: crabs.evening_detective_server.Game.ended_at:type_name -> google.protobuf.Timestamp + 236, // 38: crabs.evening_detective_server.Game.started_at:type_name -> google.protobuf.Timestamp + 236, // 39: crabs.evening_detective_server.Game.ended_at:type_name -> google.protobuf.Timestamp 109, // 40: crabs.evening_detective_server.Game.export:type_name -> crabs.evening_detective_server.GameExport 109, // 41: crabs.evening_detective_server.GameExportRsp.export:type_name -> crabs.evening_detective_server.GameExport 0, // 42: crabs.evening_detective_server.ScreenState.mode:type_name -> crabs.evening_detective_server.ScreenMode @@ -13449,7 +13621,7 @@ var file_main_proto_depIdxs = []int32{ 146, // 64: crabs.evening_detective_server.SetScreenPlanStepRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan 164, // 65: crabs.evening_detective_server.GetScreenResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion 165, // 66: crabs.evening_detective_server.GetScreenResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult - 233, // 67: crabs.evening_detective_server.ParticipationRsp.start_at:type_name -> google.protobuf.Timestamp + 236, // 67: crabs.evening_detective_server.ParticipationRsp.start_at:type_name -> google.protobuf.Timestamp 71, // 68: crabs.evening_detective_server.Team.applications:type_name -> crabs.evening_detective_server.Application 108, // 69: crabs.evening_detective_server.GetGameRsp.game:type_name -> crabs.evening_detective_server.Game 74, // 70: crabs.evening_detective_server.GetGameAnswersRsp.questions:type_name -> crabs.evening_detective_server.Question @@ -13458,11 +13630,11 @@ var file_main_proto_depIdxs = []int32{ 76, // 73: crabs.evening_detective_server.TeamResult.answers:type_name -> crabs.evening_detective_server.AnswerScore 164, // 74: crabs.evening_detective_server.GetGameResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion 165, // 75: crabs.evening_detective_server.GetGameResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult - 233, // 76: crabs.evening_detective_server.GameReview.created_at:type_name -> google.protobuf.Timestamp + 236, // 76: crabs.evening_detective_server.GameReview.created_at:type_name -> google.protobuf.Timestamp 167, // 77: crabs.evening_detective_server.CreateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview 167, // 78: crabs.evening_detective_server.GetGameReviewsRsp.reviews:type_name -> crabs.evening_detective_server.GameReview 167, // 79: crabs.evening_detective_server.ModerateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview - 233, // 80: crabs.evening_detective_server.UpdateGameReq.start_at:type_name -> google.protobuf.Timestamp + 236, // 80: crabs.evening_detective_server.UpdateGameReq.start_at:type_name -> google.protobuf.Timestamp 67, // 81: crabs.evening_detective_server.GetTeamStoryRsp.story:type_name -> crabs.evening_detective_server.Story 108, // 82: crabs.evening_detective_server.GetTeamStoryRsp.game:type_name -> crabs.evening_detective_server.Game 200, // 83: crabs.evening_detective_server.GetTeamStoryRsp.actions:type_name -> crabs.evening_detective_server.TeamAction @@ -13471,232 +13643,237 @@ var file_main_proto_depIdxs = []int32{ 215, // 86: crabs.evening_detective_server.IssueGameTicketsRsp.tickets:type_name -> crabs.evening_detective_server.Ticket 220, // 87: crabs.evening_detective_server.GetTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage 220, // 88: crabs.evening_detective_server.AcceptTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage - 233, // 89: crabs.evening_detective_server.TicketPage.start_at:type_name -> google.protobuf.Timestamp - 233, // 90: crabs.evening_detective_server.TicketPage.used_at:type_name -> google.protobuf.Timestamp - 233, // 91: crabs.evening_detective_server.DeveloperTask.createdAt:type_name -> google.protobuf.Timestamp - 233, // 92: crabs.evening_detective_server.DeveloperTask.updatedAt:type_name -> google.protobuf.Timestamp + 236, // 89: crabs.evening_detective_server.TicketPage.start_at:type_name -> google.protobuf.Timestamp + 236, // 90: crabs.evening_detective_server.TicketPage.used_at:type_name -> google.protobuf.Timestamp + 236, // 91: crabs.evening_detective_server.DeveloperTask.createdAt:type_name -> google.protobuf.Timestamp + 236, // 92: crabs.evening_detective_server.DeveloperTask.updatedAt:type_name -> google.protobuf.Timestamp 221, // 93: crabs.evening_detective_server.GetTasksRsp.tasks:type_name -> crabs.evening_detective_server.DeveloperTask 222, // 94: crabs.evening_detective_server.GetTaskAssigneesRsp.assignees:type_name -> crabs.evening_detective_server.TaskAssignee 221, // 95: crabs.evening_detective_server.TaskRsp.task:type_name -> crabs.evening_detective_server.DeveloperTask - 223, // 96: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:input_type -> crabs.evening_detective_server.GetTasksReq - 225, // 97: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:input_type -> crabs.evening_detective_server.GetTaskAssigneesReq - 227, // 98: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:input_type -> crabs.evening_detective_server.CreateTaskReq - 228, // 99: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:input_type -> crabs.evening_detective_server.UpdateTaskReq - 229, // 100: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:input_type -> crabs.evening_detective_server.SetTaskStatusReq - 230, // 101: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:input_type -> crabs.evening_detective_server.DeleteTaskReq - 155, // 102: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:input_type -> crabs.evening_detective_server.GetParticipationReq - 156, // 103: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:input_type -> crabs.evening_detective_server.AnswerParticipationReq - 4, // 104: crabs.evening_detective_server.EveningDetectiveServer.Ping:input_type -> crabs.evening_detective_server.PingReq - 6, // 105: crabs.evening_detective_server.EveningDetectiveServer.Echo:input_type -> crabs.evening_detective_server.EchoReq - 8, // 106: crabs.evening_detective_server.EveningDetectiveServer.Signup:input_type -> crabs.evening_detective_server.SignupReq - 10, // 107: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:input_type -> crabs.evening_detective_server.RefreshPasswordReq - 12, // 108: crabs.evening_detective_server.EveningDetectiveServer.Login:input_type -> crabs.evening_detective_server.LoginReq - 14, // 109: crabs.evening_detective_server.EveningDetectiveServer.Refresh:input_type -> crabs.evening_detective_server.RefreshReq - 16, // 110: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:input_type -> crabs.evening_detective_server.DeleteAccountReq - 18, // 111: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:input_type -> crabs.evening_detective_server.GetTermsReq - 20, // 112: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:input_type -> crabs.evening_detective_server.GetPrivacyReq - 22, // 113: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:input_type -> crabs.evening_detective_server.GetConsentReq - 24, // 114: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:input_type -> crabs.evening_detective_server.GetUsersReq - 27, // 115: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:input_type -> crabs.evening_detective_server.GetUserByIDReq - 29, // 116: crabs.evening_detective_server.EveningDetectiveServer.GetMe:input_type -> crabs.evening_detective_server.GetMeReq - 31, // 117: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:input_type -> crabs.evening_detective_server.ChangeUserPasswordReq - 33, // 118: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:input_type -> crabs.evening_detective_server.AddUserRoleReq - 35, // 119: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:input_type -> crabs.evening_detective_server.DeleteUserRoleReq - 37, // 120: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:input_type -> crabs.evening_detective_server.GetPermissionsReq - 39, // 121: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:input_type -> crabs.evening_detective_server.UploadFileReq - 41, // 122: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:input_type -> crabs.evening_detective_server.DownloadFileReq - 44, // 123: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:input_type -> crabs.evening_detective_server.GetPlaylistsReq - 46, // 124: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:input_type -> crabs.evening_detective_server.CreatePlaylistReq - 48, // 125: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:input_type -> crabs.evening_detective_server.UpdatePlaylistReq - 50, // 126: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:input_type -> crabs.evening_detective_server.DeletePlaylistReq - 52, // 127: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:input_type -> crabs.evening_detective_server.UploadPlaylistTrackReq - 54, // 128: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:input_type -> crabs.evening_detective_server.DeletePlaylistTrackReq - 56, // 129: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:input_type -> crabs.evening_detective_server.SetScenarioPlaylistReq - 58, // 130: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:input_type -> crabs.evening_detective_server.AddScenarioReq - 60, // 131: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:input_type -> crabs.evening_detective_server.GetMyScenariosReq - 62, // 132: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:input_type -> crabs.evening_detective_server.GetScenariosCatalogReq - 64, // 133: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:input_type -> crabs.evening_detective_server.GetScenarioReq - 64, // 134: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:input_type -> crabs.evening_detective_server.GetScenarioReq - 78, // 135: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:input_type -> crabs.evening_detective_server.UpdateScenarioReq - 80, // 136: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:input_type -> crabs.evening_detective_server.PublicScenarioReq - 82, // 137: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:input_type -> crabs.evening_detective_server.DraftScenarioReq - 84, // 138: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:input_type -> crabs.evening_detective_server.DeleteScenarioReq - 86, // 139: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:input_type -> crabs.evening_detective_server.AddScenarioPlaceReq - 88, // 140: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:input_type -> crabs.evening_detective_server.UpdateScenarioPlaceReq - 90, // 141: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:input_type -> crabs.evening_detective_server.DeleteScenarioPlaceReq - 96, // 142: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:input_type -> crabs.evening_detective_server.AddScenarioQuestionReq - 98, // 143: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:input_type -> crabs.evening_detective_server.UpdateScenarioQuestionReq - 100, // 144: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:input_type -> crabs.evening_detective_server.DeleteScenarioQuestionReq - 211, // 145: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:input_type -> crabs.evening_detective_server.UpdateScenarioBackgroundReq - 94, // 146: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:input_type -> crabs.evening_detective_server.UpdateScenarioIntroReq - 92, // 147: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:input_type -> crabs.evening_detective_server.UpdateScenarioConclusionReq - 102, // 148: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:input_type -> crabs.evening_detective_server.DownloadScenarioArchiveReq - 234, // 149: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:input_type -> google.api.HttpBody - 104, // 150: crabs.evening_detective_server.EveningDetectiveServer.AddGame:input_type -> crabs.evening_detective_server.AddGameReq - 106, // 151: crabs.evening_detective_server.EveningDetectiveServer.GetGames:input_type -> crabs.evening_detective_server.GetGamesReq - 159, // 152: crabs.evening_detective_server.EveningDetectiveServer.GetGame:input_type -> crabs.evening_detective_server.GetGameReq - 234, // 153: crabs.evening_detective_server.EveningDetectiveServer.ImportGame:input_type -> google.api.HttpBody - 111, // 154: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:input_type -> crabs.evening_detective_server.StartGameExportReq - 112, // 155: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:input_type -> crabs.evening_detective_server.GetGameExportReq - 213, // 156: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:input_type -> crabs.evening_detective_server.IssueGameTicketsReq - 216, // 157: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:input_type -> crabs.evening_detective_server.GetTicketReq - 218, // 158: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:input_type -> crabs.evening_detective_server.AcceptTicketReq - 115, // 159: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:input_type -> crabs.evening_detective_server.CreateScreenSessionReq - 117, // 160: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:input_type -> crabs.evening_detective_server.GetScreenStateReq - 119, // 161: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:input_type -> crabs.evening_detective_server.GetGameScreensReq - 122, // 162: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:input_type -> crabs.evening_detective_server.GetGameMusicReq - 124, // 163: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:input_type -> crabs.evening_detective_server.SetGameMusicReq - 126, // 164: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:input_type -> crabs.evening_detective_server.AdvanceScreenMusicReq - 128, // 165: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:input_type -> crabs.evening_detective_server.BindScreenReq - 130, // 166: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:input_type -> crabs.evening_detective_server.UnbindScreenReq - 132, // 167: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:input_type -> crabs.evening_detective_server.SetScreenSoundReq - 135, // 168: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:input_type -> crabs.evening_detective_server.GetGameMapReq - 137, // 169: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:input_type -> crabs.evening_detective_server.UpdateGameMapItemReq - 139, // 170: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:input_type -> crabs.evening_detective_server.SetScreenModeReq - 141, // 171: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:input_type -> crabs.evening_detective_server.SetScreenTimerReq - 143, // 172: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:input_type -> crabs.evening_detective_server.SendScreenCommandReq - 147, // 173: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:input_type -> crabs.evening_detective_server.GetScreenPlanReq - 149, // 174: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:input_type -> crabs.evening_detective_server.SaveScreenPlanReq - 151, // 175: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:input_type -> crabs.evening_detective_server.SetScreenPlanStepReq - 153, // 176: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:input_type -> crabs.evening_detective_server.GetScreenResultsReq - 159, // 177: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:input_type -> crabs.evening_detective_server.GetGameReq - 161, // 178: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:input_type -> crabs.evening_detective_server.GetGameAnswersReq - 163, // 179: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:input_type -> crabs.evening_detective_server.GetGameResultsReq - 168, // 180: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:input_type -> crabs.evening_detective_server.CreateGameReviewReq - 170, // 181: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:input_type -> crabs.evening_detective_server.GetGameReviewsReq - 171, // 182: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:input_type -> crabs.evening_detective_server.GetScenarioReviewsReq - 170, // 183: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:input_type -> crabs.evening_detective_server.GetGameReviewsReq - 172, // 184: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:input_type -> crabs.evening_detective_server.GetReviewsForModerationReq - 174, // 185: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:input_type -> crabs.evening_detective_server.ModerateGameReviewReq - 176, // 186: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:input_type -> crabs.evening_detective_server.UpdateGameReq - 178, // 187: crabs.evening_detective_server.EveningDetectiveServer.StartGame:input_type -> crabs.evening_detective_server.StartGameReq - 180, // 188: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:input_type -> crabs.evening_detective_server.PauseGameReq - 182, // 189: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:input_type -> crabs.evening_detective_server.PlayGameReq - 184, // 190: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:input_type -> crabs.evening_detective_server.FinishGameReq - 186, // 191: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:input_type -> crabs.evening_detective_server.ResetGameReq - 188, // 192: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:input_type -> crabs.evening_detective_server.DeleteGameReq - 190, // 193: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:input_type -> crabs.evening_detective_server.AddTeamReq - 192, // 194: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:input_type -> crabs.evening_detective_server.UpdateTeamReq - 194, // 195: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:input_type -> crabs.evening_detective_server.DeleteTeamReq - 196, // 196: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:input_type -> crabs.evening_detective_server.GiveTeamApplicationsReq - 198, // 197: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:input_type -> crabs.evening_detective_server.GetTeamStoryReq - 201, // 198: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:input_type -> crabs.evening_detective_server.AddTeamActionReq - 203, // 199: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:input_type -> crabs.evening_detective_server.DeleteLastTeamActionReq - 205, // 200: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:input_type -> crabs.evening_detective_server.GetTeamAnswersReq - 207, // 201: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:input_type -> crabs.evening_detective_server.SubmitTeamAnswersReq - 209, // 202: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:input_type -> crabs.evening_detective_server.SetTeamAnswerScoreReq - 224, // 203: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:output_type -> crabs.evening_detective_server.GetTasksRsp - 226, // 204: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:output_type -> crabs.evening_detective_server.GetTaskAssigneesRsp - 231, // 205: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:output_type -> crabs.evening_detective_server.TaskRsp - 231, // 206: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:output_type -> crabs.evening_detective_server.TaskRsp - 231, // 207: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:output_type -> crabs.evening_detective_server.TaskRsp - 232, // 208: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:output_type -> crabs.evening_detective_server.DeleteTaskRsp - 157, // 209: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp - 157, // 210: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp - 5, // 211: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp - 7, // 212: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp - 9, // 213: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp - 11, // 214: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp - 13, // 215: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp - 15, // 216: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp - 17, // 217: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:output_type -> crabs.evening_detective_server.DeleteAccountRsp - 19, // 218: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:output_type -> crabs.evening_detective_server.GetTermsRsp - 21, // 219: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:output_type -> crabs.evening_detective_server.GetPrivacyRsp - 23, // 220: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:output_type -> crabs.evening_detective_server.GetConsentRsp - 25, // 221: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp - 28, // 222: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:output_type -> crabs.evening_detective_server.GetUserByIDRsp - 30, // 223: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp - 32, // 224: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:output_type -> crabs.evening_detective_server.ChangeUserPasswordRsp - 34, // 225: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp - 36, // 226: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp - 38, // 227: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp - 40, // 228: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:output_type -> crabs.evening_detective_server.UploadFileRsp - 234, // 229: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:output_type -> google.api.HttpBody - 45, // 230: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:output_type -> crabs.evening_detective_server.GetPlaylistsRsp - 47, // 231: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:output_type -> crabs.evening_detective_server.CreatePlaylistRsp - 49, // 232: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:output_type -> crabs.evening_detective_server.UpdatePlaylistRsp - 51, // 233: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:output_type -> crabs.evening_detective_server.DeletePlaylistRsp - 53, // 234: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:output_type -> crabs.evening_detective_server.UploadPlaylistTrackRsp - 55, // 235: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:output_type -> crabs.evening_detective_server.DeletePlaylistTrackRsp - 57, // 236: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:output_type -> crabs.evening_detective_server.SetScenarioPlaylistRsp - 59, // 237: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:output_type -> crabs.evening_detective_server.AddScenarioRsp - 61, // 238: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:output_type -> crabs.evening_detective_server.GetMyScenariosRsp - 63, // 239: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:output_type -> crabs.evening_detective_server.GetScenariosCatalogRsp - 65, // 240: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp - 65, // 241: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp - 79, // 242: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:output_type -> crabs.evening_detective_server.UpdateScenarioRsp - 81, // 243: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:output_type -> crabs.evening_detective_server.PublicScenarioRsp - 83, // 244: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:output_type -> crabs.evening_detective_server.DraftScenarioRsp - 85, // 245: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:output_type -> crabs.evening_detective_server.DeleteScenarioRsp - 87, // 246: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:output_type -> crabs.evening_detective_server.AddScenarioPlaceRsp - 89, // 247: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:output_type -> crabs.evening_detective_server.UpdateScenarioPlaceRsp - 91, // 248: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:output_type -> crabs.evening_detective_server.DeleteScenarioPlaceRsp - 97, // 249: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:output_type -> crabs.evening_detective_server.AddScenarioQuestionRsp - 99, // 250: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:output_type -> crabs.evening_detective_server.UpdateScenarioQuestionRsp - 101, // 251: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:output_type -> crabs.evening_detective_server.DeleteScenarioQuestionRsp - 212, // 252: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:output_type -> crabs.evening_detective_server.UpdateScenarioBackgroundRsp - 95, // 253: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:output_type -> crabs.evening_detective_server.UpdateScenarioIntroRsp - 93, // 254: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:output_type -> crabs.evening_detective_server.UpdateScenarioConclusionRsp - 234, // 255: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:output_type -> google.api.HttpBody - 103, // 256: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:output_type -> crabs.evening_detective_server.UploadScenarioArchiveRsp - 105, // 257: crabs.evening_detective_server.EveningDetectiveServer.AddGame:output_type -> crabs.evening_detective_server.AddGameRsp - 107, // 258: crabs.evening_detective_server.EveningDetectiveServer.GetGames:output_type -> crabs.evening_detective_server.GetGamesRsp - 160, // 259: crabs.evening_detective_server.EveningDetectiveServer.GetGame:output_type -> crabs.evening_detective_server.GetGameRsp - 110, // 260: crabs.evening_detective_server.EveningDetectiveServer.ImportGame:output_type -> crabs.evening_detective_server.GameImportRsp - 113, // 261: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:output_type -> crabs.evening_detective_server.GameExportRsp - 113, // 262: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:output_type -> crabs.evening_detective_server.GameExportRsp - 214, // 263: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:output_type -> crabs.evening_detective_server.IssueGameTicketsRsp - 217, // 264: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:output_type -> crabs.evening_detective_server.GetTicketRsp - 219, // 265: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:output_type -> crabs.evening_detective_server.AcceptTicketRsp - 116, // 266: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:output_type -> crabs.evening_detective_server.CreateScreenSessionRsp - 118, // 267: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:output_type -> crabs.evening_detective_server.GetScreenStateRsp - 120, // 268: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:output_type -> crabs.evening_detective_server.GetGameScreensRsp - 123, // 269: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:output_type -> crabs.evening_detective_server.GetGameMusicRsp - 125, // 270: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:output_type -> crabs.evening_detective_server.SetGameMusicRsp - 127, // 271: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:output_type -> crabs.evening_detective_server.AdvanceScreenMusicRsp - 129, // 272: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:output_type -> crabs.evening_detective_server.BindScreenRsp - 131, // 273: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:output_type -> crabs.evening_detective_server.UnbindScreenRsp - 133, // 274: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:output_type -> crabs.evening_detective_server.SetScreenSoundRsp - 136, // 275: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:output_type -> crabs.evening_detective_server.GetGameMapRsp - 138, // 276: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:output_type -> crabs.evening_detective_server.UpdateGameMapItemRsp - 140, // 277: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:output_type -> crabs.evening_detective_server.SetScreenModeRsp - 142, // 278: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:output_type -> crabs.evening_detective_server.SetScreenTimerRsp - 144, // 279: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:output_type -> crabs.evening_detective_server.SendScreenCommandRsp - 148, // 280: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:output_type -> crabs.evening_detective_server.GetScreenPlanRsp - 150, // 281: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:output_type -> crabs.evening_detective_server.SaveScreenPlanRsp - 152, // 282: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:output_type -> crabs.evening_detective_server.SetScreenPlanStepRsp - 154, // 283: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:output_type -> crabs.evening_detective_server.GetScreenResultsRsp - 234, // 284: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:output_type -> google.api.HttpBody - 162, // 285: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:output_type -> crabs.evening_detective_server.GetGameAnswersRsp - 166, // 286: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:output_type -> crabs.evening_detective_server.GetGameResultsRsp - 169, // 287: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:output_type -> crabs.evening_detective_server.CreateGameReviewRsp - 173, // 288: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 173, // 289: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 173, // 290: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 173, // 291: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 175, // 292: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:output_type -> crabs.evening_detective_server.ModerateGameReviewRsp - 177, // 293: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:output_type -> crabs.evening_detective_server.UpdateGameRsp - 179, // 294: crabs.evening_detective_server.EveningDetectiveServer.StartGame:output_type -> crabs.evening_detective_server.StartGameRsp - 181, // 295: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:output_type -> crabs.evening_detective_server.PauseGameRsp - 183, // 296: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:output_type -> crabs.evening_detective_server.PlayGameRsp - 185, // 297: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:output_type -> crabs.evening_detective_server.FinishGameRsp - 187, // 298: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:output_type -> crabs.evening_detective_server.ResetGameRsp - 189, // 299: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:output_type -> crabs.evening_detective_server.DeleteGameRsp - 191, // 300: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:output_type -> crabs.evening_detective_server.AddTeamRsp - 193, // 301: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:output_type -> crabs.evening_detective_server.UpdateTeamRsp - 195, // 302: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:output_type -> crabs.evening_detective_server.DeleteTeamRsp - 197, // 303: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:output_type -> crabs.evening_detective_server.GiveTeamApplicationsRsp - 199, // 304: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:output_type -> crabs.evening_detective_server.GetTeamStoryRsp - 202, // 305: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:output_type -> crabs.evening_detective_server.AddTeamActionRsp - 204, // 306: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:output_type -> crabs.evening_detective_server.DeleteLastTeamActionRsp - 206, // 307: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:output_type -> crabs.evening_detective_server.GetTeamAnswersRsp - 208, // 308: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:output_type -> crabs.evening_detective_server.SubmitTeamAnswersRsp - 210, // 309: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:output_type -> crabs.evening_detective_server.SetTeamAnswerScoreRsp - 203, // [203:310] is the sub-list for method output_type - 96, // [96:203] is the sub-list for method input_type - 96, // [96:96] is the sub-list for extension type_name - 96, // [96:96] is the sub-list for extension extendee - 0, // [0:96] is the sub-list for field type_name + 237, // 96: crabs.evening_detective_server.ApplyGameResultsPackageReq.package:type_name -> google.api.HttpBody + 223, // 97: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:input_type -> crabs.evening_detective_server.GetTasksReq + 225, // 98: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:input_type -> crabs.evening_detective_server.GetTaskAssigneesReq + 227, // 99: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:input_type -> crabs.evening_detective_server.CreateTaskReq + 228, // 100: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:input_type -> crabs.evening_detective_server.UpdateTaskReq + 229, // 101: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:input_type -> crabs.evening_detective_server.SetTaskStatusReq + 230, // 102: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:input_type -> crabs.evening_detective_server.DeleteTaskReq + 155, // 103: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:input_type -> crabs.evening_detective_server.GetParticipationReq + 156, // 104: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:input_type -> crabs.evening_detective_server.AnswerParticipationReq + 4, // 105: crabs.evening_detective_server.EveningDetectiveServer.Ping:input_type -> crabs.evening_detective_server.PingReq + 6, // 106: crabs.evening_detective_server.EveningDetectiveServer.Echo:input_type -> crabs.evening_detective_server.EchoReq + 8, // 107: crabs.evening_detective_server.EveningDetectiveServer.Signup:input_type -> crabs.evening_detective_server.SignupReq + 10, // 108: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:input_type -> crabs.evening_detective_server.RefreshPasswordReq + 12, // 109: crabs.evening_detective_server.EveningDetectiveServer.Login:input_type -> crabs.evening_detective_server.LoginReq + 14, // 110: crabs.evening_detective_server.EveningDetectiveServer.Refresh:input_type -> crabs.evening_detective_server.RefreshReq + 16, // 111: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:input_type -> crabs.evening_detective_server.DeleteAccountReq + 18, // 112: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:input_type -> crabs.evening_detective_server.GetTermsReq + 20, // 113: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:input_type -> crabs.evening_detective_server.GetPrivacyReq + 22, // 114: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:input_type -> crabs.evening_detective_server.GetConsentReq + 24, // 115: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:input_type -> crabs.evening_detective_server.GetUsersReq + 27, // 116: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:input_type -> crabs.evening_detective_server.GetUserByIDReq + 29, // 117: crabs.evening_detective_server.EveningDetectiveServer.GetMe:input_type -> crabs.evening_detective_server.GetMeReq + 31, // 118: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:input_type -> crabs.evening_detective_server.ChangeUserPasswordReq + 33, // 119: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:input_type -> crabs.evening_detective_server.AddUserRoleReq + 35, // 120: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:input_type -> crabs.evening_detective_server.DeleteUserRoleReq + 37, // 121: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:input_type -> crabs.evening_detective_server.GetPermissionsReq + 39, // 122: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:input_type -> crabs.evening_detective_server.UploadFileReq + 41, // 123: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:input_type -> crabs.evening_detective_server.DownloadFileReq + 44, // 124: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:input_type -> crabs.evening_detective_server.GetPlaylistsReq + 46, // 125: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:input_type -> crabs.evening_detective_server.CreatePlaylistReq + 48, // 126: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:input_type -> crabs.evening_detective_server.UpdatePlaylistReq + 50, // 127: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:input_type -> crabs.evening_detective_server.DeletePlaylistReq + 52, // 128: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:input_type -> crabs.evening_detective_server.UploadPlaylistTrackReq + 54, // 129: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:input_type -> crabs.evening_detective_server.DeletePlaylistTrackReq + 56, // 130: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:input_type -> crabs.evening_detective_server.SetScenarioPlaylistReq + 58, // 131: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:input_type -> crabs.evening_detective_server.AddScenarioReq + 60, // 132: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:input_type -> crabs.evening_detective_server.GetMyScenariosReq + 62, // 133: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:input_type -> crabs.evening_detective_server.GetScenariosCatalogReq + 64, // 134: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:input_type -> crabs.evening_detective_server.GetScenarioReq + 64, // 135: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:input_type -> crabs.evening_detective_server.GetScenarioReq + 78, // 136: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:input_type -> crabs.evening_detective_server.UpdateScenarioReq + 80, // 137: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:input_type -> crabs.evening_detective_server.PublicScenarioReq + 82, // 138: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:input_type -> crabs.evening_detective_server.DraftScenarioReq + 84, // 139: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:input_type -> crabs.evening_detective_server.DeleteScenarioReq + 86, // 140: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:input_type -> crabs.evening_detective_server.AddScenarioPlaceReq + 88, // 141: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:input_type -> crabs.evening_detective_server.UpdateScenarioPlaceReq + 90, // 142: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:input_type -> crabs.evening_detective_server.DeleteScenarioPlaceReq + 96, // 143: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:input_type -> crabs.evening_detective_server.AddScenarioQuestionReq + 98, // 144: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:input_type -> crabs.evening_detective_server.UpdateScenarioQuestionReq + 100, // 145: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:input_type -> crabs.evening_detective_server.DeleteScenarioQuestionReq + 211, // 146: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:input_type -> crabs.evening_detective_server.UpdateScenarioBackgroundReq + 94, // 147: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:input_type -> crabs.evening_detective_server.UpdateScenarioIntroReq + 92, // 148: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:input_type -> crabs.evening_detective_server.UpdateScenarioConclusionReq + 102, // 149: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:input_type -> crabs.evening_detective_server.DownloadScenarioArchiveReq + 237, // 150: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:input_type -> google.api.HttpBody + 104, // 151: crabs.evening_detective_server.EveningDetectiveServer.AddGame:input_type -> crabs.evening_detective_server.AddGameReq + 106, // 152: crabs.evening_detective_server.EveningDetectiveServer.GetGames:input_type -> crabs.evening_detective_server.GetGamesReq + 159, // 153: crabs.evening_detective_server.EveningDetectiveServer.GetGame:input_type -> crabs.evening_detective_server.GetGameReq + 237, // 154: crabs.evening_detective_server.EveningDetectiveServer.ImportGame:input_type -> google.api.HttpBody + 233, // 155: crabs.evening_detective_server.EveningDetectiveServer.DownloadGameResultsPackage:input_type -> crabs.evening_detective_server.GameResultsPackageReq + 234, // 156: crabs.evening_detective_server.EveningDetectiveServer.ApplyGameResultsPackage:input_type -> crabs.evening_detective_server.ApplyGameResultsPackageReq + 111, // 157: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:input_type -> crabs.evening_detective_server.StartGameExportReq + 112, // 158: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:input_type -> crabs.evening_detective_server.GetGameExportReq + 213, // 159: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:input_type -> crabs.evening_detective_server.IssueGameTicketsReq + 216, // 160: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:input_type -> crabs.evening_detective_server.GetTicketReq + 218, // 161: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:input_type -> crabs.evening_detective_server.AcceptTicketReq + 115, // 162: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:input_type -> crabs.evening_detective_server.CreateScreenSessionReq + 117, // 163: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:input_type -> crabs.evening_detective_server.GetScreenStateReq + 119, // 164: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:input_type -> crabs.evening_detective_server.GetGameScreensReq + 122, // 165: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:input_type -> crabs.evening_detective_server.GetGameMusicReq + 124, // 166: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:input_type -> crabs.evening_detective_server.SetGameMusicReq + 126, // 167: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:input_type -> crabs.evening_detective_server.AdvanceScreenMusicReq + 128, // 168: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:input_type -> crabs.evening_detective_server.BindScreenReq + 130, // 169: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:input_type -> crabs.evening_detective_server.UnbindScreenReq + 132, // 170: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:input_type -> crabs.evening_detective_server.SetScreenSoundReq + 135, // 171: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:input_type -> crabs.evening_detective_server.GetGameMapReq + 137, // 172: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:input_type -> crabs.evening_detective_server.UpdateGameMapItemReq + 139, // 173: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:input_type -> crabs.evening_detective_server.SetScreenModeReq + 141, // 174: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:input_type -> crabs.evening_detective_server.SetScreenTimerReq + 143, // 175: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:input_type -> crabs.evening_detective_server.SendScreenCommandReq + 147, // 176: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:input_type -> crabs.evening_detective_server.GetScreenPlanReq + 149, // 177: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:input_type -> crabs.evening_detective_server.SaveScreenPlanReq + 151, // 178: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:input_type -> crabs.evening_detective_server.SetScreenPlanStepReq + 153, // 179: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:input_type -> crabs.evening_detective_server.GetScreenResultsReq + 159, // 180: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:input_type -> crabs.evening_detective_server.GetGameReq + 161, // 181: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:input_type -> crabs.evening_detective_server.GetGameAnswersReq + 163, // 182: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:input_type -> crabs.evening_detective_server.GetGameResultsReq + 168, // 183: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:input_type -> crabs.evening_detective_server.CreateGameReviewReq + 170, // 184: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:input_type -> crabs.evening_detective_server.GetGameReviewsReq + 171, // 185: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:input_type -> crabs.evening_detective_server.GetScenarioReviewsReq + 170, // 186: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:input_type -> crabs.evening_detective_server.GetGameReviewsReq + 172, // 187: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:input_type -> crabs.evening_detective_server.GetReviewsForModerationReq + 174, // 188: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:input_type -> crabs.evening_detective_server.ModerateGameReviewReq + 176, // 189: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:input_type -> crabs.evening_detective_server.UpdateGameReq + 178, // 190: crabs.evening_detective_server.EveningDetectiveServer.StartGame:input_type -> crabs.evening_detective_server.StartGameReq + 180, // 191: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:input_type -> crabs.evening_detective_server.PauseGameReq + 182, // 192: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:input_type -> crabs.evening_detective_server.PlayGameReq + 184, // 193: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:input_type -> crabs.evening_detective_server.FinishGameReq + 186, // 194: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:input_type -> crabs.evening_detective_server.ResetGameReq + 188, // 195: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:input_type -> crabs.evening_detective_server.DeleteGameReq + 190, // 196: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:input_type -> crabs.evening_detective_server.AddTeamReq + 192, // 197: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:input_type -> crabs.evening_detective_server.UpdateTeamReq + 194, // 198: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:input_type -> crabs.evening_detective_server.DeleteTeamReq + 196, // 199: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:input_type -> crabs.evening_detective_server.GiveTeamApplicationsReq + 198, // 200: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:input_type -> crabs.evening_detective_server.GetTeamStoryReq + 201, // 201: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:input_type -> crabs.evening_detective_server.AddTeamActionReq + 203, // 202: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:input_type -> crabs.evening_detective_server.DeleteLastTeamActionReq + 205, // 203: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:input_type -> crabs.evening_detective_server.GetTeamAnswersReq + 207, // 204: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:input_type -> crabs.evening_detective_server.SubmitTeamAnswersReq + 209, // 205: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:input_type -> crabs.evening_detective_server.SetTeamAnswerScoreReq + 224, // 206: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:output_type -> crabs.evening_detective_server.GetTasksRsp + 226, // 207: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:output_type -> crabs.evening_detective_server.GetTaskAssigneesRsp + 231, // 208: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:output_type -> crabs.evening_detective_server.TaskRsp + 231, // 209: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:output_type -> crabs.evening_detective_server.TaskRsp + 231, // 210: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:output_type -> crabs.evening_detective_server.TaskRsp + 232, // 211: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:output_type -> crabs.evening_detective_server.DeleteTaskRsp + 157, // 212: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp + 157, // 213: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp + 5, // 214: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp + 7, // 215: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp + 9, // 216: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp + 11, // 217: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp + 13, // 218: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp + 15, // 219: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp + 17, // 220: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:output_type -> crabs.evening_detective_server.DeleteAccountRsp + 19, // 221: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:output_type -> crabs.evening_detective_server.GetTermsRsp + 21, // 222: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:output_type -> crabs.evening_detective_server.GetPrivacyRsp + 23, // 223: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:output_type -> crabs.evening_detective_server.GetConsentRsp + 25, // 224: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp + 28, // 225: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:output_type -> crabs.evening_detective_server.GetUserByIDRsp + 30, // 226: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp + 32, // 227: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:output_type -> crabs.evening_detective_server.ChangeUserPasswordRsp + 34, // 228: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp + 36, // 229: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp + 38, // 230: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp + 40, // 231: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:output_type -> crabs.evening_detective_server.UploadFileRsp + 237, // 232: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:output_type -> google.api.HttpBody + 45, // 233: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:output_type -> crabs.evening_detective_server.GetPlaylistsRsp + 47, // 234: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:output_type -> crabs.evening_detective_server.CreatePlaylistRsp + 49, // 235: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:output_type -> crabs.evening_detective_server.UpdatePlaylistRsp + 51, // 236: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:output_type -> crabs.evening_detective_server.DeletePlaylistRsp + 53, // 237: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:output_type -> crabs.evening_detective_server.UploadPlaylistTrackRsp + 55, // 238: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:output_type -> crabs.evening_detective_server.DeletePlaylistTrackRsp + 57, // 239: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:output_type -> crabs.evening_detective_server.SetScenarioPlaylistRsp + 59, // 240: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:output_type -> crabs.evening_detective_server.AddScenarioRsp + 61, // 241: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:output_type -> crabs.evening_detective_server.GetMyScenariosRsp + 63, // 242: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:output_type -> crabs.evening_detective_server.GetScenariosCatalogRsp + 65, // 243: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp + 65, // 244: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp + 79, // 245: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:output_type -> crabs.evening_detective_server.UpdateScenarioRsp + 81, // 246: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:output_type -> crabs.evening_detective_server.PublicScenarioRsp + 83, // 247: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:output_type -> crabs.evening_detective_server.DraftScenarioRsp + 85, // 248: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:output_type -> crabs.evening_detective_server.DeleteScenarioRsp + 87, // 249: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:output_type -> crabs.evening_detective_server.AddScenarioPlaceRsp + 89, // 250: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:output_type -> crabs.evening_detective_server.UpdateScenarioPlaceRsp + 91, // 251: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:output_type -> crabs.evening_detective_server.DeleteScenarioPlaceRsp + 97, // 252: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:output_type -> crabs.evening_detective_server.AddScenarioQuestionRsp + 99, // 253: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:output_type -> crabs.evening_detective_server.UpdateScenarioQuestionRsp + 101, // 254: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:output_type -> crabs.evening_detective_server.DeleteScenarioQuestionRsp + 212, // 255: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:output_type -> crabs.evening_detective_server.UpdateScenarioBackgroundRsp + 95, // 256: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:output_type -> crabs.evening_detective_server.UpdateScenarioIntroRsp + 93, // 257: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:output_type -> crabs.evening_detective_server.UpdateScenarioConclusionRsp + 237, // 258: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:output_type -> google.api.HttpBody + 103, // 259: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:output_type -> crabs.evening_detective_server.UploadScenarioArchiveRsp + 105, // 260: crabs.evening_detective_server.EveningDetectiveServer.AddGame:output_type -> crabs.evening_detective_server.AddGameRsp + 107, // 261: crabs.evening_detective_server.EveningDetectiveServer.GetGames:output_type -> crabs.evening_detective_server.GetGamesRsp + 160, // 262: crabs.evening_detective_server.EveningDetectiveServer.GetGame:output_type -> crabs.evening_detective_server.GetGameRsp + 110, // 263: crabs.evening_detective_server.EveningDetectiveServer.ImportGame:output_type -> crabs.evening_detective_server.GameImportRsp + 237, // 264: crabs.evening_detective_server.EveningDetectiveServer.DownloadGameResultsPackage:output_type -> google.api.HttpBody + 235, // 265: crabs.evening_detective_server.EveningDetectiveServer.ApplyGameResultsPackage:output_type -> crabs.evening_detective_server.GameResultsPackageRsp + 113, // 266: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:output_type -> crabs.evening_detective_server.GameExportRsp + 113, // 267: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:output_type -> crabs.evening_detective_server.GameExportRsp + 214, // 268: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:output_type -> crabs.evening_detective_server.IssueGameTicketsRsp + 217, // 269: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:output_type -> crabs.evening_detective_server.GetTicketRsp + 219, // 270: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:output_type -> crabs.evening_detective_server.AcceptTicketRsp + 116, // 271: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:output_type -> crabs.evening_detective_server.CreateScreenSessionRsp + 118, // 272: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:output_type -> crabs.evening_detective_server.GetScreenStateRsp + 120, // 273: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:output_type -> crabs.evening_detective_server.GetGameScreensRsp + 123, // 274: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:output_type -> crabs.evening_detective_server.GetGameMusicRsp + 125, // 275: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:output_type -> crabs.evening_detective_server.SetGameMusicRsp + 127, // 276: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:output_type -> crabs.evening_detective_server.AdvanceScreenMusicRsp + 129, // 277: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:output_type -> crabs.evening_detective_server.BindScreenRsp + 131, // 278: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:output_type -> crabs.evening_detective_server.UnbindScreenRsp + 133, // 279: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:output_type -> crabs.evening_detective_server.SetScreenSoundRsp + 136, // 280: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:output_type -> crabs.evening_detective_server.GetGameMapRsp + 138, // 281: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:output_type -> crabs.evening_detective_server.UpdateGameMapItemRsp + 140, // 282: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:output_type -> crabs.evening_detective_server.SetScreenModeRsp + 142, // 283: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:output_type -> crabs.evening_detective_server.SetScreenTimerRsp + 144, // 284: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:output_type -> crabs.evening_detective_server.SendScreenCommandRsp + 148, // 285: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:output_type -> crabs.evening_detective_server.GetScreenPlanRsp + 150, // 286: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:output_type -> crabs.evening_detective_server.SaveScreenPlanRsp + 152, // 287: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:output_type -> crabs.evening_detective_server.SetScreenPlanStepRsp + 154, // 288: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:output_type -> crabs.evening_detective_server.GetScreenResultsRsp + 237, // 289: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:output_type -> google.api.HttpBody + 162, // 290: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:output_type -> crabs.evening_detective_server.GetGameAnswersRsp + 166, // 291: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:output_type -> crabs.evening_detective_server.GetGameResultsRsp + 169, // 292: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:output_type -> crabs.evening_detective_server.CreateGameReviewRsp + 173, // 293: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 173, // 294: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 173, // 295: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 173, // 296: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 175, // 297: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:output_type -> crabs.evening_detective_server.ModerateGameReviewRsp + 177, // 298: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:output_type -> crabs.evening_detective_server.UpdateGameRsp + 179, // 299: crabs.evening_detective_server.EveningDetectiveServer.StartGame:output_type -> crabs.evening_detective_server.StartGameRsp + 181, // 300: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:output_type -> crabs.evening_detective_server.PauseGameRsp + 183, // 301: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:output_type -> crabs.evening_detective_server.PlayGameRsp + 185, // 302: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:output_type -> crabs.evening_detective_server.FinishGameRsp + 187, // 303: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:output_type -> crabs.evening_detective_server.ResetGameRsp + 189, // 304: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:output_type -> crabs.evening_detective_server.DeleteGameRsp + 191, // 305: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:output_type -> crabs.evening_detective_server.AddTeamRsp + 193, // 306: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:output_type -> crabs.evening_detective_server.UpdateTeamRsp + 195, // 307: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:output_type -> crabs.evening_detective_server.DeleteTeamRsp + 197, // 308: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:output_type -> crabs.evening_detective_server.GiveTeamApplicationsRsp + 199, // 309: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:output_type -> crabs.evening_detective_server.GetTeamStoryRsp + 202, // 310: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:output_type -> crabs.evening_detective_server.AddTeamActionRsp + 204, // 311: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:output_type -> crabs.evening_detective_server.DeleteLastTeamActionRsp + 206, // 312: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:output_type -> crabs.evening_detective_server.GetTeamAnswersRsp + 208, // 313: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:output_type -> crabs.evening_detective_server.SubmitTeamAnswersRsp + 210, // 314: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:output_type -> crabs.evening_detective_server.SetTeamAnswerScoreRsp + 206, // [206:315] is the sub-list for method output_type + 97, // [97:206] is the sub-list for method input_type + 97, // [97:97] is the sub-list for extension type_name + 97, // [97:97] is the sub-list for extension extendee + 0, // [0:97] is the sub-list for field type_name } func init() { file_main_proto_init() } @@ -13719,7 +13896,7 @@ func file_main_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_main_proto_rawDesc), len(file_main_proto_rawDesc)), NumEnums: 4, - NumMessages: 229, + NumMessages: 232, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/main.pb.gw.go b/proto/main.pb.gw.go index cf63923..abdacf0 100644 --- a/proto/main.pb.gw.go +++ b/proto/main.pb.gw.go @@ -2080,6 +2080,90 @@ func local_request_EveningDetectiveServer_ImportGame_0(ctx context.Context, mars return msg, metadata, err } +func request_EveningDetectiveServer_DownloadGameResultsPackage_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GameResultsPackageReq + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := client.DownloadGameResultsPackage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_DownloadGameResultsPackage_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GameResultsPackageReq + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := server.DownloadGameResultsPackage(ctx, &protoReq) + return msg, metadata, err +} + +func request_EveningDetectiveServer_ApplyGameResultsPackage_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ApplyGameResultsPackageReq + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Package); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := client.ApplyGameResultsPackage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_ApplyGameResultsPackage_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ApplyGameResultsPackageReq + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Package); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := server.ApplyGameResultsPackage(ctx, &protoReq) + return msg, metadata, err +} + func request_EveningDetectiveServer_StartGameExport_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq StartGameExportReq @@ -5311,6 +5395,46 @@ func RegisterEveningDetectiveServerHandlerServer(ctx context.Context, mux *runti } forward_EveningDetectiveServer_ImportGame_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadGameResultsPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/DownloadGameResultsPackage", runtime.WithHTTPPathPattern("/api/games/{ID}/results-package/download")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_DownloadGameResultsPackage_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_DownloadGameResultsPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_ApplyGameResultsPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/ApplyGameResultsPackage", runtime.WithHTTPPathPattern("/api/games/{ID}/results-package/apply")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_ApplyGameResultsPackage_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_ApplyGameResultsPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_StartGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -7317,6 +7441,40 @@ func RegisterEveningDetectiveServerHandlerClient(ctx context.Context, mux *runti } forward_EveningDetectiveServer_ImportGame_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadGameResultsPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/DownloadGameResultsPackage", runtime.WithHTTPPathPattern("/api/games/{ID}/results-package/download")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_DownloadGameResultsPackage_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_DownloadGameResultsPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_ApplyGameResultsPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/ApplyGameResultsPackage", runtime.WithHTTPPathPattern("/api/games/{ID}/results-package/apply")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_ApplyGameResultsPackage_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_ApplyGameResultsPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_StartGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -8212,6 +8370,8 @@ var ( pattern_EveningDetectiveServer_GetGames_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"api", "games"}, "")) pattern_EveningDetectiveServer_GetGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"api", "games", "ID"}, "")) pattern_EveningDetectiveServer_ImportGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "games", "import"}, "")) + pattern_EveningDetectiveServer_DownloadGameResultsPackage_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"api", "games", "ID", "results-package", "download"}, "")) + pattern_EveningDetectiveServer_ApplyGameResultsPackage_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"api", "games", "ID", "results-package", "apply"}, "")) pattern_EveningDetectiveServer_StartGameExport_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "ID", "export"}, "")) pattern_EveningDetectiveServer_GetGameExport_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "ID", "export"}, "")) pattern_EveningDetectiveServer_IssueGameTickets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "gameID", "tickets"}, "")) @@ -8322,6 +8482,8 @@ var ( forward_EveningDetectiveServer_GetGames_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetGame_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_ImportGame_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_DownloadGameResultsPackage_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_ApplyGameResultsPackage_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_StartGameExport_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetGameExport_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_IssueGameTickets_0 = runtime.ForwardResponseMessage diff --git a/proto/main_grpc.pb.go b/proto/main_grpc.pb.go index e5f21d0..d7e2710 100644 --- a/proto/main_grpc.pb.go +++ b/proto/main_grpc.pb.go @@ -84,6 +84,8 @@ const ( EveningDetectiveServer_GetGames_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGames" EveningDetectiveServer_GetGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGame" EveningDetectiveServer_ImportGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/ImportGame" + EveningDetectiveServer_DownloadGameResultsPackage_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DownloadGameResultsPackage" + EveningDetectiveServer_ApplyGameResultsPackage_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/ApplyGameResultsPackage" EveningDetectiveServer_StartGameExport_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/StartGameExport" EveningDetectiveServer_GetGameExport_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGameExport" EveningDetectiveServer_IssueGameTickets_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/IssueGameTickets" @@ -202,6 +204,9 @@ type EveningDetectiveServerClient interface { GetGame(ctx context.Context, in *GetGameReq, opts ...grpc.CallOption) (*GetGameRsp, error) // HTTP uploads are streamed by a dedicated handler, bypassing gRPC message limits. ImportGame(ctx context.Context, in *httpbody.HttpBody, opts ...grpc.CallOption) (*GameImportRsp, error) + // Dedicated HTTP handlers stream ZIPs; gRPC retains its message size limit. + DownloadGameResultsPackage(ctx context.Context, in *GameResultsPackageReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) + ApplyGameResultsPackage(ctx context.Context, in *ApplyGameResultsPackageReq, opts ...grpc.CallOption) (*GameResultsPackageRsp, error) StartGameExport(ctx context.Context, in *StartGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) GetGameExport(ctx context.Context, in *GetGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) IssueGameTickets(ctx context.Context, in *IssueGameTicketsReq, opts ...grpc.CallOption) (*IssueGameTicketsRsp, error) @@ -847,6 +852,26 @@ func (c *eveningDetectiveServerClient) ImportGame(ctx context.Context, in *httpb return out, nil } +func (c *eveningDetectiveServerClient) DownloadGameResultsPackage(ctx context.Context, in *GameResultsPackageReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(httpbody.HttpBody) + err := c.cc.Invoke(ctx, EveningDetectiveServer_DownloadGameResultsPackage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eveningDetectiveServerClient) ApplyGameResultsPackage(ctx context.Context, in *ApplyGameResultsPackageReq, opts ...grpc.CallOption) (*GameResultsPackageRsp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GameResultsPackageRsp) + err := c.cc.Invoke(ctx, EveningDetectiveServer_ApplyGameResultsPackage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *eveningDetectiveServerClient) StartGameExport(ctx context.Context, in *StartGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GameExportRsp) @@ -1404,6 +1429,9 @@ type EveningDetectiveServerServer interface { GetGame(context.Context, *GetGameReq) (*GetGameRsp, error) // HTTP uploads are streamed by a dedicated handler, bypassing gRPC message limits. ImportGame(context.Context, *httpbody.HttpBody) (*GameImportRsp, error) + // Dedicated HTTP handlers stream ZIPs; gRPC retains its message size limit. + DownloadGameResultsPackage(context.Context, *GameResultsPackageReq) (*httpbody.HttpBody, error) + ApplyGameResultsPackage(context.Context, *ApplyGameResultsPackageReq) (*GameResultsPackageRsp, error) StartGameExport(context.Context, *StartGameExportReq) (*GameExportRsp, error) GetGameExport(context.Context, *GetGameExportReq) (*GameExportRsp, error) IssueGameTickets(context.Context, *IssueGameTicketsReq) (*IssueGameTicketsRsp, error) @@ -1643,6 +1671,12 @@ func (UnimplementedEveningDetectiveServerServer) GetGame(context.Context, *GetGa func (UnimplementedEveningDetectiveServerServer) ImportGame(context.Context, *httpbody.HttpBody) (*GameImportRsp, error) { return nil, status.Error(codes.Unimplemented, "method ImportGame not implemented") } +func (UnimplementedEveningDetectiveServerServer) DownloadGameResultsPackage(context.Context, *GameResultsPackageReq) (*httpbody.HttpBody, error) { + return nil, status.Error(codes.Unimplemented, "method DownloadGameResultsPackage not implemented") +} +func (UnimplementedEveningDetectiveServerServer) ApplyGameResultsPackage(context.Context, *ApplyGameResultsPackageReq) (*GameResultsPackageRsp, error) { + return nil, status.Error(codes.Unimplemented, "method ApplyGameResultsPackage not implemented") +} func (UnimplementedEveningDetectiveServerServer) StartGameExport(context.Context, *StartGameExportReq) (*GameExportRsp, error) { return nil, status.Error(codes.Unimplemented, "method StartGameExport not implemented") } @@ -2856,6 +2890,42 @@ func _EveningDetectiveServer_ImportGame_Handler(srv interface{}, ctx context.Con return interceptor(ctx, in, info, handler) } +func _EveningDetectiveServer_DownloadGameResultsPackage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GameResultsPackageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).DownloadGameResultsPackage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_DownloadGameResultsPackage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).DownloadGameResultsPackage(ctx, req.(*GameResultsPackageReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _EveningDetectiveServer_ApplyGameResultsPackage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyGameResultsPackageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).ApplyGameResultsPackage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_ApplyGameResultsPackage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).ApplyGameResultsPackage(ctx, req.(*ApplyGameResultsPackageReq)) + } + return interceptor(ctx, in, info, handler) +} + func _EveningDetectiveServer_StartGameExport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StartGameExportReq) if err := dec(in); err != nil { @@ -3977,6 +4047,14 @@ var EveningDetectiveServer_ServiceDesc = grpc.ServiceDesc{ MethodName: "ImportGame", Handler: _EveningDetectiveServer_ImportGame_Handler, }, + { + MethodName: "DownloadGameResultsPackage", + Handler: _EveningDetectiveServer_DownloadGameResultsPackage_Handler, + }, + { + MethodName: "ApplyGameResultsPackage", + Handler: _EveningDetectiveServer_ApplyGameResultsPackage_Handler, + }, { MethodName: "StartGameExport", Handler: _EveningDetectiveServer_StartGameExport_Handler,