mirror of
https://github.com/jwetzell/showbridge-go.git
synced 2026-09-06 13:49:00 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 176a42c7c1 | |||
| 23556d5869 | |||
| bb8c884775 | |||
| 8023af90fd | |||
| 4b97937f95 | |||
| 9f5bdc9fd2 | |||
| d80a02ba0c | |||
| 71cf2506a3 |
@@ -218,7 +218,7 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
|
||||
uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
||||
|
||||
@@ -6,8 +6,10 @@ require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.1
|
||||
github.com/expr-lang/expr v1.17.8
|
||||
github.com/extism/go-sdk v1.7.1
|
||||
github.com/go-sql-driver/mysql v1.10.1
|
||||
github.com/google/jsonschema-go v0.4.3
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/jackc/pgx/v5 v5.10.0
|
||||
github.com/jwetzell/artnet-go v0.3.0
|
||||
github.com/jwetzell/free-d-go v0.2.0
|
||||
github.com/jwetzell/osc-go v0.3.1
|
||||
@@ -20,11 +22,12 @@ require (
|
||||
go.bug.st/serial v1.8.0
|
||||
golang.org/x/time v0.15.0
|
||||
modernc.org/quickjs v0.24.2
|
||||
modernc.org/sqlite v1.57.0
|
||||
modernc.org/sqlite v1.58.0
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.2.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/dustin/go-humanize v1.0.1 // indirect
|
||||
@@ -33,6 +36,9 @@ require (
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/compress v1.19.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/minio/highwayhash v1.0.4 // indirect
|
||||
@@ -52,9 +58,9 @@ require (
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/sync v0.22.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/text v0.41.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
modernc.org/libc v1.75.4 // indirect
|
||||
modernc.org/libc v1.75.6 // indirect
|
||||
modernc.org/libquickjs v0.13.1 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.12.1 // indirect
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.2-default-no-op h1:p2zFsAzvhIpFya8AIOHIbWf7NGvO34QpLGclyf7nXj8=
|
||||
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=
|
||||
@@ -6,6 +8,7 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
@@ -18,6 +21,8 @@ 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/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw=
|
||||
github.com/extism/go-sdk v1.7.1/go.mod h1:IT+Xdg5AZM9hVtpFUA+uZCJMge/hbvshl8bwzLtFyKA=
|
||||
github.com/go-sql-driver/mysql v1.10.1 h1:arlSnNLq6a5yxGxV7qg9lF4j0C+KwD6NbQyKr9QL6ME=
|
||||
github.com/go-sql-driver/mysql v1.10.1/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -36,6 +41,14 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f h1:NW3E2QSchEk63/fjeEvWOa2cE02FSv9ox//VE/N4c8g=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20260505044615-1ff4bf46051f/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
|
||||
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jwetzell/artnet-go v0.3.0 h1:MDHElOSbpgmIbYGHO9SoxsT7ynrYtV5/UHGT82geHk0=
|
||||
github.com/jwetzell/artnet-go v0.3.0/go.mod h1:zqRsSsrd6rPwJacwscPteDqGIqevjZ3Z6dpp092VJ1w=
|
||||
github.com/jwetzell/free-d-go v0.2.0 h1:8WQW4du8Sf3d18aUzk9n5jZtHE6WdDQHDFjkFffvycc=
|
||||
@@ -48,11 +61,8 @@ github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi
|
||||
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
@@ -79,6 +89,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
|
||||
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/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZjBaFj3HgFonKXUcwgJ4djLb6i42S3Q=
|
||||
@@ -112,6 +125,8 @@ golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
|
||||
@@ -121,6 +136,7 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.29.2 h1:h6+9ciCnPKutf4I03CvheAvDLX7+IHlqR6Iy6J+cgd8=
|
||||
@@ -135,8 +151,8 @@ modernc.org/gc/v3 v3.1.5 h1:21ldfPfRYE31Tb7B3mwAK8gy1AxP4+dKjrOQPfqakoc=
|
||||
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/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.75.4 h1:EHQJNYDC6LiDIOqM76862xe4frbDc7IzEOZTtGxZV8Q=
|
||||
modernc.org/libc v1.75.4/go.mod h1:bO5o2ztHxBb2rjz0PgdHN0sSMw57CgxGFLZ3Qd/QpVQ=
|
||||
modernc.org/libc v1.75.6 h1:yKk8qo+Di4gkmvRboK8ocCqH22FiUCR6jRy2OwtCRus=
|
||||
modernc.org/libc v1.75.6/go.mod h1:bO5o2ztHxBb2rjz0PgdHN0sSMw57CgxGFLZ3Qd/QpVQ=
|
||||
modernc.org/libquickjs v0.13.1 h1:uCb9AYyEyL1JS2dnKtLZKWH/vDb36cx1Mr1SIdbzb8A=
|
||||
modernc.org/libquickjs v0.13.1/go.mod h1:tCEsA1Zda1+C5JagFIJGqjYZOxDPFOUYjK3dGhEeq0g=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
@@ -149,8 +165,8 @@ modernc.org/quickjs v0.24.2 h1:wfVrO+6ailTzKHA7LAlknnOXH/rJyiIgw4+WNI0m6ew=
|
||||
modernc.org/quickjs v0.24.2/go.mod h1:4SZg8rXHeX2pO2VpBVmqSDrIOYD/UF5Cnh3ew4tzFng=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.57.0 h1:qNQP6xnx5M0ISNtlnxoOX0+cD5bJ0/gr9aMmndFczzg=
|
||||
modernc.org/sqlite v1.57.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/sqlite v1.58.0 h1:38u40/bwkfM7f0Myhosl+SEMltSDxnGdQf8o6Kjmys0=
|
||||
modernc.org/sqlite v1.58.0/go.mod h1:rsD2CckafgObKC4DhBlGBf+RiHxkc3hINGt1Xw32tVY=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/jsonschema-go/jsonschema"
|
||||
"github.com/jwetzell/showbridge-go/internal/common"
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterModule(ModuleRegistration{
|
||||
Type: "db.mysql",
|
||||
Title: "MySQL Database",
|
||||
ParamsSchema: &jsonschema.Schema{
|
||||
Type: "object",
|
||||
Properties: map[string]*jsonschema.Schema{
|
||||
"dsn": {
|
||||
Title: "Database DSN",
|
||||
Description: "the connection DSN for the MySQL database",
|
||||
Type: "string",
|
||||
MinLength: new(1),
|
||||
},
|
||||
},
|
||||
Required: []string{"dsn"},
|
||||
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
|
||||
},
|
||||
New: func(config config.ModuleConfig) (common.Module, error) {
|
||||
params := config.Params
|
||||
|
||||
dsnString, err := params.GetString("dsn")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db.mysql dsn error: %w", err)
|
||||
}
|
||||
|
||||
return &DbMysql{Dsn: dsnString, config: config, logger: CreateLogger(config)}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type DbMysql struct {
|
||||
config config.ModuleConfig
|
||||
Dsn string
|
||||
ctx context.Context
|
||||
inputHandler common.InputHandler
|
||||
db *sql.DB
|
||||
logger *slog.Logger
|
||||
dbMu sync.Mutex
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (dbs *DbMysql) Id() string {
|
||||
return dbs.config.Id
|
||||
}
|
||||
|
||||
func (dbs *DbMysql) Type() string {
|
||||
return dbs.config.Type
|
||||
}
|
||||
|
||||
func (dbs *DbMysql) Start(ctx context.Context, inputHandler common.InputHandler) error {
|
||||
dbs.logger.Debug("running")
|
||||
dbs.inputHandler = inputHandler
|
||||
moduleContext, cancel := context.WithCancel(ctx)
|
||||
dbs.ctx = moduleContext
|
||||
dbs.cancel = cancel
|
||||
|
||||
db, err := sql.Open("mysql", dbs.Dsn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db.mysql error connecting to database: %w", err)
|
||||
}
|
||||
|
||||
// TODO(jwetzell): make configurable
|
||||
db.SetConnMaxLifetime(time.Minute * 3)
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(10)
|
||||
|
||||
dbs.dbMu.Lock()
|
||||
dbs.db = db
|
||||
dbs.dbMu.Unlock()
|
||||
<-dbs.ctx.Done()
|
||||
dbs.logger.Debug("done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbs *DbMysql) Stop() {
|
||||
if dbs.cancel != nil {
|
||||
defer dbs.cancel()
|
||||
}
|
||||
dbs.dbMu.Lock()
|
||||
defer dbs.dbMu.Unlock()
|
||||
if dbs.db != nil {
|
||||
dbs.db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (dbs *DbMysql) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
|
||||
dbs.dbMu.Lock()
|
||||
defer dbs.dbMu.Unlock()
|
||||
if dbs.db == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
return dbs.db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/google/jsonschema-go/jsonschema"
|
||||
"github.com/jwetzell/showbridge-go/internal/common"
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterModule(ModuleRegistration{
|
||||
Type: "db.postgres",
|
||||
Title: "PostgreSQL Database",
|
||||
ParamsSchema: &jsonschema.Schema{
|
||||
Type: "object",
|
||||
Properties: map[string]*jsonschema.Schema{
|
||||
"url": {
|
||||
Title: "Database URL",
|
||||
Description: "the connection URL for the PostgreSQL database",
|
||||
Type: "string",
|
||||
MinLength: new(1),
|
||||
},
|
||||
},
|
||||
Required: []string{"url"},
|
||||
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
|
||||
},
|
||||
New: func(config config.ModuleConfig) (common.Module, error) {
|
||||
params := config.Params
|
||||
|
||||
urlString, err := params.GetString("url")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db.postgres url error: %w", err)
|
||||
}
|
||||
|
||||
return &DbPostgres{Url: urlString, config: config, logger: CreateLogger(config)}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type DbPostgres struct {
|
||||
config config.ModuleConfig
|
||||
Url string
|
||||
ctx context.Context
|
||||
inputHandler common.InputHandler
|
||||
db *sql.DB
|
||||
logger *slog.Logger
|
||||
dbMu sync.Mutex
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (dbs *DbPostgres) Id() string {
|
||||
return dbs.config.Id
|
||||
}
|
||||
|
||||
func (dbs *DbPostgres) Type() string {
|
||||
return dbs.config.Type
|
||||
}
|
||||
|
||||
func (dbs *DbPostgres) Start(ctx context.Context, inputHandler common.InputHandler) error {
|
||||
dbs.logger.Debug("running")
|
||||
dbs.inputHandler = inputHandler
|
||||
moduleContext, cancel := context.WithCancel(ctx)
|
||||
dbs.ctx = moduleContext
|
||||
dbs.cancel = cancel
|
||||
|
||||
db, err := sql.Open("pgx", dbs.Url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db.postgres error connecting to database: %w", err)
|
||||
}
|
||||
dbs.dbMu.Lock()
|
||||
dbs.db = db
|
||||
dbs.dbMu.Unlock()
|
||||
<-dbs.ctx.Done()
|
||||
dbs.logger.Debug("done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbs *DbPostgres) Stop() {
|
||||
if dbs.cancel != nil {
|
||||
defer dbs.cancel()
|
||||
}
|
||||
dbs.dbMu.Lock()
|
||||
defer dbs.dbMu.Unlock()
|
||||
if dbs.db != nil {
|
||||
dbs.db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (dbs *DbPostgres) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
|
||||
dbs.dbMu.Lock()
|
||||
defer dbs.dbMu.Unlock()
|
||||
if dbs.db == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
return dbs.db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package module_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/module"
|
||||
)
|
||||
|
||||
func TestDbMySQLFromRegistry(t *testing.T) {
|
||||
registration, ok := module.GetModuleRegistration("db.mysql")
|
||||
if !ok {
|
||||
t.Fatalf("db.mysql module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.mysql",
|
||||
Params: map[string]any{
|
||||
"dsn": "mysql:mysql@tcp(127.0.0.1:3306)/test",
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create db.mysql module: %s", err)
|
||||
}
|
||||
|
||||
if moduleInstance.Id() != "test" {
|
||||
t.Fatalf("db.mysql module has wrong id: %s", moduleInstance.Id())
|
||||
}
|
||||
|
||||
if moduleInstance.Type() != "db.mysql" {
|
||||
t.Fatalf("db.mysql module has wrong type: %s", moduleInstance.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoodDbMySQL(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
}{}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("db.mysql")
|
||||
if !ok {
|
||||
t.Fatalf("db.mysql module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.mysql",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("db.mysql failed to create module: %s", err)
|
||||
}
|
||||
// TODO(jwetzell) this is kind of hacky
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
moduleInstance.Stop()
|
||||
}()
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("db.mysql failed to start: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadDbMySQL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
errorString string
|
||||
}{
|
||||
{
|
||||
name: "no dsn param",
|
||||
params: map[string]any{},
|
||||
errorString: "db.mysql dsn error: not found",
|
||||
},
|
||||
{
|
||||
name: "non-string dsn",
|
||||
params: map[string]any{"dsn": 123},
|
||||
errorString: "db.mysql dsn error: not a string",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("db.mysql")
|
||||
if !ok {
|
||||
t.Fatalf("db.mysql module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.mysql",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if test.errorString != err.Error() {
|
||||
t.Fatalf("db.mysql got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("db.mysql expected to fail")
|
||||
}
|
||||
|
||||
if err.Error() != test.errorString {
|
||||
t.Fatalf("db.mysql got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package module_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/module"
|
||||
)
|
||||
|
||||
func TestDbPostgresFromRegistry(t *testing.T) {
|
||||
registration, ok := module.GetModuleRegistration("db.postgres")
|
||||
if !ok {
|
||||
t.Fatalf("db.postgres module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.postgres",
|
||||
Params: map[string]any{
|
||||
"url": "postgres://localhost:5432",
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create db.postgres module: %s", err)
|
||||
}
|
||||
|
||||
if moduleInstance.Id() != "test" {
|
||||
t.Fatalf("db.postgres module has wrong id: %s", moduleInstance.Id())
|
||||
}
|
||||
|
||||
if moduleInstance.Type() != "db.postgres" {
|
||||
t.Fatalf("db.postgres module has wrong type: %s", moduleInstance.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoodDbPostgres(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
}{}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("db.postgres")
|
||||
if !ok {
|
||||
t.Fatalf("db.postgres module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.postgres",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("db.postgres failed to create module: %s", err)
|
||||
}
|
||||
// TODO(jwetzell) this is kind of hacky
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
moduleInstance.Stop()
|
||||
}()
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("db.postgres failed to start: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadDbPostgres(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
errorString string
|
||||
}{
|
||||
{
|
||||
name: "no url param",
|
||||
params: map[string]any{},
|
||||
errorString: "db.postgres url error: not found",
|
||||
},
|
||||
{
|
||||
name: "non-string url",
|
||||
params: map[string]any{"url": 123},
|
||||
errorString: "db.postgres url error: not a string",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("db.postgres")
|
||||
if !ok {
|
||||
t.Fatalf("db.postgres module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "db.postgres",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if test.errorString != err.Error() {
|
||||
t.Fatalf("db.postgres got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("db.postgres expected to fail")
|
||||
}
|
||||
|
||||
if err.Error() != test.errorString {
|
||||
t.Fatalf("db.postgres got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user