twitchapon

[Twi]tch [Cha]nnel [Po]ints Rewards Redemption Listener
git clone git://bsandro.tech/twitchapon
Log | Files | Refs | README | LICENSE

commit 1c8b6c7052496d54d09ea1c81b79662ff2ac9ab3
parent c3a413952823574bf8836baad6141cea1de01156
Author: bsandro <brian.drosan@gmail.com>
Date:   Tue, 18 May 2021 02:59:54 +0300

Channel points rewards message structure defined

Diffstat:
MTODO | 1+
Mclient.go | 15++++++++++-----
Mlisten.go | 14++++++++++++--
Amessage.go | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/TODO b/TODO @@ -2,6 +2,7 @@ Brief TODO list of features to implement. Symbols as I use them: "-" is "planned", "?" is "questionable", "+" is "done" - https://github.com/Palakis/obs-websocket compatibility +- remove the dependency on x/net/websocket library - configurable map of input events bound to output obs commands - put some comments in the code - unmarshal nested json received in messages and forward it properly diff --git a/client.go b/client.go @@ -6,14 +6,18 @@ import ( "log" ) +// generic msg struct, fits MESSAGE, RESPONSE and PING type TMessage struct { - Type string `json:"type"` - Data struct { + Type string `json:"type"` + Nonce string `json:"nonce"` + Error string `json:"error"` + Data struct { Topic string `json:"topic"` Message string `json:"message"` } `json:"data"` } +// global, shame on me var App TApp func ListenJob() { @@ -23,10 +27,11 @@ func ListenJob() { log.Fatal(err) } // ignore PING and RESPONSE for now - if msg.Type != "MESSAGE" { - continue + if msg.Type == "RESPONSE" { + ProcessResponse(&msg) + } else if msg.Type == "MESSAGE" { + ProcessMessage(&msg) } - fmt.Println("Message received!") } App.WaitGroup.Done() diff --git a/listen.go b/listen.go @@ -7,8 +7,8 @@ import ( type TListenRequest struct { MsgType string `json:"type"` - // Nonce string `json:"nonce"` // optional - Data struct { + Nonce string `json:"nonce"` + Data struct { Topics []string `json:"topics"` AuthToken string `json:"auth_token"` } `json:"data"` @@ -18,6 +18,7 @@ func OnListen(auth_token string, user_id string) interface{} { var req TListenRequest req.MsgType = "LISTEN" req.Data.AuthToken = auth_token + req.Nonce = "listen-channel-points" req.Data.Topics = append(req.Data.Topics, fmt.Sprintf("channel-points-channel-v1.%s", user_id)) return &req } @@ -25,5 +26,14 @@ func OnListen(auth_token string, user_id string) interface{} { func RequestListen() error { msg := OnListen(App.Auth.AccessToken, App.User.Id) websocket.JSON.Send(App.Connection, msg) + fmt.Println("Sending channel points events subscription...") return nil } + +func ProcessResponse(msg *TMessage) { + if msg.Error == "" { + fmt.Printf("Received valid response for request '%'\n", msg.Nonce) + } else { + fmt.Printf("Received response for request '%s' with the following error: %s\n", msg.Nonce, msg.Error) + } +} diff --git a/message.go b/message.go @@ -0,0 +1,63 @@ +package main + +import ( + "encoding/json" + "fmt" +) + +type TChannelPointsMessage struct { + MsgType string `json:"type"` + Data struct { + Timestamp string `json:"timestamp"` + Redemption struct { + Id string `json:"id"` + User struct { + Id string `json:"id"` + Login string `json:"login"` + DisplayName string `json:"display_name"` + } `json:"user"` + ChannelId string `json:"channel_id"` + RedeemedAt string `json:"redeemed_at"` + Reward struct { + Id string `json:"id"` + ChannelId string `json:"channel_id"` + Title string `json:"title"` + Prompt string `json:"prompt"` + Cost float64 `json:"cost"` + IsUserInputRequired bool `json:"is_user_input_required"` + IsSubOnly bool `json:"is_sub_only"` + Image struct { + Url1x string `json:"url_1x"` + Url2x string `json:"url_2x"` + Url4x string `json:"url_4x"` + } `json:"image"` + DefaultImage struct { + Url1x string `json:"url_1x"` + Url2x string `json:"url_2x"` + Url4x string `json:"url_4x"` + } `json:"default_image"` + BackgroundColor string `json:"background_color"` + IsEnabled bool `json:"is_enabled"` + IsPaused bool `json:"is_paused"` + IsInStock bool `json:"is_in_stock"` + MaxPerStream struct { + IsEnabled bool `json:"is_enabled"` + MaxPerStream float64 `json:"max_per_stream"` + } `json:"max_per_stream"` + ShouldRedemptionSkipRequestQueue bool `json:"should_redemption_skip_request_queue"` + } `json:"reward"` + UserInput string `json:"user_input"` + Status string `json:"status"` + } `json:"redemption"` + } `json:"data"` +} + +func ProcessMessage(msg *TMessage) { + fmt.Println("Got valid message:", msg.Data.Message) + var chanPointsMsg TChannelPointsMessage + if err := json.Unmarshal([]byte(msg.Data.Message), &chanPointsMsg); err != nil { + fmt.Println("Json parse error", err) + } else { + fmt.Println("Json parse ok") + } +}