package rumble import ( "context" "encoding/json" "github.com/r3labs/sse" ) const ( ChatBadgeRecurringSubscription = "recurring_subscription" ChatBadgeLocalsSupporter = "locals_supporter" ChatTypeInit = "init" ChatTypeMessages = "messages" ChatTypeMuteUsers = "mute_users" ChatTypeDeleteMessages = "delete_messages" ChatTypeSubscriber = "locals_supporter" ChatTypeRaiding = "raid_confirmed" ChatTypePinMessage = "pin_message" ChatTypeUnpinMessage = "unpin_message" ) type ChatEventChannels struct { ErrorCh chan error } type RegisterChatEventsOptions struct { } // TODO: for every true bool, create channel, otherwise nil. // TODO: always create error channel func RegisterChatEvents(opts RegisterChatEventsOptions) *ChatEventChannels { } type chatClient struct { cancel context.CancelFunc sseCancel context.CancelFunc sseCl *sse.Client sseEvent chan *sse.Event } type RawChatEventChannel struct { ID string `json:"id"` Image1 string `json:"image.1"` Link string `json:"link"` Username string `json:"username"` } type RawChatEventBlockData struct { Text string `json:"text"` } type RawChatEventBlock struct { Data RawChatEventBlockData `json:"data"` Type string `json:"type"` } type RawChatEventNotification struct { Badge string `json:"badge"` Text string `json:"text"` } type RawChatEventRaidNotification struct { StartTs int64 `json:"start_ts"` } type RawChatEventRant struct { Duration int `json:"duration"` ExpiresOn string `json:"expires_on"` PriceCents int `json:"price_cents"` } type RawChatEventMessage struct { Blocks []RawChatEventBlock `json:"blocks"` ChannelID *int64 `json:"channel_id"` ID string `json:"id"` Notification *RawChatEventNotification `json:"notification"` RaidNotification *RawChatEventRaidNotification `json:"raid_notification"` Rant *RawChatEventRant `json:"rant"` Text string `json:"text"` Time string `json:"time"` UserID string `json:"user_id"` } type RawChatEventUser struct { Badges []string `json:"badges"` Color string `json:"color"` ID string `json:"id"` Image1 string `json:"image.1"` IsFollower bool `json:"is_follower"` Link string `json:"link"` Username string `json:"username"` } type RawChatEventData struct { Channels []RawChatEventChannel `json:"channels"` Messages []RawChatEventMessage `json:"messages"` Users []RawChatEventUser `json:"users"` } type RawChatEvent struct { Data RawChatEventData `json:"data"` RequestID string `json:"request_id"` Type string `json:"type"` } type RawChatEventAny struct { Data any `json:"data"` Type string `json:"type"` } type RawChatEventDataNoChannels struct { // Channels [][]string `json:"channels"` Channels [][]any `json:"channels"` Messages []RawChatEventMessage `json:"messages"` Users []RawChatEventUser `json:"users"` } type RawChatEventNoChannels struct { Data RawChatEventDataNoChannels `json:"data"` RequestID string `json:"request_id"` Type string `json:"type"` } type ChatBase struct { Data any `json:"data"` Type string `json:"type"` } func (rce RawChatEvent) users() map[string]RawChatEventUser { uMap := map[string]RawChatEventUser{} for _, user := range rce.Data.Users { uMap[user.ID] = user } return uMap } func (rce RawChatEvent) channels() map[string]RawChatEventChannel { cMap := map[string]RawChatEventChannel{} for _, channel := range rce.Data.Channels { cMap[channel.ID] = channel } return cMap } // func (rce RawChatEvent) parse() ([]ChatEvent, error) { // events := []ChatEvent{} // users := rce.users() // channels := rce.channels() // for _, message := range rce.Data.Messages { // var event ChatEvent // user, exists := users[message.UserID] // if !exists { // return nil, fmt.Errorf("missing user information for user ID: %s", message.UserID) // } // event.Badges = user.Badges // event.Color = user.Color // event.ImageUrl = user.Image1 // event.IsFollower = user.IsFollower // if message.RaidNotification != nil { // event.Raid = true // } // if message.Rant != nil { // event.Rant = message.Rant.PriceCents // } // if message.Notification != nil { // if message.Notification.Badge == ChatBadgeRecurringSubscription { // event.Sub = true // } // } // event.Text = message.Text // t, err := time.Parse(time.RFC3339, message.Time) // if err != nil { // return nil, fmt.Errorf("error parsing message time: %v", err) // } // event.Time = t // event.Type = rce.Type // event.Username = user.Username // if message.ChannelID != nil { // cid := strconv.Itoa(int(*message.ChannelID)) // channel, exists := channels[cid] // if !exists { // return nil, fmt.Errorf("missing channel information for channel ID: %s", cid) // } // event.ImageUrl = channel.Image1 // event.ChannelName = channel.Username // } // events = append(events, event) // } // return events, nil // } // type ChatEvent struct { // Badges []string // ChannelName string // Color string // ImageUrl string // Init bool // IsFollower bool // Raid bool // Rant int // Sub bool // Text string // Time time.Time // Type string // Username string // } func (cl *chatClient) start(ctx context.Context, eventCh chan *sse.Event) { for { select { case <-ctx.Done(): cl.sseCancel() return case event := <-eventCh: if event == nil { // handleError(fmt.Errorf("received nil event")) } else { cl.handleEvent(event) // chats, err := parseEvent(event.Data) // if err != nil { // handleError(err) // } else { // for _, chat := range chats { // handle(chat) // } // } } } } } func (cl *chatClient) handleEvent(e *sse.Event) { var base ChatBase err := json.Unmarshal(e, &base) if err != nil { // send error return } } // func parseEvent(event []byte) ([]ChatEvent, error) { // var rce RawChatEvent // err := json.Unmarshal(event, &rce) // if err != nil { // var rcenc RawChatEventNoChannels // errnc := json.Unmarshal(event, &rcenc) // if errnc != nil { // var rcea RawChatEventAny // errany := json.Unmarshal(event, &rcea) // if errany != nil { // return nil, fmt.Errorf("error un-marshaling event: %v", err) // } // // ChatEvent type not supported, return empty events // return []ChatEvent{}, nil // } // rce.Data.Messages = rcenc.Data.Messages // rce.Data.Users = rcenc.Data.Users // rce.RequestID = rcenc.RequestID // rce.Type = rcenc.Type // } // events, err := rce.parse() // if err != nil { // return nil, fmt.Errorf("error parsing raw chat event: %v", err) // } // return events, nil // }