irc.go
1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "net/url" 7 "strings" 8 "time" 9 10 "github.com/gorilla/websocket" 11 ) 12 13 func ConnectTwitchChat(app App, channelName string, chats chan<- ChatMessage, interrupt chan struct{}, terminate chan<- struct{}) { 14 u := url.URL{Scheme: "ws", Host: TWITCH_IRC_HOST} 15 16 c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 17 if err != nil { 18 log.Printf("%24s | IRC error: %s\n", channelName, err) 19 interrupt <- struct{}{} 20 return 21 } 22 inactive := time.NewTimer(5 * time.Minute) 23 timeLimit := time.NewTimer(60 * time.Minute) 24 25 // validate token, if invalid use refresh token and update app in memory, rewrite env file 26 ok := HelixValidateToken(app) 27 28 if !ok { 29 newTokens := HelixRefreshToken(app) 30 app.Token = newTokens.AccessToken 31 app.RefreshToken = newTokens.AccessToken 32 } 33 34 c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("PASS oauth:%s", app.Token))) 35 c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("NICK %s", app.User))) 36 c.WriteMessage(websocket.TextMessage, []byte("CAP REQ :twitch.tv/tags")) 37 c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("JOIN #%s", channelName))) 38 39 go func() { 40 for { 41 msgtype, message, err := c.ReadMessage() 42 if err != nil { 43 log.Printf("%24s | IRC error (%d): %s\n", channelName, msgtype, err) 44 interrupt <- struct{}{} 45 return 46 } 47 48 if strings.Contains(string(message), "PING") { 49 c.WriteMessage(websocket.TextMessage, []byte("PONG :tmi.twitch.tv")) 50 } 51 52 if strings.Contains(string(message), "PRIVMSG") { 53 parsed, err := ParseMessage(string(message)) 54 if err != nil { 55 log.Println(err) 56 interrupt <- struct{}{} 57 return 58 } 59 if (ChatMessage{}) != parsed { 60 chats <- parsed 61 inactive.Reset(5 * time.Minute) 62 } 63 } 64 } 65 }() 66 67 select { 68 case <-inactive.C: 69 log.Printf("%24s | INACTIVE disconnecting from chat...\n", channelName) 70 c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) 71 terminate <- struct{}{} 72 return 73 case <-timeLimit.C: 74 log.Printf("%24s | TIME LIMIT disconnecting from chat...\n", channelName) 75 c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) 76 terminate <- struct{}{} 77 return 78 case <-interrupt: 79 log.Printf("%24s | INTERRUPT disconnecting from chat...\n", channelName) 80 c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) 81 terminate <- struct{}{} 82 return 83 } 84 }