Initial checkin

This commit is contained in:
Justin Hawkins 2024-06-27 20:10:18 +09:30
parent 8cebd67505
commit 4f0a2aeac8
6 changed files with 964 additions and 0 deletions

301
events_received.go Normal file
View File

@ -0,0 +1,301 @@
package streamdeck
import (
"encoding/json"
"reflect"
)
var receivedEventTypeMap = map[string]reflect.Type{}
func init() {
receivedEventTypeMap["keyUp"] = reflect.TypeOf(ERKeyUp{})
receivedEventTypeMap["didReceiveSettingsPayload"] = reflect.TypeOf(ERDidReceiveSettingsPayload{})
receivedEventTypeMap["didReceiveSettings"] = reflect.TypeOf(ERDidReceiveSettings{})
receivedEventTypeMap["globalSettings"] = reflect.TypeOf(ERGlobalSettings{})
receivedEventTypeMap["didReceiveDeepLink"] = reflect.TypeOf(ERDidReceiveDeepLink{})
receivedEventTypeMap["touchTap"] = reflect.TypeOf(ERTouchTap{})
receivedEventTypeMap["dialDown"] = reflect.TypeOf(ERDialDown{})
receivedEventTypeMap["dialUp"] = reflect.TypeOf(ERDialUp{})
receivedEventTypeMap["dialRotate"] = reflect.TypeOf(ERDialRotate{})
receivedEventTypeMap["keyDown"] = reflect.TypeOf(ERKeyDown{})
receivedEventTypeMap["willAppear"] = reflect.TypeOf(ERWillAppear{})
receivedEventTypeMap["willDisappear"] = reflect.TypeOf(ERWillDisappear{})
receivedEventTypeMap["titleParametersDidChange"] = reflect.TypeOf(ERTitleParametersDidChange{})
receivedEventTypeMap["deviceDidConnect"] = reflect.TypeOf(ERDeviceDidConnect{})
receivedEventTypeMap["deviceDidDisconnect"] = reflect.TypeOf(ERDeviceDidDisconnect{})
receivedEventTypeMap["applicationDidLaunch"] = reflect.TypeOf(ERApplicationDidLaunch{})
receivedEventTypeMap["applicationDidTerminate"] = reflect.TypeOf(ERApplicationDidTerminate{})
receivedEventTypeMap["applicationSystemDidWakeUp"] = reflect.TypeOf(ERApplicationSystemDidWakeUp{})
receivedEventTypeMap["applicationPropertyInspectorDidAppear"] = reflect.TypeOf(ERApplicationPropertyInspectorDidAppear{})
receivedEventTypeMap["applicationPropertyInspectorDidDisappear"] = reflect.TypeOf(ERApplicationPropertyInspectorDidDisappear{})
receivedEventTypeMap["applicationPropertySendToPlugin"] = reflect.TypeOf(ERApplicationPropertySendToPlugin{})
receivedEventTypeMap["applicationPropertySendToPropertyInspector"] = reflect.TypeOf(ERApplicationPropertySendToPropertyInspector{})
}
type ERBase struct {
Event string `json:"event"`
}
//{Action: Event:deviceDidConnect Context: Device:A1DA463F033AD2616E05636CD16F064F Payload:[]}"}
type ERCommon struct {
Action string `json:"action"`
Event string `json:"event"`
Context string `json:"context"`
Device string `json:"device"`
}
// https://docs.elgato.com/sdk/plugins/events-received#didreceivesettings
type ERDidReceiveSettingsPayload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
IsInMultiAction bool `json:"isInMultiAction"`
}
type ERDidReceiveSettings struct {
ERCommon
Payload ERDidReceiveSettingsPayload `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#didreceiveglobalsettings
type ERGlobalSettings struct {
Event string `json:"event"`
Payload json.RawMessage `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#didreceivedeeplink
type ERDidReceiveDeepLink struct {
Event string `json:"event"`
Payload struct {
Url string `json:"url"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#touchtap-sd
type ERTouchTap struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Controller string `json:"controller"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
TapPosition []int `json:"tapPos"`
Hold bool `json:"hold"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#dialdown-sd
type ERDialDown struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Controller string `json:"controller"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#dialup-sd
type ERDialUp struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Controller string `json:"controller"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#dialrotate-sd
type ERDialRotate struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Controller string `json:"controller"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
Ticks int `json:"ticks"`
Pressed bool `json:"pressed"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#keydown
type ERKeyDown struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
State int `json:"state"`
UserDesiredState int `json:"userDesiredState"`
IsInMultiAction bool `json:"isInMultiAction"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#keyup
type ERKeyUp struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
State int `json:"state"`
UserDesiredState int `json:"userDesiredState"`
IsInMultiAction bool `json:"isInMultiAction"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#willappear
type ERWillAppear struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
Controller string `json:"controller"`
State int `json:"state"`
IsInMultiAction bool `json:"isInMultiAction"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#willdisappear
const ERWillDisappearAction = "willDisappear"
type ERWillDisappear struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
Controller string `json:"controller"`
State int `json:"state"`
IsInMultiAction bool `json:"isInMultiAction"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#titleparametersdidchange
type ERTitleParametersDidChange struct {
ERCommon
Payload struct {
Settings json.RawMessage `json:"settings"`
Coordinates struct {
Column int `json:"column"`
Row int `json:"row"`
} `json:"coordinates"`
State int `json:"state"`
Title string `json:"title"`
TitleParameters struct {
FontFamily string `json:"fontFamily"`
FontSize int `json:"fontSize"`
FontStyle string `json:"fontStyle"`
FontUnderline bool `json:"fontUnderline"`
ShowTitle bool `json:"showTitle"`
TitleAlignment string `json:"titleAlignment"`
TitleColor string `json:"titleColor"`
} `json:"titleParameters"`
} `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#devicedidconnect
type ERDeviceDidConnect struct {
Event string `json:"event"`
Device string `json:"device"`
DeviceInfo struct {
Name string `json:"name"`
DeviceType int `json:"type"`
Size struct {
Columns int `json:"columns"`
Rows int `json:"rows"`
} `json:"size"`
} `json:"deviceInfo"`
}
// https://docs.elgato.com/sdk/plugins/events-received#devicediddisconnect
type ERDeviceDidDisconnect struct {
Event string `json:"event"`
Device string `json:"device"`
}
// https://docs.elgato.com/sdk/plugins/events-received#applicationdidlaunch
type ERApplicationDidLaunch struct {
Event string `json:"event"`
Payload struct {
Application string `json:"application"`
}
}
// https://docs.elgato.com/sdk/plugins/events-received#applicationdidterminate
type ERApplicationDidTerminate struct {
Event string `json:"event"`
Payload struct {
Application string `json:"application"`
}
}
// https://docs.elgato.com/sdk/plugins/events-received#systemdidwakeup
type ERApplicationSystemDidWakeUp struct {
Event string `json:"event"`
}
// https://docs.elgato.com/sdk/plugins/events-received#propertyinspectordidappear
type ERApplicationPropertyInspectorDidAppear struct {
ERCommon
}
// https://docs.elgato.com/sdk/plugins/events-received#propertyinspectordiddisappear
type ERApplicationPropertyInspectorDidDisappear struct {
ERCommon
}
// https://docs.elgato.com/sdk/plugins/events-received#sendtoplugin
type ERApplicationPropertySendToPlugin struct {
Action string `json:"action"`
Event string `json:"event"`
Context string `json:"context"`
Payload json.RawMessage `json:"payload"`
}
// https://docs.elgato.com/sdk/plugins/events-received#sendtopropertyinspector
type ERApplicationPropertySendToPropertyInspector struct {
Action string `json:"action"`
Event string `json:"event"`
Context string `json:"context"`
Payload json.RawMessage `json:"payload"`
}

385
events_send.go Normal file
View File

@ -0,0 +1,385 @@
package streamdeck
import (
"bytes"
"encoding/base64"
"encoding/json"
"image"
"image/png"
)
type EventTarget int
const EventTargetBoth = 0
const EventTargetHardware = 1
const EventTargetSoftware = 2
type ESCommon struct {
Event string `json:"event"`
Context string `json:"context"`
}
type ESCommonNoContext struct {
Event string `json:"event"`
}
type ESOpenMessage struct {
ESCommonNoContext
UUID string `json:"uuid"`
}
// https://docs.elgato.com/sdk/plugins/events-sent#setsettings
type ESSetSettings struct {
ESCommon
Payload json.RawMessage
}
func NewESSetSettings(context string, payload json.RawMessage) ESSetSettings {
return ESSetSettings{
ESCommon: ESCommon{
Event: "setSettings",
Context: context,
},
Payload: payload,
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#getsettings
type ESGetSettings struct {
ESCommon
}
func NewESGetSettings(context string) ESGetSettings {
return ESGetSettings{
ESCommon: ESCommon{
Event: "getSettings",
Context: context,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#setglobalsettings
type ESSetGlobalSettings struct {
ESCommon
Payload json.RawMessage
}
func NewESSetGlobalSettings(context string, payload json.RawMessage) ESSetGlobalSettings {
return ESSetGlobalSettings{
ESCommon: ESCommon{
Event: "setGlobalSettings",
Context: context,
},
Payload: payload,
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#getglobalsettings
type ESGetGlobalSettings struct {
ESCommon
}
func NewESGetGlobalSettings(context string) ESGetGlobalSettings {
return ESGetGlobalSettings{
ESCommon: ESCommon{
Event: "getGlobalSettings",
Context: context,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#openurl
type ESOpenURL struct {
ESCommonNoContext
Payload ESOpenURLPayload `json:"payload"`
}
type ESOpenURLPayload struct {
URL string `json:"url"`
}
func NewESOpenURL(url string) ESOpenURL {
return ESOpenURL{
ESCommonNoContext: ESCommonNoContext{Event: "openUrl"},
Payload: ESOpenURLPayload{
URL: url,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#logmessage
type ESLogMessage struct {
ESCommonNoContext
Payload ESLogMessagePayload `json:"payload"`
}
type ESLogMessagePayload struct {
Message string `json:"message"`
}
func NewESLogMessage(message string) ESLogMessage {
return ESLogMessage{
ESCommonNoContext: ESCommonNoContext{Event: "logMessage"},
Payload: ESLogMessagePayload{Message: message},
}
}
// setTitle https://docs.elgato.com/sdk/plugins/events-sent#settitle
type ESSetTitle struct {
ESCommon
Payload ESSetTitlePayload `json:"payload"`
}
type ESSetTitlePayload struct {
Title string `json:"title"`
Target EventTarget `json:"target"`
State int `json:"state"`
}
func NewESSetTitle(context string, title string, target EventTarget, state int) ESSetTitle {
return ESSetTitle{
ESCommon: ESCommon{
Event: "setTitle",
Context: context,
},
Payload: ESSetTitlePayload{
Title: title,
Target: target,
State: state,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#setimage
type ESSetImage struct {
ESCommon
Payload ESSetImagePayload `json:"payload"`
}
type ESSetImagePayload struct {
Image string `json:"title"`
Target EventTarget `json:"target"`
State int `json:"state"`
}
func NewESSetImagePayload(context string, imageBase64 string, target EventTarget, state int) ESSetImage {
return ESSetImage{
ESCommon: ESCommon{
Event: "setImage",
Context: context,
},
Payload: ESSetImagePayload{
Image: imageBase64,
Target: target,
State: state,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#setfeedback-sd
type ESSetFeedback struct {
ESCommon
Payload json.RawMessage `json:"payload"`
}
func NewESSetFeedback(context string, payload json.RawMessage) ESSetFeedback {
return ESSetFeedback{
ESCommon: ESCommon{
Event: "setFeedback",
Context: context,
},
Payload: payload,
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#setfeedbacklayout-sd
type ESSetFeedbackLayout struct {
ESCommon
Payload ESSetFeedbackLayoutPayload `json:"payload"`
}
type ESSetFeedbackLayoutPayload struct {
Layout string `json:"layout"`
}
func NewESSetFeedbackLayout(context string, layout string) ESSetFeedbackLayout {
return ESSetFeedbackLayout{
ESCommon: ESCommon{
Event: "setFeedbackLayout",
Context: context,
},
Payload: ESSetFeedbackLayoutPayload{
Layout: layout,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#settriggerdescription-sd
type ESSetTriggerDescription struct {
ESCommon
Payload ESSetTriggerDescriptionPayload `json:"payload"`
}
type ESSetTriggerDescriptionPayload struct {
Rotate string `json:"rotate,omitempty"`
Push string `json:"push,omitempty"`
Touch string `json:"touch,omitempty"`
LongTouch string `json:"longTouch,omitempty"`
}
func NewESSetTriggerDescription(context string, rotate, push, touch, longTouch string) ESSetTriggerDescription {
return ESSetTriggerDescription{
ESCommon: ESCommon{
Event: "setTriggerDescription",
Context: context,
},
Payload: ESSetTriggerDescriptionPayload{
Rotate: rotate,
Push: push,
Touch: touch,
LongTouch: longTouch,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#showalert
type ESShowAlert struct {
ESCommon
}
func NewESShowAlert(context string) ESShowAlert {
return ESShowAlert{
ESCommon: ESCommon{
Event: "showAlert",
Context: context,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#showok
type ESShowOK struct {
ESCommon
}
func NewESShowOK(context string) ESShowOK {
return ESShowOK{
ESCommon: ESCommon{
Event: "showOk",
Context: context,
},
}
}
//https://docs.elgato.com/sdk/plugins/events-sent#setstate
type ESSetState struct {
ESCommon
Payload ESSetStatePayload `json:"payload"`
}
type ESSetStatePayload struct {
State int `json:"state"`
}
func NewESSetState(context string, state int) ESSetImage {
return ESSetImage{
ESCommon: ESCommon{
Event: "setState",
Context: context,
},
Payload: ESSetImagePayload{
State: state,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#switchtoprofile
type ESSwitchToProfile struct {
ESCommon
Device string `json:"device"`
Payload ESSwitchToProfilePayload `json:"payload"`
}
type ESSwitchToProfilePayload struct {
Profile string `json:"profile"`
Page int `json:"page"`
}
func NewESSwitchToProfile(context string, device, profileName string, page int) ESSwitchToProfile {
return ESSwitchToProfile{
ESCommon: ESCommon{
Event: "switchToProfile",
Context: context,
},
Device: device,
Payload: ESSwitchToProfilePayload{
Profile: profileName,
Page: page,
},
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#sendtopropertyinspector
type ESSendToPropertyInspector struct {
ESCommon
Action string `json:"action"`
Payload json.RawMessage
}
func NewESSendToPropertyInspector(context string, action string, payload json.RawMessage) ESSendToPropertyInspector {
return ESSendToPropertyInspector{
ESCommon: ESCommon{
Event: "sendToPropertyInspector",
Context: context,
},
Action: action,
Payload: payload,
}
}
// https://docs.elgato.com/sdk/plugins/events-sent#sendtoplugin
type ESSendToPlugin struct {
ESCommon
Action string `json:"action"`
Payload json.RawMessage
}
func NewESSendToPlugin(context string, action string, payload json.RawMessage) ESSendToPlugin {
return ESSendToPlugin{
ESCommon: ESCommon{
Event: "sendToPlugin",
Context: context,
},
Action: action,
Payload: payload,
}
}
/// --------- helpers ----------
// Turns an image.Image into a string suitable for delivering
// via a ESSetImage struct
func ImageToPayload(i image.Image) string {
out := bytes.Buffer{}
b64 := base64.NewEncoder(base64.RawStdEncoding, &out)
err := png.Encode(b64, i)
if err != nil {
panic(err)
}
return "data:image/png;base64," + out.String()
}
// Turns an image.Image into a string suitable for delivering
// via a ESSetImage struct
func SVGToPayload(context string, svg string) string {
return "data:image/svg+xml;charset=utf8," + svg
}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module github.com/tardisx/streamdeck-plugin
go 1.22.1
require github.com/gorilla/websocket v1.5.3

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=

202
streamdeck.go Normal file
View File

@ -0,0 +1,202 @@
package streamdeck
import (
"bytes"
"encoding/json"
"fmt"
"io"
"reflect"
"github.com/gorilla/websocket"
)
type logger interface {
Info(string, ...any)
Error(string, ...any)
Debug(string, ...any)
}
type nullLogger struct{}
func (nl nullLogger) Info(string, ...any) {}
func (nl nullLogger) Error(string, ...any) {}
func (nl nullLogger) Debug(string, ...any) {}
type EventHandler struct {
MsgType string
Handler func()
}
type Connection struct {
ws *websocket.Conn
logger logger
handlers map[reflect.Type]reflect.Value
done chan (bool)
}
func New() Connection {
return Connection{
handlers: make(map[reflect.Type]reflect.Value),
logger: nullLogger{},
done: make(chan bool),
}
}
func NewWithLogger(l logger) Connection {
c := New()
c.logger = l
return c
}
func (conn *Connection) Connect(port int, openEvent string, uuid string) error {
c, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://localhost:%d", port), nil)
if err != nil {
return err
}
conn.ws = c
msg := ESOpenMessage{
ESCommonNoContext: ESCommonNoContext{
Event: openEvent,
},
UUID: uuid,
}
conn.logger.Debug(fmt.Sprintf("writing openMessage: %+v", msg))
err = c.WriteJSON(msg)
if err != nil {
conn.logger.Error(err.Error())
panic(err)
}
// run the reader forever
conn.logger.Info("starting reader")
go conn.reader()
return nil
}
func (c *Connection) WaitForPluginExit() {
<-c.done
}
// RegisterHandler registers a function to be called for a particular event. The
// event to be handled is determined by the functions single parameter type.
// This should be called before Connect to be sure your application is ready to
// receive events. You can register as many handlers as you like, but only one
// function per event type. This function will panic if the wrong kind of
// function is passed in, or if you try to register more than one for a single
// event type.
func (r *Connection) RegisterHandler(handler any) {
hType := reflect.TypeOf(handler)
if hType.Kind() != reflect.Func {
panic("handler must be a function")
}
// Assuming the function takes exactly one argument
if hType.NumIn() != 1 {
panic("handler func must take exactly one argument")
}
argType := hType.In(0)
// check its a valid one (one that matches an event type)
valid := false
for i := range receivedEventTypeMap {
if receivedEventTypeMap[i] == argType {
valid = true
break
}
}
if !valid {
panic("you cannot register a handler with this argument type")
}
_, alreadyExists := r.handlers[argType]
if alreadyExists {
panic("handler for " + argType.Name() + " already exists")
}
r.handlers[argType] = reflect.ValueOf(handler)
}
func (conn *Connection) Send(e any) error {
b, _ := json.Marshal(e)
conn.logger.Debug(fmt.Sprintf("sending: %s", string(b)))
return conn.ws.WriteJSON(e)
}
func (conn *Connection) handle(event any) {
conn.logger.Debug(fmt.Sprintf("handle: incoming a %T", event))
argType := reflect.TypeOf(event)
handler, ok := conn.handlers[argType]
if !ok {
conn.logger.Debug(fmt.Sprintf("handle: no handler registered for type %s", argType))
return
} else {
conn.logger.Debug(fmt.Sprintf("handle: found handler function for type %s", argType))
v := []reflect.Value{reflect.ValueOf(event)}
conn.logger.Debug(fmt.Sprintf("handle: handler func: %+v", handler))
conn.logger.Debug(fmt.Sprintf("handle: handler var: %+v", v))
conn.logger.Debug("handle: calling handler function")
handler.Call(v)
}
}
func (conn *Connection) reader() {
for {
_, r, err := conn.ws.NextReader()
if err != nil {
conn.logger.Error(err.Error())
break
}
b := bytes.Buffer{}
r = io.TeeReader(r, &b)
base := ERBase{}
err = json.NewDecoder(r).Decode(&base)
if err != nil {
conn.logger.Error("cannot decode: " + err.Error())
continue
}
t, ok := receivedEventTypeMap[base.Event]
if !ok {
conn.logger.Error(fmt.Sprintf("no type registered for event '%s'", base.Event))
continue
}
d, err := conn.unmarshalToConcrete(t, b.Bytes())
if err != nil {
conn.logger.Error("cannot unmarshal: " + err.Error())
continue
}
conn.handle(d)
}
conn.logger.Info("websocket closed, shutting down reader")
conn.done <- true
}
// unmarshalToConcrete takes a reflect.Type and a byte slice, creates a concrete
// instance of the type and unmarshals the JSON byte slice into it.
func (conn *Connection) unmarshalToConcrete(t reflect.Type, b []byte) (any, error) {
// t is a reflect.Type of the thing we need to decode into
d := reflect.New(t).Interface()
conn.logger.Info(fmt.Sprintf("instance is a %T", d))
err := json.Unmarshal(b, &d)
if err != nil {
return nil, fmt.Errorf("could not unmarshal this:\n%s\ninto a %v (%v)\nbecause: %s", string(b), d, t, err.Error())
}
// get concrete instance of d into v
v := reflect.ValueOf(d).Elem().Interface()
conn.logger.Info(fmt.Sprintf("NOW instance is a %T", v))
conn.logger.Debug(fmt.Sprintf("reader: unmarshalled to: %+v", v))
return v, nil
}

69
streamdesk_test.go Normal file
View File

@ -0,0 +1,69 @@
package streamdeck
import (
"testing"
)
type testLogger struct {
t *testing.T
}
func (tl testLogger) Info(s string, x ...any) { tl.t.Log(s, x) }
func (tl testLogger) Debug(s string, x ...any) { tl.t.Log(s, x) }
func (tl testLogger) Error(s string, x ...any) { tl.t.Log(s, x) }
func TestReflection(t *testing.T) {
c := NewWithLogger(testLogger{t: t})
// incoming
in := ERDidReceiveSettingsPayload{}
ranHandler := false
c.RegisterHandler(func(event ERDidReceiveSettingsPayload) {
ranHandler = true
})
c.handle(in)
if !ranHandler {
t.Error("did not run handler")
}
}
func TestUmmarshal(t *testing.T) {
b := []byte(`
{
"action": "com.elgato.example.action1",
"event": "keyUp",
"context": "ABC123",
"device": "DEF456",
"payload": {
"settings": {},
"coordinates": {
"column": 3,
"row": 1
},
"state": 0,
"userDesiredState": 1,
"isInMultiAction": false
}
}`)
c := NewWithLogger(testLogger{t: t})
keyUp, err := c.unmarshalToConcrete(receivedEventTypeMap["keyUp"], b)
if err != nil {
t.Error(err)
}
realKeyUp, ok := keyUp.(ERKeyUp)
if !ok {
t.Errorf("wrong type (is %T)", keyUp)
}
if realKeyUp.Context != "ABC123" {
t.Error("wrong value")
}
}