Compare commits

...

32 Commits

Author SHA1 Message Date
Joel Wetzell 419bcf7ad4 fix extension on windows builds 2026-05-17 13:13:41 -05:00
Joel Wetzell c52c4299e9 add release creation and artificat upload 2026-05-17 13:06:36 -05:00
Joel Wetzell 8bfcbea992 remove zig setup from macos jobs 2026-05-17 12:53:46 -05:00
Joel Wetzell b31442b794 split macos and build natively 2026-05-17 12:53:05 -05:00
Joel Wetzell 6a324a41b5 add job to setup release properties 2026-05-17 12:43:15 -05:00
Joel Wetzell 49227f9a82 add macos build job 2026-05-17 12:32:57 -05:00
Joel Wetzell 2ba309636f set CGO enabled for native go builds 2026-05-17 12:19:33 -05:00
Joel Wetzell 1d8756508d split linux build into two 2026-05-17 12:17:19 -05:00
Joel Wetzell 69e839efb2 add step to install alsa 2026-05-17 11:44:38 -05:00
Joel Wetzell dd28c40b19 only docker build and push on tag 2026-05-17 11:40:03 -05:00
Joel Wetzell 410c2c4e1f start working on getting rid of gorelease and full cross platform builds 2026-05-17 11:39:00 -05:00
Joel Wetzell e9d5688852 Merge pull request #155 from jwetzell/config-file-permission-bits
tighten up permission bits on config file writes
2026-05-17 10:09:24 -05:00
Joel Wetzell df532d7677 Merge pull request #154 from jwetzell/fix/http-server-read-header-timeout
add read header timeout to http servers
2026-05-17 10:08:00 -05:00
Joel Wetzell 727d63cc32 tighten up permission bits on config file writes 2026-05-17 10:05:27 -05:00
Joel Wetzell 9125b323ff add read header timeout to http servers 2026-05-17 10:03:48 -05:00
Joel Wetzell ad4aa91e08 minor linting things 2026-05-17 09:50:08 -05:00
Joel Wetzell 4bdfe0b00a add error return to database module 2026-05-17 09:50:01 -05:00
Joel Wetzell 2fdf6d1a61 rearrange error return 2026-05-17 09:49:36 -05:00
Joel Wetzell b4d4ef3421 cleanup some error handling lint issues 2026-05-17 09:48:49 -05:00
Joel Wetzell 8752b35ea4 Merge pull request #153 from jwetzell/fix/serial-client-closing
close serial client more reliably
2026-05-17 09:06:36 -05:00
Joel Wetzell e5c8e01bf0 close serial client more reliably 2026-05-17 08:37:11 -05:00
Joel Wetzell 91063f50da better port error message for serial.client 2026-05-17 08:35:59 -05:00
Joel Wetzell 08941ceaa0 Merge pull request #152 from jwetzell/fix/serial-client-schema
fix params schema for serial.client
2026-05-17 07:54:59 -05:00
Joel Wetzell acb834405e fix params schema for serial.client 2026-05-17 07:53:20 -05:00
Joel Wetzell ac2930b91b take reference to module for future process calls 2026-05-14 22:35:31 -05:00
Joel Wetzell d16e247a3a update artnet-go 2026-05-14 20:50:40 -05:00
Joel Wetzell a134a8929f update free-d-go 2026-05-14 19:50:38 -05:00
Joel Wetzell ad91be50c4 pre-intialize and instance of the WASM script to use in process 2026-05-14 19:50:38 -05:00
Joel Wetzell d4abe7ed2d todo's 2026-05-14 19:50:38 -05:00
Joel Wetzell 0912949f31 add return early option for slice casting 2026-05-14 19:50:38 -05:00
Joel Wetzell b4b5e17265 Merge pull request #151 from jwetzell/benchmarks
add basic benchmark for most processors
2026-05-14 19:48:31 -05:00
Joel Wetzell 9eb05c8360 add basic benchmark for most processors 2026-05-14 19:44:19 -05:00
67 changed files with 1495 additions and 115 deletions
+191 -10
View File
@@ -4,13 +4,45 @@ on:
push: push:
tags: tags:
- "v*" - "v*"
workflow_dispatch:
permissions: permissions:
contents: write contents: write
jobs: jobs:
goreleaser: setup_release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
version: ${{ steps.set_version.outputs.version }}
short_commit: ${{ steps.set_commit.outputs.short_commit }}
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: set environment variables
run: echo "SHOWBRIDGE_VERSION=${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: clean tag
if: startsWith(github.ref, 'refs/tags/v')
run: echo "SHOWBRIDGE_VERSION=${SHOWBRIDGE_VERSION#v}" >> $GITHUB_ENV
- name: set version
id: set_version
run: echo "version=${SHOWBRIDGE_VERSION}" >> $GITHUB_OUTPUT
- name: set commit
id: set_commit
run: echo "short_commit=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
- name: create release
uses: softprops/action-gh-release@v3
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
generate_release_notes: true
linux_amd64:
runs-on: ubuntu-24.04
needs: setup_release
env:
SHOWBRIDGE_VERSION: ${{ needs.setup_release.outputs.version }}
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
@@ -20,18 +52,166 @@ jobs:
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: release - name: install alsa lib
uses: goreleaser/goreleaser-action@v7 run: sudo apt-get install -y libasound2-dev
- name: build
run: |
CGO_ENABLED=1 go build -o showbridge -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
tar -czf showbridge_${SHOWBRIDGE_VERSION}_linux-amd64.tar.gz showbridge
- name: upload linux artifacts
uses: actions/upload-artifact@v7
if: github.event_name == 'workflow_dispatch'
with: with:
workdir: cmd/showbridge name: showbridge-linux-amd64
distribution: goreleaser path: |
version: "v2.13.0" showbridge_*.tar.gz
args: release --clean - name: upload artifacts to release
env: uses: softprops/action-gh-release@v3
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
files: showbridge_*.tar.gz
linux_arm64:
runs-on: ubuntu-24.04-arm
needs: setup_release
env:
SHOWBRIDGE_VERSION: ${{ needs.setup_release.outputs.version }}
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- name: install alsa lib
run: sudo apt-get install -y libasound2-dev
- name: build
run: |
CGO_ENABLED=1 go build -o showbridge -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
tar -czf showbridge_${SHOWBRIDGE_VERSION}_linux-arm64.tar.gz showbridge
- name: upload linux artifacts
uses: actions/upload-artifact@v7
if: github.event_name == 'workflow_dispatch'
with:
name: showbridge-linux-arm64
path: |
showbridge_*.tar.gz
- name: upload artifacts to release
uses: softprops/action-gh-release@v3
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
files: showbridge_*.tar.gz
windows:
runs-on: ubuntu-latest
needs: setup_release
env:
SHOWBRIDGE_VERSION: ${{ needs.setup_release.outputs.version }}
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- name: setup zig
uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: build amd64
run: |
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC="zig cc -target x86_64-windows-gnu" CXX="zig c++ -target x86_64-windows-gnu" go build -o showbridge.exe -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
zip showbridge_${SHOWBRIDGE_VERSION}_windows-amd64.zip showbridge.exe
- name: build arm64
run: |
CGO_ENABLED=1 GOOS=windows GOARCH=arm64 CC="zig cc -target aarch64-windows-gnu" CXX="zig c++ -target aarch64-windows-gnu" go build -o showbridge.exe -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
zip showbridge_${SHOWBRIDGE_VERSION}_windows-arm64.zip showbridge.exe
- name: upload windows artifacts
uses: actions/upload-artifact@v7
if: github.event_name == 'workflow_dispatch'
with:
name: showbridge-windows
path: |
showbridge_*.zip
- name: upload artifacts to release
uses: softprops/action-gh-release@v3
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
files: showbridge_*.zip
macos_arm64:
runs-on: macos-26
needs: setup_release
env:
SHOWBRIDGE_VERSION: ${{ needs.setup_release.outputs.version }}
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- name: build
run: |
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o showbridge -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
tar -czf showbridge_${SHOWBRIDGE_VERSION}_macOS-arm64.tar.gz showbridge
- name: upload macos artifacts
uses: actions/upload-artifact@v7
if: github.event_name == 'workflow_dispatch'
with:
name: showbridge-macos-arm64
path: |
showbridge_*.tar.gz
- name: upload artifacts to release
uses: softprops/action-gh-release@v3
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
files: showbridge_*.tar.gz
macos_amd64:
runs-on: macos-26-intel
needs: setup_release
env:
SHOWBRIDGE_VERSION: ${{ needs.setup_release.outputs.version }}
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- name: build
run: |
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o showbridge -ldflags="-s -w -X main.version=${SHOWBRIDGE_VERSION}-${SHORT_COMMIT}" ./cmd/showbridge
tar -czf showbridge_${SHOWBRIDGE_VERSION}_macOS-amd64.tar.gz showbridge
- name: upload macos artifacts
uses: actions/upload-artifact@v7
if: github.event_name == 'workflow_dispatch'
with:
name: showbridge-macos-amd64
path: |
showbridge_*.tar.gz
- name: upload artifacts to release
uses: softprops/action-gh-release@v3
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')
with:
draft: true
files: showbridge_*.tar.gz
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: goreleaser needs: linux_amd64
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
@@ -57,6 +237,7 @@ jobs:
- name: Build and push - name: Build and push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
if: github.ref_type == 'tag'
with: with:
push: true push: true
context: ./ context: ./
+6 -3
View File
@@ -127,6 +127,9 @@ func readConfig(configPath string) (config.Config, error) {
} }
validatedConfigBytes, err := json.Marshal(yamlMap) validatedConfigBytes, err := json.Marshal(yamlMap)
if err != nil {
return config.Config{}, err
}
err = json.Unmarshal(validatedConfigBytes, &cfg) err = json.Unmarshal(validatedConfigBytes, &cfg)
if err != nil { if err != nil {
@@ -142,7 +145,7 @@ func writeConfig(configPath string, newConfig config.Config) error {
return err return err
} }
err = os.WriteFile(configPath, configBytes, 0644) err = os.WriteFile(configPath, configBytes, 0600)
if err != nil { if err != nil {
return err return err
} }
@@ -156,7 +159,7 @@ func run(ctx context.Context, c *cli.Command) error {
return errors.New("config path cannot be empty") return errors.New("config path cannot be empty")
} }
logLevel := slog.LevelInfo var logLevel slog.Level
logLevelFromFlag := c.String("log-level") logLevelFromFlag := c.String("log-level")
@@ -260,7 +263,7 @@ func (app *showbridgeApp) handleChannels() {
app.routerMutex.Unlock() app.routerMutex.Unlock()
continue continue
} }
err, moduleErrors, routeErrors := app.router.UpdateConfig(config, false) moduleErrors, routeErrors, err := app.router.UpdateConfig(config, false)
if err != nil { if err != nil {
app.logger.Error("failed to update router config", "error", err) app.logger.Error("failed to update router config", "error", err)
app.routerMutex.Unlock() app.routerMutex.Unlock()
+3 -3
View File
@@ -15,9 +15,9 @@ func (r *Router) GetRunningConfig() config.Config {
return r.runningConfig return r.runningConfig
} }
func (r *Router) UpdateConfig(newConfig config.Config, triggerChangeChan bool) (error, []config.ModuleError, []config.RouteError) { func (r *Router) UpdateConfig(newConfig config.Config, triggerChangeChan bool) ([]config.ModuleError, []config.RouteError, error) {
if !r.runningConfigMu.TryLock() { if !r.runningConfigMu.TryLock() {
return errors.New("config update in progress"), nil, nil return nil, nil, errors.New("config update in progress")
} }
defer r.runningConfigMu.Unlock() defer r.runningConfigMu.Unlock()
oldConfig := r.runningConfig oldConfig := r.runningConfig
@@ -81,5 +81,5 @@ func (r *Router) UpdateConfig(newConfig config.Config, triggerChangeChan bool) (
r.ConfigChange <- newConfig r.ConfigChange <- newConfig
} }
return nil, moduleErrors, routeErrors return moduleErrors, routeErrors, nil
} }
+2 -2
View File
@@ -10,8 +10,8 @@ require (
github.com/extism/go-sdk v1.7.1 github.com/extism/go-sdk v1.7.1
github.com/google/jsonschema-go v0.4.3 github.com/google/jsonschema-go v0.4.3
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/jwetzell/artnet-go v0.2.1 github.com/jwetzell/artnet-go v0.2.2
github.com/jwetzell/free-d-go v0.1.0 github.com/jwetzell/free-d-go v0.1.1
github.com/jwetzell/osc-go v0.3.0 github.com/jwetzell/osc-go v0.3.0
github.com/jwetzell/psn-go v0.3.0 github.com/jwetzell/psn-go v0.3.0
github.com/nats-io/nats-server/v2 v2.14.0 github.com/nats-io/nats-server/v2 v2.14.0
+4 -4
View File
@@ -65,10 +65,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f h1:NW3E2QS
github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
github.com/jwetzell/artnet-go v0.2.1 h1:iYTKWcwYrF5kBkYfkw2UbWvoueeA23iKEn7fR27mWZE= github.com/jwetzell/artnet-go v0.2.2 h1:vaXSmRrSlEdETPZ/gvw6aAmVqzQm0i+gfAwyIQkVsB0=
github.com/jwetzell/artnet-go v0.2.1/go.mod h1:gli97Z32a0kMkZ6taoTiK7/lqHcF/dhiGjGJdx/PxqA= github.com/jwetzell/artnet-go v0.2.2/go.mod h1:gli97Z32a0kMkZ6taoTiK7/lqHcF/dhiGjGJdx/PxqA=
github.com/jwetzell/free-d-go v0.1.0 h1:xHt6dvyit98X+OC3jVzV0aLidxbyzi3vI9QiYkteEtA= github.com/jwetzell/free-d-go v0.1.1 h1:pzY2c4qRxKFBZ2jO3z512ysvUI0BUmgd4mSlWPiFVRM=
github.com/jwetzell/free-d-go v0.1.0/go.mod h1:KmrkooRARRaxJTBSPvwt/6IMAIaHH1R8bSA8cwbbELw= github.com/jwetzell/free-d-go v0.1.1/go.mod h1:KmrkooRARRaxJTBSPvwt/6IMAIaHH1R8bSA8cwbbELw=
github.com/jwetzell/osc-go v0.3.0 h1:z75TxuQSEmdcmZ56OAepkDa3m88SdZh//3m4nBb/XZI= github.com/jwetzell/osc-go v0.3.0 h1:z75TxuQSEmdcmZ56OAepkDa3m88SdZh//3m4nBb/XZI=
github.com/jwetzell/osc-go v0.3.0/go.mod h1:kCs329JxY6Qjga08tRQ/Gl0PqhgQzLIMpOhm6uszvIc= github.com/jwetzell/osc-go v0.3.0/go.mod h1:kCs329JxY6Qjga08tRQ/Gl0PqhgQzLIMpOhm6uszvIc=
github.com/jwetzell/psn-go v0.3.0 h1:WVpCEmExYE8a+I5hQak5jNJJp2x35VdGX/VuMUKPmhY= github.com/jwetzell/psn-go v0.3.0 h1:WVpCEmExYE8a+I5hQak5jNJJp2x35VdGX/VuMUKPmhY=
+8 -4
View File
@@ -53,12 +53,16 @@ func (as *ApiServer) Start(config config.ApiConfig) {
as.serverMu.Lock() as.serverMu.Lock()
defer as.serverMu.Unlock() defer as.serverMu.Unlock()
as.server = &http.Server{ as.server = &http.Server{
Addr: fmt.Sprintf(":%d", as.config.Port), Addr: fmt.Sprintf(":%d", as.config.Port),
Handler: mux, ReadHeaderTimeout: 5 * time.Second,
Handler: mux,
} }
go func() { go func() {
as.server.ListenAndServe() err := as.server.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
as.logger.Error("server error", "error", err)
}
as.shutdown() as.shutdown()
}() }()
} }
@@ -148,7 +152,7 @@ func (as *ApiServer) handleConfigHTTP(w http.ResponseWriter, req *http.Request)
http.Error(w, "Bad request", http.StatusBadRequest) http.Error(w, "Bad request", http.StatusBadRequest)
return return
} }
err, moduleErrors, routeErrors := as.configurableRouter.UpdateConfig(newConfig, true) moduleErrors, routeErrors, err := as.configurableRouter.UpdateConfig(newConfig, true)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusConflict) http.Error(w, err.Error(), http.StatusConflict)
return return
+16
View File
@@ -81,11 +81,19 @@ func GetAnyAsByte(value any) (byte, bool) {
} }
func GetAnyAsByteSlice(value any) ([]byte, bool) { func GetAnyAsByteSlice(value any) ([]byte, bool) {
// already a []byte
byteSlice, ok := value.([]byte)
if ok {
return byteSlice, true
}
// check for a slice
v := reflect.ValueOf(value) v := reflect.ValueOf(value)
if v.Kind() != reflect.Slice { if v.Kind() != reflect.Slice {
return nil, false return nil, false
} }
// try to convert each element to a byte
result := make([]byte, v.Len()) result := make([]byte, v.Len())
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
elem := v.Index(i).Interface() elem := v.Index(i).Interface()
@@ -99,6 +107,14 @@ func GetAnyAsByteSlice(value any) ([]byte, bool) {
} }
func GetAnyAsIntSlice(value any) ([]int, bool) { func GetAnyAsIntSlice(value any) ([]int, bool) {
// already a []byte
intSlice, ok := value.([]int)
if ok {
return intSlice, true
}
// check for a slice
v := reflect.ValueOf(value) v := reflect.ValueOf(value)
if v.Kind() != reflect.Slice { if v.Kind() != reflect.Slice {
return nil, false return nil, false
+1 -1
View File
@@ -22,5 +22,5 @@ type KeyValueModule interface {
} }
type DatabaseModule interface { type DatabaseModule interface {
Database() *sql.DB Database() (*sql.DB, error)
} }
+1 -1
View File
@@ -7,6 +7,6 @@ type Config struct {
} }
type Configurable interface { type Configurable interface {
UpdateConfig(newConfig Config, triggerChangeChannel bool) (error, []ModuleError, []RouteError) UpdateConfig(newConfig Config, triggerChangeChannel bool) ([]ModuleError, []RouteError, error)
GetRunningConfig() Config GetRunningConfig() Config
} }
+3 -2
View File
@@ -25,9 +25,10 @@ func (sf *SlipFramer) Decode(data []byte) [][]byte {
} }
if escapeNext { if escapeNext {
if packetByte == ESC_END { switch packetByte {
case ESC_END:
sf.buffer = append(sf.buffer, END) sf.buffer = append(sf.buffer, END)
} else if packetByte == ESC_ESC { case ESC_ESC:
sf.buffer = append(sf.buffer, ESC) sf.buffer = append(sf.buffer, ESC)
} }
escapeNext = false escapeNext = false
+5 -2
View File
@@ -79,6 +79,9 @@ func (t *DbSqlite) Stop() {
} }
} }
func (t *DbSqlite) Database() *sql.DB { func (t *DbSqlite) Database() (*sql.DB, error) {
return t.db if t.db == nil {
return nil, fmt.Errorf("database not initialized")
}
return t.db, nil
} }
+4 -2
View File
@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"time"
"github.com/google/jsonschema-go/jsonschema" "github.com/google/jsonschema-go/jsonschema"
"github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/common"
@@ -163,8 +164,9 @@ func (hs *HTTPServer) Start(ctx context.Context, router common.RouteIO) error {
hs.cancel = cancel hs.cancel = cancel
httpServer := &http.Server{ httpServer := &http.Server{
Addr: fmt.Sprintf(":%d", hs.Port), Addr: fmt.Sprintf(":%d", hs.Port),
Handler: hs, ReadHeaderTimeout: 5 * time.Second,
Handler: hs,
} }
go func() { go func() {
+14 -3
View File
@@ -43,8 +43,13 @@ func init() {
Title: "Baud Rate", Title: "Baud Rate",
Type: "integer", Type: "integer",
}, },
"framing": {
Title: "Framing Method",
Type: "string",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"},
},
}, },
Required: []string{"port", "baudRate"}, Required: []string{"port", "baudRate", "framing"},
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}}, AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
}, },
New: func(config config.ModuleConfig) (common.Module, error) { New: func(config config.ModuleConfig) (common.Module, error) {
@@ -91,7 +96,7 @@ func (sc *SerialClient) SetupPort() error {
port, err := serial.Open(sc.Port, sc.Mode) port, err := serial.Open(sc.Port, sc.Mode)
if err != nil { if err != nil {
return fmt.Errorf("serial.client can't open input port: %s", sc.Port) return err
} }
sc.port = port sc.port = port
@@ -120,9 +125,12 @@ func (sc *SerialClient) Start(ctx context.Context, router common.RouteIO) error
if err != nil { if err != nil {
if sc.ctx.Err() != nil { if sc.ctx.Err() != nil {
sc.logger.Debug("done") sc.logger.Debug("done")
if sc.port != nil {
sc.port.Close()
}
return nil return nil
} }
sc.logger.Error("port setup error", "error", err.Error()) sc.logger.Error("port setup error", "port", sc.Port, "error", err.Error())
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
continue continue
} }
@@ -131,6 +139,9 @@ func (sc *SerialClient) Start(ctx context.Context, router common.RouteIO) error
select { select {
case <-sc.ctx.Done(): case <-sc.ctx.Done():
sc.logger.Debug("done") sc.logger.Debug("done")
if sc.port != nil {
sc.port.Close()
}
return nil return nil
default: default:
READ: READ:
+1 -1
View File
@@ -236,7 +236,7 @@ func (ts *TCPServer) Output(ctx context.Context, payload any) error {
for _, connection := range ts.connections { for _, connection := range ts.connections {
_, err := connection.Write(payloadBytes) _, err := connection.Write(payloadBytes)
if err != nil { if err != nil {
errorString.WriteString(fmt.Sprintf("%s\n", err.Error())) fmt.Fprintf(&errorString, "%s\n", err.Error())
} }
} }
ts.connectionsMu.Unlock() ts.connectionsMu.Unlock()
+24 -14
View File
@@ -17,34 +17,43 @@ type DbQuery struct {
ModuleId string ModuleId string
Query *template.Template Query *template.Template
logger *slog.Logger logger *slog.Logger
module common.DatabaseModule
} }
func (dq *DbQuery) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) { func (dq *DbQuery) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) {
if wrappedPayload.Modules == nil { if dq.module == nil {
wrappedPayload.End = true if wrappedPayload.Modules == nil {
return wrappedPayload, errors.New("db.query wrapped payload has no modules") wrappedPayload.End = true
return wrappedPayload, errors.New("db.query wrapped payload has no modules")
}
module, ok := wrappedPayload.Modules[dq.ModuleId]
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("db.query unable to find module with id: %s", dq.ModuleId)
}
dbModule, ok := module.(common.DatabaseModule)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("db.query module with id %s is not a DatabaseModule", dq.ModuleId)
}
dq.module = dbModule
} }
module, ok := wrappedPayload.Modules[dq.ModuleId] db, err := dq.module.Database()
if !ok { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("db.query unable to find module with id: %s", dq.ModuleId) return wrappedPayload, fmt.Errorf("db.query error getting database from module: %w", err)
} }
dbModule, ok := module.(common.DatabaseModule)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("db.query module with id %s is not a DatabaseModule", dq.ModuleId)
}
db := dbModule.Database()
if db == nil { if db == nil {
wrappedPayload.End = true wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("db.query module with id %s returned nil database", dq.ModuleId) return wrappedPayload, fmt.Errorf("db.query module with id %s returned nil database", dq.ModuleId)
} }
var queryBuffer bytes.Buffer var queryBuffer bytes.Buffer
err := dq.Query.Execute(&queryBuffer, wrappedPayload) err = dq.Query.Execute(&queryBuffer, wrappedPayload)
if err != nil { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
@@ -65,6 +74,7 @@ func (dq *DbQuery) Process(ctx context.Context, wrappedPayload common.WrappedPay
return wrappedPayload, fmt.Errorf("db.query error getting columns: %w", err) return wrappedPayload, fmt.Errorf("db.query error getting columns: %w", err)
} }
// TODO(jwetzell): optimize this
results := make([]map[string]any, 0) results := make([]map[string]any, 0)
for rows.Next() { for rows.Next() {
+20 -16
View File
@@ -16,27 +16,31 @@ type KVGet struct {
ModuleId string ModuleId string
Key string Key string
logger *slog.Logger logger *slog.Logger
module common.KeyValueModule
} }
func (kvg *KVGet) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) { func (kvg *KVGet) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) {
if wrappedPayload.Modules == nil { if kvg.module == nil {
wrappedPayload.End = true if wrappedPayload.Modules == nil {
return wrappedPayload, errors.New("kv.get wrapped payload has no modules") wrappedPayload.End = true
return wrappedPayload, errors.New("kv.get wrapped payload has no modules")
}
module, ok := wrappedPayload.Modules[kvg.ModuleId]
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.get unable to find module with id: %s", kvg.ModuleId)
}
kvModule, ok := module.(common.KeyValueModule)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.get module with id %s is not a KeyValueModule", kvg.ModuleId)
}
kvg.module = kvModule
} }
module, ok := wrappedPayload.Modules[kvg.ModuleId] value, err := kvg.module.Get(kvg.Key)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.get unable to find module with id: %s", kvg.ModuleId)
}
kvModule, ok := module.(common.KeyValueModule)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.get module with id %s is not a KeyValueModule", kvg.ModuleId)
}
value, err := kvModule.Get(kvg.Key)
if err != nil { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.get error getting key: %w", err) return wrappedPayload, fmt.Errorf("kv.get error getting key: %w", err)
+18 -15
View File
@@ -19,25 +19,28 @@ type KVSet struct {
Key string Key string
Value *template.Template Value *template.Template
logger *slog.Logger logger *slog.Logger
module common.KeyValueModule
} }
func (kvs *KVSet) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) { func (kvs *KVSet) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) {
if kvs.module == nil {
if wrappedPayload.Modules == nil {
wrappedPayload.End = true
return wrappedPayload, errors.New("kv.set wrapped payload has no modules")
}
if wrappedPayload.Modules == nil { module, ok := wrappedPayload.Modules[kvs.ModuleId]
wrappedPayload.End = true if !ok {
return wrappedPayload, errors.New("kv.set wrapped payload has no modules") wrappedPayload.End = true
} return wrappedPayload, fmt.Errorf("kv.set unable to find module with id: %s", kvs.ModuleId)
}
module, ok := wrappedPayload.Modules[kvs.ModuleId] kvModule, ok := module.(common.KeyValueModule)
if !ok { if !ok {
wrappedPayload.End = true wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.set unable to find module with id: %s", kvs.ModuleId) return wrappedPayload, fmt.Errorf("kv.set module with id %s is not a KeyValueModule", kvs.ModuleId)
} }
kvs.module = kvModule
kvModule, ok := module.(common.KeyValueModule)
if !ok {
wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.set module with id %s is not a KeyValueModule", kvs.ModuleId)
} }
var valueBuffer bytes.Buffer var valueBuffer bytes.Buffer
@@ -48,7 +51,7 @@ func (kvs *KVSet) Process(ctx context.Context, wrappedPayload common.WrappedPayl
return wrappedPayload, err return wrappedPayload, err
} }
err = kvModule.Set(kvs.Key, valueBuffer.String()) err = kvs.module.Set(kvs.Key, valueBuffer.String())
if err != nil { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
return wrappedPayload, fmt.Errorf("kv.set error setting key: %w", err) return wrappedPayload, fmt.Errorf("kv.set error setting key: %w", err)
@@ -35,6 +35,11 @@ func (mccc *MIDIControlChangeCreate) Process(ctx context.Context, wrappedPayload
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var controlBuffer bytes.Buffer var controlBuffer bytes.Buffer
err = mccc.Control.Execute(&controlBuffer, templateData) err = mccc.Control.Execute(&controlBuffer, templateData)
@@ -45,6 +50,11 @@ func (mccc *MIDIControlChangeCreate) Process(ctx context.Context, wrappedPayload
controlValue, err := strconv.ParseUint(controlBuffer.String(), 10, 8) controlValue, err := strconv.ParseUint(controlBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var valueBuffer bytes.Buffer var valueBuffer bytes.Buffer
err = mccc.Value.Execute(&valueBuffer, templateData) err = mccc.Value.Execute(&valueBuffer, templateData)
@@ -55,6 +65,11 @@ func (mccc *MIDIControlChangeCreate) Process(ctx context.Context, wrappedPayload
valueValue, err := strconv.ParseUint(valueBuffer.String(), 10, 8) valueValue, err := strconv.ParseUint(valueBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
payloadMessage := midi.ControlChange(uint8(channelValue), uint8(controlValue), uint8(valueValue)) payloadMessage := midi.ControlChange(uint8(channelValue), uint8(controlValue), uint8(valueValue))
wrappedPayload.Payload = payloadMessage wrappedPayload.Payload = payloadMessage
return wrappedPayload, nil return wrappedPayload, nil
@@ -35,6 +35,11 @@ func (mnoc *MIDINoteOffCreate) Process(ctx context.Context, wrappedPayload commo
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var noteBuffer bytes.Buffer var noteBuffer bytes.Buffer
err = mnoc.Note.Execute(&noteBuffer, templateData) err = mnoc.Note.Execute(&noteBuffer, templateData)
@@ -45,6 +50,11 @@ func (mnoc *MIDINoteOffCreate) Process(ctx context.Context, wrappedPayload commo
noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8) noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var velocityBuffer bytes.Buffer var velocityBuffer bytes.Buffer
err = mnoc.Velocity.Execute(&velocityBuffer, templateData) err = mnoc.Velocity.Execute(&velocityBuffer, templateData)
@@ -54,6 +64,12 @@ func (mnoc *MIDINoteOffCreate) Process(ctx context.Context, wrappedPayload commo
} }
velocityValue, err := strconv.ParseUint(velocityBuffer.String(), 10, 8) velocityValue, err := strconv.ParseUint(velocityBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
payloadMessage := midi.NoteOffVelocity(uint8(channelValue), uint8(noteValue), uint8(velocityValue)) payloadMessage := midi.NoteOffVelocity(uint8(channelValue), uint8(noteValue), uint8(velocityValue))
wrappedPayload.Payload = payloadMessage wrappedPayload.Payload = payloadMessage
return wrappedPayload, nil return wrappedPayload, nil
+15
View File
@@ -35,6 +35,11 @@ func (mnoc *MIDINoteOnCreate) Process(ctx context.Context, wrappedPayload common
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var noteBuffer bytes.Buffer var noteBuffer bytes.Buffer
err = mnoc.Note.Execute(&noteBuffer, templateData) err = mnoc.Note.Execute(&noteBuffer, templateData)
@@ -45,6 +50,11 @@ func (mnoc *MIDINoteOnCreate) Process(ctx context.Context, wrappedPayload common
noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8) noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var velocityBuffer bytes.Buffer var velocityBuffer bytes.Buffer
err = mnoc.Velocity.Execute(&velocityBuffer, templateData) err = mnoc.Velocity.Execute(&velocityBuffer, templateData)
@@ -54,6 +64,11 @@ func (mnoc *MIDINoteOnCreate) Process(ctx context.Context, wrappedPayload common
} }
velocityValue, err := strconv.ParseUint(velocityBuffer.String(), 10, 8) velocityValue, err := strconv.ParseUint(velocityBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
payloadMessage := midi.NoteOn(uint8(channelValue), uint8(noteValue), uint8(velocityValue)) payloadMessage := midi.NoteOn(uint8(channelValue), uint8(noteValue), uint8(velocityValue))
wrappedPayload.Payload = payloadMessage wrappedPayload.Payload = payloadMessage
return wrappedPayload, nil return wrappedPayload, nil
@@ -34,6 +34,11 @@ func (mpcc *MIDIProgramChangeCreate) Process(ctx context.Context, wrappedPayload
channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
var programBuffer bytes.Buffer var programBuffer bytes.Buffer
err = mpcc.Program.Execute(&programBuffer, templateData) err = mpcc.Program.Execute(&programBuffer, templateData)
@@ -44,6 +49,11 @@ func (mpcc *MIDIProgramChangeCreate) Process(ctx context.Context, wrappedPayload
programValue, err := strconv.ParseUint(programBuffer.String(), 10, 8) programValue, err := strconv.ParseUint(programBuffer.String(), 10, 8)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
payloadMessage := midi.ProgramChange(uint8(channelValue), uint8(programValue)) payloadMessage := midi.ProgramChange(uint8(channelValue), uint8(programValue))
wrappedPayload.Payload = payloadMessage wrappedPayload.Payload = payloadMessage
return wrappedPayload, nil return wrappedPayload, nil
+6 -2
View File
@@ -32,9 +32,13 @@ func (sj *ScriptJS) Process(ctx context.Context, wrappedPayload common.WrappedPa
} }
} }
sj.vm.SetProperty(sj.vm.GlobalObject(), sj.payloadAtom, wrappedPayload.Payload) err := sj.vm.SetProperty(sj.vm.GlobalObject(), sj.payloadAtom, wrappedPayload.Payload)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
_, err := sj.vm.Eval(sj.Program, quickjs.EvalGlobal) _, err = sj.vm.Eval(sj.Program, quickjs.EvalGlobal)
if err != nil { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
+9 -10
View File
@@ -14,7 +14,7 @@ import (
type ScriptWASM struct { type ScriptWASM struct {
config config.ProcessorConfig config config.ProcessorConfig
Program *extism.CompiledPlugin Program *extism.Plugin
Function string Function string
} }
@@ -28,14 +28,7 @@ func (sw *ScriptWASM) Process(ctx context.Context, wrappedPayload common.Wrapped
return wrappedPayload, fmt.Errorf("script.wasm can only process a byte array") return wrappedPayload, fmt.Errorf("script.wasm can only process a byte array")
} }
program, err := sw.Program.Instance(ctx, extism.PluginInstanceConfig{}) _, output, err := sw.Program.Call(sw.Function, payloadBytes)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
_, output, err := program.Call(sw.Function, payloadBytes)
if err != nil { if err != nil {
wrappedPayload.End = true wrappedPayload.End = true
@@ -117,7 +110,13 @@ func init() {
return nil, err return nil, err
} }
return &ScriptWASM{config: processorConfig, Program: program, Function: functionString}, nil programInstance, err := program.Instance(context.Background(), extism.PluginInstanceConfig{})
if err != nil {
return nil, err
}
return &ScriptWASM{config: processorConfig, Program: programInstance, Function: functionString}, nil
}, },
}) })
} }
@@ -41,7 +41,7 @@ func TestGoodArtnetPacketDecode(t *testing.T) {
name: "number", name: "number",
payload: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, payload: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
expected: &artnet.ArtDmx{ expected: &artnet.ArtDmx{
ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpDmx, OpCode: artnet.OpDmx,
ProtVerHi: 0, ProtVerHi: 0,
ProtVerLo: 14, ProtVerLo: 14,
@@ -49,7 +49,6 @@ func TestGoodArtnetPacketDecode(t *testing.T) {
Physical: 0, Physical: 0,
SubUni: 1, SubUni: 1,
Net: 0, Net: 0,
Length: 512,
Data: make([]uint8, 512), Data: make([]uint8, 512),
}, },
}, },
@@ -106,3 +105,15 @@ func TestBadArtnetPacketDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkArtnetPacketDecode(b *testing.B) {
processorInstance := processor.ArtNetPacketDecode{}
payload := []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("artnet.packet.decode processing failed: %s", err)
}
}
}
@@ -41,7 +41,7 @@ func TestGoodArtnetPacketEncode(t *testing.T) {
name: "number", name: "number",
expected: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, expected: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
payload: &artnet.ArtDmx{ payload: &artnet.ArtDmx{
ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpDmx, OpCode: artnet.OpDmx,
ProtVerHi: 0, ProtVerHi: 0,
ProtVerLo: 14, ProtVerLo: 14,
@@ -49,7 +49,6 @@ func TestGoodArtnetPacketEncode(t *testing.T) {
Physical: 0, Physical: 0,
SubUni: 1, SubUni: 1,
Net: 0, Net: 0,
Length: 512,
Data: make([]uint8, 512), Data: make([]uint8, 512),
}, },
}, },
@@ -101,3 +100,25 @@ func TestBadArtnetPacketEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkArtnetPacketEncode(b *testing.B) {
processorInstance := processor.ArtNetPacketEncode{}
payload := &artnet.ArtDmx{
ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00},
OpCode: artnet.OpDmx,
ProtVerHi: 0,
ProtVerLo: 14,
Sequence: 237,
Physical: 0,
SubUni: 1,
Net: 0,
Data: make([]uint8, 512),
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("artnet.packet.encode processing failed: %s", err)
}
}
}
+29
View File
@@ -301,3 +301,32 @@ func TestBadDbQuery(t *testing.T) {
}) })
} }
} }
func BenchmarkDbQuery(b *testing.B) {
registration, ok := processor.ProcessorRegistry["db.query"]
if !ok {
b.Fatalf("db.query processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "db.query",
Params: map[string]any{
"module": "test",
"query": "SELECT * FROM test;",
},
})
if err != nil {
b.Fatalf("db.query failed to create processor: %s", err)
}
modules := map[string]common.Module{
"test": test.NewTestDBModule("test"),
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: nil, Modules: modules})
if err != nil {
b.Fatalf("db.query processing failed: %s", err)
}
}
}
+26
View File
@@ -118,3 +118,29 @@ func TestBadDebugLog(t *testing.T) {
}) })
} }
} }
func BenchmarkDebugLog(b *testing.B) {
registration, ok := processor.ProcessorRegistry["debug.log"]
if !ok {
b.Fatalf("debug.log processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "debug.log",
Params: nil,
})
if err != nil {
b.Fatalf("debug.log failed to create processor: %s", err)
}
modules := map[string]common.Module{}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count, Modules: modules})
if err != nil {
b.Fatalf("debug.log processing failed: %s", err)
}
count++
}
}
@@ -124,3 +124,29 @@ func TestBadFilterChange(t *testing.T) {
}) })
} }
} }
func BenchmarkFilterChange(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.change"]
if !ok {
b.Fatalf("filter.change processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.change",
Params: nil,
})
if err != nil {
b.Fatalf("filter.change failed to create processor: %s", err)
}
modules := map[string]common.Module{}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count, Modules: modules})
if err != nil {
b.Fatalf("filter.change processing failed: %s", err)
}
count++
}
}
@@ -171,3 +171,30 @@ func TestBadFilterExpr(t *testing.T) {
}) })
} }
} }
func BenchmarkFilterExpr(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.expr"]
if !ok {
b.Fatalf("filter.expr processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.expr",
Params: map[string]any{
"expression": "Payload % 2 == 0",
},
})
if err != nil {
b.Fatalf("filter.expr failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("filter.expr processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/common"
@@ -173,3 +174,30 @@ func TestBadFilterRegex(t *testing.T) {
}) })
} }
} }
func BenchmarkFilterRegex(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.regex"]
if !ok {
b.Fatalf("filter.regex processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.regex",
Params: map[string]any{
"pattern": ".*",
},
})
if err != nil {
b.Fatalf("filter.regex failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("%d", count)})
if err != nil {
b.Fatalf("filter.regex processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/common"
@@ -164,3 +165,28 @@ func TestBadFloatParse(t *testing.T) {
}) })
} }
} }
func BenchmarkFloatParse(b *testing.B) {
registration, ok := processor.ProcessorRegistry["float.parse"]
if !ok {
b.Fatalf("float.parse processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "float.parse",
Params: nil,
})
if err != nil {
b.Fatalf("float.parse failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("%d", count)})
if err != nil {
b.Fatalf("float.parse processing failed: %s", err)
}
count++
}
}
@@ -184,3 +184,29 @@ func TestBadFloatRandom(t *testing.T) {
}) })
} }
} }
func BenchmarkFloatRandom(b *testing.B) {
registration, ok := processor.ProcessorRegistry["float.random"]
if !ok {
b.Fatalf("float.random processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "float.random",
Params: map[string]any{
"min": 0.0,
"max": 1.0,
},
})
if err != nil {
b.Fatalf("float.random failed to create processor: %s", err)
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: nil})
if err != nil {
b.Fatalf("float.random processing failed: %s", err)
}
}
}
@@ -877,3 +877,38 @@ func TestBadFreeDCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkFreeDCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["freed.create"]
if !ok {
b.Fatalf("freed.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "freed.create",
Params: map[string]any{
"id": "0",
"pan": "0",
"tilt": "0",
"roll": "0",
"posX": "0",
"posY": "0",
"posZ": "0",
"zoom": "0",
"focus": "0",
},
})
if err != nil {
b.Fatalf("freed.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("freed.create processing failed: %s", err)
}
count++
}
}
@@ -102,3 +102,17 @@ func TestBadFreeDDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkFreeDDecode(b *testing.B) {
processorInstance := processor.FreeDDecode{}
payload := []byte{0xd1, 0x01, 0x5a, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x7f, 0xff, 0x40, 0x7f, 0xff, 0x80, 0x7f, 0xff,
0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 50,
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("freed.encode processing failed: %s", err)
}
}
}
@@ -102,3 +102,25 @@ func TestBadFreeDEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkFreeDEncode(b *testing.B) {
processorInstance := processor.FreeDEncode{}
payload := freeD.FreeDPosition{
ID: 1,
Pan: 180,
Tilt: 90,
Roll: -180,
PosX: 131069,
PosY: 131070,
PosZ: 131071,
Zoom: 66051,
Focus: 263430,
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("freed.encode processing failed: %s", err)
}
}
}
@@ -157,3 +157,31 @@ func TestBadHTTPResponseCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkHTTPResponseCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["http.response.create"]
if !ok {
b.Fatalf("http.response.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "http.response.create",
Params: map[string]any{
"status": 200,
"bodyTemplate": "Hello, {{.Payload}}!",
},
})
if err != nil {
b.Fatalf("http.response.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("http.response.create processing failed: %s", err)
}
count++
}
}
+26
View File
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/common"
@@ -198,3 +199,28 @@ func TestBadIntParse(t *testing.T) {
}) })
} }
} }
func BenchmarkIntParse(b *testing.B) {
registration, ok := processor.ProcessorRegistry["int.parse"]
if !ok {
b.Fatalf("int.parse processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.parse",
Params: nil,
})
if err != nil {
b.Fatalf("int.parse failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("%d", count)})
if err != nil {
b.Fatalf("int.parse processing failed: %s", err)
}
count++
}
}
@@ -195,3 +195,29 @@ func TestBadIntRandom(t *testing.T) {
}) })
} }
} }
func BenchmarkIntRandom(b *testing.B) {
registration, ok := processor.ProcessorRegistry["int.random"]
if !ok {
b.Fatalf("int.random processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.random",
Params: map[string]any{
"min": 0,
"max": 100,
},
})
if err != nil {
b.Fatalf("int.random failed to create processor: %s", err)
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: nil})
if err != nil {
b.Fatalf("int.random processing failed: %s", err)
}
}
}
+30
View File
@@ -169,3 +169,33 @@ func TestBadIntScale(t *testing.T) {
}) })
} }
} }
func BenchmarkIntScale(b *testing.B) {
registration, ok := processor.ProcessorRegistry["int.scale"]
if !ok {
b.Fatalf("int.scale processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "int.scale",
Params: map[string]any{
"inMin": 0,
"inMax": 100,
"outMin": 0,
"outMax": 127,
},
})
if err != nil {
b.Fatalf("int.scale failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count % 100})
if err != nil {
b.Fatalf("int.scale processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
@@ -124,3 +125,27 @@ func TestBadJsonDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkJsonDecode(b *testing.B) {
registration, ok := processor.ProcessorRegistry["json.decode"]
if !ok {
b.Fatalf("json.decode processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "json.decode",
})
if err != nil {
b.Fatalf("json.decode failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: []byte(fmt.Sprintf("{\"key\":%d}", count))})
if err != nil {
b.Fatalf("json.decode processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"slices" "slices"
"testing" "testing"
@@ -113,3 +114,27 @@ func TestBadJsonEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkJsonEncode(b *testing.B) {
registration, ok := processor.ProcessorRegistry["json.encode"]
if !ok {
b.Fatalf("json.encode processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "json.encode",
})
if err != nil {
b.Fatalf("json.encode failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("{\"key\":%d}", count)})
if err != nil {
b.Fatalf("json.encode processing failed: %s", err)
}
count++
}
}
+30 -12
View File
@@ -58,21 +58,10 @@ func TestGoodKvGet(t *testing.T) {
expected any expected any
}{ }{
{ {
name: "basic value", name: "basic key",
params: map[string]any{ params: map[string]any{
"module": "test", "module": "test",
"key": "test", "key": "test",
"value": "hello",
},
payload: "hello",
expected: "test",
},
{
name: "template value",
params: map[string]any{
"module": "test",
"key": "test",
"value": "{{.Payload}}",
}, },
payload: "hello", payload: "hello",
expected: "test", expected: "test",
@@ -232,3 +221,32 @@ func TestBadKvGet(t *testing.T) {
}) })
} }
} }
func BenchmarkKvGet(b *testing.B) {
registration, ok := processor.ProcessorRegistry["kv.get"]
if !ok {
b.Fatalf("kv.get processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "kv.get",
Params: map[string]any{
"module": "test",
"key": "test",
},
})
if err != nil {
b.Fatalf("kv.get failed to create processor: %s", err)
}
modules := map[string]common.Module{
"test": test.NewTestKVModule("test"),
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: nil, Modules: modules})
if err != nil {
b.Fatalf("kv.get processing failed: %s", err)
}
}
}
+32
View File
@@ -281,3 +281,35 @@ func TestBadKvSet(t *testing.T) {
}) })
} }
} }
func BenchmarkKvSet(b *testing.B) {
registration, ok := processor.ProcessorRegistry["kv.set"]
if !ok {
b.Fatalf("kv.set processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "kv.set",
Params: map[string]any{
"module": "test",
"key": "test",
"value": "{{.Payload}}",
},
})
if err != nil {
b.Fatalf("kv.set failed to create processor: %s", err)
}
modules := map[string]common.Module{
"test": test.NewTestKVModule("test"),
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count, Modules: modules})
if err != nil {
b.Fatalf("kv.set processing failed: %s", err)
}
count++
}
}
@@ -159,3 +159,32 @@ func TestBadMIDIControlChangeCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDIControlChangeCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["midi.control_change.create"]
if !ok {
b.Fatalf("midi.control_change.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.control_change.create",
Params: map[string]any{
"channel": "1",
"control": "64",
"value": "127",
},
})
if err != nil {
b.Fatalf("midi.control_change.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("midi.control_change.create processing failed: %s", err)
}
count++
}
}
@@ -91,3 +91,15 @@ func TestBadMIDIMessageDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDIMessageDecode(b *testing.B) {
processorInstance := processor.MIDIMessageDecode{}
payload := []byte{0x90, 0x40, 0x7F}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("midi.message.decode processing failed: %s", err)
}
}
}
@@ -89,3 +89,15 @@ func TestBadMIDIMessageEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDIMessageEncode(b *testing.B) {
processorInstance := processor.MIDIMessageEncode{}
payload := midi.NoteOn(1, 60, 127)
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("midi.message.encode processing failed: %s", err)
}
}
}
@@ -150,3 +150,15 @@ func TestBadMIDIMessageUnpack(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDIMessageUnpack(b *testing.B) {
processorInstance := processor.MIDIMessageUnpack{}
payload := midi.NoteOn(1, 60, 127)
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("midi.message.unpack processing failed: %s", err)
}
}
}
@@ -158,3 +158,32 @@ func TestBadMIDINoteOffCretea(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDINoteOffCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["midi.note_off.create"]
if !ok {
b.Fatalf("midi.note_off.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.note_off.create",
Params: map[string]any{
"channel": "1",
"note": "60",
"velocity": "100",
},
})
if err != nil {
b.Fatalf("midi.note_off.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("midi.note_off.create processing failed: %s", err)
}
count++
}
}
@@ -155,3 +155,32 @@ func TestBadMIDINoteOnCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDINoteOnCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["midi.note_on.create"]
if !ok {
b.Fatalf("midi.note_on.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.note_on.create",
Params: map[string]any{
"channel": "1",
"note": "60",
"velocity": "100",
},
})
if err != nil {
b.Fatalf("midi.note_on.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("midi.note_off.create processing failed: %s", err)
}
count++
}
}
@@ -145,3 +145,31 @@ func TestBadMIDIProgramChangeCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkMIDIProgramChangeCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["midi.program_change.create"]
if !ok {
b.Fatalf("midi.program_change.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "midi.program_change.create",
Params: map[string]any{
"channel": "1",
"program": "60",
},
})
if err != nil {
b.Fatalf("midi.program_change.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("midi.program_change.create processing failed: %s", err)
}
count++
}
}
@@ -240,3 +240,33 @@ func TestBadMQTTMessageCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkMQTTMessageCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["mqtt.message.create"]
if !ok {
b.Fatalf("mqtt.message.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "mqtt.message.create",
Params: map[string]any{
"topic": "test/topic",
"qos": 1,
"retained": true,
"payload": "{{.Payload}}",
},
})
if err != nil {
b.Fatalf("mqtt.message.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("mqtt.message.create processing failed: %s", err)
}
count++
}
}
@@ -208,3 +208,31 @@ func TestBadNATSMessageCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkNATSMessageCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["nats.message.create"]
if !ok {
b.Fatalf("nats.message.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "nats.message.create",
Params: map[string]any{
"subject": "test.subject",
"payload": "{{.Payload}}",
},
})
if err != nil {
b.Fatalf("nats.message.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("nats.message.create processing failed: %s", err)
}
count++
}
}
@@ -400,3 +400,32 @@ func TestBadOSCMessageCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkOSCMessageCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["osc.message.create"]
if !ok {
b.Fatalf("osc.message.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "osc.message.create",
Params: map[string]any{
"address": "/hello",
"args": []any{"{{.Payload}}"},
"types": "i",
},
})
if err != nil {
b.Fatalf("osc.message.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("osc.message.create processing failed: %s", err)
}
count++
}
}
@@ -121,3 +121,15 @@ func TestBadOSCMessageDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkOSCMessageDecode(b *testing.B) {
processorInstance := processor.OSCMessageDecode{}
payload := []byte{47, 116, 101, 115, 116, 0, 0, 0, 44, 105, 0, 0, 0, 0, 0, 42}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("osc.message.decode processing failed: %s", err)
}
}
}
@@ -112,3 +112,23 @@ func TestBadOSCMessageEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkOSCMessageEncode(b *testing.B) {
processorInstance := processor.OSCMessageEncode{}
payload := &osc.OSCMessage{
Address: "/test",
Args: []osc.OSCArg{
{
Type: "i",
Value: int32(42),
},
},
}
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: payload})
if err != nil {
b.Fatalf("osc.message.encode processing failed: %s", err)
}
}
}
@@ -146,3 +146,30 @@ func TestBadScriptExpr(t *testing.T) {
}) })
} }
} }
func BenchmarkScriptExpr(b *testing.B) {
registration, ok := processor.ProcessorRegistry["script.expr"]
if !ok {
b.Fatalf("script.expr processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.expr",
Params: map[string]any{
"expression": "Payload % 2",
},
})
if err != nil {
b.Fatalf("script.expr failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("script.expr processing failed: %s", err)
}
count++
}
}
+34
View File
@@ -209,6 +209,13 @@ func TestBadScriptJS(t *testing.T) {
Params: test.params, Params: test.params,
}) })
if err != nil {
if test.errorString != err.Error() {
t.Fatalf("script.js got error '%s', expected '%s'", err.Error(), test.errorString)
}
return
}
got, err := processorInstance.Process(t.Context(), common.WrappedPayload{Payload: test.payload}) got, err := processorInstance.Process(t.Context(), common.WrappedPayload{Payload: test.payload})
if err == nil { if err == nil {
@@ -221,3 +228,30 @@ func TestBadScriptJS(t *testing.T) {
}) })
} }
} }
func BenchmarkScriptJS(b *testing.B) {
registration, ok := processor.ProcessorRegistry["script.js"]
if !ok {
b.Fatalf("script.js processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.js",
Params: map[string]any{
"program": "payload = payload + 1",
},
})
if err != nil {
b.Fatalf("script.js failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("script.js processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
@@ -188,3 +189,30 @@ func TestBadScriptWASM(t *testing.T) {
}) })
} }
} }
func BenchmarkScriptWASM(b *testing.B) {
registration, ok := processor.ProcessorRegistry["script.wasm"]
if !ok {
b.Fatalf("script.wasm processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "script.wasm",
Params: map[string]any{
"path": "good.wasm",
},
})
if err != nil {
b.Fatalf("script.wasm failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: []byte(fmt.Sprintf("%d", count))})
if err != nil {
b.Fatalf("script.wasm processing failed: %s", err)
}
count++
}
}
@@ -212,3 +212,32 @@ func TestBadSipResponseAudioCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkSipResponseAudioCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["sip.response.audio.create"]
if !ok {
b.Fatalf("sip.response.audio.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "sip.response.audio.create",
Params: map[string]any{
"preWait": 0,
"audioFile": "good.wav",
"postWait": 0,
},
})
if err != nil {
b.Fatalf("sip.response.audio.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("sip.response.audio.create processing failed: %s", err)
}
count++
}
}
@@ -220,3 +220,32 @@ func TestBadSipResponseDTMFCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkSipResponseDTMFCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["sip.response.dtmf.create"]
if !ok {
b.Fatalf("sip.response.dtmf.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "sip.response.dtmf.create",
Params: map[string]any{
"preWait": 0,
"digits": "{{.Payload}}",
"postWait": 0,
},
})
if err != nil {
b.Fatalf("sip.response.dtmf.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("sip.response.dtmf.create processing failed: %s", err)
}
count++
}
}
@@ -186,3 +186,30 @@ func TestBadStringCreate(t *testing.T) {
}) })
} }
} }
func BenchmarkStringCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["string.create"]
if !ok {
b.Fatalf("string.create processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.create",
Params: map[string]any{
"template": "{{.Payload}}",
},
})
if err != nil {
b.Fatalf("string.create failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: count})
if err != nil {
b.Fatalf("string.create processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"testing" "testing"
"github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/common"
@@ -98,3 +99,27 @@ func TestBadStringDecode(t *testing.T) {
}) })
} }
} }
func BenchmarkStringDecode(b *testing.B) {
registration, ok := processor.ProcessorRegistry["string.decode"]
if !ok {
b.Fatalf("string.decode processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.decode",
})
if err != nil {
b.Fatalf("string.decode failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: []byte(fmt.Sprintf("%d", count))})
if err != nil {
b.Fatalf("string.decode processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"slices" "slices"
"testing" "testing"
@@ -104,3 +105,27 @@ func TestBadStringEncode(t *testing.T) {
}) })
} }
} }
func BenchmarkStringEncode(b *testing.B) {
registration, ok := processor.ProcessorRegistry["string.encode"]
if !ok {
b.Fatalf("string.encode processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.encode",
})
if err != nil {
b.Fatalf("string.encode failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("%d", count)})
if err != nil {
b.Fatalf("string.encode processing failed: %s", err)
}
count++
}
}
@@ -1,6 +1,7 @@
package processor_test package processor_test
import ( import (
"fmt"
"slices" "slices"
"testing" "testing"
@@ -153,3 +154,30 @@ func TestBadStringSplit(t *testing.T) {
}) })
} }
} }
func BenchmarkStringSplit(b *testing.B) {
registration, ok := processor.ProcessorRegistry["string.split"]
if !ok {
b.Fatalf("string.split processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "string.split",
Params: map[string]any{
"separator": ",",
},
})
if err != nil {
b.Fatalf("string.split failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: fmt.Sprintf("%d,%d,%d", count, count, count)})
if err != nil {
b.Fatalf("string.split processing failed: %s", err)
}
count++
}
}
@@ -191,3 +191,30 @@ func TestBadStructFieldGet(t *testing.T) {
}) })
} }
} }
func BenchmarkStructFieldGet(b *testing.B) {
registration, ok := processor.ProcessorRegistry["struct.field.get"]
if !ok {
b.Fatalf("struct.field.get processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "struct.field.get",
Params: map[string]any{
"name": "Data",
},
})
if err != nil {
b.Fatalf("struct.field.get failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: test.TestStruct{Data: count}})
if err != nil {
b.Fatalf("struct.field.get processing failed: %s", err)
}
count++
}
}
@@ -216,3 +216,30 @@ func TestBadStructMethodGet(t *testing.T) {
}) })
} }
} }
func BenchmarkStructMethodGet(b *testing.B) {
registration, ok := processor.ProcessorRegistry["struct.method.get"]
if !ok {
b.Fatalf("struct.method.get processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "struct.method.get",
Params: map[string]any{
"name": "GetData",
},
})
if err != nil {
b.Fatalf("struct.method.get failed to create processor: %s", err)
}
count := 0
for b.Loop() {
_, err := processorInstance.Process(b.Context(), common.WrappedPayload{Payload: test.TestStruct{Data: count}})
if err != nil {
b.Fatalf("struct.method.get processing failed: %s", err)
}
count++
}
}
+10 -4
View File
@@ -79,11 +79,14 @@ func (m *TestDBModule) Start(ctx context.Context, router common.RouteIO) error {
return nil return nil
} }
func (m *TestDBModule) Database() *sql.DB { func (m *TestDBModule) Database() (*sql.DB, error) {
if m.db == nil { if m.db == nil {
db, _ := sql.Open("sqlite", ":memory:") db, err := sql.Open("sqlite", ":memory:")
if err != nil {
return nil, err
}
db.Exec(` _, err = db.Exec(`
CREATE TABLE test ( CREATE TABLE test (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
value TEXT value TEXT
@@ -91,9 +94,12 @@ func (m *TestDBModule) Database() *sql.DB {
INSERT INTO test (id, value) VALUES (1, 'test-1'), (2, 'test-2'); INSERT INTO test (id, value) VALUES (1, 'test-1'), (2, 'test-2');
`) `)
if err != nil {
return nil, err
}
m.db = db m.db = db
} }
return m.db return m.db, nil
} }
func (m *TestDBModule) Stop() {} func (m *TestDBModule) Stop() {}