components/resolver: Use database instead of file approach

This commit is contained in:
Tom Wiesing 2022-10-05 16:35:47 +02:00
parent f6b38f055d
commit 32107265d4
No known key found for this signature in database
10 changed files with 165 additions and 103 deletions

View file

@ -14,8 +14,6 @@ type Control struct {
component.ComponentBase
Servables []component.Servable
ResolverFile string // TODO: this shouldn't be needed!
}
func (control Control) Name() string {
@ -48,7 +46,6 @@ func (control *Control) Stack(env environment.Environment) component.StackWithRe
"SELF_RESOLVER_BLOCK_FILE": control.Config.SelfResolverBlockFile,
},
TouchFiles: []string{control.ResolverFile},
CopyContextFiles: []string{core.Executable},
})
return stt

View file

@ -35,9 +35,9 @@ type MetaStorage interface {
// Any other metadata with the same key is deleted.
Set(key MetaKey, value any) error
// Add serializes values and stores each as associated with the provided key.
// Already existing metadata is left intact.
Add(key MetaKey, values ...any) error
// Set serializes values and stores them with the provided key.
// Any other metadata with the same key is deleted.
SetAll(key MetaKey, values ...any) error
// Purge removes all metadata, regardless of key.
Purge() error
@ -163,13 +163,19 @@ func (s *storage) Set(key MetaKey, value any) error {
})
}
func (s *storage) Add(key MetaKey, values ...any) error {
func (s *storage) SetAll(key MetaKey, values ...any) error {
table, err := s.SQL.QueryTable(true, models.MetadataTable)
if err != nil {
return err
}
return table.Transaction(func(tx *gorm.DB) error {
// delete the old values
status := tx.Where(&models.Metadatum{Slug: s.Slug, Key: string(key)}).Delete(&models.Metadatum{})
if err := status.Error; err != nil {
return err
}
for _, value := range values {
bytes, err := json.Marshal(value)
if err != nil {

View file

@ -82,6 +82,29 @@ func hasAnyPrefix(candidate string, prefixes []string) bool {
)
}
var PrefixConfigKey MetaKey = "prefix"
// Prefixes returns the prefixes for the instance
func (wisski *WissKI) PrefixesCached() (results []string, err error) {
err = wisski.Metadata().GetAll(PrefixConfigKey, func(index, total int) any {
if results == nil {
results = make([]string, total)
}
return &results[index]
})
return
}
// UpdatePrefixes updates the cached prefixes of this instance
func (wisski *WissKI) UpdatePrefixes() error {
prefixes, err := wisski.Prefixes()
if err != nil {
return err
}
return wisski.Metadata().SetAll(PrefixConfigKey, slicesx.AsAny(prefixes)...)
}
// PrefixConfig returns the prefix config belonging to this instance.
func (wisski *WissKI) PrefixConfig() (config string, err error) {
// if the user requested to skip the prefix, then don't do anything with it!

View file

@ -8,10 +8,6 @@ import (
"github.com/tkw1536/goprogram/lib/reflectx"
)
//
// META
//
var metaCache sync.Map
// getMeta gets the component belonging to a component type
@ -118,7 +114,7 @@ func filterSubtype(sliceS reflect.Value, iface reflect.Type) reflect.Value {
result := reflect.MakeSlice(reflect.SliceOf(iface), 0, len)
for i := 0; i < len; i++ {
element := sliceS.Index(i)
if element.Type().Implements(iface) {
if element.Elem().Type().Implements(iface) {
result = reflect.Append(result, element.Elem().Convert(iface))
}
}

View file

@ -2,15 +2,14 @@ package resolver
import (
"fmt"
"io/fs"
"net/http"
"path/filepath"
"regexp"
"time"
"github.com/FAU-CDI/wdresolve"
"github.com/FAU-CDI/wdresolve/resolvers"
"github.com/FAU-CDI/wisski-distillery/internal/component"
"github.com/FAU-CDI/wisski-distillery/internal/component/control"
"github.com/FAU-CDI/wisski-distillery/internal/component/instances"
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
"github.com/tkw1536/goprogram/stream"
)
@ -18,13 +17,13 @@ import (
type Resolver struct {
component.ComponentBase
Control *control.Control
ResolverFile string
Instances *instances.Instances
handler lazy.Lazy[wdresolve.ResolveHandler]
prefixes lazy.Lazy[map[string]string] // cached prefixes (from the server)
handler lazy.Lazy[wdresolve.ResolveHandler] // handler
}
func (Resolver) Name() string { return "resolver" }
func (*Resolver) Name() string { return "resolver" }
func (resolver *Resolver) Routes() []string { return []string{"/go/", "/wisski/get/"} }
@ -50,35 +49,48 @@ func (resolver *Resolver) Handler(route string, io stream.IOStream) (http.Handle
io.Printf("registering legacy domain %s\n", domain)
}
configPath := resolver.ConfigPath()
{
// load the prefix path!
var fs fs.File
fs, err = resolver.Environment.Open(configPath)
io.Println("loading prefixes from ", configPath)
if err != nil {
return
}
defer fs.Close()
// read the file
var prefixes resolvers.Prefix
prefixes, err = resolvers.ReadPrefixes(fs)
if err != nil {
return
}
// and use that as the resolver!
p.Resolver = resolvers.InOrder{
prefixes,
fallback,
}
return p
// resolve the prefixes
p.Resolver = resolvers.InOrder{
resolver,
fallback,
}
return p
}), err
}
func (resolver *Resolver) ConfigPath() string {
return filepath.Join(resolver.Control.Path(), resolver.ResolverFile)
func (resolver *Resolver) Target(uri string) string {
return wdresolve.PrefixTarget(resolver, uri)
}
// allow reloading prefixes from the server every minute
const prefixesRefresh = time.Minute
func (resolver *Resolver) Prefixes() (prefixes map[string]string) {
// reset the prefixes after a specific time, but only if requested
resolver.prefixes.ResetAfter(prefixesRefresh)
return resolver.prefixes.Get(resolver.freshPrefixes)
}
func (resolver *Resolver) freshPrefixes() map[string]string {
instances, err := resolver.Instances.All()
if err != nil {
return nil
}
gPrefixes := make(map[string]string)
for _, instance := range instances {
url := instance.URL().String()
// failed to fetch prefixes for this particular instance
// => skip it!
prefixes, err := instance.PrefixesCached()
if err != nil {
continue
}
for _, p := range prefixes {
gPrefixes[url] = p
}
}
return gPrefixes
}