513 lines
18 KiB
Go
513 lines
18 KiB
Go
package transcoder
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
usermodel "galaxy/model/user"
|
|
userfbs "galaxy/schema/fbs/user"
|
|
|
|
flatbuffers "github.com/google/flatbuffers/go"
|
|
)
|
|
|
|
// GetMyAccountRequestToPayload converts usermodel.GetMyAccountRequest to
|
|
// FlatBuffers bytes suitable for the authenticated gateway transport.
|
|
func GetMyAccountRequestToPayload(request *usermodel.GetMyAccountRequest) ([]byte, error) {
|
|
if request == nil {
|
|
return nil, errors.New("encode get my account request payload: request is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(32)
|
|
userfbs.GetMyAccountRequestStart(builder)
|
|
offset := userfbs.GetMyAccountRequestEnd(builder)
|
|
userfbs.FinishGetMyAccountRequestBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToGetMyAccountRequest converts FlatBuffers payload bytes into
|
|
// usermodel.GetMyAccountRequest.
|
|
func PayloadToGetMyAccountRequest(data []byte) (result *usermodel.GetMyAccountRequest, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode get my account request payload: data is empty")
|
|
}
|
|
|
|
defer recoverUserDecodePanic("decode get my account request payload", &result, &err)
|
|
|
|
_ = userfbs.GetRootAsGetMyAccountRequest(data, 0)
|
|
return &usermodel.GetMyAccountRequest{}, nil
|
|
}
|
|
|
|
// UpdateMyProfileRequestToPayload converts usermodel.UpdateMyProfileRequest to
|
|
// FlatBuffers bytes suitable for the authenticated gateway transport.
|
|
func UpdateMyProfileRequestToPayload(request *usermodel.UpdateMyProfileRequest) ([]byte, error) {
|
|
if request == nil {
|
|
return nil, errors.New("encode update my profile request payload: request is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(128)
|
|
displayName := builder.CreateString(request.DisplayName)
|
|
|
|
userfbs.UpdateMyProfileRequestStart(builder)
|
|
userfbs.UpdateMyProfileRequestAddDisplayName(builder, displayName)
|
|
offset := userfbs.UpdateMyProfileRequestEnd(builder)
|
|
userfbs.FinishUpdateMyProfileRequestBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToUpdateMyProfileRequest converts FlatBuffers payload bytes into
|
|
// usermodel.UpdateMyProfileRequest.
|
|
func PayloadToUpdateMyProfileRequest(data []byte) (result *usermodel.UpdateMyProfileRequest, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode update my profile request payload: data is empty")
|
|
}
|
|
|
|
defer recoverUserDecodePanic("decode update my profile request payload", &result, &err)
|
|
|
|
request := userfbs.GetRootAsUpdateMyProfileRequest(data, 0)
|
|
return &usermodel.UpdateMyProfileRequest{
|
|
DisplayName: string(request.DisplayName()),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMySettingsRequestToPayload converts
|
|
// usermodel.UpdateMySettingsRequest to FlatBuffers bytes suitable for the
|
|
// authenticated gateway transport.
|
|
func UpdateMySettingsRequestToPayload(request *usermodel.UpdateMySettingsRequest) ([]byte, error) {
|
|
if request == nil {
|
|
return nil, errors.New("encode update my settings request payload: request is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(128)
|
|
preferredLanguage := builder.CreateString(request.PreferredLanguage)
|
|
timeZone := builder.CreateString(request.TimeZone)
|
|
|
|
userfbs.UpdateMySettingsRequestStart(builder)
|
|
userfbs.UpdateMySettingsRequestAddPreferredLanguage(builder, preferredLanguage)
|
|
userfbs.UpdateMySettingsRequestAddTimeZone(builder, timeZone)
|
|
offset := userfbs.UpdateMySettingsRequestEnd(builder)
|
|
userfbs.FinishUpdateMySettingsRequestBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToUpdateMySettingsRequest converts FlatBuffers payload bytes into
|
|
// usermodel.UpdateMySettingsRequest.
|
|
func PayloadToUpdateMySettingsRequest(data []byte) (result *usermodel.UpdateMySettingsRequest, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode update my settings request payload: data is empty")
|
|
}
|
|
|
|
defer recoverUserDecodePanic("decode update my settings request payload", &result, &err)
|
|
|
|
request := userfbs.GetRootAsUpdateMySettingsRequest(data, 0)
|
|
return &usermodel.UpdateMySettingsRequest{
|
|
PreferredLanguage: string(request.PreferredLanguage()),
|
|
TimeZone: string(request.TimeZone()),
|
|
}, nil
|
|
}
|
|
|
|
// AccountResponseToPayload converts usermodel.AccountResponse to FlatBuffers
|
|
// bytes suitable for the authenticated gateway transport.
|
|
func AccountResponseToPayload(response *usermodel.AccountResponse) ([]byte, error) {
|
|
if response == nil {
|
|
return nil, errors.New("encode account response payload: response is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(512)
|
|
accountOffset, err := encodeAccount(builder, response.Account)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("encode account response payload: %w", err)
|
|
}
|
|
|
|
userfbs.AccountResponseStart(builder)
|
|
userfbs.AccountResponseAddAccount(builder, accountOffset)
|
|
offset := userfbs.AccountResponseEnd(builder)
|
|
userfbs.FinishAccountResponseBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToAccountResponse converts FlatBuffers payload bytes into
|
|
// usermodel.AccountResponse.
|
|
func PayloadToAccountResponse(data []byte) (result *usermodel.AccountResponse, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode account response payload: data is empty")
|
|
}
|
|
|
|
defer recoverUserDecodePanic("decode account response payload", &result, &err)
|
|
|
|
response := userfbs.GetRootAsAccountResponse(data, 0)
|
|
account := response.Account(nil)
|
|
if account == nil {
|
|
return nil, errors.New("decode account response payload: account is missing")
|
|
}
|
|
|
|
decodedAccount, err := decodeAccount(account)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode account response payload: %w", err)
|
|
}
|
|
|
|
return &usermodel.AccountResponse{Account: decodedAccount}, nil
|
|
}
|
|
|
|
// ErrorResponseToPayload converts usermodel.ErrorResponse to FlatBuffers bytes
|
|
// suitable for the authenticated gateway transport.
|
|
func ErrorResponseToPayload(response *usermodel.ErrorResponse) ([]byte, error) {
|
|
if response == nil {
|
|
return nil, errors.New("encode error response payload: response is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(128)
|
|
errorOffset := encodeErrorBody(builder, response.Error)
|
|
|
|
userfbs.ErrorResponseStart(builder)
|
|
userfbs.ErrorResponseAddError(builder, errorOffset)
|
|
offset := userfbs.ErrorResponseEnd(builder)
|
|
userfbs.FinishErrorResponseBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToErrorResponse converts FlatBuffers payload bytes into
|
|
// usermodel.ErrorResponse.
|
|
func PayloadToErrorResponse(data []byte) (result *usermodel.ErrorResponse, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode error response payload: data is empty")
|
|
}
|
|
|
|
defer recoverUserDecodePanic("decode error response payload", &result, &err)
|
|
|
|
response := userfbs.GetRootAsErrorResponse(data, 0)
|
|
errorBody := response.Error(nil)
|
|
if errorBody == nil {
|
|
return nil, errors.New("decode error response payload: error is missing")
|
|
}
|
|
|
|
return &usermodel.ErrorResponse{
|
|
Error: usermodel.ErrorBody{
|
|
Code: string(errorBody.Code()),
|
|
Message: string(errorBody.Message()),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func encodeAccount(builder *flatbuffers.Builder, account usermodel.Account) (flatbuffers.UOffsetT, error) {
|
|
entitlementOffset, err := encodeEntitlementSnapshot(builder, account.Entitlement)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encode account: %w", err)
|
|
}
|
|
|
|
activeSanctionOffsets := make([]flatbuffers.UOffsetT, len(account.ActiveSanctions))
|
|
for index := range account.ActiveSanctions {
|
|
activeSanctionOffsets[index], err = encodeActiveSanction(builder, account.ActiveSanctions[index])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encode account active sanction %d: %w", index, err)
|
|
}
|
|
}
|
|
|
|
var activeSanctionsVector flatbuffers.UOffsetT
|
|
if len(activeSanctionOffsets) > 0 {
|
|
userfbs.AccountViewStartActiveSanctionsVector(builder, len(activeSanctionOffsets))
|
|
for index := len(activeSanctionOffsets) - 1; index >= 0; index-- {
|
|
builder.PrependUOffsetT(activeSanctionOffsets[index])
|
|
}
|
|
activeSanctionsVector = builder.EndVector(len(activeSanctionOffsets))
|
|
}
|
|
|
|
activeLimitOffsets := make([]flatbuffers.UOffsetT, len(account.ActiveLimits))
|
|
for index := range account.ActiveLimits {
|
|
activeLimitOffsets[index], err = encodeActiveLimit(builder, account.ActiveLimits[index])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encode account active limit %d: %w", index, err)
|
|
}
|
|
}
|
|
|
|
var activeLimitsVector flatbuffers.UOffsetT
|
|
if len(activeLimitOffsets) > 0 {
|
|
userfbs.AccountViewStartActiveLimitsVector(builder, len(activeLimitOffsets))
|
|
for index := len(activeLimitOffsets) - 1; index >= 0; index-- {
|
|
builder.PrependUOffsetT(activeLimitOffsets[index])
|
|
}
|
|
activeLimitsVector = builder.EndVector(len(activeLimitOffsets))
|
|
}
|
|
|
|
userID := builder.CreateString(account.UserID)
|
|
email := builder.CreateString(account.Email)
|
|
userName := builder.CreateString(account.UserName)
|
|
var displayName flatbuffers.UOffsetT
|
|
if account.DisplayName != "" {
|
|
displayName = builder.CreateString(account.DisplayName)
|
|
}
|
|
preferredLanguage := builder.CreateString(account.PreferredLanguage)
|
|
timeZone := builder.CreateString(account.TimeZone)
|
|
|
|
var declaredCountry flatbuffers.UOffsetT
|
|
if account.DeclaredCountry != "" {
|
|
declaredCountry = builder.CreateString(account.DeclaredCountry)
|
|
}
|
|
|
|
userfbs.AccountViewStart(builder)
|
|
userfbs.AccountViewAddUserId(builder, userID)
|
|
userfbs.AccountViewAddEmail(builder, email)
|
|
userfbs.AccountViewAddUserName(builder, userName)
|
|
if displayName != 0 {
|
|
userfbs.AccountViewAddDisplayName(builder, displayName)
|
|
}
|
|
userfbs.AccountViewAddPreferredLanguage(builder, preferredLanguage)
|
|
userfbs.AccountViewAddTimeZone(builder, timeZone)
|
|
if declaredCountry != 0 {
|
|
userfbs.AccountViewAddDeclaredCountry(builder, declaredCountry)
|
|
}
|
|
userfbs.AccountViewAddEntitlement(builder, entitlementOffset)
|
|
if activeSanctionsVector != 0 {
|
|
userfbs.AccountViewAddActiveSanctions(builder, activeSanctionsVector)
|
|
}
|
|
if activeLimitsVector != 0 {
|
|
userfbs.AccountViewAddActiveLimits(builder, activeLimitsVector)
|
|
}
|
|
userfbs.AccountViewAddCreatedAtMs(builder, account.CreatedAt.UTC().UnixMilli())
|
|
userfbs.AccountViewAddUpdatedAtMs(builder, account.UpdatedAt.UTC().UnixMilli())
|
|
|
|
return userfbs.AccountViewEnd(builder), nil
|
|
}
|
|
|
|
func decodeAccount(account *userfbs.AccountView) (usermodel.Account, error) {
|
|
entitlement := account.Entitlement(nil)
|
|
if entitlement == nil {
|
|
return usermodel.Account{}, errors.New("account entitlement is missing")
|
|
}
|
|
|
|
decodedEntitlement, err := decodeEntitlementSnapshot(entitlement)
|
|
if err != nil {
|
|
return usermodel.Account{}, fmt.Errorf("decode account entitlement: %w", err)
|
|
}
|
|
|
|
createdAt := time.UnixMilli(account.CreatedAtMs()).UTC()
|
|
updatedAt := time.UnixMilli(account.UpdatedAtMs()).UTC()
|
|
|
|
result := usermodel.Account{
|
|
UserID: string(account.UserId()),
|
|
Email: string(account.Email()),
|
|
UserName: string(account.UserName()),
|
|
DisplayName: string(account.DisplayName()),
|
|
PreferredLanguage: string(account.PreferredLanguage()),
|
|
TimeZone: string(account.TimeZone()),
|
|
DeclaredCountry: string(account.DeclaredCountry()),
|
|
Entitlement: decodedEntitlement,
|
|
ActiveSanctions: make([]usermodel.ActiveSanction, 0, account.ActiveSanctionsLength()),
|
|
ActiveLimits: make([]usermodel.ActiveLimit, 0, account.ActiveLimitsLength()),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
}
|
|
|
|
activeSanction := new(userfbs.ActiveSanction)
|
|
for index := 0; index < account.ActiveSanctionsLength(); index++ {
|
|
if !account.ActiveSanctions(activeSanction, index) {
|
|
return usermodel.Account{}, fmt.Errorf("account active sanction %d is missing", index)
|
|
}
|
|
|
|
decodedSanction, err := decodeActiveSanction(activeSanction)
|
|
if err != nil {
|
|
return usermodel.Account{}, fmt.Errorf("decode account active sanction %d: %w", index, err)
|
|
}
|
|
result.ActiveSanctions = append(result.ActiveSanctions, decodedSanction)
|
|
}
|
|
|
|
activeLimit := new(userfbs.ActiveLimit)
|
|
for index := 0; index < account.ActiveLimitsLength(); index++ {
|
|
if !account.ActiveLimits(activeLimit, index) {
|
|
return usermodel.Account{}, fmt.Errorf("account active limit %d is missing", index)
|
|
}
|
|
|
|
decodedLimit, err := decodeActiveLimit(activeLimit)
|
|
if err != nil {
|
|
return usermodel.Account{}, fmt.Errorf("decode account active limit %d: %w", index, err)
|
|
}
|
|
result.ActiveLimits = append(result.ActiveLimits, decodedLimit)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func encodeEntitlementSnapshot(builder *flatbuffers.Builder, snapshot usermodel.EntitlementSnapshot) (flatbuffers.UOffsetT, error) {
|
|
actorOffset := encodeActorRef(builder, snapshot.Actor)
|
|
planCode := builder.CreateString(snapshot.PlanCode)
|
|
source := builder.CreateString(snapshot.Source)
|
|
reasonCode := builder.CreateString(snapshot.ReasonCode)
|
|
|
|
userfbs.EntitlementSnapshotStart(builder)
|
|
userfbs.EntitlementSnapshotAddPlanCode(builder, planCode)
|
|
userfbs.EntitlementSnapshotAddIsPaid(builder, snapshot.IsPaid)
|
|
userfbs.EntitlementSnapshotAddSource(builder, source)
|
|
userfbs.EntitlementSnapshotAddActor(builder, actorOffset)
|
|
userfbs.EntitlementSnapshotAddReasonCode(builder, reasonCode)
|
|
userfbs.EntitlementSnapshotAddStartsAtMs(builder, snapshot.StartsAt.UTC().UnixMilli())
|
|
if snapshot.EndsAt != nil {
|
|
userfbs.EntitlementSnapshotAddEndsAtMs(builder, snapshot.EndsAt.UTC().UnixMilli())
|
|
}
|
|
userfbs.EntitlementSnapshotAddUpdatedAtMs(builder, snapshot.UpdatedAt.UTC().UnixMilli())
|
|
|
|
return userfbs.EntitlementSnapshotEnd(builder), nil
|
|
}
|
|
|
|
func decodeEntitlementSnapshot(snapshot *userfbs.EntitlementSnapshot) (usermodel.EntitlementSnapshot, error) {
|
|
actor := snapshot.Actor(nil)
|
|
if actor == nil {
|
|
return usermodel.EntitlementSnapshot{}, errors.New("entitlement actor is missing")
|
|
}
|
|
|
|
decodedActor, err := decodeActorRef(actor)
|
|
if err != nil {
|
|
return usermodel.EntitlementSnapshot{}, fmt.Errorf("decode entitlement actor: %w", err)
|
|
}
|
|
|
|
return usermodel.EntitlementSnapshot{
|
|
PlanCode: string(snapshot.PlanCode()),
|
|
IsPaid: snapshot.IsPaid(),
|
|
Source: string(snapshot.Source()),
|
|
Actor: decodedActor,
|
|
ReasonCode: string(snapshot.ReasonCode()),
|
|
StartsAt: time.UnixMilli(snapshot.StartsAtMs()).UTC(),
|
|
EndsAt: optionalUnixMilli(snapshot.EndsAtMs()),
|
|
UpdatedAt: time.UnixMilli(snapshot.UpdatedAtMs()).UTC(),
|
|
}, nil
|
|
}
|
|
|
|
func encodeActiveSanction(builder *flatbuffers.Builder, sanction usermodel.ActiveSanction) (flatbuffers.UOffsetT, error) {
|
|
actorOffset := encodeActorRef(builder, sanction.Actor)
|
|
sanctionCode := builder.CreateString(sanction.SanctionCode)
|
|
scope := builder.CreateString(sanction.Scope)
|
|
reasonCode := builder.CreateString(sanction.ReasonCode)
|
|
|
|
userfbs.ActiveSanctionStart(builder)
|
|
userfbs.ActiveSanctionAddSanctionCode(builder, sanctionCode)
|
|
userfbs.ActiveSanctionAddScope(builder, scope)
|
|
userfbs.ActiveSanctionAddReasonCode(builder, reasonCode)
|
|
userfbs.ActiveSanctionAddActor(builder, actorOffset)
|
|
userfbs.ActiveSanctionAddAppliedAtMs(builder, sanction.AppliedAt.UTC().UnixMilli())
|
|
if sanction.ExpiresAt != nil {
|
|
userfbs.ActiveSanctionAddExpiresAtMs(builder, sanction.ExpiresAt.UTC().UnixMilli())
|
|
}
|
|
|
|
return userfbs.ActiveSanctionEnd(builder), nil
|
|
}
|
|
|
|
func decodeActiveSanction(sanction *userfbs.ActiveSanction) (usermodel.ActiveSanction, error) {
|
|
actor := sanction.Actor(nil)
|
|
if actor == nil {
|
|
return usermodel.ActiveSanction{}, errors.New("sanction actor is missing")
|
|
}
|
|
|
|
decodedActor, err := decodeActorRef(actor)
|
|
if err != nil {
|
|
return usermodel.ActiveSanction{}, fmt.Errorf("decode sanction actor: %w", err)
|
|
}
|
|
|
|
return usermodel.ActiveSanction{
|
|
SanctionCode: string(sanction.SanctionCode()),
|
|
Scope: string(sanction.Scope()),
|
|
ReasonCode: string(sanction.ReasonCode()),
|
|
Actor: decodedActor,
|
|
AppliedAt: time.UnixMilli(sanction.AppliedAtMs()).UTC(),
|
|
ExpiresAt: optionalUnixMilli(sanction.ExpiresAtMs()),
|
|
}, nil
|
|
}
|
|
|
|
func encodeActiveLimit(builder *flatbuffers.Builder, limit usermodel.ActiveLimit) (flatbuffers.UOffsetT, error) {
|
|
actorOffset := encodeActorRef(builder, limit.Actor)
|
|
limitCode := builder.CreateString(limit.LimitCode)
|
|
reasonCode := builder.CreateString(limit.ReasonCode)
|
|
|
|
userfbs.ActiveLimitStart(builder)
|
|
userfbs.ActiveLimitAddLimitCode(builder, limitCode)
|
|
userfbs.ActiveLimitAddValue(builder, int64(limit.Value))
|
|
userfbs.ActiveLimitAddReasonCode(builder, reasonCode)
|
|
userfbs.ActiveLimitAddActor(builder, actorOffset)
|
|
userfbs.ActiveLimitAddAppliedAtMs(builder, limit.AppliedAt.UTC().UnixMilli())
|
|
if limit.ExpiresAt != nil {
|
|
userfbs.ActiveLimitAddExpiresAtMs(builder, limit.ExpiresAt.UTC().UnixMilli())
|
|
}
|
|
|
|
return userfbs.ActiveLimitEnd(builder), nil
|
|
}
|
|
|
|
func decodeActiveLimit(limit *userfbs.ActiveLimit) (usermodel.ActiveLimit, error) {
|
|
actor := limit.Actor(nil)
|
|
if actor == nil {
|
|
return usermodel.ActiveLimit{}, errors.New("limit actor is missing")
|
|
}
|
|
|
|
decodedActor, err := decodeActorRef(actor)
|
|
if err != nil {
|
|
return usermodel.ActiveLimit{}, fmt.Errorf("decode limit actor: %w", err)
|
|
}
|
|
|
|
value, err := int64ToInt(limit.Value(), "value")
|
|
if err != nil {
|
|
return usermodel.ActiveLimit{}, err
|
|
}
|
|
|
|
return usermodel.ActiveLimit{
|
|
LimitCode: string(limit.LimitCode()),
|
|
Value: value,
|
|
ReasonCode: string(limit.ReasonCode()),
|
|
Actor: decodedActor,
|
|
AppliedAt: time.UnixMilli(limit.AppliedAtMs()).UTC(),
|
|
ExpiresAt: optionalUnixMilli(limit.ExpiresAtMs()),
|
|
}, nil
|
|
}
|
|
|
|
func encodeActorRef(builder *flatbuffers.Builder, actor usermodel.ActorRef) flatbuffers.UOffsetT {
|
|
actorType := builder.CreateString(actor.Type)
|
|
|
|
var actorID flatbuffers.UOffsetT
|
|
if actor.ID != "" {
|
|
actorID = builder.CreateString(actor.ID)
|
|
}
|
|
|
|
userfbs.ActorRefStart(builder)
|
|
userfbs.ActorRefAddType(builder, actorType)
|
|
if actorID != 0 {
|
|
userfbs.ActorRefAddId(builder, actorID)
|
|
}
|
|
|
|
return userfbs.ActorRefEnd(builder)
|
|
}
|
|
|
|
func decodeActorRef(actor *userfbs.ActorRef) (usermodel.ActorRef, error) {
|
|
return usermodel.ActorRef{
|
|
Type: string(actor.Type()),
|
|
ID: string(actor.Id()),
|
|
}, nil
|
|
}
|
|
|
|
func encodeErrorBody(builder *flatbuffers.Builder, errorBody usermodel.ErrorBody) flatbuffers.UOffsetT {
|
|
code := builder.CreateString(errorBody.Code)
|
|
message := builder.CreateString(errorBody.Message)
|
|
|
|
userfbs.ErrorBodyStart(builder)
|
|
userfbs.ErrorBodyAddCode(builder, code)
|
|
userfbs.ErrorBodyAddMessage(builder, message)
|
|
|
|
return userfbs.ErrorBodyEnd(builder)
|
|
}
|
|
|
|
func optionalUnixMilli(value int64) *time.Time {
|
|
if value == 0 {
|
|
return nil
|
|
}
|
|
|
|
decoded := time.UnixMilli(value).UTC()
|
|
return &decoded
|
|
}
|
|
|
|
func recoverUserDecodePanic[T any](message string, result **T, err *error) {
|
|
if recovered := recover(); recovered != nil {
|
|
*result = nil
|
|
*err = fmt.Errorf("%s: panic recovered: %v", message, recovered)
|
|
}
|
|
}
|