streamdeck-obs-replay/obsws/client.go

93 lines
2.4 KiB
Go

package obsws
import (
"strconv"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/mitchellh/mapstructure"
)
const bufferSize = 100
var (
receiveTimeout = time.Duration(0)
messageID = 0
lock = sync.Mutex{}
)
// Client is the interface to obs-websocket.
// Client{Host: "localhost", Port: 4444} will probably work if you haven't configured OBS.
type Client struct {
Host string // Host (probably "localhost").
Port int // Port (OBS default is 4444).
Password string // Password (OBS default is "").
conn *websocket.Conn // Underlying connection to OBS.
receiveTimeout time.Duration // Maximum blocking time for receiving request responses
connected bool // True until Disconnect is called.
handlers map[string]func(e Event) // Event handlers.
respQ chan map[string]interface{} // Queue of received responses.
}
// poll listens for responses/events.
// This function blocks until Disconnect is called.
func (c *Client) poll() {
Logger.Println("started polling")
for c.connected {
m := make(map[string]interface{})
if err := c.conn.ReadJSON(&m); err != nil {
if !c.connected {
return
}
Logger.Println("read from WS:", err)
continue
}
if _, ok := m["message-id"]; ok {
c.handleResponse(m)
} else {
c.handleEvent(m)
}
}
}
// Connected returns wheter or not the client is connected.
func (c *Client) Connected() bool {
return c.connected
}
// SetReceiveTimeout sets the maximum blocking time for receiving request responses.
// If set to 0 (the default), there is no timeout.
func SetReceiveTimeout(timeout time.Duration) {
receiveTimeout = timeout
}
// getMessageID generates a string that the client has not yet used.
func getMessageID() string {
lock.Lock()
messageID++
id := strconv.Itoa(messageID)
lock.Unlock()
return id
}
// mapToStruct serializes a map into a struct.
func mapToStruct(data map[string]interface{}, dest interface{}) error {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: dest,
})
if err != nil {
Logger.Println("initializing decoder:", err)
return err
}
if err = decoder.Decode(data); err != nil {
Logger.Printf("unmarshalling map -> %T: %v", dest, err)
Logger.Printf("input: %#v\n", data)
return err
}
return nil
}