This commit is contained in:
2026-10-11 13:26:38 +07:00
parent 74a45da402
commit 6f2b63511c
17 changed files with 1254 additions and 304 deletions
+37
View File
@@ -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;
}
+14 -1
View File
@@ -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 {
@@ -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": {
+44 -5
View File
@@ -350,7 +350,7 @@ RustFS и создать `<marker>.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 ГиБ не проверяются.
+153
View File
@@ -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()})
})
}
@@ -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, "Не удалось обработать результаты")
}
}
@@ -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),
}
}
+63
View File
@@ -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)
}
}
+43 -36
View File
@@ -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,
}
}
@@ -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)
@@ -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)
}
}
}
@@ -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
}
@@ -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)
}
@@ -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)
}
+418 -241
View File
@@ -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,
},
+162
View File
@@ -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
+78
View File
@@ -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,