twink/vendor/sourcery.dny.nu/pana/internal/loader/loader.go

98 lines
2.5 KiB
Go
Raw Permalink Normal View History

2025-12-05 12:20:05 +01:00
package loader
import (
"context"
"maps"
"slices"
"strings"
"sync"
ld "sourcery.dny.nu/longdistance"
"sourcery.dny.nu/pana/internal/json"
"sourcery.dny.nu/pana/vocab/geojson"
gts "sourcery.dny.nu/pana/vocab/gotosocial"
"sourcery.dny.nu/pana/vocab/litepub"
as "sourcery.dny.nu/pana/vocab/w3/activitystreams"
credv1 "sourcery.dny.nu/pana/vocab/w3id/credentialsv1"
idv1 "sourcery.dny.nu/pana/vocab/w3id/identityv1"
secv1 "sourcery.dny.nu/pana/vocab/w3id/securityv1"
)
// Builtin is a remote context cache.
type Builtin struct {
domains map[string]ld.Document
paths map[string]ld.Document
pathKeys []string
lock sync.RWMutex
}
func New() *Builtin {
b := &Builtin{
domains: make(map[string]ld.Document, 8),
paths: make(map[string]ld.Document, 2),
}
b.RegisterContextURL(as.IRI, as.ContextDocument)
b.RegisterContextURL(gts.IRI, gts.ContextDocument)
b.RegisterContextURL(credv1.IRI, credv1.ContextDocument)
b.RegisterContextURL(idv1.IRI, idv1.ContextDocument)
b.RegisterContextURL(secv1.IRI, secv1.ContextDocument)
b.RegisterContextURL(litepub.IRI, litepub.ContextDocument)
b.RegisterContextURL(geojson.IRI, geojson.ContextDocument)
b.RegisterContextPath("/litepub-0.1.jsonld", litepub.ContextDocument1dot0)
return b
}
// Get is an [ld.RemoteContextLoaderFunc].
func (b *Builtin) Get(_ context.Context, url string) (ld.Document, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if doc, ok := b.domains[url]; ok {
return doc, nil
}
for _, path := range b.pathKeys {
if strings.HasSuffix(url, path) {
doc := b.paths[path]
doc.URL = url
return doc, nil
}
}
return ld.Document{}, ld.ErrLoadingRemoteContext
}
// RegisterContextURL adds or overrides a context document for the specified
// remote context URL in the loader.
func (b *Builtin) RegisterContextURL(url string, doc json.RawMessage) error {
b.lock.Lock()
defer b.lock.Unlock()
ctx, err := json.GetContextDocument(doc)
if err != nil {
return err
}
b.domains[url] = ld.Document{URL: url, Context: ctx}
return nil
}
// RegisterContextPath adds or overrides a context document for the specified
// remote path in the loader.
//
// Paths are always matches as URL suffixes.
func (b *Builtin) RegisterContextPath(path string, doc json.RawMessage) error {
b.lock.Lock()
defer b.lock.Unlock()
ctx, err := json.GetContextDocument(doc)
if err != nil {
return err
}
b.paths[path] = ld.Document{URL: "", Context: ctx}
b.pathKeys = slices.Collect(maps.Keys(b.paths))
return nil
}