view socket/conn.go @ 12:aaf85ae1f942

add very simple html template
author Dennis C. M. <dennis@denniscm.com>
date Thu, 20 Mar 2025 11:12:21 +0000
parents 6d91c612310a
children
line wrap: on
line source

package socket

import (
	"encoding/json"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/denniscmcom/pacobot/bot"
	"github.com/denniscmcom/pacobot/event"
	"github.com/gorilla/websocket"
)

func Connect(authToken string) {
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	baseUrl := url.URL{Scheme: "wss", Host: "eventsub.wss.twitch.tv", Path: "/ws"}

	log.Println("socket: connecting...")
	conn, _, err := websocket.DefaultDialer.Dial(baseUrl.String(), nil)

	if err != nil {
		log.Fatal(err)
	}

	defer conn.Close()

	log.Println("socket: connected")

	var timeout time.Ticker
	done := make(chan struct{})

	go readMsg(done, conn, &timeout, authToken)

	for {
		select {
		case <-interrupt:
			closeConn(conn)

			select {
			case <-done:
			case <-time.After(time.Second):
			}
			return
		case <-done:
			log.Println("socket: connection closed by server")
			Connect(authToken)
		case <-timeout.C:
			log.Println("socket: connection lost")
			timeout.Stop()
			Connect(authToken)
		}
	}
}

func readMsg(done chan struct{}, conn *websocket.Conn, timeout *time.Ticker, authToken string) {
	defer close(done)
	var timeout_secs time.Duration

	for {
		log.Println("socket: waiting for msg...")
		_, msg, err := conn.ReadMessage()

		if err != nil {
			break
		}

		var metadataMsg MetadataMsg

		if err := json.Unmarshal(msg, &metadataMsg); err != nil {
			log.Fatal(err)
		}

		msgType := metadataMsg.Metadata.MsgType
		log.Printf("socket: %s msg received", msgType)

		switch msgType {
		case "session_welcome":
			var welcomeMsg WelcomeMsg

			if err := json.Unmarshal(msg, &welcomeMsg); err != nil {
				log.Fatal(err)
			}

			timeout_secs = time.Duration(welcomeMsg.Payload.Session.KeepaliveTimeoutSecs+3) * time.Second
			timeout = time.NewTicker(timeout_secs)
			defer timeout.Stop()

			event.SubChannelChatMsg(authToken, welcomeMsg.Payload.Session.Id)

		case "session_keepalive":
			timeout.Reset(timeout_secs)
			log.Println("socket: timeout resetted")

		case "notification":
			var metadataEvent MetadataEvent

			if err := json.Unmarshal(msg, &metadataEvent); err != nil {
				log.Fatal(err)
			}

			subType := metadataEvent.Metadata.SubType
			log.Printf("socket: %s event received", subType)

			switch subType {
			case "channel.chat.message":
				var channelChatMsgEvent ChannelChatMsgEvent

				if err := json.Unmarshal(msg, &channelChatMsgEvent); err != nil {
					log.Fatal(err)
				}

				chatMsg := channelChatMsgEvent.Payload.Event.Msg.Text

				if strings.HasPrefix(chatMsg, "!") {
					if channelChatMsgEvent.Payload.Event.ChatterUserName == "denniscmartin" {
						go bot.HandleCmd(strings.Split(chatMsg[1:], " "))
					}
				}
			}

		default:
			log.Fatalf("socket: %s message type not implemented", msgType)
		}
	}
}

func closeConn(conn *websocket.Conn) {
	err := conn.WriteMessage(
		websocket.CloseMessage,
		websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))

	if err != nil {
		log.Fatal(err)
	}

	log.Println("socket: connection closed")
}