package transcoder import ( "errors" "fmt" "time" lobbymodel "galaxy/model/lobby" lobbyfbs "galaxy/schema/fbs/lobby" flatbuffers "github.com/google/flatbuffers/go" ) // MyGamesListRequestToPayload converts a typed lobbymodel.MyGamesListRequest // to FlatBuffers bytes suitable for the authenticated gateway transport. func MyGamesListRequestToPayload(request *lobbymodel.MyGamesListRequest) ([]byte, error) { if request == nil { return nil, errors.New("encode my games list request payload: request is nil") } builder := flatbuffers.NewBuilder(32) lobbyfbs.MyGamesListRequestStart(builder) offset := lobbyfbs.MyGamesListRequestEnd(builder) lobbyfbs.FinishMyGamesListRequestBuffer(builder, offset) return builder.FinishedBytes(), nil } // PayloadToMyGamesListRequest converts FlatBuffers payload bytes into // lobbymodel.MyGamesListRequest. func PayloadToMyGamesListRequest(data []byte) (result *lobbymodel.MyGamesListRequest, err error) { if len(data) == 0 { return nil, errors.New("decode my games list request payload: data is empty") } defer recoverLobbyDecodePanic("decode my games list request payload", &result, &err) _ = lobbyfbs.GetRootAsMyGamesListRequest(data, 0) return &lobbymodel.MyGamesListRequest{}, nil } // MyGamesListResponseToPayload converts lobbymodel.MyGamesListResponse to // FlatBuffers bytes suitable for the authenticated gateway transport. func MyGamesListResponseToPayload(response *lobbymodel.MyGamesListResponse) ([]byte, error) { if response == nil { return nil, errors.New("encode my games list response payload: response is nil") } builder := flatbuffers.NewBuilder(512) itemOffsets := make([]flatbuffers.UOffsetT, len(response.Items)) for index := range response.Items { itemOffsets[index] = encodeGameSummary(builder, response.Items[index]) } var itemsVector flatbuffers.UOffsetT if len(itemOffsets) > 0 { lobbyfbs.MyGamesListResponseStartItemsVector(builder, len(itemOffsets)) for index := len(itemOffsets) - 1; index >= 0; index-- { builder.PrependUOffsetT(itemOffsets[index]) } itemsVector = builder.EndVector(len(itemOffsets)) } lobbyfbs.MyGamesListResponseStart(builder) if itemsVector != 0 { lobbyfbs.MyGamesListResponseAddItems(builder, itemsVector) } offset := lobbyfbs.MyGamesListResponseEnd(builder) lobbyfbs.FinishMyGamesListResponseBuffer(builder, offset) return builder.FinishedBytes(), nil } // PayloadToMyGamesListResponse converts FlatBuffers payload bytes into // lobbymodel.MyGamesListResponse. func PayloadToMyGamesListResponse(data []byte) (result *lobbymodel.MyGamesListResponse, err error) { if len(data) == 0 { return nil, errors.New("decode my games list response payload: data is empty") } defer recoverLobbyDecodePanic("decode my games list response payload", &result, &err) response := lobbyfbs.GetRootAsMyGamesListResponse(data, 0) out := &lobbymodel.MyGamesListResponse{ Items: make([]lobbymodel.GameSummary, 0, response.ItemsLength()), } summary := new(lobbyfbs.GameSummary) for index := 0; index < response.ItemsLength(); index++ { if !response.Items(summary, index) { return nil, fmt.Errorf("decode my games list response payload: items[%d] is missing", index) } out.Items = append(out.Items, decodeGameSummary(summary)) } return out, nil } // OpenEnrollmentRequestToPayload converts lobbymodel.OpenEnrollmentRequest to // FlatBuffers bytes suitable for the authenticated gateway transport. func OpenEnrollmentRequestToPayload(request *lobbymodel.OpenEnrollmentRequest) ([]byte, error) { if request == nil { return nil, errors.New("encode open enrollment request payload: request is nil") } builder := flatbuffers.NewBuilder(64) gameID := builder.CreateString(request.GameID) lobbyfbs.OpenEnrollmentRequestStart(builder) lobbyfbs.OpenEnrollmentRequestAddGameId(builder, gameID) offset := lobbyfbs.OpenEnrollmentRequestEnd(builder) lobbyfbs.FinishOpenEnrollmentRequestBuffer(builder, offset) return builder.FinishedBytes(), nil } // PayloadToOpenEnrollmentRequest converts FlatBuffers payload bytes into // lobbymodel.OpenEnrollmentRequest. func PayloadToOpenEnrollmentRequest(data []byte) (result *lobbymodel.OpenEnrollmentRequest, err error) { if len(data) == 0 { return nil, errors.New("decode open enrollment request payload: data is empty") } defer recoverLobbyDecodePanic("decode open enrollment request payload", &result, &err) request := lobbyfbs.GetRootAsOpenEnrollmentRequest(data, 0) return &lobbymodel.OpenEnrollmentRequest{ GameID: string(request.GameId()), }, nil } // OpenEnrollmentResponseToPayload converts lobbymodel.OpenEnrollmentResponse to // FlatBuffers bytes suitable for the authenticated gateway transport. func OpenEnrollmentResponseToPayload(response *lobbymodel.OpenEnrollmentResponse) ([]byte, error) { if response == nil { return nil, errors.New("encode open enrollment response payload: response is nil") } builder := flatbuffers.NewBuilder(64) gameID := builder.CreateString(response.GameID) status := builder.CreateString(response.Status) lobbyfbs.OpenEnrollmentResponseStart(builder) lobbyfbs.OpenEnrollmentResponseAddGameId(builder, gameID) lobbyfbs.OpenEnrollmentResponseAddStatus(builder, status) offset := lobbyfbs.OpenEnrollmentResponseEnd(builder) lobbyfbs.FinishOpenEnrollmentResponseBuffer(builder, offset) return builder.FinishedBytes(), nil } // PayloadToOpenEnrollmentResponse converts FlatBuffers payload bytes into // lobbymodel.OpenEnrollmentResponse. func PayloadToOpenEnrollmentResponse(data []byte) (result *lobbymodel.OpenEnrollmentResponse, err error) { if len(data) == 0 { return nil, errors.New("decode open enrollment response payload: data is empty") } defer recoverLobbyDecodePanic("decode open enrollment response payload", &result, &err) response := lobbyfbs.GetRootAsOpenEnrollmentResponse(data, 0) return &lobbymodel.OpenEnrollmentResponse{ GameID: string(response.GameId()), Status: string(response.Status()), }, nil } // LobbyErrorResponseToPayload converts lobbymodel.ErrorResponse to FlatBuffers // bytes suitable for the authenticated gateway transport. func LobbyErrorResponseToPayload(response *lobbymodel.ErrorResponse) ([]byte, error) { if response == nil { return nil, errors.New("encode lobby error response payload: response is nil") } builder := flatbuffers.NewBuilder(128) code := builder.CreateString(response.Error.Code) message := builder.CreateString(response.Error.Message) lobbyfbs.ErrorBodyStart(builder) lobbyfbs.ErrorBodyAddCode(builder, code) lobbyfbs.ErrorBodyAddMessage(builder, message) errorOffset := lobbyfbs.ErrorBodyEnd(builder) lobbyfbs.ErrorResponseStart(builder) lobbyfbs.ErrorResponseAddError(builder, errorOffset) offset := lobbyfbs.ErrorResponseEnd(builder) lobbyfbs.FinishErrorResponseBuffer(builder, offset) return builder.FinishedBytes(), nil } // PayloadToLobbyErrorResponse converts FlatBuffers payload bytes into // lobbymodel.ErrorResponse. func PayloadToLobbyErrorResponse(data []byte) (result *lobbymodel.ErrorResponse, err error) { if len(data) == 0 { return nil, errors.New("decode lobby error response payload: data is empty") } defer recoverLobbyDecodePanic("decode lobby error response payload", &result, &err) response := lobbyfbs.GetRootAsErrorResponse(data, 0) body := response.Error(nil) if body == nil { return nil, errors.New("decode lobby error response payload: error is missing") } return &lobbymodel.ErrorResponse{ Error: lobbymodel.ErrorBody{ Code: string(body.Code()), Message: string(body.Message()), }, }, nil } func encodeGameSummary(builder *flatbuffers.Builder, summary lobbymodel.GameSummary) flatbuffers.UOffsetT { gameID := builder.CreateString(summary.GameID) gameName := builder.CreateString(summary.GameName) gameType := builder.CreateString(summary.GameType) status := builder.CreateString(summary.Status) ownerUserID := builder.CreateString(summary.OwnerUserID) lobbyfbs.GameSummaryStart(builder) lobbyfbs.GameSummaryAddGameId(builder, gameID) lobbyfbs.GameSummaryAddGameName(builder, gameName) lobbyfbs.GameSummaryAddGameType(builder, gameType) lobbyfbs.GameSummaryAddStatus(builder, status) lobbyfbs.GameSummaryAddOwnerUserId(builder, ownerUserID) lobbyfbs.GameSummaryAddMinPlayers(builder, int32(summary.MinPlayers)) lobbyfbs.GameSummaryAddMaxPlayers(builder, int32(summary.MaxPlayers)) lobbyfbs.GameSummaryAddEnrollmentEndsAtMs(builder, summary.EnrollmentEndsAt.UTC().UnixMilli()) lobbyfbs.GameSummaryAddCreatedAtMs(builder, summary.CreatedAt.UTC().UnixMilli()) lobbyfbs.GameSummaryAddUpdatedAtMs(builder, summary.UpdatedAt.UTC().UnixMilli()) return lobbyfbs.GameSummaryEnd(builder) } func decodeGameSummary(summary *lobbyfbs.GameSummary) lobbymodel.GameSummary { return lobbymodel.GameSummary{ GameID: string(summary.GameId()), GameName: string(summary.GameName()), GameType: string(summary.GameType()), Status: string(summary.Status()), OwnerUserID: string(summary.OwnerUserId()), MinPlayers: int(summary.MinPlayers()), MaxPlayers: int(summary.MaxPlayers()), EnrollmentEndsAt: time.UnixMilli(summary.EnrollmentEndsAtMs()).UTC(), CreatedAt: time.UnixMilli(summary.CreatedAtMs()).UTC(), UpdatedAt: time.UnixMilli(summary.UpdatedAtMs()).UTC(), } } func recoverLobbyDecodePanic[T any](message string, result **T, err *error) { if recovered := recover(); recovered != nil { *result = nil *err = fmt.Errorf("%s: panic recovered: %v", message, recovered) } }