Adding Slack modules

This commit is contained in:
lwoodard
2026-04-13 11:27:18 -06:00
parent 1d9f0b519b
commit 639a08a808
5 changed files with 522 additions and 9 deletions

View File

@@ -23,6 +23,7 @@ import (
"github.com/WoodardDigital/streamdeck-go/internal/config"
"github.com/WoodardDigital/streamdeck-go/internal/device"
"github.com/WoodardDigital/streamdeck-go/internal/modules"
"github.com/fsnotify/fsnotify"
"github.com/srwiley/oksvg"
"github.com/srwiley/rasterx"
@@ -51,6 +52,11 @@ func main() {
log.Fatalf("config: %v", err)
}
reg, err := modules.LoadRegistry(config.ModulesPath(*cfgPath))
if err != nil {
log.Fatalf("modules: %v", err)
}
// Open device — if not present at startup, wait for it.
sd := mustConnect(cfg.Device.VendorID, cfg.Device.ProductID)
@@ -61,7 +67,7 @@ func main() {
startRun := func() {
go func() {
deviceDied := run(ctx, sd, cfg)
deviceDied := run(ctx, sd, cfg, reg)
runDone <- deviceDied
}()
}
@@ -91,13 +97,15 @@ func main() {
ctx, cancel = context.WithCancel(context.Background())
startRun()
// Config file changed — reload and restart run().
// Config file or modules file changed — reload and restart run().
case event, ok := <-watcher.Events:
if !ok {
cancel()
return
}
if filepath.Clean(event.Name) != filepath.Clean(*cfgPath) {
cfgChanged := filepath.Clean(event.Name) == filepath.Clean(*cfgPath)
modChanged := filepath.Clean(event.Name) == filepath.Clean(config.ModulesPath(*cfgPath))
if !cfgChanged && !modChanged {
continue
}
if !event.Has(fsnotify.Write) && !event.Has(fsnotify.Create) {
@@ -114,6 +122,12 @@ func main() {
} else {
cfg = newCfg
}
newReg, err := modules.LoadRegistry(config.ModulesPath(*cfgPath))
if err != nil {
log.Printf("reload: bad modules: %v — keeping current modules", err)
} else {
reg = newReg
}
ctx, cancel = context.WithCancel(context.Background())
startRun()
@@ -129,7 +143,7 @@ func main() {
// run initialises the deck and handles button presses until ctx is cancelled
// or the device dies. Returns true if the device died, false if ctx was cancelled.
func run(ctx context.Context, sd *device.StreamDeck, cfg *config.Config) (deviceDied bool) {
func run(ctx context.Context, sd *device.StreamDeck, cfg *config.Config, reg *modules.Registry) (deviceDied bool) {
// Recover from any panic inside this goroutine tree.
defer func() {
if r := recover(); r != nil {
@@ -157,6 +171,24 @@ func run(ctx context.Context, sd *device.StreamDeck, cfg *config.Config) (device
triggers := make(map[int]chan struct{})
for keyIdx, keyCfg := range cfg.Keys {
// Resolve module-based commands to shell strings before any other logic.
if keyCfg.Module != "" {
resolved, err := reg.Resolve(keyCfg.Module, keyCfg.Function, keyCfg.Params)
if err != nil {
log.Printf("key %d: module: %v", keyIdx, err)
continue
}
keyCfg.Command = resolved
}
if keyCfg.Poll != nil && keyCfg.Poll.Module != "" {
resolved, err := reg.Resolve(keyCfg.Poll.Module, keyCfg.Poll.Function, keyCfg.Poll.Params)
if err != nil {
log.Printf("key %d: poll module: %v", keyIdx, err)
continue
}
keyCfg.Poll.Command = resolved
}
// Toggle/status key: managed by a polling goroutine.
if keyCfg.Poll != nil {
if keyCfg.IconTrue == "" || keyCfg.IconFalse == "" {