htmgo/framework/service/locator.go

85 lines
1.4 KiB
Go
Raw Normal View History

package service
import (
"log"
"reflect"
"sync"
)
type Lifecycle = string
var (
Singleton Lifecycle = "singleton"
Transient Lifecycle = "transient"
)
type Provider struct {
cb func() any
lifecycle Lifecycle
}
type Locator struct {
services map[string]Provider
cache map[string]any
mutex sync.RWMutex
}
func NewLocator() *Locator {
return &Locator{
services: make(map[string]Provider),
cache: make(map[string]any),
mutex: sync.RWMutex{},
}
}
func (l *Locator) setCache(key string, value any) {
l.cache[key] = value
}
func (l *Locator) clearCache(key string) {
delete(l.cache, key)
}
func (l *Locator) getCache(key string) any {
return l.cache[key]
}
func Get[T any](locator *Locator) *T {
locator.mutex.RLock()
i := new(T)
t := reflect.TypeOf(i).String()
cached := locator.getCache(t)
if cached != nil {
locator.mutex.RUnlock()
return cached.(*T)
}
entry, ok := locator.services[t]
if !ok {
log.Fatalf("%s is not registered in the service locator", t)
}
cb := entry.cb().(*T)
locator.mutex.RUnlock()
locator.mutex.Lock()
if entry.lifecycle == Singleton {
locator.setCache(t, cb)
}
locator.mutex.Unlock()
return cb
}
func Set[T any](locator *Locator, lifecycle Lifecycle, value func() *T) {
t := reflect.TypeOf(value)
rt := t.Out(0)
key := rt.String()
locator.services[key] = Provider{
cb: func() any {
return value()
},
lifecycle: lifecycle,
}
locator.clearCache(key)
}