feat(keyvalue): add badger as keyvalue store

KeyValue store will be used by Incidents, so that the functions
can decide based on history not just on the event that triggered them.
This commit is contained in:
Tine 2024-04-28 16:06:49 +02:00
parent e77764c4b9
commit bb1ba5ed58
Signed by: mentos1386
SSH key fingerprint: SHA256:MNtTsLbihYaWF8j1fkOHfkKNlnN1JQfxEU/rBU8nCGw
9 changed files with 142 additions and 17 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ node_modules/
# Database # Database
zdravko.db* zdravko.db*
zdravko_kv.db*
temporal.db* temporal.db*
# Keys # Keys

6
go.mod
View file

@ -3,6 +3,7 @@ module code.tjo.space/mentos1386/zdravko
go 1.21.6 go 1.21.6
require ( require (
github.com/dgraph-io/badger/v4 v4.2.0
github.com/go-playground/validator/v10 v10.18.0 github.com/go-playground/validator/v10 v10.18.0
github.com/golang-jwt/jwt/v5 v5.2.0 github.com/golang-jwt/jwt/v5 v5.2.0
github.com/gorilla/sessions v1.2.2 github.com/gorilla/sessions v1.2.2
@ -16,6 +17,7 @@ require (
github.com/spf13/viper v1.18.2 github.com/spf13/viper v1.18.2
github.com/temporalio/ui-server/v2 v2.23.0 github.com/temporalio/ui-server/v2 v2.23.0
go.k6.io/k6 v0.49.0 go.k6.io/k6 v0.49.0
go.temporal.io/api v1.27.0
go.temporal.io/sdk v1.26.0-rc.2 go.temporal.io/sdk v1.26.0-rc.2
go.temporal.io/server v1.22.4 go.temporal.io/server v1.22.4
golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/exp v0.0.0-20231127185646-65229373498e
@ -49,6 +51,7 @@ require (
github.com/chromedp/sysutil v1.0.0 // indirect github.com/chromedp/sysutil v1.0.0 // indirect
github.com/coreos/go-oidc/v3 v3.1.0 // indirect github.com/coreos/go-oidc/v3 v3.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.9.0 // indirect github.com/dlclark/regexp2 v1.9.0 // indirect
@ -71,10 +74,12 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/mock v1.7.0-rc.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect github.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect
github.com/google/s2a-go v0.1.7 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
@ -165,7 +170,6 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.temporal.io/api v1.27.0 // indirect
go.temporal.io/version v0.3.0 // indirect go.temporal.io/version v0.3.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.0 // indirect go.uber.org/dig v1.17.0 // indirect

11
go.sum
View file

@ -89,7 +89,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs=
github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgryski/go-farm v0.0.0-20140601200337-fc41e106ee0e/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20140601200337-fc41e106ee0e/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@ -103,6 +108,7 @@ github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d h1:wi6jN5LVt/ljaBG4ue7
github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@ -172,6 +178,8 @@ github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -198,6 +206,8 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -653,6 +663,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -12,7 +12,8 @@ import (
type ServerConfig struct { type ServerConfig struct {
Port string `validate:"required"` Port string `validate:"required"`
RootUrl string `validate:"required,url"` RootUrl string `validate:"required,url"`
DatabasePath string `validate:"required"` SqliteDatabasePath string `validate:"required"`
KeyValueDatabasePath string `validate:"required"`
SessionSecret string `validate:"required"` SessionSecret string `validate:"required"`
Jwt ServerJwt `validate:"required"` Jwt ServerJwt `validate:"required"`
@ -47,7 +48,8 @@ func NewServerConfig() *ServerConfig {
// Set defaults // Set defaults
v.SetDefault("port", GetEnvOrDefault("PORT", "8000")) v.SetDefault("port", GetEnvOrDefault("PORT", "8000"))
v.SetDefault("rooturl", GetEnvOrDefault("ROOT_URL", "http://localhost:8000")) v.SetDefault("rooturl", GetEnvOrDefault("ROOT_URL", "http://localhost:8000"))
v.SetDefault("databasepath", GetEnvOrDefault("DATABASE_PATH", "zdravko.db")) v.SetDefault("sqlitedatabasepath", GetEnvOrDefault("SQLITE_DATABASE_PATH", "zdravko.db"))
v.SetDefault("keyvaluedatabasepath", GetEnvOrDefault("KEYVALUE_DATABASE_PATH", "zdravko_kv.db"))
v.SetDefault("sessionsecret", os.Getenv("SESSION_SECRET")) v.SetDefault("sessionsecret", os.Getenv("SESSION_SECRET"))
v.SetDefault("temporal.uihost", GetEnvOrDefault("TEMPORAL_UI_HOST", "127.0.0.1:8223")) v.SetDefault("temporal.uihost", GetEnvOrDefault("TEMPORAL_UI_HOST", "127.0.0.1:8223"))
v.SetDefault("temporal.serverhost", GetEnvOrDefault("TEMPORAL_SERVER_HOST", "127.0.0.1:7233")) v.SetDefault("temporal.serverhost", GetEnvOrDefault("TEMPORAL_SERVER_HOST", "127.0.0.1:7233"))

View file

@ -4,6 +4,7 @@ import (
"log/slog" "log/slog"
"code.tjo.space/mentos1386/zdravko/internal/config" "code.tjo.space/mentos1386/zdravko/internal/config"
"code.tjo.space/mentos1386/zdravko/internal/kv"
"code.tjo.space/mentos1386/zdravko/web/templates/components" "code.tjo.space/mentos1386/zdravko/web/templates/components"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -27,6 +28,7 @@ func GetPageByTitle(pages []*components.Page, title string) *components.Page {
type BaseHandler struct { type BaseHandler struct {
db *sqlx.DB db *sqlx.DB
kvStore kv.KeyValueStore
config *config.ServerConfig config *config.ServerConfig
logger *slog.Logger logger *slog.Logger
@ -35,11 +37,12 @@ type BaseHandler struct {
store *sessions.CookieStore store *sessions.CookieStore
} }
func NewBaseHandler(db *sqlx.DB, temporal client.Client, config *config.ServerConfig, logger *slog.Logger) *BaseHandler { func NewBaseHandler(db *sqlx.DB, kvStore kv.KeyValueStore, temporal client.Client, config *config.ServerConfig, logger *slog.Logger) *BaseHandler {
store := sessions.NewCookieStore([]byte(config.SessionSecret)) store := sessions.NewCookieStore([]byte(config.SessionSecret))
return &BaseHandler{ return &BaseHandler{
db: db, db: db,
kvStore: kvStore,
config: config, config: config,
logger: logger, logger: logger,
temporal: temporal, temporal: temporal,

82
internal/kv/badger.go Normal file
View file

@ -0,0 +1,82 @@
package kv
import (
"time"
badger "github.com/dgraph-io/badger/v4"
"github.com/pkg/errors"
)
type BadgerKeyValueStore struct {
db *badger.DB
}
func NewBadgerKeyValueStore(path string) (*BadgerKeyValueStore, error) {
db, err := badger.Open(badger.DefaultOptions(path))
if err != nil {
return nil, errors.Wrap(err, "failed to open badger db")
}
return &BadgerKeyValueStore{db: db}, nil
}
func (b *BadgerKeyValueStore) Close() error {
return b.db.Close()
}
func (b *BadgerKeyValueStore) Set(key string, value []byte, ttl time.Duration) error {
return b.db.Update(func(txn *badger.Txn) error {
e := badger.NewEntry([]byte(key), value).WithTTL(ttl)
return txn.SetEntry(e)
})
}
func (b *BadgerKeyValueStore) Increment(key string) (int, error) {
var value int
return value, b.db.Update(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(key))
if err != nil {
return err
}
valCopy, err := item.ValueCopy(nil)
if err != nil {
return err
}
value = int(valCopy[0]) + 1
return txn.Set([]byte(key), []byte{byte(value)})
})
}
func (b *BadgerKeyValueStore) Get(key string) ([]byte, error) {
var value []byte
return value, b.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(key))
if err != nil {
return err
}
valCopy, err := item.ValueCopy(value)
if err != nil {
return err
}
value = valCopy
return nil
})
}
func (b *BadgerKeyValueStore) Delete(key string) error {
return b.db.Update(func(txn *badger.Txn) error {
return txn.Delete([]byte(key))
})
}
func (b *BadgerKeyValueStore) Keys(prefix string) ([]string, error) {
var keys []string
return keys, b.db.View(func(txn *badger.Txn) error {
itr := txn.NewIterator(badger.DefaultIteratorOptions)
defer itr.Close()
for itr.Seek([]byte(prefix)); itr.ValidForPrefix([]byte(prefix)); itr.Next() {
item := itr.Item()
keys = append(keys, string(item.Key()))
}
return nil
})
}

13
internal/kv/kv.go Normal file
View file

@ -0,0 +1,13 @@
package kv
import "time"
type KeyValueStore interface {
Close() error
Get(key string) ([]byte, error)
Set(key string, value []byte, ttl time.Duration) error
Increment(key string) (int, error)
Delete(key string) error
Keys(prefix string) ([]string, error)
}

View file

@ -6,6 +6,7 @@ import (
"code.tjo.space/mentos1386/zdravko/internal/config" "code.tjo.space/mentos1386/zdravko/internal/config"
"code.tjo.space/mentos1386/zdravko/internal/handlers" "code.tjo.space/mentos1386/zdravko/internal/handlers"
"code.tjo.space/mentos1386/zdravko/internal/kv"
"code.tjo.space/mentos1386/zdravko/web/static" "code.tjo.space/mentos1386/zdravko/web/static"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
@ -15,16 +16,17 @@ import (
func Routes( func Routes(
e *echo.Echo, e *echo.Echo,
db *sqlx.DB, sqlDb *sqlx.DB,
kvStore kv.KeyValueStore,
temporalClient client.Client, temporalClient client.Client,
cfg *config.ServerConfig, cfg *config.ServerConfig,
logger *slog.Logger, logger *slog.Logger,
) { ) {
h := handlers.NewBaseHandler(db, temporalClient, cfg, logger) h := handlers.NewBaseHandler(sqlDb, kvStore, temporalClient, cfg, logger)
// Health // Health
e.GET("/health", func(c echo.Context) error { e.GET("/health", func(c echo.Context) error {
err := db.Ping() err := sqlDb.Ping()
if err != nil { if err != nil {
return err return err
} }

View file

@ -6,10 +6,12 @@ import (
"code.tjo.space/mentos1386/zdravko/database" "code.tjo.space/mentos1386/zdravko/database"
"code.tjo.space/mentos1386/zdravko/internal/config" "code.tjo.space/mentos1386/zdravko/internal/config"
"code.tjo.space/mentos1386/zdravko/internal/kv"
"code.tjo.space/mentos1386/zdravko/internal/temporal" "code.tjo.space/mentos1386/zdravko/internal/temporal"
"code.tjo.space/mentos1386/zdravko/web/templates" "code.tjo.space/mentos1386/zdravko/web/templates"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"github.com/pkg/errors"
) )
type Server struct { type Server struct {
@ -33,14 +35,19 @@ func (s *Server) Name() string {
} }
func (s *Server) Start() error { func (s *Server) Start() error {
db, err := database.ConnectToDatabase(s.logger, s.cfg.DatabasePath) sqliteDb, err := database.ConnectToDatabase(s.logger, s.cfg.SqliteDatabasePath)
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to connect to sqlite")
} }
temporalClient, err := temporal.ConnectServerToTemporal(s.logger, s.cfg) temporalClient, err := temporal.ConnectServerToTemporal(s.logger, s.cfg)
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to connect to temporal")
}
kvStore, err := kv.NewBadgerKeyValueStore(s.cfg.KeyValueDatabasePath)
if err != nil {
return errors.Wrap(err, "failed to open kv store")
} }
s.worker = NewWorker(temporalClient, s.cfg) s.worker = NewWorker(temporalClient, s.cfg)
@ -49,7 +56,7 @@ func (s *Server) Start() error {
s.echo.Use(middleware.Logger()) s.echo.Use(middleware.Logger())
s.echo.Use(middleware.Recover()) s.echo.Use(middleware.Recover())
s.echo.Use(middleware.Secure()) s.echo.Use(middleware.Secure())
Routes(s.echo, db, temporalClient, s.cfg, s.logger) Routes(s.echo, sqliteDb, kvStore, temporalClient, s.cfg, s.logger)
go func() { go func() {
if err := s.worker.Start(); err != nil { if err := s.worker.Start(); err != nil {