package lobby import ( "encoding/base64" "encoding/json" "errors" "log/slog" "reflect" "strings" ) type LobbyMessage struct { MessageType string `json:"message_type"` Message any `json:"message"` } type Name struct { Name string `json:"name"` } type Chat struct { From string `json:"from"` Message string `json:"message"` } type Invite struct { From string `json:"from"` To string `json:"to"` } type PendingInvite struct { Recipient string `json:"recipient"` } type Accept struct { From string `json:"from"` To string `json:"to"` } type Accepted struct { Accepter string `json:"accepter"` GameID string `json:"game_id"` } type StartGame struct { To string `json:"to"` GameID string `json:"game_id"` } type Decline struct { From string `json:"from"` To string `json:"to"` } type Disconnect struct { From string `json:"from"` } type Connect struct { From string `json:"from"` } type Error struct { Message string `json:"message"` } func Marshal(a LobbyMessage) ([]byte, error) { slog.Debug("Marshalling message", slog.Any("message type", a.MessageType)) bm, err := json.Marshal(a.Message) if err != nil { return nil, err } a.Message = bm return json.Marshal(a) } // Use this to get the appropriate message type into the message field then assert the // right struct accordingly to safely access the fields you need. func Unmarshal(b []byte) (LobbyMessage, error) { lm := LobbyMessage{} err := json.Unmarshal(b, &lm) if err != nil { return lm, err } smsg, ok := lm.Message.(string) if !ok { slog.Debug("error asserting message to string") } slog.Debug("type of message", slog.Any("type of message", reflect.TypeOf(smsg)), slog.String("message", smsg)) jsonBytes, err := base64.StdEncoding.DecodeString(smsg) lm.Message = jsonBytes switch strings.ToLower(lm.MessageType) { case "name": n := Name{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &n) if err != nil { slog.Debug("Error", slog.Any("error", err)) return lm, err } lm.Message = n return lm, nil case "chat": c := Chat{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &c) if err != nil { slog.Debug("chat", slog.Any("error", err)) return lm, err } lm.Message = c return lm, nil case "invite": i := Invite{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &i) if err != nil { slog.Debug("invite", slog.Any("error", err)) return lm, err } lm.Message = i return lm, nil case "pending_invite": pi := PendingInvite{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &pi) if err != nil { slog.Debug("pending_invite", slog.Any("error", err)) return lm, err } lm.Message = pi case "accept": a := Accept{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &a) if err != nil { slog.Debug("accept", slog.Any("error", err)) return lm, err } lm.Message = a return lm, nil case "accepted": a := Accepted{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &a) if err != nil { slog.Debug("accepted", slog.Any("error", err)) return lm, err } lm.Message = a return lm, nil case "start_game": sg := StartGame{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &sg) if err != nil { slog.Debug("start_game", slog.Any("error", err)) return lm, err } lm.Message = sg return lm, nil case "decline": d := Decline{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &d) if err != nil { slog.Debug("decline", slog.Any("error", err)) return lm, err } lm.Message = d return lm, nil case "disconnect": di := Disconnect{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &di) if err != nil { slog.Debug("disconnect", slog.Any("error", err)) return lm, err } lm.Message = di return lm, nil case "connect": co := Connect{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &co) if err != nil { slog.Debug("connect", slog.Any("error", err)) return lm, err } lm.Message = co return lm, nil case "error": e := Error{} bs, ok := lm.Message.([]byte) if !ok { return lm, err } err := json.Unmarshal(bs, &e) if err != nil { slog.Debug("error", slog.Any("error", err)) return lm, err } lm.Message = e return lm, nil default: return lm, errors.New("unknown message type") } return lm, errors.New("unknown message type") }