Compare commits

...

5 Commits

12 changed files with 103 additions and 80 deletions

14
go.mod
View File

@ -9,17 +9,17 @@ require (
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect
github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/klauspost/compress v1.18.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.34.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sys v0.35.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)

15
go.sum
View File

@ -6,6 +6,8 @@ github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yh
github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w=
github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM=
github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI=
github.com/dgraph-io/ristretto/v2 v2.3.0 h1:qTQ38m7oIyd4GAed/QkUZyPFNMnvVWyazGXRwvOt5zk=
github.com/dgraph-io/ristretto/v2 v2.3.0/go.mod h1:gpoRV3VzrEY1a9dWAYV6T1U7YzfgttXdd/ZzL1s9OZM=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@ -27,19 +29,32 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,14 +1,13 @@
package joist
package routing
import (
"fmt"
"net/http"
)
type (
HandlerFn func(w http.ResponseWriter, r *http.Request) error
MiddlewareFn func(HandlerFn) HandlerFn
)
type HandlerFn func(w http.ResponseWriter, r *http.Request) error
type Middlewares []func(http.ResponseWriter, *http.Request)
func (h HandlerFn) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil {

View File

@ -1,4 +1,4 @@
package joist
package routing
import (
"context"
@ -7,37 +7,37 @@ import (
"sync"
"time"
"git.markbailey.dev/cerbervs/joist/internal/badger"
jerr "git.markbailey.dev/cerbervs/joist/internal/errors"
"git.markbailey.dev/cerbervs/joist/internal/storage"
)
type routeCache struct {
type RouteCache struct {
rs map[string]string
ris map[string]*RouteInfo
s Storer
s storage.Storer
ttl time.Duration
}
type RouteCacheOpt func(*routeCache)
type RouteCacheOpt func(*RouteCache)
var (
rcOnce sync.Once
cache *routeCache
cache *RouteCache
)
func WithTTL(ttl time.Duration) RouteCacheOpt {
return func(r *routeCache) {
return func(r *RouteCache) {
r.ttl = ttl
}
}
func WithStore(store Storer) RouteCacheOpt {
return func(r *routeCache) {
func WithStore(store storage.Storer) RouteCacheOpt {
return func(r *RouteCache) {
r.s = store
}
}
func NewRouteCacheService(opts ...RouteCacheOpt) (*routeCache, error) {
func NewRouteCacheService(opts ...RouteCacheOpt) (*RouteCache, error) {
rcOnce.Do(func() {
c, err := newRouteCache(opts...)
if err != nil {
@ -54,14 +54,14 @@ func NewRouteCacheService(opts ...RouteCacheOpt) (*routeCache, error) {
return cache, nil
}
func (r *routeCache) All() (map[string]string, error) {
func (r *RouteCache) All() (map[string]string, error) {
if r.rs == nil {
return nil, jerr.ErrCacheUninitialized
}
return r.rs, nil
}
func (r *routeCache) Add(name string, path string) error {
func (r *RouteCache) Add(name string, path string) error {
ttl := r.ttl
if ttl == 0 {
ttl = 1 * time.Hour
@ -76,7 +76,7 @@ func (r *routeCache) Add(name string, path string) error {
return nil
}
func (r *routeCache) GetPath(name string) (string, error) {
func (r *RouteCache) GetPath(name string) (string, error) {
if path, ok := r.rs[name]; ok {
return path, nil
}
@ -88,7 +88,7 @@ func (r *routeCache) GetPath(name string) (string, error) {
return "", errors.New("route not found in cache")
}
func (r *routeCache) AddRouteInfo(routeInfo RouteInfo) error {
func (r *RouteCache) AddRouteInfo(routeInfo RouteInfo) error {
ttl := r.ttl
if ttl == 0 {
ttl = 1 * time.Hour
@ -113,7 +113,7 @@ func (r *routeCache) AddRouteInfo(routeInfo RouteInfo) error {
return nil
}
func (r *routeCache) GetRouteInfo(name string) (RouteInfo, error) {
func (r *RouteCache) GetRouteInfo(name string) (RouteInfo, error) {
if ri, ok := r.ris[name]; ok {
return *ri, nil
}
@ -131,13 +131,13 @@ func (r *routeCache) GetRouteInfo(name string) (RouteInfo, error) {
return RouteInfo{}, errors.New("route info not found in cache")
}
func newRouteCache(opts ...RouteCacheOpt) (*routeCache, error) {
s, err := badger.NewBadgerStore(badger.WithSubDir("route_cache"))
func newRouteCache(opts ...RouteCacheOpt) (*RouteCache, error) {
s, err := storage.NewBadgerStore(storage.WithSubDir("route_cache"))
if err != nil {
return nil, jerr.Wrap(jerr.ErrFailedToCreateRouteCache, err)
}
cache := &routeCache{
cache := &RouteCache{
rs: make(map[string]string),
s: s,
}

View File

@ -1,4 +1,4 @@
package joist
package routing
import "testing"

View File

@ -0,0 +1,26 @@
package routing
type RouteInfo struct {
Method string
Name string
Path string
Description string
Title string
}
func NewRouteInfo(method, path, description, title string) (*RouteInfo, error) {
name, err := convertRouteToRouteName(path)
if err != nil {
return &RouteInfo{}, err
}
return &RouteInfo{
Method: method,
Name: name,
Path: path,
Description: description,
Title: title,
}, nil
}
type routeInfoKey struct{}

View File

@ -1,59 +1,29 @@
package joist
package routing
import (
"context"
"log"
"net/http"
"regexp"
"strings"
"time"
jerr "git.markbailey.dev/cerbervs/joist/internal/errors"
"github.com/go-chi/chi/v5"
)
type RouteInfo struct {
Method string
Name string
Path string
Description string
Title string
type RouteCacher interface {
Add(string, string) error
AddRouteInfo(RouteInfo) error
GetPath(string) (string, error)
GetRouteInfo(string) (RouteInfo, error)
All() (map[string]string, error)
}
func NewRouteInfo(method, path, description, title string) (RouteInfo, error) {
name, err := convertRouteToRouteName(path)
if err != nil {
return RouteInfo{}, err
}
return RouteInfo{
Method: method,
Name: name,
Path: path,
Description: description,
Title: title,
}, nil
}
type routeInfoKey struct{}
type Router struct {
chi.Mux
*chi.Mux
cache RouteCacher
cacheTTL time.Duration
}
func NewRouter() Router {
ttl := 8 * time.Hour
cache, err := NewRouteCacheService(WithTTL(ttl))
if err != nil {
log.Fatal(jerr.Wrap(err, jerr.ErrRouterNotCreated))
}
return Router{cache: cache, cacheTTL: ttl}
}
func (ro *Router) WithRouteInfo(ri RouteInfo, h HandlerFn) http.HandlerFunc {
ro.cache.AddRouteInfo(ri)

View File

@ -0,0 +1,20 @@
package routing
import (
"log"
"time"
"git.markbailey.dev/cerbervs/joist/internal/errors"
chi "github.com/go-chi/chi/v5"
)
func NewRouter() *Router {
ttl := 8 * time.Hour
cache, err := NewRouteCacheService(WithTTL(ttl))
if err != nil {
log.Fatal(errors.Wrap(err, errors.ErrRouterNotCreated))
}
return &Router{Mux: chi.NewRouter(), cache: cache, cacheTTL: ttl}
}

View File

@ -1,4 +1,4 @@
package badger
package storage
import (
"context"

View File

@ -1,4 +1,4 @@
package badger
package storage
import (
"context"

View File

@ -1,4 +1,4 @@
package joist
package storage
import (
"context"
@ -12,11 +12,3 @@ type Storer interface {
GetForPrefix(ctx context.Context, prefix string) (map[string][]byte, error)
Put(ctx context.Context, key string, val []byte, ttl time.Duration) error
}
type RouteCacher interface {
Add(name string, path string) error
AddRouteInfo(routeInfo RouteInfo) error
GetPath(name string) (string, error)
GetRouteInfo(name string) (RouteInfo, error)
All() (map[string]string, error)
}

1
joist.go Normal file
View File

@ -0,0 +1 @@
package joist