Compare commits

...

110 Commits

Author SHA1 Message Date
Joel Wetzell 92c661354c add id field to route and processor 2026-08-11 20:39:54 -05:00
Joel Wetzell c07ce2de73 Merge pull request #214 from jwetzell/dependabot/go_modules/modernc.org/quickjs-0.23.0
Bump modernc.org/quickjs from 0.22.0 to 0.23.0
2026-08-11 20:07:38 -05:00
dependabot[bot] 2a2fd04b78 Bump modernc.org/quickjs from 0.22.0 to 0.23.0
Bumps [modernc.org/quickjs](https://gitlab.com/cznic/quickjs) from 0.22.0 to 0.23.0.
- [Commits](https://gitlab.com/cznic/quickjs/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: modernc.org/quickjs
  dependency-version: 0.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-12 01:05:15 +00:00
Joel Wetzell ad01ba62bb Merge pull request #215 from jwetzell/dependabot/go_modules/github.com/redis/go-redis/v9-9.22.0
Bump github.com/redis/go-redis/v9 from 9.21.0 to 9.22.0
2026-08-11 20:03:38 -05:00
Joel Wetzell c20bd9d448 Merge pull request #216 from jwetzell/dependabot/go_modules/modernc.org/sqlite-1.56.0
Bump modernc.org/sqlite from 1.55.0 to 1.56.0
2026-08-11 20:03:27 -05:00
Joel Wetzell 8f681b0cb6 Merge pull request #217 from jwetzell/fix/mqtt-client-locking
fix lock releasing in mqtt client on error
2026-08-11 20:02:58 -05:00
Joel Wetzell 7c0a504616 fix lock releasing in mqtt client on error 2026-08-11 19:58:33 -05:00
dependabot[bot] 9af0991a0d Bump modernc.org/sqlite from 1.55.0 to 1.56.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.55.0 to 1.56.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.55.0...v1.56.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.56.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-11 17:23:58 +00:00
dependabot[bot] b22fdbe6ef Bump github.com/redis/go-redis/v9 from 9.21.0 to 9.22.0
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.21.0 to 9.22.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.21.0...v9.22.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-11 17:23:51 +00:00
Joel Wetzell a1f7bca743 Merge pull request #212 from jwetzell/dependabot/github_actions/docker/login-action-4.6.0
Bump docker/login-action from 4.5.2 to 4.6.0
2026-08-04 14:28:35 -05:00
Joel Wetzell dbb1fed79f Merge pull request #213 from jwetzell/dependabot/go_modules/github.com/nats-io/nats-server/v2-2.14.4
Bump github.com/nats-io/nats-server/v2 from 2.14.3 to 2.14.4
2026-08-04 14:28:25 -05:00
dependabot[bot] c4e338a517 Bump github.com/nats-io/nats-server/v2 from 2.14.3 to 2.14.4
Bumps [github.com/nats-io/nats-server/v2](https://github.com/nats-io/nats-server) from 2.14.3 to 2.14.4.
- [Release notes](https://github.com/nats-io/nats-server/releases)
- [Changelog](https://github.com/nats-io/nats-server/blob/main/RELEASES.md)
- [Commits](https://github.com/nats-io/nats-server/compare/v2.14.3...v2.14.4)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats-server/v2
  dependency-version: 2.14.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-04 17:23:29 +00:00
dependabot[bot] eddeb4655b Bump docker/login-action from 4.5.2 to 4.6.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.5.2 to 4.6.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/371161bbe7024a29a25c5e19bfcbc0804fe9ad2c...dbcb813823bdd20940b903addbd779551569679f)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-04 17:23:20 +00:00
Joel Wetzell 4f34de7fa8 Merge pull request #207 from jwetzell/dependabot/go_modules/go.bug.st/serial-1.8.0
Bump go.bug.st/serial from 1.7.1 to 1.8.0
2026-07-29 08:32:53 -05:00
dependabot[bot] e47a5fff5f Bump go.bug.st/serial from 1.7.1 to 1.8.0
Bumps [go.bug.st/serial](https://github.com/bugst/go-serial) from 1.7.1 to 1.8.0.
- [Release notes](https://github.com/bugst/go-serial/releases)
- [Commits](https://github.com/bugst/go-serial/compare/v1.7.1...v1.8.0)

---
updated-dependencies:
- dependency-name: go.bug.st/serial
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 13:17:39 +00:00
Joel Wetzell a1aa80c9ee Merge pull request #208 from jwetzell/dependabot/go_modules/modernc.org/sqlite-1.54.0
Bump modernc.org/sqlite from 1.53.0 to 1.55.0
2026-07-29 08:15:27 -05:00
Joel Wetzell d926bd3f7d Merge pull request #206 from jwetzell/dependabot/github_actions/actions/setup-go-7
Bump actions/setup-go from 6 to 7
2026-07-29 08:02:54 -05:00
Joel Wetzell aee67547cf Merge pull request #209 from jwetzell/dependabot/github_actions/docker/login-action-4.5.2
Bump docker/login-action from 4.4.0 to 4.5.2
2026-07-29 08:02:30 -05:00
dependabot[bot] 5e2c85244f Bump modernc.org/sqlite from 1.53.0 to 1.55.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.53.0 to 1.55.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.53.0...v1.55.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 13:02:20 +00:00
Joel Wetzell f314fed2d9 Merge pull request #210 from jwetzell/dependabot/go_modules/github.com/emiago/diago-0.31.0
Bump github.com/emiago/diago from 0.30.0 to 0.31.0
2026-07-29 08:02:04 -05:00
Joel Wetzell 32deb2032b Merge pull request #211 from jwetzell/dependabot/go_modules/modernc.org/quickjs-0.22.0
Bump modernc.org/quickjs from 0.21.0 to 0.22.0
2026-07-29 08:00:24 -05:00
dependabot[bot] 6852a3e917 Bump modernc.org/quickjs from 0.21.0 to 0.22.0
Bumps [modernc.org/quickjs](https://gitlab.com/cznic/quickjs) from 0.21.0 to 0.22.0.
- [Commits](https://gitlab.com/cznic/quickjs/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: modernc.org/quickjs
  dependency-version: 0.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 17:23:41 +00:00
dependabot[bot] 2874f2c7ff Bump github.com/emiago/diago from 0.30.0 to 0.31.0
Bumps [github.com/emiago/diago](https://github.com/emiago/diago) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/emiago/diago/releases)
- [Commits](https://github.com/emiago/diago/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: github.com/emiago/diago
  dependency-version: 0.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 17:23:33 +00:00
dependabot[bot] a9f35fa4f7 Bump docker/login-action from 4.4.0 to 4.5.2
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.4.0 to 4.5.2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/af1e73f918a031802d376d3c8bbc3fe56130a9b0...371161bbe7024a29a25c5e19bfcbc0804fe9ad2c)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.5.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 17:23:28 +00:00
dependabot[bot] 5aa9961742 Bump actions/setup-go from 6 to 7
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-21 17:23:15 +00:00
Joel Wetzell 4914db403e Merge pull request #205 from jwetzell/dependabot/go_modules/github.com/emiago/diago-0.30.0
Bump github.com/emiago/diago from 0.29.0 to 0.30.0
2026-07-18 13:16:27 -05:00
dependabot[bot] fd49fa2795 Bump github.com/emiago/diago from 0.29.0 to 0.30.0
Bumps [github.com/emiago/diago](https://github.com/emiago/diago) from 0.29.0 to 0.30.0.
- [Release notes](https://github.com/emiago/diago/releases)
- [Commits](https://github.com/emiago/diago/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: github.com/emiago/diago
  dependency-version: 0.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-14 17:23:39 +00:00
Joel Wetzell b86ca20592 syntax cleanup 2026-07-09 22:22:22 -05:00
Joel Wetzell 777f9c43de Merge pull request #196 from jwetzell/dependabot/go_modules/github.com/nats-io/nats-server/v2-2.14.3
Bump github.com/nats-io/nats-server/v2 from 2.14.2 to 2.14.3
2026-07-07 14:55:03 -05:00
dependabot[bot] 8ebbed482d Bump github.com/nats-io/nats-server/v2 from 2.14.2 to 2.14.3
Bumps [github.com/nats-io/nats-server/v2](https://github.com/nats-io/nats-server) from 2.14.2 to 2.14.3.
- [Release notes](https://github.com/nats-io/nats-server/releases)
- [Changelog](https://github.com/nats-io/nats-server/blob/main/RELEASES.md)
- [Commits](https://github.com/nats-io/nats-server/compare/v2.14.2...v2.14.3)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats-server/v2
  dependency-version: 2.14.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 19:28:50 +00:00
Joel Wetzell 27ef3f7766 Merge pull request #201 from jwetzell/dependabot/go_modules/github.com/emiago/sipgo-1.4.3
Bump github.com/emiago/sipgo from 1.4.0 to 1.4.3
2026-07-07 14:28:46 -05:00
Joel Wetzell 2b71829d47 Merge pull request #198 from jwetzell/dependabot/github_actions/docker/setup-buildx-action-4.2.0
Bump docker/setup-buildx-action from 4.1.0 to 4.2.0
2026-07-07 14:28:29 -05:00
Joel Wetzell cf1dcd305f Merge pull request #197 from jwetzell/dependabot/github_actions/docker/setup-qemu-action-4.2.0
Bump docker/setup-qemu-action from 4.1.0 to 4.2.0
2026-07-07 14:27:35 -05:00
Joel Wetzell 2c05549edb Merge pull request #194 from jwetzell/dependabot/go_modules/github.com/urfave/cli/v3-3.10.1
Bump github.com/urfave/cli/v3 from 3.10.0 to 3.10.1
2026-07-07 14:27:19 -05:00
Joel Wetzell 10fc3584e1 Merge pull request #199 from jwetzell/dependabot/github_actions/docker/metadata-action-6.2.0
Bump docker/metadata-action from 6.1.0 to 6.2.0
2026-07-07 14:27:02 -05:00
Joel Wetzell 0b26835eb6 Merge pull request #200 from jwetzell/dependabot/github_actions/docker/build-push-action-7.3.0
Bump docker/build-push-action from 7.2.0 to 7.3.0
2026-07-07 14:26:40 -05:00
Joel Wetzell c47f6fedff Merge pull request #202 from jwetzell/dependabot/github_actions/docker/login-action-4.4.0
Bump docker/login-action from 4.2.0 to 4.4.0
2026-07-07 14:26:27 -05:00
Joel Wetzell 250e0f2b0b Merge pull request #203 from jwetzell/dependabot/go_modules/modernc.org/quickjs-0.21.0
Bump modernc.org/quickjs from 0.18.2 to 0.21.0
2026-07-07 14:26:17 -05:00
dependabot[bot] e02ddf4255 Bump modernc.org/quickjs from 0.18.2 to 0.21.0
Bumps [modernc.org/quickjs](https://gitlab.com/cznic/quickjs) from 0.18.2 to 0.21.0.
- [Commits](https://gitlab.com/cznic/quickjs/compare/v0.18.2...v0.21.0)

---
updated-dependencies:
- dependency-name: modernc.org/quickjs
  dependency-version: 0.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:54 +00:00
dependabot[bot] 5c8ab7a2db Bump github.com/emiago/sipgo from 1.4.0 to 1.4.3
Bumps [github.com/emiago/sipgo](https://github.com/emiago/sipgo) from 1.4.0 to 1.4.3.
- [Release notes](https://github.com/emiago/sipgo/releases)
- [Commits](https://github.com/emiago/sipgo/compare/v1.4.0...v1.4.3)

---
updated-dependencies:
- dependency-name: github.com/emiago/sipgo
  dependency-version: 1.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:46 +00:00
dependabot[bot] 58edcff9b4 Bump docker/login-action from 4.2.0 to 4.4.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.2.0 to 4.4.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/650006c6eb7dba73a995cc03b0b2d7f5ca915bee...af1e73f918a031802d376d3c8bbc3fe56130a9b0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:46 +00:00
dependabot[bot] 74dbb26911 Bump docker/build-push-action from 7.2.0 to 7.3.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.2.0 to 7.3.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/f9f3042f7e2789586610d6e8b85c8f03e5195baf...53b7df96c91f9c12dcc8a07bcb9ccacbed38856a)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:42 +00:00
dependabot[bot] ccc1b4ac34 Bump docker/metadata-action from 6.1.0 to 6.2.0
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9...dc802804100637a589fabce1cb79ff13a1411302)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:36 +00:00
dependabot[bot] 7e95b52774 Bump docker/setup-buildx-action from 4.1.0 to 4.2.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5...bb05f3f5519dd87d3ba754cc423b652a5edd6d2c)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:32 +00:00
dependabot[bot] 4eb78fa719 Bump docker/setup-qemu-action from 4.1.0 to 4.2.0
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/06116385d9baf250c9f4dcb4858b16962ea869c3...96fe6ef7f33517b61c61be40b68a1882f3264fb8)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-07 17:23:29 +00:00
dependabot[bot] 66d30e9faf Bump github.com/urfave/cli/v3 from 3.10.0 to 3.10.1
Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v3.10.0...v3.10.1)

---
updated-dependencies:
- dependency-name: github.com/urfave/cli/v3
  dependency-version: 3.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-30 17:23:18 +00:00
Joel Wetzell 04ba102768 Merge pull request #191 from jwetzell/dependabot/github_actions/actions/checkout-7
Bump actions/checkout from 6 to 7
2026-06-29 10:26:10 -05:00
Joel Wetzell 49c1f90912 Merge pull request #192 from jwetzell/dependabot/go_modules/modernc.org/sqlite-1.53.0
Bump modernc.org/sqlite from 1.52.0 to 1.53.0
2026-06-29 10:25:23 -05:00
Joel Wetzell 80c145a541 Merge pull request #193 from jwetzell/dependabot/go_modules/github.com/redis/go-redis/v9-9.21.0
Bump github.com/redis/go-redis/v9 from 9.20.1 to 9.21.0
2026-06-29 10:24:53 -05:00
dependabot[bot] 4119312e9d Bump github.com/redis/go-redis/v9 from 9.20.1 to 9.21.0
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.20.1 to 9.21.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.20.1...v9.21.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 17:23:52 +00:00
dependabot[bot] 5b6cfc6849 Bump modernc.org/sqlite from 1.52.0 to 1.53.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.52.0 to 1.53.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.52.0...v1.53.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 17:23:44 +00:00
dependabot[bot] c48ca01b6d Bump actions/checkout from 6 to 7
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 17:23:16 +00:00
Joel Wetzell c551499fc6 add test for common events 2026-06-21 13:09:09 -05:00
Joel Wetzell cf48d0e65e Merge pull request #188 from jwetzell/dependabot/go_modules/gitlab.com/gomidi/midi/v2-2.3.24
Bump gitlab.com/gomidi/midi/v2 from 2.3.23 to 2.3.24
2026-06-19 17:27:23 -05:00
Joel Wetzell e5578a4d5d Merge pull request #189 from jwetzell/dependabot/go_modules/github.com/redis/go-redis/v9-9.20.1
Bump github.com/redis/go-redis/v9 from 9.20.0 to 9.20.1
2026-06-19 17:26:18 -05:00
dependabot[bot] 83199650af Bump gitlab.com/gomidi/midi/v2 from 2.3.23 to 2.3.24
Bumps [gitlab.com/gomidi/midi/v2](https://gitlab.com/gomidi/midi) from 2.3.23 to 2.3.24.
- [Commits](https://gitlab.com/gomidi/midi/compare/v2.3.23...v2.3.24)

---
updated-dependencies:
- dependency-name: gitlab.com/gomidi/midi/v2
  dependency-version: 2.3.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-19 22:24:02 +00:00
dependabot[bot] fcbc96c63b Bump github.com/redis/go-redis/v9 from 9.20.0 to 9.20.1
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.20.0 to 9.20.1.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.20.0...v9.20.1)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.20.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-19 22:24:01 +00:00
Joel Wetzell fd4fbbd66d Merge pull request #190 from jwetzell/dependabot/go_modules/github.com/urfave/cli/v3-3.10.0
Bump github.com/urfave/cli/v3 from 3.9.0 to 3.10.0
2026-06-19 17:21:54 -05:00
dependabot[bot] 1dddec502f Bump github.com/urfave/cli/v3 from 3.9.0 to 3.10.0
Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v3.9.0...v3.10.0)

---
updated-dependencies:
- dependency-name: github.com/urfave/cli/v3
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-16 17:24:32 +00:00
Joel Wetzell 28e8e4f8c7 Merge pull request #186 from jwetzell/dependabot/go_modules/github.com/emiago/diago-0.29.0
Bump github.com/emiago/diago from 0.28.0 to 0.29.0
2026-06-14 15:31:50 -05:00
Joel Wetzell 34dd6a0d31 update with new return signature 2026-06-14 15:29:38 -05:00
Joel Wetzell 2af9f348e7 Merge pull request #187 from jwetzell/dependabot/go_modules/modernc.org/sqlite-1.52.0
Bump modernc.org/sqlite from 1.51.0 to 1.52.0
2026-06-10 11:34:34 -05:00
dependabot[bot] b207643f1c Bump modernc.org/sqlite from 1.51.0 to 1.52.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.51.0 to 1.52.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.51.0...v1.52.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-09 17:24:03 +00:00
dependabot[bot] ae100ec567 Bump github.com/emiago/diago from 0.28.0 to 0.29.0
Bumps [github.com/emiago/diago](https://github.com/emiago/diago) from 0.28.0 to 0.29.0.
- [Release notes](https://github.com/emiago/diago/releases)
- [Commits](https://github.com/emiago/diago/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: github.com/emiago/diago
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-09 17:23:52 +00:00
Joel Wetzell 05c027dca7 Merge pull request #181 from jwetzell/dependabot/github_actions/docker/setup-qemu-action-4.1.0
Bump docker/setup-qemu-action from 4.0.0 to 4.1.0
2026-06-07 21:13:10 -05:00
Joel Wetzell 6ef4215248 Merge pull request #182 from jwetzell/dependabot/go_modules/github.com/redis/go-redis/v9-9.20.0
Bump github.com/redis/go-redis/v9 from 9.19.0 to 9.20.0
2026-06-07 21:12:58 -05:00
Joel Wetzell ac51d9bd3d Merge pull request #183 from jwetzell/dependabot/go_modules/modernc.org/sqlite-1.51.0
Bump modernc.org/sqlite from 1.50.1 to 1.51.0
2026-06-07 21:12:42 -05:00
Joel Wetzell c01a101214 Merge pull request #184 from jwetzell/dependabot/go_modules/github.com/emiago/sipgo-1.4.0
Bump github.com/emiago/sipgo from 1.3.1 to 1.4.0
2026-06-07 21:12:22 -05:00
Joel Wetzell 7d401b9570 Merge pull request #185 from jwetzell/dependabot/go_modules/github.com/nats-io/nats-server/v2-2.14.2
Bump github.com/nats-io/nats-server/v2 from 2.14.1 to 2.14.2
2026-06-07 21:12:11 -05:00
dependabot[bot] 809c31847b Bump github.com/nats-io/nats-server/v2 from 2.14.1 to 2.14.2
Bumps [github.com/nats-io/nats-server/v2](https://github.com/nats-io/nats-server) from 2.14.1 to 2.14.2.
- [Release notes](https://github.com/nats-io/nats-server/releases)
- [Changelog](https://github.com/nats-io/nats-server/blob/main/RELEASES.md)
- [Commits](https://github.com/nats-io/nats-server/compare/v2.14.1...v2.14.2)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats-server/v2
  dependency-version: 2.14.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 00:43:00 +00:00
dependabot[bot] bdcf5a06ce Bump github.com/emiago/sipgo from 1.3.1 to 1.4.0
Bumps [github.com/emiago/sipgo](https://github.com/emiago/sipgo) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/emiago/sipgo/releases)
- [Commits](https://github.com/emiago/sipgo/compare/v1.3.1...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/emiago/sipgo
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 00:42:47 +00:00
dependabot[bot] 09a46d3634 Bump modernc.org/sqlite from 1.50.1 to 1.51.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.50.1 to 1.51.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.50.1...v1.51.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 00:42:42 +00:00
dependabot[bot] 7385f25b3d Bump github.com/redis/go-redis/v9 from 9.19.0 to 9.20.0
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.19.0 to 9.20.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.19.0...v9.20.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 00:42:37 +00:00
dependabot[bot] 94a59413a1 Bump docker/setup-qemu-action from 4.0.0 to 4.1.0
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/ce360397dd3f832beb865e1373c09c0e9f86d70a...06116385d9baf250c9f4dcb4858b16962ea869c3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 00:42:07 +00:00
Joel Wetzell b7e0d879bc Merge pull request #179 from jwetzell/fix/in-out-framer
make sure to use a distinct framer for both directions of communication
2026-06-01 21:35:58 -05:00
Joel Wetzell 9b76ee8195 make sure to use a distinct framer for both directions of communication 2026-06-01 21:32:14 -05:00
Joel Wetzell d48a89d1ef reword description 2026-06-01 18:30:19 -05:00
Joel Wetzell b01bebea54 Merge pull request #178 from jwetzell/processor-params-schema-descriptions
add description information to params for processors
2026-06-01 17:56:39 -05:00
Joel Wetzell 73905e1274 add description information to params for processors 2026-06-01 17:55:30 -05:00
Joel Wetzell 56566cf666 Merge pull request #177 from jwetzell/module-params-descriptions
add description information to params for modules
2026-06-01 17:39:30 -05:00
Joel Wetzell 5d1e6622cb add description information to params for modules 2026-06-01 17:39:00 -05:00
Joel Wetzell 81ae00c943 wrap config schema errors 2026-05-30 22:18:48 -05:00
Joel Wetzell 49e351c760 update artnet-go 2026-05-30 22:18:39 -05:00
Joel Wetzell e90356762c if tcp client is closed by stop, stop retrying 2026-05-30 22:18:28 -05:00
Joel Wetzell 68586cd588 some close work in websocket.client 2026-05-30 22:18:22 -05:00
Joel Wetzell 5e87cdcc5e Merge pull request #173 from jwetzell/dependabot/go_modules/github.com/nats-io/nats-server/v2-2.14.1
Bump github.com/nats-io/nats-server/v2 from 2.14.0 to 2.14.1
2026-05-27 22:00:49 -05:00
Joel Wetzell 2d6fa2ad19 Merge pull request #174 from jwetzell/dependabot/go_modules/go.bug.st/serial-1.7.1
Bump go.bug.st/serial from 1.7.0 to 1.7.1
2026-05-27 22:00:24 -05:00
Joel Wetzell 3ab2cade81 add more to smoke config 2026-05-27 21:02:09 -05:00
Joel Wetzell 2078d8533f Merge pull request #176 from jwetzell/fix/http-response-schema
align http.response.create schema with reality
2026-05-27 20:59:17 -05:00
Joel Wetzell 9b5a9ce6d0 align http.response.create schema with reality 2026-05-27 20:54:11 -05:00
Joel Wetzell dbeb1e8c29 Merge pull request #175 from jwetzell/chore/shutdown-rework
rework module shutdown process to cancel module context in defer
2026-05-27 20:53:31 -05:00
Joel Wetzell 0b494fce91 rework module shutdown process to cancel module context in defer 2026-05-27 20:50:33 -05:00
Joel Wetzell 52ca801fbd add context to keyvaluemodule get/set 2026-05-27 18:30:23 -05:00
Joel Wetzell 3adbae8068 Merge pull request #172 from jwetzell/dependabot/github_actions/docker/login-action-4.2.0
Bump docker/login-action from 4.1.0 to 4.2.0
2026-05-27 15:35:46 -05:00
Joel Wetzell 4ba718e2c6 Merge pull request #171 from jwetzell/dependabot/github_actions/docker/build-push-action-7.2.0
Bump docker/build-push-action from 7.1.0 to 7.2.0
2026-05-27 15:35:37 -05:00
Joel Wetzell fa595a027b Merge pull request #170 from jwetzell/dependabot/github_actions/docker/metadata-action-6.1.0
Bump docker/metadata-action from 6.0.0 to 6.1.0
2026-05-27 15:35:28 -05:00
Joel Wetzell 5660acfca6 Merge pull request #169 from jwetzell/dependabot/github_actions/docker/setup-buildx-action-4.1.0
Bump docker/setup-buildx-action from 4.0.0 to 4.1.0
2026-05-27 15:35:19 -05:00
dependabot[bot] 3a1bc74fcf Bump go.bug.st/serial from 1.7.0 to 1.7.1
Bumps [go.bug.st/serial](https://github.com/bugst/go-serial) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/bugst/go-serial/releases)
- [Commits](https://github.com/bugst/go-serial/compare/v1.7.0...v1.7.1)

---
updated-dependencies:
- dependency-name: go.bug.st/serial
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:15:14 +00:00
dependabot[bot] 62ce5bf2f8 Bump github.com/nats-io/nats-server/v2 from 2.14.0 to 2.14.1
Bumps [github.com/nats-io/nats-server/v2](https://github.com/nats-io/nats-server) from 2.14.0 to 2.14.1.
- [Release notes](https://github.com/nats-io/nats-server/releases)
- [Changelog](https://github.com/nats-io/nats-server/blob/main/RELEASES.md)
- [Commits](https://github.com/nats-io/nats-server/compare/v2.14.0...v2.14.1)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats-server/v2
  dependency-version: 2.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:15:06 +00:00
dependabot[bot] 0f70596eb0 Bump docker/login-action from 4.1.0 to 4.2.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/4907a6ddec9925e35a0a9e82d7399ccc52663121...650006c6eb7dba73a995cc03b0b2d7f5ca915bee)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:14:42 +00:00
dependabot[bot] db3d0530a5 Bump docker/build-push-action from 7.1.0 to 7.2.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/bcafcacb16a39f128d818304e6c9c0c18556b85f...f9f3042f7e2789586610d6e8b85c8f03e5195baf)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:14:37 +00:00
dependabot[bot] 6b53211267 Bump docker/metadata-action from 6.0.0 to 6.1.0
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/030e881283bb7a6894de51c315a6bfe6a94e05cf...80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:14:34 +00:00
dependabot[bot] 821d192eb7 Bump docker/setup-buildx-action from 4.0.0 to 4.1.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd...d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 23:14:31 +00:00
Joel Wetzell b50882fc4a fix error message in test 2026-05-26 17:56:08 -05:00
Joel Wetzell 438c396aeb include processor index in processpayload error 2026-05-26 17:53:34 -05:00
Joel Wetzell f175bed084 go mod tidy 2026-05-26 17:27:47 -05:00
Joel Wetzell 80f8152dfb don't export module/processor/framer registrations 2026-05-26 17:27:35 -05:00
Joel Wetzell 0ff212742a Merge pull request #168 from jwetzell/feat/rate-limiter
add rate limiting filter
2026-05-24 14:24:38 -05:00
Joel Wetzell 8fe0f7e6a2 add rate limiting filter 2026-05-24 14:19:58 -05:00
Joel Wetzell 9db958b523 only run docker job on tag 2026-05-23 11:50:45 -05:00
145 changed files with 1356 additions and 925 deletions
+19 -19
View File
@@ -17,7 +17,7 @@ jobs:
short_commit: ${{ steps.set_commit.outputs.short_commit }} short_commit: ${{ steps.set_commit.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: set environment variables - name: set environment variables
@@ -45,11 +45,11 @@ jobs:
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }} SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: setup go - name: setup go
uses: actions/setup-go@v6 uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: install alsa lib - name: install alsa lib
@@ -79,11 +79,11 @@ jobs:
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }} SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: setup go - name: setup go
uses: actions/setup-go@v6 uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: install alsa lib - name: install alsa lib
@@ -113,11 +113,11 @@ jobs:
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }} SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: setup go - name: setup go
uses: actions/setup-go@v6 uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: setup zig - name: setup zig
@@ -153,11 +153,11 @@ jobs:
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }} SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: setup go - name: setup go
uses: actions/setup-go@v6 uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: build - name: build
@@ -185,11 +185,11 @@ jobs:
SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }} SHORT_COMMIT: ${{ needs.setup_release.outputs.short_commit }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: setup go - name: setup go
uses: actions/setup-go@v6 uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: build - name: build
@@ -211,33 +211,33 @@ jobs:
files: showbridge_*.tar.gz files: showbridge_*.tar.gz
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: linux_amd64 needs: setup_release
if: github.ref_type == 'tag' && github.event_name != 'workflow_dispatch'
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Setup Docker metadata - name: Setup Docker metadata
id: meta id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with: with:
images: | images: |
jwetzell/showbridge jwetzell/showbridge
- name: Build and push - name: Build and push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
if: github.ref_type == 'tag'
with: with:
push: true push: true
context: ./ context: ./
+2 -2
View File
@@ -26,8 +26,8 @@ jobs:
- name: Install alsa - name: Install alsa
run: sudo apt-get install -y libasound2-dev run: sudo apt-get install -y libasound2-dev
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- uses: actions/setup-go@v6 - uses: actions/setup-go@v7
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: mod tidy - name: mod tidy
+2 -2
View File
@@ -106,12 +106,12 @@ func readConfig(configPath string) (config.Config, error) {
err = schema.ApplyDefaults(&yamlMap) err = schema.ApplyDefaults(&yamlMap)
if err != nil { if err != nil {
return config.Config{}, err return config.Config{}, fmt.Errorf("failed to apply defaults: %w", err)
} }
err = schema.ValidateConfig(yamlMap) err = schema.ValidateConfig(yamlMap)
if err != nil { if err != nil {
return config.Config{}, err return config.Config{}, fmt.Errorf("failed to validate config: %w", err)
} }
validatedConfigBytes, err := json.Marshal(yamlMap) validatedConfigBytes, err := json.Marshal(yamlMap)
+30 -5
View File
@@ -57,14 +57,25 @@ routes:
processors: processors:
- type: string.create - type: string.create
params: params:
template: "hello" template: "wsecho: {{.Payload.UnixMilli}}"
- type: module.output - type: module.output
params: params:
module: wsecho module: wsecho
- input: ticker
processors:
- type: string.create
params:
template: "tcpout: {{.Payload.UnixMilli}}"
- type: string.encode - type: string.encode
- type: module.output - type: module.output
params: params:
module: tcpout module: tcpout
- input: ticker
processors:
- type: string.create
params:
template: "udpout: {{.Payload.UnixMilli}}"
- type: string.encode
- type: module.output - type: module.output
params: params:
module: udpout module: udpout
@@ -74,14 +85,15 @@ routes:
params: params:
url: "http://localhost:3000/echo" url: "http://localhost:3000/echo"
method: "GET" method: "GET"
- type: struct.field.get
params:
name: "Body"
- type: string.decode
- type: debug.log - type: debug.log
- input: tcpin - input: tcpin
processors: processors:
- type: string.decode - type: string.decode
- type: debug.log - type: debug.log
- input: httpin
processors:
- type: debug.log
- input: udpin - input: udpin
processors: processors:
- type: string.decode - type: string.decode
@@ -98,12 +110,25 @@ routes:
- type: debug.log - type: debug.log
- input: natsin - input: natsin
processors: processors:
- type: struct.field.get
params:
name: "Data"
- type: string.decode
- type: debug.log - type: debug.log
- input: httpin
processors:
- type: http.response.create
params:
status: 200
bodyTemplate: "Hello, World!"
- type: module.output
params:
module: httpin
- input: ticker - input: ticker
processors: processors:
- type: string.create - type: string.create
params: params:
template: "{{.Payload}}" template: "natsout: {{.Payload}}"
- type: pubsub.publish - type: pubsub.publish
params: params:
module: natsout module: natsout
+7 -3
View File
@@ -13,11 +13,15 @@ modules:
port: 8000 port: 8000
routes: routes:
- input: http - input: http
id: http-to-osc
processors: processors:
- type: osc.message.create - id: create-osc
type: osc.message.create
params: params:
address: "{{.Payload.URL.Path}}" address: "{{.Payload.URL.Path}}"
- type: osc.message.encode - id: encode-osc
- type: module.output type: osc.message.encode
- id: output-osc
type: module.output
params: params:
module: udp module: udp
+22 -23
View File
@@ -4,29 +4,30 @@ go 1.26.3
require ( require (
github.com/eclipse/paho.mqtt.golang v1.5.1 github.com/eclipse/paho.mqtt.golang v1.5.1
github.com/emiago/diago v0.28.0 github.com/emiago/diago v0.31.0
github.com/emiago/sipgo v1.3.1 github.com/emiago/sipgo v1.4.3
github.com/expr-lang/expr v1.17.8 github.com/expr-lang/expr v1.17.8
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.3 github.com/jwetzell/artnet-go v0.3.0
github.com/jwetzell/free-d-go v0.2.0 github.com/jwetzell/free-d-go v0.2.0
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.4
github.com/nats-io/nats.go v1.52.0 github.com/nats-io/nats.go v1.52.0
github.com/redis/go-redis/v9 v9.19.0 github.com/redis/go-redis/v9 v9.22.0
github.com/urfave/cli/v3 v3.9.0 github.com/urfave/cli/v3 v3.10.1
gitlab.com/gomidi/midi/v2 v2.3.23 gitlab.com/gomidi/midi/v2 v2.3.24
go.bug.st/serial v1.7.0 go.bug.st/serial v1.8.0
modernc.org/quickjs v0.18.2 golang.org/x/time v0.15.0
modernc.org/sqlite v1.50.1 modernc.org/quickjs v0.23.0
modernc.org/sqlite v1.56.0
sigs.k8s.io/yaml v1.6.0 sigs.k8s.io/yaml v1.6.0
) )
require ( require (
github.com/antithesishq/antithesis-sdk-go v0.7.0 // indirect github.com/antithesishq/antithesis-sdk-go v0.7.2-default-no-op // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 // indirect github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 // indirect
@@ -40,11 +41,11 @@ require (
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f // indirect github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f // indirect
github.com/icholy/digest v1.1.0 // indirect github.com/icholy/digest v1.1.0 // indirect
github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/compress v1.19.0 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect github.com/mattn/go-isatty v0.0.24 // indirect
github.com/minio/highwayhash v1.0.4 // indirect github.com/minio/highwayhash v1.0.4 // indirect
github.com/nats-io/jwt/v2 v2.8.1 // indirect github.com/nats-io/jwt/v2 v2.8.2 // indirect
github.com/nats-io/nkeys v0.4.15 // indirect github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/pion/logging v0.2.4 // indirect github.com/pion/logging v0.2.4 // indirect
@@ -62,16 +63,14 @@ require (
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.51.0 // indirect golang.org/x/crypto v0.54.0 // indirect
golang.org/x/net v0.54.0 // indirect golang.org/x/net v0.56.0 // indirect
golang.org/x/sync v0.20.0 // indirect golang.org/x/sync v0.21.0 // indirect
golang.org/x/sys v0.44.0 // indirect golang.org/x/sys v0.47.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.44.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302 // indirect gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302 // indirect
modernc.org/libc v1.72.3 // indirect modernc.org/libc v1.74.4 // indirect
modernc.org/libquickjs v0.12.8 // indirect modernc.org/libquickjs v0.13.1 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect modernc.org/memory v1.11.0 // indirect
) )
+54 -54
View File
@@ -1,5 +1,5 @@
github.com/antithesishq/antithesis-sdk-go v0.7.0 h1:uWDG8BqLD1lI2ps38WDz2vXflrTX2+vLX0SvZtztJtE= github.com/antithesishq/antithesis-sdk-go v0.7.2-default-no-op h1:p2zFsAzvhIpFya8AIOHIbWf7NGvO34QpLGclyf7nXj8=
github.com/antithesishq/antithesis-sdk-go v0.7.0/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/antithesishq/antithesis-sdk-go v0.7.2-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -14,12 +14,12 @@ github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 h1:idfl8M8r
github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q= github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q=
github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE= github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE=
github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU= github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU=
github.com/emiago/diago v0.28.0 h1:VCiimhFYLoBTsxH6WrufLSt6tKWG8Fv7LfCkZHqct2E= github.com/emiago/diago v0.31.0 h1:w/GZQnMS60EBANKXMnf/MjFDlUfcfHLPOlEKiZkaNe0=
github.com/emiago/diago v0.28.0/go.mod h1:eQT6j9co9PMQ/25aUiM2jpvwxxWFXLWi2w5R3lZNmKg= github.com/emiago/diago v0.31.0/go.mod h1:CP7p9/aBZG/fQEYdtGdQkCblr1jLr1zbxODcu8MryVU=
github.com/emiago/dtls/v3 v3.0.0-20260122183559-8b8d23e359c0 h1:o4LxpUnZ1zxiQ+Qjc9kLwXcjz31NGAHmnZ7xoJto3VM= github.com/emiago/dtls/v3 v3.0.0-20260122183559-8b8d23e359c0 h1:o4LxpUnZ1zxiQ+Qjc9kLwXcjz31NGAHmnZ7xoJto3VM=
github.com/emiago/dtls/v3 v3.0.0-20260122183559-8b8d23e359c0/go.mod h1:ydcZ977eS1I6uOWodzMuw30BwvNAzT9su/xcNYSJqjA= github.com/emiago/dtls/v3 v3.0.0-20260122183559-8b8d23e359c0/go.mod h1:ydcZ977eS1I6uOWodzMuw30BwvNAzT9su/xcNYSJqjA=
github.com/emiago/sipgo v1.3.1 h1:JwcmYJtCmcjuLwB2ZxtupYilNQgwXN/JIcxp+CDq16A= github.com/emiago/sipgo v1.4.3 h1:Ju1Ilp0LhTcSHCyp2jBYAQDQ8TAwuxQHzT1IhO6jSIY=
github.com/emiago/sipgo v1.3.1/go.mod h1:DuwAxBZhKMqIzQFPGZb1MVAGU6Wuxj64oTOhd5dx/FY= github.com/emiago/sipgo v1.4.3/go.mod h1:DuwAxBZhKMqIzQFPGZb1MVAGU6Wuxj64oTOhd5dx/FY=
github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM=
github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw= github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw=
@@ -40,8 +40,8 @@ github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0= github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
@@ -52,34 +52,34 @@ 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.3 h1:yPDckAFFSbJnpjMX5Y+tFh8xiP2zH3iqZxrXZrJg91g= github.com/jwetzell/artnet-go v0.3.0 h1:MDHElOSbpgmIbYGHO9SoxsT7ynrYtV5/UHGT82geHk0=
github.com/jwetzell/artnet-go v0.2.3/go.mod h1:gli97Z32a0kMkZ6taoTiK7/lqHcF/dhiGjGJdx/PxqA= github.com/jwetzell/artnet-go v0.3.0/go.mod h1:zqRsSsrd6rPwJacwscPteDqGIqevjZ3Z6dpp092VJ1w=
github.com/jwetzell/free-d-go v0.2.0 h1:8WQW4du8Sf3d18aUzk9n5jZtHE6WdDQHDFjkFffvycc= github.com/jwetzell/free-d-go v0.2.0 h1:8WQW4du8Sf3d18aUzk9n5jZtHE6WdDQHDFjkFffvycc=
github.com/jwetzell/free-d-go v0.2.0/go.mod h1:yHuRy51NeDfN26eJ6wzZgys8qyQiS7hkYILw8yF+UJ4= github.com/jwetzell/free-d-go v0.2.0/go.mod h1:yHuRy51NeDfN26eJ6wzZgys8qyQiS7hkYILw8yF+UJ4=
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=
github.com/jwetzell/psn-go v0.3.0/go.mod h1:bcEAeti4sQM375buujb3mIfmUstD4Aby18gq3ENb6+o= github.com/jwetzell/psn-go v0.3.0/go.mod h1:bcEAeti4sQM375buujb3mIfmUstD4Aby18gq3ENb6+o=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4= github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4=
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU= github.com/nats-io/jwt/v2 v2.8.2 h1:XXRgB60MSTnqsRwejQurVDs/hcv2dkt+86GjI+I/bMc=
github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg= github.com/nats-io/jwt/v2 v2.8.2/go.mod h1:Ag/56sq9OblL4JgdYufDd16Egb17Kr/8WwwuO/forVc=
github.com/nats-io/nats-server/v2 v2.14.0 h1:+8q0HrDFotwLLcGH/legOEOnowunhK+aZ4GYBIWpQlM= github.com/nats-io/nats-server/v2 v2.14.4 h1:efgjZ8cdExAKRuqSg8UPJFprb+l7NlBtSDPhDlw3rO4=
github.com/nats-io/nats-server/v2 v2.14.0/go.mod h1:ImVUUDvfClJbb6cuJQRc1VmgDCXKM5ds0OoiG9MVOKo= github.com/nats-io/nats-server/v2 v2.14.4/go.mod h1:BltdpOYestjbtQSnVO2zGHdg5SGBZjt+GYTgB9LZq/I=
github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc=
github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
@@ -98,8 +98,8 @@ github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k
github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= github.com/redis/go-redis/v9 v9.22.0 h1:laDvpYXTJtZLloinw1fA5Kqd6HAEH2XKxOkG/PDq2F0=
github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/redis/go-redis/v9 v9.22.0/go.mod h1:y2g0Wj8rQvuK0ELM+oxSudcLtC09JScs98I/X9gRWY4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -110,16 +110,16 @@ github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZ
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk= github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk=
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA= github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU= github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
github.com/urfave/cli/v3 v3.9.0 h1:AV9lIiPv3ukYnxunaCUsHnEozptYmDN2F0+yWqLMn/c= github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY=
github.com/urfave/cli/v3 v3.9.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/zaf/g711 v1.4.0 h1:XZYkjjiAg9QTBnHqEg37m2I9q3IIDv5JRYXs2N8ma7c= github.com/zaf/g711 v1.4.0 h1:XZYkjjiAg9QTBnHqEg37m2I9q3IIDv5JRYXs2N8ma7c=
github.com/zaf/g711 v1.4.0/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo= github.com/zaf/g711 v1.4.0/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo=
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
gitlab.com/gomidi/midi/v2 v2.3.23 h1:P8NxV4EzV9c+BjpwTeB+G/qa+Xdq/UTazS2fKxY0O0g= gitlab.com/gomidi/midi/v2 v2.3.24 h1:afkq5nhlzKvZaj9QK80YbK8tH3lIlKLnPPP9HxxD7Do=
gitlab.com/gomidi/midi/v2 v2.3.23/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw= gitlab.com/gomidi/midi/v2 v2.3.24/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
go.bug.st/serial v1.7.0 h1:Svs5xR0s4JF+KIg+1d9QE4iXqEIJvTr5vESFUjSu7mE= go.bug.st/serial v1.8.0 h1:ZtnmN8aYXtPlTghwSvDWPHKBHL9TM6oFDa+KpSn4SQE=
go.bug.st/serial v1.7.0/go.mod h1:PZfOSahry47TWtrd0tvoKZvmVa7FGrc/1xG9q8Ho3xU= go.bug.st/serial v1.8.0/go.mod h1:d0MmS16Qt9b1m06yoYRNUXhRRTJV5Qg2S5EKqQtnayQ=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -128,22 +128,22 @@ go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -155,34 +155,34 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY= modernc.org/cc/v4 v4.29.1 h1:MKgdCV3WykTSPqpVrnxdEDS0HEd2FHpKZDzxzU5LyeI=
modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= modernc.org/cc/v4 v4.29.1/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/ccgo/v4 v4.34.0 h1:yRLPFZieg532OT4rp4JFNIVcquwalMX26G95WQDqwCQ= modernc.org/ccgo/v4 v4.34.6 h1:sBgfIwyN0TQ9C5hwIeuqyeAKyMWnbvj2fvpF4L11uzU=
modernc.org/ccgo/v4 v4.34.0/go.mod h1:AS5WYMyBakQ+fhsHhtP8mWB82KTGPkNNJDGfGQCe0/A= modernc.org/ccgo/v4 v4.34.6/go.mod h1:SZ8YcN9NG7XVsQYdm6jYBvi8PQP1qi+kqB6OhjqI3Fk=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= modernc.org/gc/v3 v3.1.5 h1:21ldfPfRYE31Tb7B3mwAK8gy1AxP4+dKjrOQPfqakoc=
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/gc/v3 v3.1.5/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.72.3 h1:ZnDF4tXn4NBXFutMMQC4vtbTFSXhhKzR73fv0beZEAU= modernc.org/libc v1.74.4 h1:fX1Omw4o2/1C2iRkkIsrQTasJQldLhRmuPreXLoWs9k=
modernc.org/libc v1.72.3/go.mod h1:dn0dZNnnn1clLyvRxLxYExxiKRZIRENOfqQ8XEeg4Qs= modernc.org/libc v1.74.4/go.mod h1:eeQAS9W3sZeKYMFubydxJpII9ybHWshk+7or7bLG9co=
modernc.org/libquickjs v0.12.8 h1:wJ2GGxEDcQb7j8ILZScNNP1WsXFILlo1qQ8cS3q/tPw= modernc.org/libquickjs v0.13.1 h1:uCb9AYyEyL1JS2dnKtLZKWH/vDb36cx1Mr1SIdbzb8A=
modernc.org/libquickjs v0.12.8/go.mod h1:nIPezuUN/J6aDLSaR76qNaPNNy79FH5Gkjb/x9wa/gU= modernc.org/libquickjs v0.13.1/go.mod h1:tCEsA1Zda1+C5JagFIJGqjYZOxDPFOUYjK3dGhEeq0g=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/quickjs v0.18.2 h1:v/KDawJfs4L7jSCItAKrkrHCmOL5VnDLMJOXpU8Evdk= modernc.org/quickjs v0.23.0 h1:k+px+rFrMqHm2LPMvrd+vCR+8m6eogiTkROz+YJHkj8=
modernc.org/quickjs v0.18.2/go.mod h1:U11Fhn2hC71v+DyvEN3cY4IXkjU5XxrYT0DQWvZ43+A= modernc.org/quickjs v0.23.0/go.mod h1:bFvjVk4JGlbqLYXVFt72YvwdnHbwtNIE9nQ+eh4fdi0=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.50.1 h1:l+cQvn0sd0zJJtfygGHuQJ5AjlrwXmWPw4KP3ZMwr9w= modernc.org/sqlite v1.56.0 h1:/D8e2RfFqoy/Zc6PuC76U28zFwmI/sYx1Kjm4yEn9e0=
modernc.org/sqlite v1.50.1/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= modernc.org/sqlite v1.56.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+24
View File
@@ -0,0 +1,24 @@
package common_test
import (
"testing"
"github.com/jwetzell/showbridge-go/internal/common"
)
func TestEventToJson(t *testing.T) {
e := common.Event{
Type: "test.event",
Data: map[string]any{
"key": "value",
},
}
jsonData, err := e.ToJSON()
if err != nil {
t.Fatalf("Failed to convert event to JSON: %v", err)
}
expectedJson := `{"type":"test.event","data":{"key":"value"}}`
if string(jsonData) != expectedJson {
t.Errorf("Expected JSON: %s, got: %s", expectedJson, string(jsonData))
}
}
+2 -2
View File
@@ -17,8 +17,8 @@ type OutputModule interface {
} }
type KeyValueModule interface { type KeyValueModule interface {
Get(key string) (any, error) Get(ctx context.Context, key string) (any, error)
Set(key string, value any) error Set(ctx context.Context, key string, value any) error
} }
type DatabaseModule interface { type DatabaseModule interface {
+1
View File
@@ -1,6 +1,7 @@
package config package config
type ProcessorConfig struct { type ProcessorConfig struct {
Id string `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Params Params `json:"params,omitempty"` Params Params `json:"params,omitempty"`
} }
+1
View File
@@ -1,6 +1,7 @@
package config package config
type RouteConfig struct { type RouteConfig struct {
Id string `json:"id"`
Input string `json:"input"` Input string `json:"input"`
Processors []ProcessorConfig `json:"processors"` Processors []ProcessorConfig `json:"processors"`
} }
+5 -5
View File
@@ -10,15 +10,15 @@ type Framer interface {
func GetFramer(framingType string) Framer { func GetFramer(framingType string) Framer {
switch framingType { switch framingType {
case "CR": case "CR":
return NewByteSeparatorFramer([]byte{'\r'}) return newByteSeparatorFramer([]byte{'\r'})
case "LF": case "LF":
return NewByteSeparatorFramer([]byte{'\n'}) return newByteSeparatorFramer([]byte{'\n'})
case "CRLF": case "CRLF":
return NewByteSeparatorFramer([]byte{'\r', '\n'}) return newByteSeparatorFramer([]byte{'\r', '\n'})
case "SLIP": case "SLIP":
return NewSlipFramer() return newSlipFramer()
case "RAW": case "RAW":
return NewRawFramer() return newRawFramer()
default: default:
return nil return nil
} }
+7 -7
View File
@@ -1,23 +1,23 @@
package framer package framer
type RawFramer struct{} type rawFramer struct{}
func NewRawFramer() *RawFramer { func newRawFramer() *rawFramer {
return &RawFramer{} return &rawFramer{}
} }
func (rf *RawFramer) Decode(data []byte) [][]byte { func (rf *rawFramer) Decode(data []byte) [][]byte {
return [][]byte{data} return [][]byte{data}
} }
func (rf *RawFramer) Encode(data []byte) []byte { func (rf *rawFramer) Encode(data []byte) []byte {
return data return data
} }
func (rf *RawFramer) Clear() { func (rf *rawFramer) Clear() {
// NOTE(jwetzell): no internal state to clear // NOTE(jwetzell): no internal state to clear
} }
func (rf *RawFramer) Buffer() []byte { func (rf *rawFramer) Buffer() []byte {
return []byte{} return []byte{}
} }
+7 -7
View File
@@ -4,16 +4,16 @@ import (
"bytes" "bytes"
) )
type ByteSeparatorFramer struct { type byteSeparatorFramer struct {
buffer []byte buffer []byte
separator []byte separator []byte
} }
func NewByteSeparatorFramer(separator []byte) *ByteSeparatorFramer { func newByteSeparatorFramer(separator []byte) *byteSeparatorFramer {
return &ByteSeparatorFramer{separator: separator, buffer: []byte{}} return &byteSeparatorFramer{separator: separator, buffer: []byte{}}
} }
func (bsf *ByteSeparatorFramer) Decode(data []byte) [][]byte { func (bsf *byteSeparatorFramer) Decode(data []byte) [][]byte {
messages := [][]byte{} messages := [][]byte{}
bsf.buffer = append(bsf.buffer, data...) bsf.buffer = append(bsf.buffer, data...)
@@ -28,14 +28,14 @@ func (bsf *ByteSeparatorFramer) Decode(data []byte) [][]byte {
return messages return messages
} }
func (bsf *ByteSeparatorFramer) Encode(data []byte) []byte { func (bsf *byteSeparatorFramer) Encode(data []byte) []byte {
return append(data, bsf.separator...) return append(data, bsf.separator...)
} }
func (bsf *ByteSeparatorFramer) Clear() { func (bsf *byteSeparatorFramer) Clear() {
bsf.buffer = []byte{} bsf.buffer = []byte{}
} }
func (bsf *ByteSeparatorFramer) Buffer() []byte { func (bsf *byteSeparatorFramer) Buffer() []byte {
return bsf.buffer return bsf.buffer
} }
+7 -7
View File
@@ -1,14 +1,14 @@
package framer package framer
type SlipFramer struct { type slipFramer struct {
buffer []byte buffer []byte
} }
func NewSlipFramer() *SlipFramer { func newSlipFramer() *slipFramer {
return &SlipFramer{buffer: []byte{}} return &slipFramer{buffer: []byte{}}
} }
func (sf *SlipFramer) Decode(data []byte) [][]byte { func (sf *slipFramer) Decode(data []byte) [][]byte {
messages := [][]byte{} messages := [][]byte{}
END := byte(0xc0) END := byte(0xc0)
@@ -49,7 +49,7 @@ func (sf *SlipFramer) Decode(data []byte) [][]byte {
return messages return messages
} }
func (sf *SlipFramer) Encode(data []byte) []byte { func (sf *slipFramer) Encode(data []byte) []byte {
END := byte(0xc0) END := byte(0xc0)
ESC := byte(0xdb) ESC := byte(0xdb)
ESC_END := byte(0xdc) ESC_END := byte(0xdc)
@@ -72,10 +72,10 @@ func (sf *SlipFramer) Encode(data []byte) []byte {
return encodedBytes return encodedBytes
} }
func (sf *SlipFramer) Clear() { func (sf *slipFramer) Clear() {
sf.buffer = []byte{} sf.buffer = []byte{}
} }
func (sf *SlipFramer) Buffer() []byte { func (sf *slipFramer) Buffer() []byte {
return sf.buffer return sf.buffer
} }
+6 -5
View File
@@ -22,8 +22,10 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"dsn": { "dsn": {
Type: "string", Title: "Data Source Name",
MinLength: new(1), Description: "the data source name (DSN) for the SQLite database",
Type: "string",
MinLength: new(1),
}, },
}, },
Required: []string{"dsn"}, Required: []string{"dsn"},
@@ -76,20 +78,19 @@ func (dbs *DbSqlite) Start(ctx context.Context, inputHandler common.InputHandler
dbs.db = db dbs.db = db
dbs.dbMu.Unlock() dbs.dbMu.Unlock()
<-dbs.ctx.Done() <-dbs.ctx.Done()
dbs.logger.Debug("done")
return nil return nil
} }
func (dbs *DbSqlite) Stop() { func (dbs *DbSqlite) Stop() {
if dbs.cancel != nil { if dbs.cancel != nil {
dbs.cancel() defer dbs.cancel()
} }
dbs.dbMu.Lock() dbs.dbMu.Lock()
defer dbs.dbMu.Unlock() defer dbs.dbMu.Unlock()
if dbs.db != nil { if dbs.db != nil {
dbs.db.Close() dbs.db.Close()
dbs.db = nil
} }
dbs.logger.Debug("done")
} }
func (dbs *DbSqlite) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) { func (dbs *DbSqlite) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
+8 -8
View File
@@ -24,10 +24,11 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the HTTP server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Maximum: jsonschema.Ptr[float64](65535),
}, },
}, },
Required: []string{"port"}, Required: []string{"port"},
@@ -167,12 +168,13 @@ func (hs *HTTPServer) Start(ctx context.Context, inputHandler common.InputHandle
err := httpServer.ListenAndServe() err := httpServer.ListenAndServe()
// TODO(jwetzell): handle server closed error differently // TODO(jwetzell): handle server closed error differently
if err != nil { if err != nil {
if err.Error() != "http: Server closed" { if !errors.Is(err, http.ErrServerClosed) {
return err return err
} }
} }
<-hs.ctx.Done() <-hs.ctx.Done()
hs.logger.Debug("done")
return nil return nil
} }
@@ -200,7 +202,7 @@ func (hs *HTTPServer) Output(ctx context.Context, payload any) error {
func (hs *HTTPServer) Stop() { func (hs *HTTPServer) Stop() {
if hs.cancel != nil { if hs.cancel != nil {
hs.cancel() defer hs.cancel()
} }
hs.serverMu.Lock() hs.serverMu.Lock()
defer hs.serverMu.Unlock() defer hs.serverMu.Unlock()
@@ -209,7 +211,5 @@ func (hs *HTTPServer) Stop() {
hs.server.Shutdown(shutdownCtx) hs.server.Shutdown(shutdownCtx)
shutdownCancel() shutdownCancel()
<-shutdownCtx.Done() <-shutdownCtx.Done()
hs.server = nil
} }
hs.logger.Debug("done")
} }
+5 -5
View File
@@ -22,8 +22,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"port": { "port": {
Title: "Port", Title: "Port",
Type: "string", Description: "the name of the MIDI port to listen to",
Type: "string",
}, },
}, },
Required: []string{"port"}, Required: []string{"port"},
@@ -83,17 +84,16 @@ func (mi *MIDIInput) Start(ctx context.Context, inputHandler common.InputHandler
mi.stop = stop mi.stop = stop
<-mi.ctx.Done() <-mi.ctx.Done()
mi.logger.Debug("done")
return nil return nil
} }
func (mi *MIDIInput) Stop() { func (mi *MIDIInput) Stop() {
if mi.cancel != nil { if mi.cancel != nil {
mi.cancel() defer mi.cancel()
} }
if mi.stop != nil { if mi.stop != nil {
mi.stop() mi.stop()
mi.stop = nil
} }
midi.CloseDriver() midi.CloseDriver()
mi.logger.Debug("done")
} }
+5 -4
View File
@@ -24,8 +24,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"port": { "port": {
Title: "Port", Title: "Port",
Type: "string", Description: "the name of the MIDI port to send messages to",
Type: "string",
}, },
}, },
Required: []string{"port"}, Required: []string{"port"},
@@ -86,6 +87,7 @@ func (mo *MIDIOutput) Start(ctx context.Context, inputHandler common.InputHandle
mo.sendFuncMu.Unlock() mo.sendFuncMu.Unlock()
<-mo.ctx.Done() <-mo.ctx.Done()
mo.logger.Debug("done")
return nil return nil
} }
@@ -107,8 +109,7 @@ func (mo *MIDIOutput) Output(ctx context.Context, payload any) error {
func (mo *MIDIOutput) Stop() { func (mo *MIDIOutput) Stop() {
if mo.cancel != nil { if mo.cancel != nil {
mo.cancel() defer mo.cancel()
} }
midi.CloseDriver() midi.CloseDriver()
mo.logger.Debug("done")
} }
+25 -3
View File
@@ -30,15 +30,37 @@ func RegisterModule(mod ModuleRegistration) {
moduleRegistryMu.Lock() moduleRegistryMu.Lock()
defer moduleRegistryMu.Unlock() defer moduleRegistryMu.Unlock()
if _, ok := ModuleRegistry[string(mod.Type)]; ok { _, exists := moduleRegistry[string(mod.Type)]
if exists {
panic(fmt.Sprintf("module already registered: %s", mod.Type)) panic(fmt.Sprintf("module already registered: %s", mod.Type))
} }
ModuleRegistry[string(mod.Type)] = mod moduleRegistry[string(mod.Type)] = mod
}
type ModuleRegistry map[string]ModuleRegistration
func GetModuleRegistration(moduleType string) (ModuleRegistration, bool) {
moduleRegistryMu.RLock()
defer moduleRegistryMu.RUnlock()
mod, ok := moduleRegistry[moduleType]
return mod, ok
}
func GetModuleRegistrations() []ModuleRegistration {
moduleRegistryMu.RLock()
defer moduleRegistryMu.RUnlock()
registrations := make([]ModuleRegistration, 0, len(moduleRegistry))
for _, mod := range moduleRegistry {
registrations = append(registrations, mod)
}
return registrations
} }
var ( var (
moduleRegistryMu sync.RWMutex moduleRegistryMu sync.RWMutex
ModuleRegistry = make(map[string]ModuleRegistration) moduleRegistry = make(ModuleRegistry)
) )
func CreateLogger(config config.ModuleConfig) *slog.Logger { func CreateLogger(config config.ModuleConfig) *slog.Logger {
+21 -17
View File
@@ -22,28 +22,33 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"broker": { "broker": {
Title: "Broker URL", Title: "Broker URL",
Type: "string", Description: "the URL of the MQTT broker to connect to",
Type: "string",
}, },
"topic": { "topic": {
Title: "Topic", Title: "Topic",
Type: "string", Description: "an MQTT topic to subscribe to",
Type: "string",
}, },
"clientId": { "clientId": {
Title: "Client ID", Title: "Client ID",
Type: "string", Description: "the client ID to use when connecting to the MQTT broker",
Type: "string",
}, },
"qos": { "qos": {
Title: "QoS", Title: "QoS",
Type: "integer", Description: "the QoS level to use when publishing messages",
Minimum: jsonschema.Ptr[float64](0), Type: "integer",
Maximum: jsonschema.Ptr[float64](2), Minimum: jsonschema.Ptr[float64](0),
Default: json.RawMessage(`0`), Maximum: jsonschema.Ptr[float64](2),
Default: json.RawMessage(`0`),
}, },
"retained": { "retained": {
Title: "Retained", Title: "Retained",
Type: "boolean", Description: "whether to set the retained flag when publishing messages",
Default: json.RawMessage(`false`), Type: "boolean",
Default: json.RawMessage(`false`),
}, },
}, },
Required: []string{"broker", "topic", "clientId"}, Required: []string{"broker", "topic", "clientId"},
@@ -143,15 +148,16 @@ func (mc *MQTTClient) Start(ctx context.Context, inputHandler common.InputHandle
mc.client = mqtt.NewClient(opts) mc.client = mqtt.NewClient(opts)
token := mc.client.Connect() token := mc.client.Connect()
mc.clientMu.Unlock()
token.Wait() token.Wait()
err := token.Error() err := token.Error()
if err != nil { if err != nil {
return err return err
} }
mc.clientMu.Unlock()
<-mc.ctx.Done() <-mc.ctx.Done()
mc.logger.Debug("done")
return nil return nil
} }
@@ -189,7 +195,5 @@ func (mc *MQTTClient) Stop() {
defer mc.clientMu.Unlock() defer mc.clientMu.Unlock()
if mc.client != nil { if mc.client != nil {
mc.client.Disconnect(250) mc.client.Disconnect(250)
mc.client = nil
} }
mc.logger.Debug("done")
} }
+8 -8
View File
@@ -20,12 +20,14 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"url": { "url": {
Title: "NATS Server URL", Title: "NATS Server URL",
Type: "string", Description: "the URL of the NATS server to connect to",
Type: "string",
}, },
"subject": { "subject": {
Title: "Subject", Title: "Subject",
Type: "string", Description: "the subject to subscribe to",
Type: "string",
}, },
}, },
Required: []string{"url", "subject"}, Required: []string{"url", "subject"},
@@ -102,6 +104,7 @@ func (nc *NATSClient) Start(ctx context.Context, inputHandler common.InputHandle
nc.subMu.Unlock() nc.subMu.Unlock()
<-nc.ctx.Done() <-nc.ctx.Done()
nc.logger.Debug("done")
return nil return nil
} }
@@ -135,13 +138,12 @@ func (nc *NATSClient) Publish(ctx context.Context, topic string, payload any) er
func (nc *NATSClient) Stop() { func (nc *NATSClient) Stop() {
if nc.cancel != nil { if nc.cancel != nil {
nc.cancel() defer nc.cancel()
} }
nc.subMu.Lock() nc.subMu.Lock()
defer nc.subMu.Unlock() defer nc.subMu.Unlock()
if nc.sub != nil { if nc.sub != nil {
nc.sub.Unsubscribe() nc.sub.Unsubscribe()
nc.sub = nil
} }
nc.clientMu.Lock() nc.clientMu.Lock()
@@ -150,7 +152,5 @@ func (nc *NATSClient) Stop() {
nc.client.Drain() nc.client.Drain()
// TODO(jwetzell): setup closed callback to get when client is fully closed // TODO(jwetzell): setup closed callback to get when client is fully closed
nc.client.Close() nc.client.Close()
nc.client = nil
} }
nc.logger.Debug("done")
} }
+18 -15
View File
@@ -24,16 +24,18 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the IP address to bind the NATS server to",
Default: json.RawMessage(`"0.0.0.0"`), Type: "string",
Default: json.RawMessage(`"0.0.0.0"`),
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the NATS server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Default: json.RawMessage(`4222`), Maximum: jsonschema.Ptr[float64](65535),
Default: json.RawMessage(`4222`),
}, },
}, },
Required: []string{}, Required: []string{},
@@ -96,9 +98,10 @@ func (ns *NATSServer) Start(ctx context.Context, inputHandler common.InputHandle
ns.cancel = cancel ns.cancel = cancel
natsServer, err := server.NewServer(&server.Options{ natsServer, err := server.NewServer(&server.Options{
Host: ns.Ip, Host: ns.Ip,
Port: ns.Port, Port: ns.Port,
NoLog: true, NoLog: true,
NoSigs: true,
}) })
if err != nil { if err != nil {
@@ -107,26 +110,26 @@ func (ns *NATSServer) Start(ctx context.Context, inputHandler common.InputHandle
ns.serverMu.Lock() ns.serverMu.Lock()
ns.server = natsServer ns.server = natsServer
defer ns.serverMu.Unlock()
natsServer.Start() natsServer.Start()
if !natsServer.ReadyForConnections(5 * time.Second) { if !natsServer.ReadyForConnections(5 * time.Second) {
return errors.New("nats.server failed to start") return errors.New("nats.server failed to start")
} }
ns.serverMu.Unlock()
<-ns.ctx.Done() <-ns.ctx.Done()
ns.logger.Debug("done")
return nil return nil
} }
func (ns *NATSServer) Stop() { func (ns *NATSServer) Stop() {
if ns.cancel != nil { if ns.cancel != nil {
ns.cancel() defer ns.cancel()
} }
ns.serverMu.Lock() ns.serverMu.Lock()
defer ns.serverMu.Unlock() defer ns.serverMu.Unlock()
if ns.server != nil { if ns.server != nil {
ns.server.Shutdown() ns.server.Shutdown()
ns.server.WaitForShutdown()
} }
ns.logger.Debug("done")
} }
+7 -5
View File
@@ -63,7 +63,7 @@ func (pc *PSNClient) Start(ctx context.Context, inputHandler common.InputHandler
pc.connMu.Unlock() pc.connMu.Unlock()
buffer := make([]byte, 2048) buffer := make([]byte, 2048)
for { for pc.ctx.Err() == nil {
select { select {
case <-pc.ctx.Done(): case <-pc.ctx.Done():
return nil return nil
@@ -75,7 +75,8 @@ func (pc *PSNClient) Start(ctx context.Context, inputHandler common.InputHandler
pc.connMu.Unlock() pc.connMu.Unlock()
if err != nil { if err != nil {
//NOTE(jwetzell) we hit deadline //NOTE(jwetzell) we hit deadline
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { opErr, ok := err.(*net.OpError)
if ok && opErr.Timeout() {
continue continue
} }
return err return err
@@ -99,17 +100,18 @@ func (pc *PSNClient) Start(ctx context.Context, inputHandler common.InputHandler
} }
} }
} }
<-pc.ctx.Done()
pc.logger.Debug("done")
return nil
} }
func (pc *PSNClient) Stop() { func (pc *PSNClient) Stop() {
if pc.cancel != nil { if pc.cancel != nil {
pc.cancel() defer pc.cancel()
} }
pc.connMu.Lock() pc.connMu.Lock()
defer pc.connMu.Unlock() defer pc.connMu.Unlock()
if pc.conn != nil { if pc.conn != nil {
pc.conn.Close() pc.conn.Close()
pc.conn = nil
} }
pc.logger.Debug("done")
} }
+14 -11
View File
@@ -21,12 +21,16 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"host": { "host": {
Type: "string", Title: "Host",
Description: "the hostname or IP address of the Redis server to connect to",
Type: "string",
}, },
"port": { "port": {
Type: "integer", Title: "Port",
Minimum: jsonschema.Ptr[float64](1), Description: "the port to use when connecting to the Redis server",
Maximum: jsonschema.Ptr[float64](65535), Type: "integer",
Minimum: jsonschema.Ptr[float64](1),
Maximum: jsonschema.Ptr[float64](65535),
}, },
}, },
Required: []string{"host", "port"}, Required: []string{"host", "port"},
@@ -94,25 +98,24 @@ func (rc *RedisClient) Start(ctx context.Context, inputHandler common.InputHandl
rc.clientMu.Unlock() rc.clientMu.Unlock()
<-rc.ctx.Done() <-rc.ctx.Done()
rc.logger.Debug("done")
return nil return nil
} }
func (rc *RedisClient) Stop() { func (rc *RedisClient) Stop() {
if rc.cancel != nil { if rc.cancel != nil {
rc.cancel() defer rc.cancel()
} }
rc.clientMu.Lock() rc.clientMu.Lock()
defer rc.clientMu.Unlock() defer rc.clientMu.Unlock()
if rc.client != nil { if rc.client != nil {
rc.client.Close() rc.client.Close()
rc.client = nil
} }
rc.logger.Debug("done")
} }
func (rc *RedisClient) Get(key string) (any, error) { func (rc *RedisClient) Get(ctx context.Context, key string) (any, error) {
if rc.client != nil { if rc.client != nil {
val, err := rc.client.Get(rc.ctx, key).Result() val, err := rc.client.Get(ctx, key).Result()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -121,9 +124,9 @@ func (rc *RedisClient) Get(key string) (any, error) {
return nil, errors.New("redis.client not setup") return nil, errors.New("redis.client not setup")
} }
func (rc *RedisClient) Set(key string, value any) error { func (rc *RedisClient) Set(ctx context.Context, key string, value any) error {
if rc.client != nil { if rc.client != nil {
status := rc.client.Set(rc.ctx, key, value, 0) status := rc.client.Set(ctx, key, value, 0)
return status.Err() return status.Err()
} }
return errors.New("redis.client not setup") return errors.New("redis.client not setup")
+32 -18
View File
@@ -25,17 +25,20 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"port": { "port": {
Title: "Port", Title: "Port",
Type: "string", Description: "the name of the serial port to connect to",
Type: "string",
}, },
"baudRate": { "baudRate": {
Title: "Baud Rate", Title: "Baud Rate",
Type: "integer", Description: "the baud rate to use when connecting to the serial port",
Type: "integer",
}, },
"framing": { "framing": {
Title: "Framing Method", Title: "Framing Method",
Type: "string", Description: "the method to use for framing messages on the serial port",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"}, Type: "string",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"},
}, },
}, },
Required: []string{"port", "baudRate", "framing"}, Required: []string{"port", "baudRate", "framing"},
@@ -53,12 +56,14 @@ func init() {
return nil, fmt.Errorf("serial.client framing error: %w", err) return nil, fmt.Errorf("serial.client framing error: %w", err)
} }
framer := framer.GetFramer(framingMethodString) inFramer := framer.GetFramer(framingMethodString)
if framer == nil { if inFramer == nil {
return nil, fmt.Errorf("serial.client unknown framing method: %s", framingMethodString) return nil, fmt.Errorf("serial.client unknown framing method: %s", framingMethodString)
} }
outFramer := framer.GetFramer(framingMethodString)
baudRateInt, err := params.GetInt("baudRate") baudRateInt, err := params.GetInt("baudRate")
if err != nil { if err != nil {
return nil, fmt.Errorf("serial.client baudRate error: %w", err) return nil, fmt.Errorf("serial.client baudRate error: %w", err)
@@ -68,7 +73,7 @@ func init() {
BaudRate: baudRateInt, BaudRate: baudRateInt,
} }
return &SerialClient{config: config, Port: portString, Framer: framer, Mode: &mode, logger: CreateLogger(config)}, nil return &SerialClient{config: config, Port: portString, inFramer: inFramer, outFramer: outFramer, Mode: &mode, logger: CreateLogger(config)}, nil
}, },
}) })
} }
@@ -78,7 +83,8 @@ type SerialClient struct {
ctx context.Context ctx context.Context
inputHandler common.InputHandler inputHandler common.InputHandler
Port string Port string
Framer framer.Framer inFramer framer.Framer
outFramer framer.Framer
Mode *serial.Mode Mode *serial.Mode
port serial.Port port serial.Port
logger *slog.Logger logger *slog.Logger
@@ -139,13 +145,13 @@ func (sc *SerialClient) Start(ctx context.Context, inputHandler common.InputHand
byteCount, err := sc.port.Read(buffer) byteCount, err := sc.port.Read(buffer)
if err != nil { if err != nil {
sc.Framer.Clear() sc.inFramer.Clear()
break READ break READ
} }
if sc.Framer != nil { if sc.inFramer != nil {
if byteCount > 0 { if byteCount > 0 {
messages := sc.Framer.Decode(buffer[0:byteCount]) messages := sc.inFramer.Decode(buffer[0:byteCount])
for _, message := range messages { for _, message := range messages {
if sc.inputHandler != nil { if sc.inputHandler != nil {
sc.inputHandler(sc.ctx, sc.Id(), message) sc.inputHandler(sc.ctx, sc.Id(), message)
@@ -159,6 +165,8 @@ func (sc *SerialClient) Start(ctx context.Context, inputHandler common.InputHand
} }
} }
} }
<-sc.ctx.Done()
sc.logger.Debug("done")
return nil return nil
} }
@@ -170,19 +178,25 @@ func (sc *SerialClient) Output(ctx context.Context, payload any) error {
return errors.New("serial.client can only output bytes") return errors.New("serial.client can only output bytes")
} }
_, err := sc.port.Write(sc.Framer.Encode(payloadBytes)) _, err := sc.port.Write(sc.outFramer.Encode(payloadBytes))
return err return err
} }
func (sc *SerialClient) Stop() { func (sc *SerialClient) Stop() {
if sc.cancel != nil { if sc.cancel != nil {
sc.cancel() defer sc.cancel()
} }
sc.portMu.Lock() sc.portMu.Lock()
defer sc.portMu.Unlock() defer sc.portMu.Unlock()
if sc.port != nil { if sc.port != nil {
sc.port.Close() sc.port.Close()
sc.port = nil
} }
sc.logger.Debug("done")
if sc.inFramer != nil {
sc.inFramer.Clear()
}
if sc.outFramer != nil {
sc.outFramer.Clear()
}
} }
+25 -18
View File
@@ -29,27 +29,31 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the IP address to bind the SIP server to",
Default: json.RawMessage(`"0.0.0.0"`), Type: "string",
Default: json.RawMessage(`"0.0.0.0"`),
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the SIP server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Default: json.RawMessage(`5060`), Maximum: jsonschema.Ptr[float64](65535),
Default: json.RawMessage(`5060`),
}, },
"transport": { "transport": {
Title: "Transport", Title: "Transport",
Type: "string", Description: "the transport protocol to use for the SIP server",
Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"}, Type: "string",
Default: json.RawMessage(`"udp"`), Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"},
Default: json.RawMessage(`"udp"`),
}, },
"userAgent": { "userAgent": {
Title: "User Agent", Title: "User Agent",
Type: "string", Description: "the user agent string to use",
Default: json.RawMessage(`"showbridge"`), Type: "string",
Default: json.RawMessage(`"showbridge"`),
}, },
}, },
Required: []string{}, Required: []string{},
@@ -168,6 +172,7 @@ func (scs *SIPCallServer) Start(ctx context.Context, inputHandler common.InputHa
} }
<-scs.ctx.Done() <-scs.ctx.Done()
scs.logger.Debug("done")
return nil return nil
} }
@@ -207,7 +212,10 @@ func (scs *SIPCallServer) Output(ctx context.Context, payload any) error {
payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload) payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload)
if ok { if ok {
dtmfWriter := call.inDialog.AudioWriterDTMF() dtmfWriter, err := call.inDialog.AudioWriterDTMF()
if err != nil {
return err
}
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait)) time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait))
for i, dtmfRune := range payloadDTMFResponse.Digits { for i, dtmfRune := range payloadDTMFResponse.Digits {
err := dtmfWriter.WriteDTMF(dtmfRune) err := dtmfWriter.WriteDTMF(dtmfRune)
@@ -251,12 +259,11 @@ func (scs *SIPCallServer) Output(ctx context.Context, payload any) error {
func (scs *SIPCallServer) Stop() { func (scs *SIPCallServer) Stop() {
if scs.cancel != nil { if scs.cancel != nil {
scs.cancel() defer scs.cancel()
} }
scs.uaMu.Lock() scs.uaMu.Lock()
defer scs.uaMu.Unlock() defer scs.uaMu.Unlock()
if scs.ua != nil { if scs.ua != nil {
scs.ua.Close() scs.ua.Close()
} }
scs.logger.Debug("done")
} }
+34 -23
View File
@@ -30,33 +30,38 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the IP address to bind the SIP server to",
Default: json.RawMessage(`"0.0.0.0"`), Type: "string",
Default: json.RawMessage(`"0.0.0.0"`),
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the SIP server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Default: json.RawMessage(`5060`), Maximum: jsonschema.Ptr[float64](65535),
Default: json.RawMessage(`5060`),
}, },
"transport": { "transport": {
Title: "Transport", Title: "Transport",
Type: "string", Description: "the transport protocol to use for the SIP server",
Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"}, Type: "string",
Default: json.RawMessage(`"udp"`), Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"},
Default: json.RawMessage(`"udp"`),
}, },
"userAgent": { "userAgent": {
Title: "User Agent", Title: "User Agent",
Type: "string", Description: "the user agent string to use",
Default: json.RawMessage(`"showbridge"`), Type: "string",
Default: json.RawMessage(`"showbridge"`),
}, },
"separator": { "separator": {
Title: "DTMF Separator", Title: "DTMF Separator",
Type: "string", Description: "the DTMF character to use as a separator between DTMF digit groups",
MinLength: new(1), Type: "string",
MaxLength: new(1), MinLength: new(1),
MaxLength: new(1),
}, },
}, },
Required: []string{"separator"}, Required: []string{"separator"},
@@ -190,6 +195,7 @@ func (sds *SIPDTMFServer) Start(ctx context.Context, inputHandler common.InputHa
} }
<-sds.ctx.Done() <-sds.ctx.Done()
sds.logger.Debug("done")
return nil return nil
} }
@@ -198,7 +204,10 @@ func (sds *SIPDTMFServer) HandleCall(inDialog *diago.DialogServerSession) error
inDialog.Ringing() inDialog.Ringing()
inDialog.Answer() inDialog.Answer()
reader := inDialog.AudioReaderDTMF() reader, err := inDialog.AudioReaderDTMF()
if err != nil {
return err
}
userString := "" userString := ""
return reader.Listen(func(dtmf rune) error { return reader.Listen(func(dtmf rune) error {
@@ -240,7 +249,10 @@ func (sds *SIPDTMFServer) Output(ctx context.Context, payload any) error {
payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload) payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload)
if ok { if ok {
dtmfWriter := call.inDialog.AudioWriterDTMF() dtmfWriter, err := call.inDialog.AudioWriterDTMF()
if err != nil {
return err
}
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait)) time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait))
for i, dtmfRune := range payloadDTMFResponse.Digits { for i, dtmfRune := range payloadDTMFResponse.Digits {
@@ -286,12 +298,11 @@ func (sds *SIPDTMFServer) Output(ctx context.Context, payload any) error {
func (sds *SIPDTMFServer) Stop() { func (sds *SIPDTMFServer) Stop() {
if sds.cancel != nil { if sds.cancel != nil {
sds.cancel() defer sds.cancel()
} }
sds.uaMu.Lock() sds.uaMu.Lock()
defer sds.uaMu.Unlock() defer sds.uaMu.Unlock()
if sds.ua != nil { if sds.ua != nil {
sds.ua.Close() sds.ua.Close()
} }
sds.logger.Debug("done")
} }
+57 -42
View File
@@ -23,19 +23,22 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"host": { "host": {
Title: "Host", Title: "Host",
Type: "string", Description: "the hostname or IP address of the TCP server to connect to",
Type: "string",
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port of the TCP server to connect to",
Minimum: jsonschema.Ptr[float64](1), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1),
Maximum: jsonschema.Ptr[float64](65535),
}, },
"framing": { "framing": {
Title: "Framing Method", Title: "Framing Method",
Type: "string", Description: "the method used to frame messages over the TCP connection",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"}, Type: "string",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"},
}, },
}, },
Required: []string{"host", "port", "framing"}, Required: []string{"host", "port", "framing"},
@@ -63,19 +66,22 @@ func init() {
return nil, fmt.Errorf("net.tcp.client framing error: %w", err) return nil, fmt.Errorf("net.tcp.client framing error: %w", err)
} }
framer := framer.GetFramer(framingMethodString) inFramer := framer.GetFramer(framingMethodString)
if framer == nil { if inFramer == nil {
return nil, fmt.Errorf("net.tcp.client unknown framing method: %s", framingMethodString) return nil, fmt.Errorf("net.tcp.client unknown framing method: %s", framingMethodString)
} }
return &TCPClient{framer: framer, Addr: addr, config: config, logger: CreateLogger(config)}, nil
outFramer := framer.GetFramer(framingMethodString)
return &TCPClient{inFramer: inFramer, outFramer: outFramer, Addr: addr, config: config, logger: CreateLogger(config)}, nil
}, },
}) })
} }
type TCPClient struct { type TCPClient struct {
config config.ModuleConfig config config.ModuleConfig
framer framer.Framer inFramer framer.Framer
outFramer framer.Framer
conn *net.TCPConn conn *net.TCPConn
ctx context.Context ctx context.Context
inputHandler common.InputHandler inputHandler common.InputHandler
@@ -100,11 +106,12 @@ func (tc *TCPClient) Start(ctx context.Context, inputHandler common.InputHandler
tc.ctx = moduleContext tc.ctx = moduleContext
tc.cancel = cancel tc.cancel = cancel
CONNECT_RETRY:
for tc.ctx.Err() == nil { for tc.ctx.Err() == nil {
err := tc.SetupConn() err := tc.SetupConn()
if err != nil { if err != nil {
if tc.ctx.Err() != nil { if tc.ctx.Err() != nil {
return nil break CONNECT_RETRY
} }
tc.logger.Error("connection error", "error", err.Error()) tc.logger.Error("connection error", "error", err.Error())
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
@@ -112,39 +119,42 @@ func (tc *TCPClient) Start(ctx context.Context, inputHandler common.InputHandler
} }
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
select {
case <-tc.ctx.Done():
return nil
default:
READ:
for {
select {
case <-tc.ctx.Done():
return nil
default:
byteCount, err := tc.conn.Read(buffer)
if err != nil { READ:
tc.framer.Clear() for tc.ctx.Err() == nil {
break READ tc.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 200))
byteCount, err := tc.conn.Read(buffer)
if err != nil {
opErr, ok := err.(*net.OpError)
if ok {
//NOTE(jwetzell) we hit deadline
if opErr.Timeout() {
continue
} }
}
if errors.Is(err, net.ErrClosed) {
break CONNECT_RETRY
}
break READ
}
if tc.framer != nil { if tc.inFramer != nil {
if byteCount > 0 { if byteCount > 0 {
messages := tc.framer.Decode(buffer[0:byteCount]) messages := tc.inFramer.Decode(buffer[0:byteCount])
for _, message := range messages { for _, message := range messages {
if tc.inputHandler != nil { if tc.inputHandler != nil {
tc.inputHandler(tc.ctx, tc.Id(), message) tc.inputHandler(tc.ctx, tc.Id(), message)
} else { } else {
tc.logger.Error("input received but no input handler is configured") tc.logger.Error("input received but no input handler is configured")
}
}
} }
} }
} }
} }
} }
} }
<-tc.ctx.Done()
tc.logger.Debug("done")
return nil return nil
} }
@@ -166,20 +176,25 @@ func (tc *TCPClient) Output(ctx context.Context, payload any) error {
if !ok { if !ok {
return errors.New("net.tcp.client is only able to output bytes") return errors.New("net.tcp.client is only able to output bytes")
} }
_, err := tc.conn.Write(tc.framer.Encode(payloadBytes)) _, err := tc.conn.Write(tc.inFramer.Encode(payloadBytes))
return err return err
} }
func (tc *TCPClient) Stop() { func (tc *TCPClient) Stop() {
if tc.cancel != nil { if tc.cancel != nil {
tc.cancel() defer tc.cancel()
} }
tc.connMu.Lock() tc.connMu.Lock()
defer tc.connMu.Unlock() defer tc.connMu.Unlock()
if tc.conn != nil { if tc.conn != nil {
tc.conn.Close() tc.conn.Close()
tc.conn = nil
} }
tc.logger.Debug("done")
if tc.inFramer != nil {
tc.inFramer.Clear()
}
if tc.outFramer != nil {
tc.outFramer.Clear()
}
} }
+95 -89
View File
@@ -10,7 +10,6 @@ import (
"slices" "slices"
"strings" "strings"
"sync" "sync"
"syscall"
"time" "time"
"github.com/google/jsonschema-go/jsonschema" "github.com/google/jsonschema-go/jsonschema"
@@ -27,20 +26,23 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the IP address to bind the TCP server to",
Default: json.RawMessage(`"0.0.0.0"`), Type: "string",
Default: json.RawMessage(`"0.0.0.0"`),
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the TCP server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Maximum: jsonschema.Ptr[float64](65535),
}, },
"framing": { "framing": {
Title: "Framing Method", Title: "Framing Method",
Type: "string", Description: "the method used to frame messages over the TCP connection",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"}, Type: "string",
Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"},
}, },
}, },
Required: []string{"port", "framing"}, Required: []string{"port", "framing"},
@@ -58,12 +60,14 @@ func init() {
return nil, fmt.Errorf("net.tcp.server framing error: %w", err) return nil, fmt.Errorf("net.tcp.server framing error: %w", err)
} }
framer := framer.GetFramer(framingMethodString) inFramer := framer.GetFramer(framingMethodString)
if framer == nil { if inFramer == nil {
return nil, fmt.Errorf("net.tcp.server unknown framing method: %s", framingMethodString) return nil, fmt.Errorf("net.tcp.server unknown framing method: %s", framingMethodString)
} }
outFramer := framer.GetFramer(framingMethodString)
ipString, err := params.GetString("ip") ipString, err := params.GetString("ip")
if err != nil { if err != nil {
if errors.Is(err, config.ErrParamNotFound) { if errors.Is(err, config.ErrParamNotFound) {
@@ -77,24 +81,33 @@ func init() {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &TCPServer{Framer: framer, Addr: addr, config: moduleConfig, logger: CreateLogger(moduleConfig)}, nil return &TCPServer{inFramer: inFramer, outFramer: outFramer, framerType: framingMethodString, Addr: addr, config: moduleConfig, logger: CreateLogger(moduleConfig)}, nil
}, },
}) })
} }
type tcpConnection struct {
conn *net.TCPConn
framer framer.Framer
}
type TCPServer struct { type TCPServer struct {
config config.ModuleConfig config config.ModuleConfig
Addr *net.TCPAddr Addr *net.TCPAddr
Framer framer.Framer inFramer framer.Framer
ctx context.Context outFramer framer.Framer
inputHandler common.InputHandler framerType string
wg sync.WaitGroup ctx context.Context
connections []*net.TCPConn inputHandler common.InputHandler
connectionsMu sync.RWMutex wg sync.WaitGroup
logger *slog.Logger connections []tcpConnection
cancel context.CancelFunc connectionsMu sync.RWMutex
listener *net.TCPListener logger *slog.Logger
listenerMu sync.Mutex cancel context.CancelFunc
listener *net.TCPListener
listenerMu sync.Mutex
connectionShutdownCtx context.Context
connectionShutdown context.CancelFunc
} }
func (ts *TCPServer) Id() string { func (ts *TCPServer) Id() string {
@@ -107,70 +120,44 @@ func (ts *TCPServer) Type() string {
func (ts *TCPServer) handleClient(client *net.TCPConn) { func (ts *TCPServer) handleClient(client *net.TCPConn) {
ts.connectionsMu.Lock() ts.connectionsMu.Lock()
ts.connections = append(ts.connections, client) ts.connections = append(ts.connections, tcpConnection{conn: client, framer: framer.GetFramer(ts.framerType)})
ts.connectionsMu.Unlock() ts.connectionsMu.Unlock()
ts.logger.Debug("connection accepted", "remoteAddr", client.RemoteAddr().String()) ts.logger.Debug("connection accepted", "remoteAddr", client.RemoteAddr().String())
defer client.Close() defer func() {
client.Close()
ts.connectionsMu.Lock()
for i := 0; i < len(ts.connections); i++ {
if ts.connections[i].conn == client {
ts.connections = slices.Delete(ts.connections, i, i+1)
break
}
}
ts.connectionsMu.Unlock()
ts.logger.Debug("connection closed", "remoteAddr", client.RemoteAddr().String())
}()
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
ClientRead: for ts.ctx.Err() == nil && ts.connectionShutdownCtx.Err() == nil {
for ts.ctx.Err() == nil { client.SetDeadline(time.Now().Add(time.Millisecond * 200))
select { byteCount, err := client.Read(buffer)
case <-ts.ctx.Done(): if err != nil {
client.Close() opErr, ok := err.(*net.OpError)
ts.connectionsMu.Lock() if ok {
for i := 0; i < len(ts.connections); i++ { //NOTE(jwetzell) we hit deadline
if ts.connections[i] == client { if opErr.Timeout() {
ts.connections = slices.Delete(ts.connections, i, i+1) continue
break
} }
} }
ts.connectionsMu.Unlock() break
return }
default: if ts.inFramer != nil {
client.SetDeadline(time.Now().Add(time.Millisecond * 200)) if byteCount > 0 {
byteCount, err := client.Read(buffer) messages := ts.inFramer.Decode(buffer[0:byteCount])
for _, message := range messages {
if err != nil { if ts.inputHandler != nil {
if opErr, ok := err.(*net.OpError); ok { ts.inputHandler(ts.ctx, ts.Id(), message)
//NOTE(jwetzell) we hit deadline } else {
if opErr.Timeout() { ts.logger.Error("input received but no input handler is configured")
continue ClientRead
}
if errors.Is(opErr, syscall.ECONNRESET) {
ts.connectionsMu.Lock()
for i := 0; i < len(ts.connections); i++ {
if ts.connections[i] == client {
ts.connections = slices.Delete(ts.connections, i, i+1)
break
}
}
ts.logger.Debug("connection reset", "remoteAddr", client.RemoteAddr().String())
ts.connectionsMu.Unlock()
}
}
if err.Error() == "EOF" {
ts.connectionsMu.Lock()
for i := 0; i < len(ts.connections); i++ {
if ts.connections[i] == client {
ts.connections = slices.Delete(ts.connections, i, i+1)
break
}
}
ts.connectionsMu.Unlock()
}
return
}
if ts.Framer != nil {
if byteCount > 0 {
messages := ts.Framer.Decode(buffer[0:byteCount])
for _, message := range messages {
if ts.inputHandler != nil {
ts.inputHandler(ts.ctx, ts.Id(), message)
} else {
ts.logger.Error("input received but no input handler is configured")
}
} }
} }
} }
@@ -185,6 +172,10 @@ func (ts *TCPServer) Start(ctx context.Context, inputHandler common.InputHandler
ts.ctx = moduleContext ts.ctx = moduleContext
ts.cancel = cancel ts.cancel = cancel
shutdownCtx, shutdownCancel := context.WithCancel(context.Background())
ts.connectionShutdownCtx = shutdownCtx
ts.connectionShutdown = shutdownCancel
listener, err := net.ListenTCP("tcp", ts.Addr) listener, err := net.ListenTCP("tcp", ts.Addr)
if err != nil { if err != nil {
return err return err
@@ -198,6 +189,9 @@ AcceptLoop:
for ts.ctx.Err() == nil { for ts.ctx.Err() == nil {
conn, err := listener.AcceptTCP() conn, err := listener.AcceptTCP()
if err != nil { if err != nil {
if errors.Is(err, net.ErrClosed) {
break AcceptLoop
}
select { select {
case <-ts.ctx.Done(): case <-ts.ctx.Done():
break AcceptLoop break AcceptLoop
@@ -211,6 +205,8 @@ AcceptLoop:
} }
} }
ts.wg.Done() ts.wg.Done()
<-ts.ctx.Done()
ts.logger.Debug("done")
return nil return nil
} }
@@ -221,15 +217,21 @@ func (ts *TCPServer) Output(ctx context.Context, payload any) error {
return errors.New("net.tcp.server is only able to output bytes") return errors.New("net.tcp.server is only able to output bytes")
} }
ts.connectionsMu.Lock() ts.connectionsMu.Lock()
defer ts.connectionsMu.Unlock()
var errorString strings.Builder var errorString strings.Builder
if ts.outFramer == nil {
return errors.New("no output framer configured")
}
outputBytes := ts.outFramer.Encode(payloadBytes)
for _, connection := range ts.connections { for _, connection := range ts.connections {
_, err := connection.Write(payloadBytes) _, err := connection.conn.Write(outputBytes)
if err != nil { if err != nil {
fmt.Fprintf(&errorString, "%s\n", err.Error()) fmt.Fprintf(&errorString, "%s\n", err.Error())
} }
} }
ts.connectionsMu.Unlock()
if errorString.String() == "" { if errorString.String() == "" {
return nil return nil
@@ -239,14 +241,18 @@ func (ts *TCPServer) Output(ctx context.Context, payload any) error {
func (ts *TCPServer) Stop() { func (ts *TCPServer) Stop() {
if ts.cancel != nil { if ts.cancel != nil {
ts.cancel() defer ts.cancel()
} }
if ts.connectionShutdown != nil {
ts.connectionShutdown()
}
ts.listenerMu.Lock() ts.listenerMu.Lock()
defer ts.listenerMu.Unlock() defer ts.listenerMu.Unlock()
if ts.listener != nil { if ts.listener != nil {
ts.listener.Close() ts.listener.Close()
ts.listener = nil
} }
ts.logger.Debug("waiting for connections to close")
ts.wg.Wait() ts.wg.Wait()
ts.logger.Debug("done") ts.logger.Debug("all connections closed")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestDbSqliteFromRegistry(t *testing.T) { func TestDbSqliteFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["db.sqlite"] registration, ok := module.GetModuleRegistration("db.sqlite")
if !ok { if !ok {
t.Fatalf("db.sqlite module not registered") t.Fatalf("db.sqlite module not registered")
} }
@@ -58,7 +58,7 @@ func TestGoodDbSqlite(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["db.sqlite"] registration, ok := module.GetModuleRegistration("db.sqlite")
if !ok { if !ok {
t.Fatalf("db.sqlite module not registered") t.Fatalf("db.sqlite module not registered")
} }
@@ -107,7 +107,7 @@ func TestBadDbSqlite(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["db.sqlite"] registration, ok := module.GetModuleRegistration("db.sqlite")
if !ok { if !ok {
t.Fatalf("db.sqlite module not registered") t.Fatalf("db.sqlite module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestHTTPServerFromRegistry(t *testing.T) { func TestHTTPServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["http.server"] registration, ok := module.GetModuleRegistration("http.server")
if !ok { if !ok {
t.Fatalf("http.server module not registered") t.Fatalf("http.server module not registered")
} }
@@ -52,7 +52,7 @@ func TestGoodHTTPServer(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["http.server"] registration, ok := module.GetModuleRegistration("http.server")
if !ok { if !ok {
t.Fatalf("http.server module not registered") t.Fatalf("http.server module not registered")
} }
@@ -102,7 +102,7 @@ func TestBadHTTPServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["http.server"] registration, ok := module.GetModuleRegistration("http.server")
if !ok { if !ok {
t.Fatalf("http.server module not registered") t.Fatalf("http.server module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestMIDIInputFromRegistry(t *testing.T) { func TestMIDIInputFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["midi.input"] registration, ok := module.GetModuleRegistration("midi.input")
if !ok { if !ok {
t.Fatalf("midi.input module not registered") t.Fatalf("midi.input module not registered")
} }
@@ -55,7 +55,7 @@ func TestBadMIDIInput(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["midi.input"] registration, ok := module.GetModuleRegistration("midi.input")
if !ok { if !ok {
t.Fatalf("midi.input module not registered") t.Fatalf("midi.input module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestMIDIOutputFromRegistry(t *testing.T) { func TestMIDIOutputFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["midi.output"] registration, ok := module.GetModuleRegistration("midi.output")
if !ok { if !ok {
t.Fatalf("midi.output module not registered") t.Fatalf("midi.output module not registered")
} }
@@ -55,7 +55,7 @@ func TestBadMIDIOutput(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["midi.output"] registration, ok := module.GetModuleRegistration("midi.output")
if !ok { if !ok {
t.Fatalf("midi.output module not registered") t.Fatalf("midi.output module not registered")
} }
+6 -3
View File
@@ -11,7 +11,8 @@ import (
func TestModuleBadRegistrationNoType(t *testing.T) { func TestModuleBadRegistrationNoType(t *testing.T) {
defer func() { defer func() {
if r := recover(); r == nil { r := recover()
if r == nil {
t.Fatalf("module registration should have panicked but did not") t.Fatalf("module registration should have panicked but did not")
} }
}() }()
@@ -26,7 +27,8 @@ func TestModuleBadRegistrationNoType(t *testing.T) {
func TestModuleBadRegistrationNoNew(t *testing.T) { func TestModuleBadRegistrationNoNew(t *testing.T) {
defer func() { defer func() {
if r := recover(); r == nil { r := recover()
if r == nil {
t.Fatalf("processor registration should have panicked but did not") t.Fatalf("processor registration should have panicked but did not")
} }
}() }()
@@ -39,7 +41,8 @@ func TestModuleBadRegistrationNoNew(t *testing.T) {
func TestModuleBadRegistrationExistingType(t *testing.T) { func TestModuleBadRegistrationExistingType(t *testing.T) {
defer func() { defer func() {
if r := recover(); r == nil { r := recover()
if r == nil {
t.Fatalf("processor registration should have panicked but did not") t.Fatalf("processor registration should have panicked but did not")
} }
}() }()
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestMQTTClientFromRegistry(t *testing.T) { func TestMQTTClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["mqtt.client"] registration, ok := module.GetModuleRegistration("mqtt.client")
if !ok { if !ok {
t.Fatalf("mqtt.client module not registered") t.Fatalf("mqtt.client module not registered")
} }
@@ -98,7 +98,7 @@ func TestBadMQTTClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["mqtt.client"] registration, ok := module.GetModuleRegistration("mqtt.client")
if !ok { if !ok {
t.Fatalf("mqtt.client module not registered") t.Fatalf("mqtt.client module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestNATSClientFromRegistry(t *testing.T) { func TestNATSClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["nats.client"] registration, ok := module.GetModuleRegistration("nats.client")
if !ok { if !ok {
t.Fatalf("nats.client module not registered") t.Fatalf("nats.client module not registered")
} }
@@ -76,7 +76,7 @@ func TestBadNATSClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["nats.client"] registration, ok := module.GetModuleRegistration("nats.client")
if !ok { if !ok {
t.Fatalf("nats.client module not registered") t.Fatalf("nats.client module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestNATSServerFromRegistry(t *testing.T) { func TestNATSServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["nats.server"] registration, ok := module.GetModuleRegistration("nats.server")
if !ok { if !ok {
t.Fatalf("nats.server module not registered") t.Fatalf("nats.server module not registered")
} }
@@ -53,7 +53,7 @@ func TestGoodNATSServer(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["nats.server"] registration, ok := module.GetModuleRegistration("nats.server")
if !ok { if !ok {
t.Fatalf("nats.server module not registered") t.Fatalf("nats.server module not registered")
} }
@@ -100,7 +100,7 @@ func TestBadNATSServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["nats.server"] registration, ok := module.GetModuleRegistration("nats.server")
if !ok { if !ok {
t.Fatalf("nats.server module not registered") t.Fatalf("nats.server module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestPSNClientFromRegistry(t *testing.T) { func TestPSNClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["psn.client"] registration, ok := module.GetModuleRegistration("psn.client")
if !ok { if !ok {
t.Fatalf("psn.client module not registered") t.Fatalf("psn.client module not registered")
} }
@@ -41,7 +41,7 @@ func TestBadPSNClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["psn.client"] registration, ok := module.GetModuleRegistration("psn.client")
if !ok { if !ok {
t.Fatalf("psn.client module not registered") t.Fatalf("psn.client module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestRedisClientFromRegistry(t *testing.T) { func TestRedisClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["redis.client"] registration, ok := module.GetModuleRegistration("redis.client")
if !ok { if !ok {
t.Fatalf("redis.client module not registered") t.Fatalf("redis.client module not registered")
} }
@@ -76,7 +76,7 @@ func TestBadRedisClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["redis.client"] registration, ok := module.GetModuleRegistration("redis.client")
if !ok { if !ok {
t.Fatalf("redis.client module not registered") t.Fatalf("redis.client module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestSerialClientFromRegistry(t *testing.T) { func TestSerialClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["serial.client"] registration, ok := module.GetModuleRegistration("serial.client")
if !ok { if !ok {
t.Fatalf("serial.client module not registered") t.Fatalf("serial.client module not registered")
} }
@@ -85,7 +85,7 @@ func TestBadSerialClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["serial.client"] registration, ok := module.GetModuleRegistration("serial.client")
if !ok { if !ok {
t.Fatalf("serial.client module not registered") t.Fatalf("serial.client module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestSIPCallServerFromRegistry(t *testing.T) { func TestSIPCallServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["sip.call.server"] registration, ok := module.GetModuleRegistration("sip.call.server")
if !ok { if !ok {
t.Fatalf("sip.call.server module not registered") t.Fatalf("sip.call.server module not registered")
} }
@@ -70,7 +70,7 @@ func TestBadSIPCallServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["sip.call.server"] registration, ok := module.GetModuleRegistration("sip.call.server")
if !ok { if !ok {
t.Fatalf("sip.call.server module not registered") t.Fatalf("sip.call.server module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestSIPDTMFServerFromRegistry(t *testing.T) { func TestSIPDTMFServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["sip.dtmf.server"] registration, ok := module.GetModuleRegistration("sip.dtmf.server")
if !ok { if !ok {
t.Fatalf("sip.dtmf.server module not registered") t.Fatalf("sip.dtmf.server module not registered")
} }
@@ -89,7 +89,7 @@ func TestBadSIPDTMFServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["sip.dtmf.server"] registration, ok := module.GetModuleRegistration("sip.dtmf.server")
if !ok { if !ok {
t.Fatalf("sip.dtmf.server module not registered") t.Fatalf("sip.dtmf.server module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestTCPClientFromRegistry(t *testing.T) { func TestTCPClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["net.tcp.client"] registration, ok := module.GetModuleRegistration("net.tcp.client")
if !ok { if !ok {
t.Fatalf("net.tcp.client module not registered") t.Fatalf("net.tcp.client module not registered")
} }
@@ -77,7 +77,7 @@ func TestBadTCPClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.tcp.client"] registration, ok := module.GetModuleRegistration("net.tcp.client")
if !ok { if !ok {
t.Fatalf("net.tcp.client module not registered") t.Fatalf("net.tcp.client module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestTCPServerFromRegistry(t *testing.T) { func TestTCPServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["net.tcp.server"] registration, ok := module.GetModuleRegistration("net.tcp.server")
if !ok { if !ok {
t.Fatalf("net.tcp.server module not registered") t.Fatalf("net.tcp.server module not registered")
} }
@@ -54,7 +54,7 @@ func TestGoodTCPServer(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.tcp.server"] registration, ok := module.GetModuleRegistration("net.tcp.server")
if !ok { if !ok {
t.Fatalf("net.tcp.server module not registered") t.Fatalf("net.tcp.server module not registered")
} }
@@ -149,7 +149,7 @@ func TestBadTCPServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.tcp.server"] registration, ok := module.GetModuleRegistration("net.tcp.server")
if !ok { if !ok {
t.Fatalf("net.tcp.server module not registered") t.Fatalf("net.tcp.server module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestTimeIntervalFromRegistry(t *testing.T) { func TestTimeIntervalFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["time.interval"] registration, ok := module.GetModuleRegistration("time.interval")
if !ok { if !ok {
t.Fatalf("time.interval module not registered") t.Fatalf("time.interval module not registered")
} }
@@ -52,7 +52,7 @@ func TestGoodTimeInterval(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["time.interval"] registration, ok := module.GetModuleRegistration("time.interval")
if !ok { if !ok {
t.Fatalf("time.interval module not registered") t.Fatalf("time.interval module not registered")
} }
@@ -103,7 +103,7 @@ func TestBadTimeInterval(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["time.interval"] registration, ok := module.GetModuleRegistration("time.interval")
if !ok { if !ok {
t.Fatalf("time.interval module not registered") t.Fatalf("time.interval module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestTimeTimerFromRegistry(t *testing.T) { func TestTimeTimerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["time.timer"] registration, ok := module.GetModuleRegistration("time.timer")
if !ok { if !ok {
t.Fatalf("time.timer module not registered") t.Fatalf("time.timer module not registered")
} }
@@ -52,7 +52,7 @@ func TestGoodTimeTimer(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["time.timer"] registration, ok := module.GetModuleRegistration("time.timer")
if !ok { if !ok {
t.Fatalf("time.timer module not registered") t.Fatalf("time.timer module not registered")
} }
@@ -103,7 +103,7 @@ func TestBadTimeTimer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["time.timer"] registration, ok := module.GetModuleRegistration("time.timer")
if !ok { if !ok {
t.Fatalf("time.timer module not registered") t.Fatalf("time.timer module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestUDPClientFromRegistry(t *testing.T) { func TestUDPClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.client"] registration, ok := module.GetModuleRegistration("net.udp.client")
if !ok { if !ok {
t.Fatalf("udp.client module not registered") t.Fatalf("udp.client module not registered")
} }
@@ -55,7 +55,7 @@ func TestGoodUDPClient(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.client"] registration, ok := module.GetModuleRegistration("net.udp.client")
if !ok { if !ok {
t.Fatalf("net.udp.client module not registered") t.Fatalf("net.udp.client module not registered")
} }
@@ -125,7 +125,7 @@ func TestBadUDPClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.client"] registration, ok := module.GetModuleRegistration("net.udp.client")
if !ok { if !ok {
t.Fatalf("net.udp.client module not registered") t.Fatalf("net.udp.client module not registered")
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
) )
func TestUDPMulticastFromRegistry(t *testing.T) { func TestUDPMulticastFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.multicast"] registration, ok := module.GetModuleRegistration("net.udp.multicast")
if !ok { if !ok {
t.Fatalf("udp.multicast module not registered") t.Fatalf("udp.multicast module not registered")
} }
@@ -84,7 +84,7 @@ func TestBadUDPMulticast(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.multicast"] registration, ok := module.GetModuleRegistration("net.udp.multicast")
if !ok { if !ok {
t.Fatalf("net.udp.multicast module not registered") t.Fatalf("net.udp.multicast module not registered")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
) )
func TestUDPServerFromRegistry(t *testing.T) { func TestUDPServerFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.server"] registration, ok := module.GetModuleRegistration("net.udp.server")
if !ok { if !ok {
t.Fatalf("net.udp.server module not registered") t.Fatalf("net.udp.server module not registered")
} }
@@ -52,7 +52,7 @@ func TestGoodUDPServer(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.server"] registration, ok := module.GetModuleRegistration("net.udp.server")
if !ok { if !ok {
t.Fatalf("net.udp.server module not registered") t.Fatalf("net.udp.server module not registered")
} }
@@ -128,7 +128,7 @@ func TestBadUDPServer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["net.udp.server"] registration, ok := module.GetModuleRegistration("net.udp.server")
if !ok { if !ok {
t.Fatalf("net.udp.server module not registered") t.Fatalf("net.udp.server module not registered")
} }
@@ -8,7 +8,7 @@ import (
) )
func TestWebSocketClientFromRegistry(t *testing.T) { func TestWebSocketClientFromRegistry(t *testing.T) {
registration, ok := module.ModuleRegistry["websocket.client"] registration, ok := module.GetModuleRegistration("websocket.client")
if !ok { if !ok {
t.Fatalf("websocket.client module not registered") t.Fatalf("websocket.client module not registered")
} }
@@ -64,7 +64,7 @@ func TestBadWebSocketClient(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := module.ModuleRegistry["websocket.client"] registration, ok := module.GetModuleRegistration("websocket.client")
if !ok { if !ok {
t.Fatalf("websocket.client module not registered") t.Fatalf("websocket.client module not registered")
} }
+8 -7
View File
@@ -20,8 +20,8 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"duration": { "duration": {
Title: "Duration", Title: "Duration",
Description: "time in milliseconds between emitted events",
Type: "integer", Type: "integer",
Description: "Interval duration in milliseconds",
}, },
}, },
Required: []string{"duration"}, Required: []string{"duration"},
@@ -67,25 +67,26 @@ func (i *TimeInterval) Start(ctx context.Context, inputHandler common.InputHandl
ticker := time.NewTicker(time.Millisecond * time.Duration(i.Duration)) ticker := time.NewTicker(time.Millisecond * time.Duration(i.Duration))
i.ticker = ticker i.ticker = ticker
for { for i.ctx.Err() == nil {
select { select {
case <-i.ctx.Done():
return nil
case <-ticker.C: case <-ticker.C:
if i.inputHandler != nil { if i.inputHandler != nil {
i.inputHandler(i.ctx, i.Id(), time.Now()) i.inputHandler(i.ctx, i.Id(), time.Now())
} }
default:
continue
} }
} }
<-i.ctx.Done()
i.logger.Debug("done")
return nil
} }
func (i *TimeInterval) Stop() { func (i *TimeInterval) Stop() {
if i.cancel != nil { if i.cancel != nil {
i.cancel() defer i.cancel()
} }
if i.ticker != nil { if i.ticker != nil {
i.ticker.Stop() i.ticker.Stop()
i.ticker = nil
} }
i.logger.Debug("done")
} }
+6 -5
View File
@@ -20,8 +20,8 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"duration": { "duration": {
Title: "Duration", Title: "Duration",
Description: "time in milliseconds before the timer fires",
Type: "integer", Type: "integer",
Description: "Interval duration in milliseconds",
}, },
}, },
Required: []string{"duration"}, Required: []string{"duration"},
@@ -66,7 +66,7 @@ func (t *TimeTimer) Start(ctx context.Context, inputHandler common.InputHandler)
t.cancel = cancel t.cancel = cancel
t.timer = time.NewTimer(time.Millisecond * time.Duration(t.Duration)) t.timer = time.NewTimer(time.Millisecond * time.Duration(t.Duration))
for { for t.ctx.Err() == nil {
select { select {
case <-t.ctx.Done(): case <-t.ctx.Done():
return nil return nil
@@ -76,15 +76,16 @@ func (t *TimeTimer) Start(ctx context.Context, inputHandler common.InputHandler)
} }
} }
} }
<-t.ctx.Done()
t.logger.Debug("done")
return nil
} }
func (t *TimeTimer) Stop() { func (t *TimeTimer) Stop() {
if t.cancel != nil { if t.cancel != nil {
t.cancel() defer t.cancel()
} }
if t.timer != nil { if t.timer != nil {
t.timer.Stop() t.timer.Stop()
t.timer = nil
} }
t.logger.Debug("done")
} }
+10 -10
View File
@@ -21,14 +21,16 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"host": { "host": {
Title: "Host", Title: "Host",
Type: "string", Description: "the hostname or IP address of the UDP server to connect to",
Type: "string",
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port of the UDP server to connect to",
Minimum: jsonschema.Ptr[float64](1), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1),
Maximum: jsonschema.Ptr[float64](65535),
}, },
}, },
Required: []string{"host", "port"}, Required: []string{"host", "port"},
@@ -96,6 +98,7 @@ func (uc *UDPClient) Start(ctx context.Context, inputHandler common.InputHandler
} }
<-uc.ctx.Done() <-uc.ctx.Done()
uc.logger.Debug("done")
return nil return nil
} }
@@ -120,14 +123,11 @@ func (uc *UDPClient) Output(ctx context.Context, payload any) error {
func (uc *UDPClient) Stop() { func (uc *UDPClient) Stop() {
if uc.cancel != nil { if uc.cancel != nil {
uc.cancel() defer uc.cancel()
} }
uc.connMu.Lock() uc.connMu.Lock()
defer uc.connMu.Unlock() defer uc.connMu.Unlock()
if uc.conn != nil { if uc.conn != nil {
uc.conn.Close() uc.conn.Close()
uc.conn = nil
} }
uc.logger.Debug("done")
} }
+31 -31
View File
@@ -22,14 +22,16 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the multicast address to listen on",
Type: "string",
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Maximum: jsonschema.Ptr[float64](65535),
}, },
}, },
Required: []string{"ip", "port"}, Required: []string{"ip", "port"},
@@ -93,35 +95,35 @@ func (um *UDPMulticast) Start(ctx context.Context, inputHandler common.InputHand
um.connMu.Unlock() um.connMu.Unlock()
buffer := make([]byte, 2048) buffer := make([]byte, 2048)
for { for um.ctx.Err() == nil {
select { um.conn.SetDeadline(time.Now().Add(time.Millisecond * 200))
case <-um.ctx.Done():
return nil
default:
um.connMu.Lock()
um.conn.SetDeadline(time.Now().Add(time.Millisecond * 200))
numBytes, _, err := um.conn.ReadFromUDP(buffer) numBytes, _, err := um.conn.ReadFromUDP(buffer)
um.connMu.Unlock() if err != nil {
if err != nil { if errors.Is(err, net.ErrClosed) {
//NOTE(jwetzell) we hit deadline break
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
}
return err
} }
//NOTE(jwetzell) we hit deadline
opErr, ok := err.(*net.OpError)
if ok && opErr.Timeout() {
continue
}
return err
}
if numBytes > 0 { if numBytes > 0 {
message := buffer[:numBytes] message := buffer[:numBytes]
if um.inputHandler != nil { if um.inputHandler != nil {
um.inputHandler(um.ctx, um.Id(), message) um.inputHandler(um.ctx, um.Id(), message)
} else { } else {
um.logger.Error("input received but no input handler is configured") um.logger.Error("input received but no input handler is configured")
}
} }
} }
} }
<-um.ctx.Done()
um.logger.Debug("done")
return nil
} }
func (um *UDPMulticast) Output(ctx context.Context, payload any) error { func (um *UDPMulticast) Output(ctx context.Context, payload any) error {
@@ -141,13 +143,11 @@ func (um *UDPMulticast) Output(ctx context.Context, payload any) error {
func (um *UDPMulticast) Stop() { func (um *UDPMulticast) Stop() {
if um.cancel != nil { if um.cancel != nil {
um.cancel() defer um.cancel()
} }
um.connMu.Lock() um.connMu.Lock()
defer um.connMu.Unlock() defer um.connMu.Unlock()
if um.conn != nil { if um.conn != nil {
um.conn.Close() um.conn.Close()
um.conn = nil
} }
um.logger.Debug("done")
} }
+33 -34
View File
@@ -23,22 +23,25 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"ip": { "ip": {
Title: "IP", Title: "IP",
Type: "string", Description: "the IP address to bind the UDP server to",
Default: json.RawMessage(`"0.0.0.0"`), Type: "string",
Default: json.RawMessage(`"0.0.0.0"`),
}, },
"port": { "port": {
Title: "Port", Title: "Port",
Type: "integer", Description: "the port for the UDP server to listen on",
Minimum: jsonschema.Ptr[float64](1024), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1024),
Maximum: jsonschema.Ptr[float64](65535),
}, },
"bufferSize": { "bufferSize": {
Title: "Buffer Size", Title: "Buffer Size",
Type: "integer", Description: "the size of the buffer for incoming UDP messages",
Minimum: jsonschema.Ptr[float64](1), Type: "integer",
Maximum: jsonschema.Ptr[float64](65535), Minimum: jsonschema.Ptr[float64](1),
Default: json.RawMessage("2048"), Maximum: jsonschema.Ptr[float64](65535),
Default: json.RawMessage("2048"),
}, },
}, },
Required: []string{"port"}, Required: []string{"port"},
@@ -111,32 +114,30 @@ func (us *UDPServer) Start(ctx context.Context, inputHandler common.InputHandler
} }
us.listenerMu.Lock() us.listenerMu.Lock()
us.listener = listener us.listener = listener
us.listenerMu.Unlock()
buffer := make([]byte, us.BufferSize) buffer := make([]byte, us.BufferSize)
for us.ctx.Err() == nil { for us.ctx.Err() == nil {
select { listener.SetDeadline(time.Now().Add(time.Millisecond * 200))
case <-us.ctx.Done():
return nil
default:
listener.SetDeadline(time.Now().Add(time.Millisecond * 200))
numBytes, _, err := listener.ReadFromUDP(buffer) numBytes, _, err := listener.ReadFromUDP(buffer)
if err != nil { if err != nil {
//NOTE(jwetzell) we hit deadline //NOTE(jwetzell) we hit deadline
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { opErr, ok := err.(*net.OpError)
continue if ok && opErr.Timeout() {
} continue
return err
}
message := buffer[:numBytes]
if us.inputHandler != nil {
us.inputHandler(us.ctx, us.Id(), message)
} else {
us.logger.Error("input received but no input handler is configured")
} }
break
}
message := buffer[:numBytes]
if us.inputHandler != nil {
us.inputHandler(us.ctx, us.Id(), message)
} else {
us.logger.Error("input received but no input handler is configured")
} }
} }
us.listenerMu.Unlock() <-us.ctx.Done()
us.logger.Debug("done")
return nil return nil
} }
@@ -146,13 +147,11 @@ func (us *UDPServer) Output(ctx context.Context, payload any) error {
func (us *UDPServer) Stop() { func (us *UDPServer) Stop() {
if us.cancel != nil { if us.cancel != nil {
us.cancel() defer us.cancel()
} }
us.listenerMu.Lock() us.listenerMu.Lock()
defer us.listenerMu.Unlock() defer us.listenerMu.Unlock()
if us.listener != nil { if us.listener != nil {
us.listener.Close() us.listener.Close()
us.listener = nil
} }
us.logger.Debug("done")
} }
+41 -18
View File
@@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net"
"net/url" "net/url"
"sync" "sync"
"time" "time"
@@ -24,8 +23,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"url": { "url": {
Title: "URL", Title: "URL",
Type: "string", Description: "the URL of the WebSocket server to connect",
Type: "string",
}, },
}, },
Required: []string{"url"}, Required: []string{"url"},
@@ -74,7 +74,30 @@ func (wc *WebSocketClient) Type() string {
func (wc *WebSocketClient) SetupConn() error { func (wc *WebSocketClient) SetupConn() error {
wc.connMu.Lock() wc.connMu.Lock()
defer wc.connMu.Unlock() defer wc.connMu.Unlock()
if wc.conn != nil {
wc.conn.Close()
}
conn, _, err := websocket.DefaultDialer.Dial(wc.URL.String(), nil) conn, _, err := websocket.DefaultDialer.Dial(wc.URL.String(), nil)
if err != nil {
return fmt.Errorf("websocket.client dial error: %w", err)
}
conn.SetCloseHandler(func(code int, text string) error {
// NOTE(jwetzell): attempt to send close message back to server before closing connection
err := wc.conn.WriteControl(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
time.Now().Add(time.Minute),
)
wc.connMu.Lock()
defer wc.connMu.Unlock()
if wc.conn != nil {
wc.conn.Close()
}
return err
})
wc.conn = conn wc.conn = conn
return err return err
} }
@@ -92,13 +115,13 @@ func (wc *WebSocketClient) Start(ctx context.Context, inputHandler common.InputH
wc.logger.Error("connection error", "error", err) wc.logger.Error("connection error", "error", err)
} else { } else {
// NOTE(jwetzell): enter read loop until an error occurs // NOTE(jwetzell): enter read loop until an error occurs
wc.logger.Debug("websocket connection established entering read loop")
wc.readLoop() wc.readLoop()
} }
// NOTE(jwetzell): if connection is lost or read error wait before trying again // NOTE(jwetzell): if connection is lost or read error wait before trying again
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} }
<-wc.ctx.Done() <-wc.ctx.Done()
wc.logger.Debug("done")
return nil return nil
} }
@@ -108,24 +131,22 @@ func (wc *WebSocketClient) readLoop() {
wc.logger.Error("websocket connection is not established") wc.logger.Error("websocket connection is not established")
return return
} }
// TODO(jwetzell): other ways to timeout?
wc.conn.SetReadDeadline(time.Now().Add(5 * time.Second)) wc.conn.SetReadDeadline(time.Now().Add(5 * time.Second))
messageType, message, err := wc.conn.ReadMessage() messageType, message, err := wc.conn.ReadMessage()
if err != nil { if err != nil {
if opErr, ok := err.(*net.OpError); ok {
// NOTE(jwetzell) we hit deadline
if opErr.Timeout() {
continue
}
// NOTE(jwetzell) connection was closed
if errors.Is(opErr, net.ErrClosed) {
continue
}
}
wc.logger.Error("websocket read error", "error", err)
return return
} }
if wc.inputHandler != nil { if wc.inputHandler != nil {
switch messageType { switch messageType {
case websocket.CloseMessage:
return
case websocket.PingMessage:
err := wc.conn.WriteMessage(websocket.PongMessage, nil)
if err != nil {
wc.logger.Error("websocket pong error", "error", err)
return
}
case websocket.TextMessage: case websocket.TextMessage:
wc.inputHandler(wc.ctx, wc.Id(), string(message)) wc.inputHandler(wc.ctx, wc.Id(), string(message))
case websocket.BinaryMessage: case websocket.BinaryMessage:
@@ -182,13 +203,15 @@ func (wc *WebSocketClient) Output(ctx context.Context, payload any) error {
func (wc *WebSocketClient) Stop() { func (wc *WebSocketClient) Stop() {
if wc.cancel != nil { if wc.cancel != nil {
wc.cancel() defer wc.cancel()
} }
wc.connMu.Lock() wc.connMu.Lock()
defer wc.connMu.Unlock() defer wc.connMu.Unlock()
if wc.conn != nil { if wc.conn != nil {
err := wc.conn.WriteControl(websocket.CloseMessage, nil, time.Now().Add(time.Minute))
if err != nil {
wc.logger.Error("websocket close error", "error", err)
}
wc.conn.Close() wc.conn.Close()
wc.conn = nil
} }
wc.logger.Debug("done")
} }
+2 -2
View File
@@ -22,13 +22,13 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"module": { "module": {
Title: "Module ID", Title: "Module ID",
Type: "string",
Description: "ID of the database module to query", Description: "ID of the database module to query",
Type: "string",
}, },
"query": { "query": {
Title: "Query", Title: "Query",
Type: "string",
Description: "SQL query to execute", Description: "SQL query to execute",
Type: "string",
}, },
}, },
Required: []string{"module", "query"}, Required: []string{"module", "query"},
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"expression": { "expression": {
Title: "Expression", Title: "Expression",
Type: "string", Description: "Expr expression to evaluate, must return a boolean",
Type: "string",
}, },
}, },
Required: []string{"expression"}, Required: []string{"expression"},
+58
View File
@@ -0,0 +1,58 @@
package processor
import (
"context"
"fmt"
"github.com/google/jsonschema-go/jsonschema"
"github.com/jwetzell/showbridge-go/internal/common"
"github.com/jwetzell/showbridge-go/internal/config"
"golang.org/x/time/rate"
)
func init() {
RegisterProcessor(ProcessorRegistration{
Type: "filter.rate",
Title: "Filter by Rate",
ParamsSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"rate": {
Title: "Rate",
Description: "number of events to allow per second",
Type: "integer",
},
},
Required: []string{"rate"},
},
New: func(config config.ProcessorConfig) (Processor, error) {
params := config.Params
rateInt, err := params.GetInt("rate")
if err != nil {
return nil, fmt.Errorf("filter.rate rate error: %w", err)
}
limiter := rate.NewLimiter(rate.Limit(rateInt), rateInt*2)
return &FilterRate{config: config, limiter: limiter}, nil
},
})
}
type FilterRate struct {
config config.ProcessorConfig
limiter *rate.Limiter
}
func (fc *FilterRate) Process(ctx context.Context, wrappedPayload common.WrappedPayload) (common.WrappedPayload, error) {
err := fc.limiter.Wait(ctx)
if err != nil {
wrappedPayload.End = true
return wrappedPayload, err
}
return wrappedPayload, nil
}
func (fc *FilterRate) Type() string {
return fc.config.Type
}
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"pattern": { "pattern": {
Title: "Pattern", Title: "Pattern",
Type: "string", Description: "regex pattern to match against",
Type: "string",
}, },
}, },
Required: []string{"pattern"}, Required: []string{"pattern"},
+5 -4
View File
@@ -20,10 +20,11 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"bitSize": { "bitSize": {
Title: "Bit Size", Title: "Bit Size",
Type: "integer", Description: "bit size of the resulting float",
Enum: []any{32, 64}, Type: "integer",
Default: json.RawMessage("64"), Enum: []any{32, 64},
Default: json.RawMessage("64"),
}, },
}, },
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}}, AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
+11 -8
View File
@@ -20,18 +20,21 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"bitSize": { "bitSize": {
Title: "Bit Size", Title: "Bit Size",
Type: "integer", Description: "bit size of the resulting float",
Enum: []any{32, 64}, Type: "integer",
Default: json.RawMessage("32"), Enum: []any{32, 64},
Default: json.RawMessage("32"),
}, },
"min": { "min": {
Title: "Minimum", Title: "Minimum",
Type: "number", Description: "inclusive minimum value of the random float",
Type: "number",
}, },
"max": { "max": {
Title: "Maximum", Title: "Maximum",
Type: "number", Description: "exclusive maximum value of the random float",
Type: "number",
}, },
}, },
Required: []string{"min", "max"}, Required: []string{"min", "max"},
+27 -18
View File
@@ -21,40 +21,49 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"id": { "id": {
Title: "Camera ID", Title: "Camera ID",
Type: "string", Description: "ID of the camera this FreeD position corresponds to",
Type: "string",
}, },
"pan": { "pan": {
Title: "Pan", Title: "Pan",
Type: "string", Description: "pan angle of the camera",
Type: "string",
}, },
"tilt": { "tilt": {
Title: "Tilt", Title: "Tilt",
Type: "string", Description: "tilt angle of the camera",
Type: "string",
}, },
"roll": { "roll": {
Title: "Roll", Title: "Roll",
Type: "string", Description: "roll angle of the camera",
Type: "string",
}, },
"posX": { "posX": {
Title: "Position X", Title: "Position X",
Type: "string", Description: "X coordinate of the camera's position",
Type: "string",
}, },
"posY": { "posY": {
Title: "Position Y", Title: "Position Y",
Type: "string", Description: "Y coordinate of the camera's position",
Type: "string",
}, },
"posZ": { "posZ": {
Title: "Position Z", Title: "Position Z",
Type: "string", Description: "Z coordinate of the camera's position",
Type: "string",
}, },
"zoom": { "zoom": {
Title: "Zoom", Title: "Zoom",
Type: "string", Description: "zoom level of the camera",
Type: "string",
}, },
"focus": { "focus": {
Title: "Focus", Title: "Focus",
Type: "string", Description: "focus level of the camera",
Type: "string",
}, },
}, },
Required: []string{ Required: []string{
+7 -5
View File
@@ -22,13 +22,15 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"method": { "method": {
Title: "HTTP Method", Title: "HTTP Method",
Type: "string", Description: "method to use for the HTTP request",
Enum: []any{"GET", "POST", "PUT", "PATCH", "DELETE"}, Type: "string",
Enum: []any{"GET", "POST", "PUT", "PATCH", "DELETE"},
}, },
"url": { "url": {
Title: "URL", Title: "URL",
Type: "string", Description: "URL to send the HTTP request to",
Type: "string",
}, },
}, },
Required: []string{"method", "url"}, Required: []string{"method", "url"},
+8 -6
View File
@@ -19,15 +19,17 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"status": { "status": {
Title: "Status Code", Title: "Status Code",
Type: "integer", Description: "status code to set on the response",
Type: "integer",
}, },
"body": { "bodyTemplate": {
Title: "Body", Title: "Body Template",
Type: "string", Description: "template for the response body",
Type: "string",
}, },
}, },
Required: []string{"status", "body"}, Required: []string{"status", "bodyTemplate"},
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}}, AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
}, },
New: func(config config.ProcessorConfig) (Processor, error) { New: func(config config.ProcessorConfig) (Processor, error) {
+10 -8
View File
@@ -20,16 +20,18 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"base": { "base": {
Title: "Base", Title: "Base",
Type: "integer", Description: "numerical base to use for parsing the integer",
Enum: []any{0, 2, 8, 10, 16}, Type: "integer",
Default: json.RawMessage("10"), Enum: []any{0, 2, 8, 10, 16},
Default: json.RawMessage("10"),
}, },
"bitSize": { "bitSize": {
Title: "Bit Size", Title: "Bit Size",
Type: "integer", Description: "bit size of the resulting integer",
Enum: []any{0, 8, 16, 32, 64}, Type: "integer",
Default: json.RawMessage("64"), Enum: []any{0, 8, 16, 32, 64},
Default: json.RawMessage("64"),
}, },
}, },
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}}, AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
+6 -4
View File
@@ -19,12 +19,14 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"min": { "min": {
Title: "Minimum", Title: "Minimum",
Type: "integer", Description: "inclusive minimum value of the random integer",
Type: "integer",
}, },
"max": { "max": {
Title: "Maximum", Title: "Maximum",
Type: "integer", Description: "inclusive maximum value of the random integer",
Type: "integer",
}, },
}, },
Required: []string{"min", "max"}, Required: []string{"min", "max"},
+12 -8
View File
@@ -18,20 +18,24 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"inMin": { "inMin": {
Title: "Input Minimum", Title: "Input Minimum",
Type: "integer", Description: "minimum value of the input integer",
Type: "integer",
}, },
"inMax": { "inMax": {
Title: "Input Maximum", Title: "Input Maximum",
Type: "integer", Description: "maximum value of the input integer",
Type: "integer",
}, },
"outMin": { "outMin": {
Title: "Output Minimum", Title: "Output Minimum",
Type: "integer", Description: "minimum value of the output integer",
Type: "integer",
}, },
"outMax": { "outMax": {
Title: "Output Maximum", Title: "Output Maximum",
Type: "integer", Description: "maximum value of the output integer",
Type: "integer",
}, },
}, },
Required: []string{"inMin", "inMax", "outMin", "outMax"}, Required: []string{"inMin", "inMax", "outMin", "outMax"},
+7 -5
View File
@@ -19,12 +19,14 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"module": { "module": {
Title: "Module ID", Title: "Module ID",
Type: "string", Description: "ID of the key-value module to get the value from",
Type: "string",
}, },
"key": { "key": {
Title: "Key", Title: "Key",
Type: "string", Description: "key to retrieve from the key-value module",
Type: "string",
}, },
}, },
Required: []string{"module", "key"}, Required: []string{"module", "key"},
@@ -77,7 +79,7 @@ func (kvg *KVGet) Process(ctx context.Context, wrappedPayload common.WrappedPayl
kvg.module = kvModule kvg.module = kvModule
} }
value, err := kvg.module.Get(kvg.Key) value, err := kvg.module.Get(ctx, 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)
+7 -5
View File
@@ -19,12 +19,14 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"module": { "module": {
Title: "Module ID", Title: "Module ID",
Type: "string", Description: "ID of the key-value module to set the value in",
Type: "string",
}, },
"key": { "key": {
Title: "Key", Title: "Key",
Type: "string", Description: "key to set in the key-value module",
Type: "string",
}, },
}, },
Required: []string{"module", "key"}, Required: []string{"module", "key"},
@@ -78,7 +80,7 @@ func (kvs *KVSet) Process(ctx context.Context, wrappedPayload common.WrappedPayl
kvs.module = kvModule kvs.module = kvModule
} }
err := kvs.module.Set(kvs.Key, wrappedPayload.Payload) err := kvs.module.Set(ctx, kvs.Key, wrappedPayload.Payload)
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)
@@ -23,16 +23,19 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"channel": { "channel": {
Title: "Channel", Title: "Channel",
Type: "string", Description: "channel number for the control change message",
Type: "string",
}, },
"control": { "control": {
Title: "Control", Title: "Control",
Type: "string", Description: "control number for the control change message",
Type: "string",
}, },
"value": { "value": {
Title: "Value", Title: "Value",
Type: "string", Description: "value for the control change message",
Type: "string",
}, },
}, },
Required: []string{"channel", "control", "value"}, Required: []string{"channel", "control", "value"},
+9 -6
View File
@@ -23,16 +23,19 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"channel": { "channel": {
Title: "Channel", Title: "Channel",
Type: "string", Description: "channel number for the note off message",
Type: "string",
}, },
"note": { "note": {
Title: "Note", Title: "Note",
Type: "string", Description: "note number for the note off message",
Type: "string",
}, },
"velocity": { "velocity": {
Title: "Velocity", Title: "Velocity",
Type: "string", Description: "velocity for the note off message",
Type: "string",
}, },
}, },
Required: []string{"channel", "note", "velocity"}, Required: []string{"channel", "note", "velocity"},
+9 -6
View File
@@ -23,16 +23,19 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"channel": { "channel": {
Title: "Channel", Title: "Channel",
Type: "string", Description: "channel number for the note on message",
Type: "string",
}, },
"note": { "note": {
Title: "Note", Title: "Note",
Type: "string", Description: "note number for the note on message",
Type: "string",
}, },
"velocity": { "velocity": {
Title: "Velocity", Title: "Velocity",
Type: "string", Description: "velocity for the note on message",
Type: "string",
}, },
}, },
Required: []string{"channel", "note", "velocity"}, Required: []string{"channel", "note", "velocity"},
@@ -23,12 +23,14 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"channel": { "channel": {
Title: "Channel", Title: "Channel",
Type: "string", Description: "channel number for the program change message",
Type: "string",
}, },
"program": { "program": {
Title: "Program", Title: "Program",
Type: "string", Description: "program number for the program change message",
Type: "string",
}, },
}, },
Required: []string{"type", "channel", "program"}, Required: []string{"type", "channel", "program"},
+1 -1
View File
@@ -20,8 +20,8 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"module": { "module": {
Title: "Module ID", Title: "Module ID",
Type: "string",
Description: "ID of module to send output to", Description: "ID of module to send output to",
Type: "string",
}, },
}, },
Required: []string{"module"}, Required: []string{"module"},
+9 -6
View File
@@ -23,19 +23,22 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"address": { "address": {
Title: "Address", Title: "Address",
Type: "string", Description: "OSC address for the message",
Type: "string",
}, },
"args": { "args": {
Title: "Arguments", Title: "Arguments",
Type: "array", Description: "arguments for the OSC message",
Type: "array",
Items: &jsonschema.Schema{ Items: &jsonschema.Schema{
Type: "string", Type: "string",
}, },
}, },
"types": { "types": {
Title: "Argument Types", Title: "Argument Types",
Type: "string", Description: "string of OSC types corresponding to the arguments in args",
Type: "string",
}, },
}, },
Required: []string{"address"}, Required: []string{"address"},
+24 -3
View File
@@ -35,13 +35,34 @@ func RegisterProcessor(processor ProcessorRegistration) {
processorRegistryMu.Lock() processorRegistryMu.Lock()
defer processorRegistryMu.Unlock() defer processorRegistryMu.Unlock()
if _, ok := ProcessorRegistry[string(processor.Type)]; ok { _, exists := processorRegistry[string(processor.Type)]
if exists {
panic(fmt.Sprintf("processor already registered: %s", processor.Type)) panic(fmt.Sprintf("processor already registered: %s", processor.Type))
} }
ProcessorRegistry[string(processor.Type)] = processor processorRegistry[string(processor.Type)] = processor
}
type ProcessorRegistry map[string]ProcessorRegistration
func GetProcessorRegistration(processorType string) (ProcessorRegistration, bool) {
processorRegistryMu.RLock()
defer processorRegistryMu.RUnlock()
processor, ok := processorRegistry[processorType]
return processor, ok
}
func GetProcessorRegistrations() []ProcessorRegistration {
processorRegistryMu.RLock()
defer processorRegistryMu.RUnlock()
registrations := make([]ProcessorRegistration, 0, len(processorRegistry))
for _, processor := range processorRegistry {
registrations = append(registrations, processor)
}
return registrations
} }
var ( var (
processorRegistryMu sync.RWMutex processorRegistryMu sync.RWMutex
ProcessorRegistry = make(map[string]ProcessorRegistration) processorRegistry = make(map[string]ProcessorRegistration)
) )
+2 -2
View File
@@ -22,13 +22,13 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"module": { "module": {
Title: "Module ID", Title: "Module ID",
Type: "string",
Description: "ID of the module to publish to", Description: "ID of the module to publish to",
Type: "string",
}, },
"topic": { "topic": {
Title: "Topic", Title: "Topic",
Description: "topic to publish to",
Type: "string", Type: "string",
Description: "Topic to publish to",
}, },
}, },
Required: []string{"module", "topic"}, Required: []string{"module", "topic"},
+1 -1
View File
@@ -20,8 +20,8 @@ func init() {
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"source": { "source": {
Title: "Source", Title: "Source",
Type: "string",
Description: "source to report as to the router", Description: "source to report as to the router",
Type: "string",
}, },
}, },
Required: []string{"source"}, Required: []string{"source"},
+3 -2
View File
@@ -25,8 +25,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"expression": { "expression": {
Title: "Expression", Title: "Expression",
Type: "string", Description: "Expr expression to evaluate",
Type: "string",
}, },
}, },
Required: []string{"expression"}, Required: []string{"expression"},
+3 -2
View File
@@ -18,8 +18,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"program": { "program": {
Title: "Program", Title: "Program",
Type: "string", Description: "JavaScript program to run",
Type: "string",
}, },
}, },
Required: []string{"program"}, Required: []string{"program"},
+11 -8
View File
@@ -20,18 +20,21 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"path": { "path": {
Title: "Path", Title: "Path",
Type: "string", Description: "path to the WASM plugin to load",
Type: "string",
}, },
"function": { "function": {
Title: "Function", Title: "Function",
Type: "string", Description: "exported function to call on the WASM plugin",
Default: json.RawMessage(`"process"`), Type: "string",
Default: json.RawMessage(`"process"`),
}, },
"enableWasi": { "enableWasi": {
Title: "Enable WASI", Title: "Enable WASI",
Type: "boolean", Description: "whether to enable WASI when running the WASM plugin",
Default: json.RawMessage("false"), Type: "boolean",
Default: json.RawMessage("false"),
}, },
}, },
Required: []string{"path"}, Required: []string{"path"},
@@ -19,15 +19,19 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"preWait": { "preWait": {
Title: "Pre Wait (ms)", Title: "Pre Wait (ms)",
Type: "integer", Description: "number of milliseconds to wait before playing the audio",
}, Type: "integer",
"postWait": {
Title: "Post Wait (ms)",
Type: "integer",
}, },
"audioFile": { "audioFile": {
Type: "string", Title: "Audio File",
Description: "path to the audio file to play",
Type: "string",
},
"postWait": {
Title: "Post Wait (ms)",
Description: "number of milliseconds to wait after playing the audio",
Type: "integer",
}, },
}, },
Required: []string{"preWait", "postWait", "audioFile"}, Required: []string{"preWait", "postWait", "audioFile"},
+11 -7
View File
@@ -21,15 +21,19 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"preWait": { "preWait": {
Title: "Pre Wait (ms)", Title: "Pre Wait (ms)",
Type: "integer", Description: "number of milliseconds to wait before sending the DTMF tones",
}, Type: "integer",
"postWait": {
Title: "Post Wait (ms)",
Type: "integer",
}, },
"digits": { "digits": {
Type: "string", Title: "Digits",
Description: "DTMF digits to send",
Type: "string",
},
"postWait": {
Title: "Post Wait (ms)",
Description: "number of milliseconds to wait after sending the DTMF tones",
Type: "integer",
}, },
}, },
Required: []string{"preWait", "postWait", "digits"}, Required: []string{"preWait", "postWait", "digits"},
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"template": { "template": {
Title: "Template", Title: "Template",
Type: "string", Description: "template to evaluate",
Type: "string",
}, },
}, },
Required: []string{"template"}, Required: []string{"template"},
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"separator": { "separator": {
Title: "Separator", Title: "Separator",
Type: "string", Description: "separator to split the string on",
Type: "string",
}, },
}, },
Required: []string{"separator"}, Required: []string{"separator"},
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"name": { "name": {
Title: "Field Name", Title: "Field Name",
Type: "string", Description: "name of the struct field to extract",
Type: "string",
}, },
}, },
Required: []string{"name"}, Required: []string{"name"},
+3 -2
View File
@@ -19,8 +19,9 @@ func init() {
Type: "object", Type: "object",
Properties: map[string]*jsonschema.Schema{ Properties: map[string]*jsonschema.Schema{
"name": { "name": {
Title: "Method Name", Title: "Method Name",
Type: "string", Description: "name of the struct method to extract and call (with no arguments)",
Type: "string",
}, },
}, },
Required: []string{"name"}, Required: []string{"name"},
@@ -11,7 +11,7 @@ import (
) )
func TestArtnetPacketDecodeFromRegistry(t *testing.T) { func TestArtnetPacketDecodeFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["artnet.packet.decode"] registration, ok := processor.GetProcessorRegistration("artnet.packet.decode")
if !ok { if !ok {
t.Fatalf("artnet.packet.decode processor not registered") t.Fatalf("artnet.packet.decode processor not registered")
} }
@@ -41,15 +41,11 @@ 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: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, Sequence: 237,
OpCode: artnet.OpDmx, Physical: 0,
ProtVerHi: 0, SubUni: 1,
ProtVerLo: 14, Net: 0,
Sequence: 237, Data: make([]uint8, 512),
Physical: 0,
SubUni: 1,
Net: 0,
Data: make([]uint8, 512),
}, },
}, },
} }
@@ -11,7 +11,7 @@ import (
) )
func TestArtnetPacketEncodeFromRegistry(t *testing.T) { func TestArtnetPacketEncodeFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["artnet.packet.encode"] registration, ok := processor.GetProcessorRegistration("artnet.packet.encode")
if !ok { if !ok {
t.Fatalf("artnet.packet.encode processor not registered") t.Fatalf("artnet.packet.encode processor not registered")
} }
@@ -41,15 +41,11 @@ 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: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, Sequence: 237,
OpCode: artnet.OpDmx, Physical: 0,
ProtVerHi: 0, SubUni: 1,
ProtVerLo: 14, Net: 0,
Sequence: 237, Data: make([]uint8, 512),
Physical: 0,
SubUni: 1,
Net: 0,
Data: make([]uint8, 512),
}, },
}, },
} }
@@ -104,15 +100,11 @@ func TestBadArtnetPacketEncode(t *testing.T) {
func BenchmarkArtnetPacketEncode(b *testing.B) { func BenchmarkArtnetPacketEncode(b *testing.B) {
processorInstance := processor.ArtNetPacketEncode{} processorInstance := processor.ArtNetPacketEncode{}
payload := &artnet.ArtDmx{ payload := &artnet.ArtDmx{
ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, Sequence: 237,
OpCode: artnet.OpDmx, Physical: 0,
ProtVerHi: 0, SubUni: 1,
ProtVerLo: 14, Net: 0,
Sequence: 237, Data: make([]uint8, 512),
Physical: 0,
SubUni: 1,
Net: 0,
Data: make([]uint8, 512),
} }
for b.Loop() { for b.Loop() {
+5 -5
View File
@@ -12,7 +12,7 @@ import (
) )
func TestDbQueryFromRegistry(t *testing.T) { func TestDbQueryFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["db.query"] registration, ok := processor.GetProcessorRegistration("db.query")
if !ok { if !ok {
t.Fatalf("db.query processor not registered") t.Fatalf("db.query processor not registered")
} }
@@ -100,7 +100,7 @@ func TestGoodDbQuery(t *testing.T) {
} }
for _, testCase := range testCases { for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["db.query"] registration, ok := processor.GetProcessorRegistration("db.query")
if !ok { if !ok {
t.Fatalf("db.query processor not registered") t.Fatalf("db.query processor not registered")
} }
@@ -243,7 +243,7 @@ func TestBadDbQuery(t *testing.T) {
errorString: "db.query unable to find module with id: test", errorString: "db.query unable to find module with id: test",
}, },
{ {
name: "module not a DatabseModule", name: "module not a DatabaseModule",
payload: test.TestStruct{Data: "hello"}, payload: test.TestStruct{Data: "hello"},
params: map[string]any{ params: map[string]any{
"module": "test", "module": "test",
@@ -259,7 +259,7 @@ func TestBadDbQuery(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["db.query"] registration, ok := processor.GetProcessorRegistration("db.query")
if !ok { if !ok {
t.Fatalf("db.query processor not registered") t.Fatalf("db.query processor not registered")
} }
@@ -293,7 +293,7 @@ func TestBadDbQuery(t *testing.T) {
} }
func BenchmarkDbQuery(b *testing.B) { func BenchmarkDbQuery(b *testing.B) {
registration, ok := processor.ProcessorRegistry["db.query"] registration, ok := processor.GetProcessorRegistration("db.query")
if !ok { if !ok {
b.Fatalf("db.query processor not registered") b.Fatalf("db.query processor not registered")
} }
+4 -4
View File
@@ -10,7 +10,7 @@ import (
) )
func TestDebugLogFromRegistry(t *testing.T) { func TestDebugLogFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["debug.log"] registration, ok := processor.GetProcessorRegistration("debug.log")
if !ok { if !ok {
t.Fatalf("debug.log processor not registered") t.Fatalf("debug.log processor not registered")
} }
@@ -52,7 +52,7 @@ func TestGoodDebugLog(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["debug.log"] registration, ok := processor.GetProcessorRegistration("debug.log")
if !ok { if !ok {
t.Fatalf("debug.log processor not registered") t.Fatalf("debug.log processor not registered")
} }
@@ -89,7 +89,7 @@ func TestBadDebugLog(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["debug.log"] registration, ok := processor.GetProcessorRegistration("debug.log")
if !ok { if !ok {
t.Fatalf("debug.log processor not registered") t.Fatalf("debug.log processor not registered")
} }
@@ -120,7 +120,7 @@ func TestBadDebugLog(t *testing.T) {
} }
func BenchmarkDebugLog(b *testing.B) { func BenchmarkDebugLog(b *testing.B) {
registration, ok := processor.ProcessorRegistry["debug.log"] registration, ok := processor.GetProcessorRegistration("debug.log")
if !ok { if !ok {
b.Fatalf("debug.log processor not registered") b.Fatalf("debug.log processor not registered")
} }
@@ -10,7 +10,7 @@ import (
) )
func TestFilterChangeFromRegistry(t *testing.T) { func TestFilterChangeFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.change"] registration, ok := processor.GetProcessorRegistration("filter.change")
if !ok { if !ok {
t.Fatalf("filter.change processor not registered") t.Fatalf("filter.change processor not registered")
} }
@@ -58,7 +58,7 @@ func TestGoodFilterChange(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.change"] registration, ok := processor.GetProcessorRegistration("filter.change")
if !ok { if !ok {
t.Fatalf("filter.change processor not registered") t.Fatalf("filter.change processor not registered")
} }
@@ -95,7 +95,7 @@ func TestBadFilterChange(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.change"] registration, ok := processor.GetProcessorRegistration("filter.change")
if !ok { if !ok {
t.Fatalf("filter.change processor not registered") t.Fatalf("filter.change processor not registered")
} }
@@ -126,7 +126,7 @@ func TestBadFilterChange(t *testing.T) {
} }
func BenchmarkFilterChange(b *testing.B) { func BenchmarkFilterChange(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.change"] registration, ok := processor.GetProcessorRegistration("filter.change")
if !ok { if !ok {
b.Fatalf("filter.change processor not registered") b.Fatalf("filter.change processor not registered")
} }
+4 -4
View File
@@ -10,7 +10,7 @@ import (
) )
func TestFilterExprFromRegistry(t *testing.T) { func TestFilterExprFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.expr"] registration, ok := processor.GetProcessorRegistration("filter.expr")
if !ok { if !ok {
t.Fatalf("filter.expr processor not registered") t.Fatalf("filter.expr processor not registered")
} }
@@ -71,7 +71,7 @@ func TestGoodFilterExpr(t *testing.T) {
for _, testCase := range testCases { for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.expr"] registration, ok := processor.GetProcessorRegistration("filter.expr")
if !ok { if !ok {
t.Fatalf("filter.expr processor not registered") t.Fatalf("filter.expr processor not registered")
} }
@@ -144,7 +144,7 @@ func TestBadFilterExpr(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.expr"] registration, ok := processor.GetProcessorRegistration("filter.expr")
if !ok { if !ok {
t.Fatalf("filter.expr processor not registered") t.Fatalf("filter.expr processor not registered")
} }
@@ -173,7 +173,7 @@ func TestBadFilterExpr(t *testing.T) {
} }
func BenchmarkFilterExpr(b *testing.B) { func BenchmarkFilterExpr(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.expr"] registration, ok := processor.GetProcessorRegistration("filter.expr")
if !ok { if !ok {
b.Fatalf("filter.expr processor not registered") b.Fatalf("filter.expr processor not registered")
} }
+116
View File
@@ -0,0 +1,116 @@
package processor_test
import (
"testing"
"github.com/jwetzell/showbridge-go/internal/common"
"github.com/jwetzell/showbridge-go/internal/config"
"github.com/jwetzell/showbridge-go/internal/processor"
"github.com/jwetzell/showbridge-go/internal/test"
)
func TestFilterRateFromRegistry(t *testing.T) {
registration, ok := processor.GetProcessorRegistration("filter.rate")
if !ok {
t.Fatalf("filter.rate processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.rate",
Params: map[string]any{
"rate": 1,
},
})
if err != nil {
t.Fatalf("failed to create filter.rate processor: %s", err)
}
if processorInstance.Type() != "filter.rate" {
t.Fatalf("filter.rate processor has wrong type: %s", processorInstance.Type())
}
}
func TestGoodFilterRate(t *testing.T) {
testCases := []struct {
name string
params map[string]any
payload any
match bool
}{}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
registration, ok := processor.GetProcessorRegistration("filter.rate")
if !ok {
t.Fatalf("filter.rate processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.rate",
Params: testCase.params,
})
if err != nil {
t.Fatalf("filter.rate failed to create processor: %s", err)
}
_, err = processorInstance.Process(t.Context(), common.WrappedPayload{Payload: testCase.payload})
// TODO(jwetzell): figure out how to test the rate limiting behavior
})
}
}
func TestBadFilterRate(t *testing.T) {
tests := []struct {
name string
params map[string]any
payload any
errorString string
}{
{
name: "no rate parameter",
params: map[string]any{
// no rate parameter
},
payload: test.TestStruct{},
errorString: "filter.rate rate error: not found",
},
{
name: "non-int rate parameter",
params: map[string]any{
"rate": "12345",
},
payload: test.TestStruct{},
errorString: "filter.rate rate error: not a number",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
registration, ok := processor.GetProcessorRegistration("filter.rate")
if !ok {
t.Fatalf("filter.rate processor not registered")
}
processorInstance, err := registration.New(config.ProcessorConfig{
Type: "filter.rate",
Params: test.params,
})
if err != nil {
if err.Error() != test.errorString {
t.Fatalf("filter.rate got error '%s', expected '%s'", err.Error(), test.errorString)
}
return
}
got, err := processorInstance.Process(t.Context(), common.WrappedPayload{Payload: test.payload})
if err == nil {
t.Fatalf("filter.rate expected to fail but succeeded, got: %v", got)
}
if err.Error() != test.errorString {
t.Fatalf("filter.rate got error '%s', expected '%s'", err.Error(), test.errorString)
}
})
}
}
+4 -4
View File
@@ -10,7 +10,7 @@ import (
) )
func TestFilterRegexFromRegistry(t *testing.T) { func TestFilterRegexFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.regex"] registration, ok := processor.GetProcessorRegistration("filter.regex")
if !ok { if !ok {
t.Fatalf("filter.regex processor not registered") t.Fatalf("filter.regex processor not registered")
} }
@@ -77,7 +77,7 @@ func TestGoodFilterRegex(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.regex"] registration, ok := processor.GetProcessorRegistration("filter.regex")
if !ok { if !ok {
t.Fatalf("filter.regex processor not registered") t.Fatalf("filter.regex processor not registered")
} }
@@ -145,7 +145,7 @@ func TestBadFilterRegex(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["filter.regex"] registration, ok := processor.GetProcessorRegistration("filter.regex")
if !ok { if !ok {
t.Fatalf("filter.regex processor not registered") t.Fatalf("filter.regex processor not registered")
} }
@@ -176,7 +176,7 @@ func TestBadFilterRegex(t *testing.T) {
} }
func BenchmarkFilterRegex(b *testing.B) { func BenchmarkFilterRegex(b *testing.B) {
registration, ok := processor.ProcessorRegistry["filter.regex"] registration, ok := processor.GetProcessorRegistration("filter.regex")
if !ok { if !ok {
b.Fatalf("filter.regex processor not registered") b.Fatalf("filter.regex processor not registered")
} }
+4 -4
View File
@@ -10,7 +10,7 @@ import (
) )
func TestFloatParseFromRegistry(t *testing.T) { func TestFloatParseFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.parse"] registration, ok := processor.GetProcessorRegistration("float.parse")
if !ok { if !ok {
t.Fatalf("float.parse processor not registered") t.Fatalf("float.parse processor not registered")
} }
@@ -63,7 +63,7 @@ func TestGoodFloatParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.parse"] registration, ok := processor.GetProcessorRegistration("float.parse")
if !ok { if !ok {
t.Fatalf("float.parse processor not registered") t.Fatalf("float.parse processor not registered")
} }
@@ -136,7 +136,7 @@ func TestBadFloatParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.parse"] registration, ok := processor.GetProcessorRegistration("float.parse")
if !ok { if !ok {
t.Fatalf("float.parse processor not registered") t.Fatalf("float.parse processor not registered")
} }
@@ -167,7 +167,7 @@ func TestBadFloatParse(t *testing.T) {
} }
func BenchmarkFloatParse(b *testing.B) { func BenchmarkFloatParse(b *testing.B) {
registration, ok := processor.ProcessorRegistry["float.parse"] registration, ok := processor.GetProcessorRegistration("float.parse")
if !ok { if !ok {
b.Fatalf("float.parse processor not registered") b.Fatalf("float.parse processor not registered")
} }
+4 -4
View File
@@ -9,7 +9,7 @@ import (
) )
func TestFloatRandomFromRegistry(t *testing.T) { func TestFloatRandomFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.random"] registration, ok := processor.GetProcessorRegistration("float.random")
if !ok { if !ok {
t.Fatalf("float.random processor not registered") t.Fatalf("float.random processor not registered")
} }
@@ -57,7 +57,7 @@ func TestGoodFloatRandom(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.random"] registration, ok := processor.GetProcessorRegistration("float.random")
if !ok { if !ok {
t.Fatalf("float.random processor not registered") t.Fatalf("float.random processor not registered")
} }
@@ -155,7 +155,7 @@ func TestBadFloatRandom(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["float.random"] registration, ok := processor.GetProcessorRegistration("float.random")
if !ok { if !ok {
t.Fatalf("float.random processor not registered") t.Fatalf("float.random processor not registered")
} }
@@ -186,7 +186,7 @@ func TestBadFloatRandom(t *testing.T) {
} }
func BenchmarkFloatRandom(b *testing.B) { func BenchmarkFloatRandom(b *testing.B) {
registration, ok := processor.ProcessorRegistry["float.random"] registration, ok := processor.GetProcessorRegistration("float.random")
if !ok { if !ok {
b.Fatalf("float.random processor not registered") b.Fatalf("float.random processor not registered")
} }
@@ -11,7 +11,7 @@ import (
) )
func TestFreeDCreateFromRegistry(t *testing.T) { func TestFreeDCreateFromRegistry(t *testing.T) {
registration, ok := processor.ProcessorRegistry["freed.create"] registration, ok := processor.GetProcessorRegistration("freed.create")
if !ok { if !ok {
t.Fatalf("freed.create processor not registered") t.Fatalf("freed.create processor not registered")
} }
@@ -89,7 +89,7 @@ func TestGoodFreeDCreate(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["freed.create"] registration, ok := processor.GetProcessorRegistration("freed.create")
if !ok { if !ok {
t.Fatalf("freed.create processor not registered") t.Fatalf("freed.create processor not registered")
} }
@@ -848,7 +848,7 @@ func TestBadFreeDCreate(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
registration, ok := processor.ProcessorRegistry["freed.create"] registration, ok := processor.GetProcessorRegistration("freed.create")
if !ok { if !ok {
t.Fatalf("freed.create processor not registered") t.Fatalf("freed.create processor not registered")
} }
@@ -879,7 +879,7 @@ func TestBadFreeDCreate(t *testing.T) {
} }
func BenchmarkFreeDCreate(b *testing.B) { func BenchmarkFreeDCreate(b *testing.B) {
registration, ok := processor.ProcessorRegistry["freed.create"] registration, ok := processor.GetProcessorRegistration("freed.create")
if !ok { if !ok {
b.Fatalf("freed.create processor not registered") b.Fatalf("freed.create processor not registered")
} }

Some files were not shown because too many files have changed in this diff Show More