package joist import ( "context" "regexp" "strings" "sync" "time" "git.markbailey.dev/cerbervs/joist/internal/badger" jerr "git.markbailey.dev/cerbervs/joist/internal/errors" ) const suff = "route_cache" type routeCache struct { rs map[string]string s Storer ttl time.Duration } type RouteCacheOpt func(*routeCache) var ( rcLock sync.Mutex rcOnce sync.Once c *routeCache ) func WithTTL(ttl time.Duration) RouteCacheOpt { return func(r *routeCache) { r.ttl = ttl } } func WithStore(store Storer) RouteCacheOpt { return func(r *routeCache) { r.s = store } } func NewRouteCache(opts ...RouteCacheOpt) (*routeCache, error) { s, err := badger.NewBadgerStore(badger.WithSubDir("route_cache")) if err != nil { return nil, jerr.NewContextAwareErr(jerr.ErrCacheUninitialized, err) } c = &routeCache{ rs: make(map[string]string), s: s, } for _, opt := range opts { opt(c) } return c, nil } 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 { ttl := r.ttl if ttl == 0 { ttl = 1 * time.Hour } if err := r.s.Put(context.Background(), name, []byte(path), ttl); err != nil { return err } return nil } func (r *routeCache) GetPath(name string) (string, error) { if path, ok := r.rs[name]; ok { return path, nil } return string(""), jerr.NewErrRouteNotFound(string(name)) } func (r *routeCache) GetDescription(name string) (string, error) { // TODO: implement return "", nil } func convertRouteToRouteName(route string) (string, error) { name := "app" if route == "/" { return name + ".home", nil } route = strings.ReplaceAll(route, "/", ".") route = strings.ReplaceAll(route, "-", "_") paramRegex := regexp.MustCompile(`\.{[^}]*}`) params := paramRegex.FindAllString(route, -1) route = paramRegex.ReplaceAllString(route, "") if len(params) > 0 { route += ".params" } name += strings.TrimRight(route, ".") return name, nil }