Merge pull request #81 from jwetzell/feat/richer-templating-data

use a struct to pass multiple pieces of data into templating context
This commit is contained in:
Joel Wetzell
2026-03-04 12:40:37 -06:00
committed by GitHub
12 changed files with 82 additions and 46 deletions

View File

@@ -26,8 +26,10 @@ type FreeDCreate struct {
func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var idBuffer bytes.Buffer
err := fc.Id.Execute(&idBuffer, payload)
err := fc.Id.Execute(&idBuffer, templateData)
if err != nil {
return nil, err
@@ -42,7 +44,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var panBuffer bytes.Buffer
err = fc.Pan.Execute(&panBuffer, payload)
err = fc.Pan.Execute(&panBuffer, templateData)
if err != nil {
return nil, err
@@ -57,7 +59,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var tiltBuffer bytes.Buffer
err = fc.Tilt.Execute(&tiltBuffer, payload)
err = fc.Tilt.Execute(&tiltBuffer, templateData)
if err != nil {
return nil, err
@@ -72,7 +74,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var rollBuffer bytes.Buffer
err = fc.Tilt.Execute(&rollBuffer, payload)
err = fc.Tilt.Execute(&rollBuffer, templateData)
if err != nil {
return nil, err
@@ -87,7 +89,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var posXBuffer bytes.Buffer
err = fc.PosX.Execute(&posXBuffer, payload)
err = fc.PosX.Execute(&posXBuffer, templateData)
if err != nil {
return nil, err
@@ -102,7 +104,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var posYBuffer bytes.Buffer
err = fc.PosY.Execute(&posYBuffer, payload)
err = fc.PosY.Execute(&posYBuffer, templateData)
if err != nil {
return nil, err
@@ -117,7 +119,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var posZBuffer bytes.Buffer
err = fc.PosZ.Execute(&posZBuffer, payload)
err = fc.PosZ.Execute(&posZBuffer, templateData)
if err != nil {
return nil, err
@@ -132,7 +134,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var zoomBuffer bytes.Buffer
err = fc.Zoom.Execute(&zoomBuffer, payload)
err = fc.Zoom.Execute(&zoomBuffer, templateData)
if err != nil {
return nil, err
@@ -147,7 +149,7 @@ func (fc *FreeDCreate) Process(ctx context.Context, payload any) (any, error) {
}
var focusBuffer bytes.Buffer
err = fc.Focus.Execute(&focusBuffer, payload)
err = fc.Focus.Execute(&focusBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -18,8 +18,10 @@ type HTTPRequestCreate struct {
func (hrc *HTTPRequestCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var urlBuffer bytes.Buffer
err := hrc.URL.Execute(&urlBuffer, payload)
err := hrc.URL.Execute(&urlBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -21,8 +21,10 @@ type HTTPResponse struct {
}
func (hre *HTTPResponseCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var bodyBuffer bytes.Buffer
err := hre.BodyTmpl.Execute(&bodyBuffer, payload)
err := hre.BodyTmpl.Execute(&bodyBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -65,9 +65,10 @@ func newMidiNoteOnCreate(config config.ProcessorConfig) (Processor, error) {
}
return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var channelBuffer bytes.Buffer
err := channelTemplate.Execute(&channelBuffer, payload)
err := channelTemplate.Execute(&channelBuffer, templateData)
if err != nil {
return nil, err
@@ -76,7 +77,7 @@ func newMidiNoteOnCreate(config config.ProcessorConfig) (Processor, error) {
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
var noteBuffer bytes.Buffer
err = noteTemplate.Execute(&noteBuffer, payload)
err = noteTemplate.Execute(&noteBuffer, templateData)
if err != nil {
return nil, err
@@ -85,7 +86,7 @@ func newMidiNoteOnCreate(config config.ProcessorConfig) (Processor, error) {
noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8)
var velocityBuffer bytes.Buffer
err = velocityTemplate.Execute(&velocityBuffer, payload)
err = velocityTemplate.Execute(&velocityBuffer, templateData)
if err != nil {
return nil, err
@@ -136,8 +137,10 @@ func newMidiNoteOffCreate(config config.ProcessorConfig) (Processor, error) {
return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var channelBuffer bytes.Buffer
err := channelTemplate.Execute(&channelBuffer, payload)
err := channelTemplate.Execute(&channelBuffer, templateData)
if err != nil {
return nil, err
@@ -146,7 +149,7 @@ func newMidiNoteOffCreate(config config.ProcessorConfig) (Processor, error) {
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
var noteBuffer bytes.Buffer
err = noteTemplate.Execute(&noteBuffer, payload)
err = noteTemplate.Execute(&noteBuffer, templateData)
if err != nil {
return nil, err
@@ -155,7 +158,7 @@ func newMidiNoteOffCreate(config config.ProcessorConfig) (Processor, error) {
noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8)
var velocityBuffer bytes.Buffer
err = velocityTemplate.Execute(&velocityBuffer, payload)
err = velocityTemplate.Execute(&velocityBuffer, templateData)
if err != nil {
return nil, err
@@ -207,8 +210,10 @@ func newMidiControlChangeCreate(config config.ProcessorConfig) (Processor, error
return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var channelBuffer bytes.Buffer
err := channelTemplate.Execute(&channelBuffer, payload)
err := channelTemplate.Execute(&channelBuffer, templateData)
if err != nil {
return nil, err
@@ -217,7 +222,7 @@ func newMidiControlChangeCreate(config config.ProcessorConfig) (Processor, error
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
var controlBuffer bytes.Buffer
err = controlTemplate.Execute(&controlBuffer, payload)
err = controlTemplate.Execute(&controlBuffer, templateData)
if err != nil {
return nil, err
@@ -226,7 +231,7 @@ func newMidiControlChangeCreate(config config.ProcessorConfig) (Processor, error
controlValue, err := strconv.ParseUint(controlBuffer.String(), 10, 8)
var valueBuffer bytes.Buffer
err = valueTemplate.Execute(&valueBuffer, payload)
err = valueTemplate.Execute(&valueBuffer, templateData)
if err != nil {
return nil, err
@@ -266,9 +271,10 @@ func newMidiProgramChangeCreate(config config.ProcessorConfig) (Processor, error
}
return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var channelBuffer bytes.Buffer
err := channelTemplate.Execute(&channelBuffer, payload)
err := channelTemplate.Execute(&channelBuffer, templateData)
if err != nil {
return nil, err
@@ -277,7 +283,7 @@ func newMidiProgramChangeCreate(config config.ProcessorConfig) (Processor, error
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
var programBuffer bytes.Buffer
err = programTemplate.Execute(&programBuffer, payload)
err = programTemplate.Execute(&programBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -21,9 +21,10 @@ type NATSMessageCreate struct {
}
func (nmc *NATSMessageCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var payloadBuffer bytes.Buffer
err := nmc.Payload.Execute(&payloadBuffer, payload)
err := nmc.Payload.Execute(&payloadBuffer, templateData)
if err != nil {
return nil, err
@@ -32,7 +33,7 @@ func (nmc *NATSMessageCreate) Process(ctx context.Context, payload any) (any, er
payloadString := payloadBuffer.String()
var subjectBuffer bytes.Buffer
err = nmc.Subject.Execute(&subjectBuffer, payload)
err = nmc.Subject.Execute(&subjectBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -22,8 +22,10 @@ type OSCMessageCreate struct {
func (omc *OSCMessageCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var addressBuffer bytes.Buffer
err := omc.Address.Execute(&addressBuffer, payload)
err := omc.Address.Execute(&addressBuffer, templateData)
if err != nil {
return nil, err
@@ -47,7 +49,7 @@ func (omc *OSCMessageCreate) Process(ctx context.Context, payload any) (any, err
for argIndex, argTemplate := range omc.Args {
var argBuffer bytes.Buffer
err := argTemplate.Execute(&argBuffer, payload)
err := argTemplate.Execute(&argBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"sync"
"github.com/jwetzell/showbridge-go/internal/common"
"github.com/jwetzell/showbridge-go/internal/config"
)
@@ -45,3 +46,17 @@ func GetAnyAs[T any](p any) (T, bool) {
typed, ok := p.(T)
return typed, ok
}
type TemplateData struct {
Payload any
Modules any
}
func GetTemplateData(ctx context.Context, payload any) TemplateData {
templateData := TemplateData{Payload: payload}
modules := ctx.Value(common.ModulesContextKey)
if modules != nil {
templateData.Modules = modules
}
return templateData
}

View File

@@ -24,8 +24,10 @@ type SipAudioFileResponse struct {
func (scc *SipResponseAudioCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var audioFileBuffer bytes.Buffer
err := scc.AudioFile.Execute(&audioFileBuffer, payload)
err := scc.AudioFile.Execute(&audioFileBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -27,8 +27,10 @@ type SipDTMFResponse struct {
func (scc *SipResponseDTMFCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var digitsBuffer bytes.Buffer
err := scc.Digits.Execute(&digitsBuffer, payload)
err := scc.Digits.Execute(&digitsBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -15,8 +15,10 @@ type StringCreate struct {
}
func (sc *StringCreate) Process(ctx context.Context, payload any) (any, error) {
templateData := GetTemplateData(ctx, payload)
var templateBuffer bytes.Buffer
err := sc.Template.Execute(&templateBuffer, payload)
err := sc.Template.Execute(&templateBuffer, templateData)
if err != nil {
return nil, err

View File

@@ -49,7 +49,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and no args",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
},
payload: map[string]any{"Value": "value"},
expected: &osc.OSCMessage{Address: "/test/value"},
@@ -57,7 +57,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and string arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{"arg1"},
"types": "s",
},
@@ -67,7 +67,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and mixed args",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{"arg1", "42", "3.14"},
"types": "sif",
},
@@ -84,7 +84,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and int64 arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{"42"},
"types": "h",
},
@@ -94,7 +94,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and double arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{"42"},
"types": "d",
},
@@ -104,7 +104,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and true arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{""},
"types": "T",
},
@@ -114,7 +114,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and false arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{""},
"types": "F",
},
@@ -124,7 +124,7 @@ func TestGoodOSCMessageCreate(t *testing.T) {
{
name: "address with template and nil arg",
params: map[string]any{
"address": "/test/{{.Value}}",
"address": "/test/{{.Payload.Value}}",
"args": []interface{}{""},
"types": "N",
},
@@ -286,7 +286,7 @@ func TestBadOSCMessageCreate(t *testing.T) {
"address": "/test/{{.missing}}",
},
payload: "test",
errorString: "template: address:1:8: executing \"address\" at <.missing>: can't evaluate field missing in type string",
errorString: "template: address:1:8: executing \"address\" at <.missing>: can't evaluate field missing in type processor.TemplateData",
},
{
name: "address doesn't start with slash",
@@ -304,7 +304,7 @@ func TestBadOSCMessageCreate(t *testing.T) {
"types": "s",
},
payload: "test",
errorString: "template: arg:1:2: executing \"arg\" at <.missing>: can't evaluate field missing in type string",
errorString: "template: arg:1:2: executing \"arg\" at <.missing>: can't evaluate field missing in type processor.TemplateData",
},
}

View File

@@ -16,7 +16,7 @@ func TestStringCreateFromRegistry(t *testing.T) {
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.create",
Params: map[string]any{
"template": "{{.}}",
"template": "{{.Payload}}",
},
})
if err != nil {
@@ -50,31 +50,31 @@ func TestGoodStringCreate(t *testing.T) {
}{
{
name: "string payload",
params: map[string]any{"template": "{{.}}"},
params: map[string]any{"template": "{{.Payload}}"},
payload: "hello",
expected: "hello",
},
{
name: "number payload",
params: map[string]any{"template": "{{.}}"},
params: map[string]any{"template": "{{.Payload}}"},
payload: 4,
expected: "4",
},
{
name: "boolean payload",
params: map[string]any{"template": "{{.}}"},
params: map[string]any{"template": "{{.Payload}}"},
payload: true,
expected: "true",
},
{
name: "struct payload - field",
params: map[string]any{"template": "{{.Data}}"},
params: map[string]any{"template": "{{.Payload.Data}}"},
payload: TestStruct{Data: "test"},
expected: "test",
},
{
name: "struct payload - method",
params: map[string]any{"template": "{{.GetData}}"},
params: map[string]any{"template": "{{.Payload.GetData}}"},
payload: TestStruct{Data: "test"},
expected: "test",
},
@@ -148,7 +148,7 @@ func TestBadStringCreate(t *testing.T) {
params: map[string]any{
"template": "{{.Invalid}}",
},
errorString: "template: template:1:2: executing \"template\" at <.Invalid>: can't evaluate field Invalid in type string",
errorString: "template: template:1:2: executing \"template\" at <.Invalid>: can't evaluate field Invalid in type processor.TemplateData",
},
}