101 lines
2.2 KiB
Go
101 lines
2.2 KiB
Go
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||
|
|
||
|
package target
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net/url"
|
||
|
"strings"
|
||
|
"path/filepath"
|
||
|
"log/slog"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrUnknownTargetType = errors.New("Unknown target type")
|
||
|
TargetTypes *Types = NewTypes()
|
||
|
)
|
||
|
|
||
|
type TypeName string //`json:"type"`
|
||
|
|
||
|
type TypeFactory func(*url.URL) DocTarget
|
||
|
|
||
|
type Types struct {
|
||
|
registry map[string]TypeFactory
|
||
|
}
|
||
|
|
||
|
func NewTypes() *Types {
|
||
|
return &Types{registry: make(map[string]TypeFactory)}
|
||
|
}
|
||
|
|
||
|
func (t *Types) Register(names []string, factory TypeFactory) {
|
||
|
for _,name := range names {
|
||
|
t.registry[name] = factory
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t *Types) FromExtension(path string) (TypeFactory, error) {
|
||
|
elements := strings.Split(path, ".")
|
||
|
numberOfElements := len(elements)
|
||
|
if numberOfElements > 2 {
|
||
|
if src := t.Get(strings.Join(elements[numberOfElements - 2: numberOfElements - 1], ".")); src != nil {
|
||
|
return src, nil
|
||
|
}
|
||
|
}
|
||
|
if src := t.Get(elements[numberOfElements - 1]); src != nil {
|
||
|
return src, nil
|
||
|
}
|
||
|
return nil, fmt.Errorf("%w: %s", ErrUnknownTargetType, path)
|
||
|
}
|
||
|
|
||
|
func (t *Types) New(uri string) (DocTarget, error) {
|
||
|
if uri == "" {
|
||
|
uri = "file://-"
|
||
|
}
|
||
|
|
||
|
u, e := url.Parse(uri)
|
||
|
if u == nil || e != nil {
|
||
|
return nil, fmt.Errorf("%w: %s", ErrUnknownTargetType, e)
|
||
|
}
|
||
|
|
||
|
if u.Scheme == "" {
|
||
|
u.Scheme = "file"
|
||
|
}
|
||
|
|
||
|
path := filepath.Join(u.Hostname(), u.Path)
|
||
|
if d, lookupErr := t.FromExtension(path); d != nil {
|
||
|
slog.Info("Target.New", "target", t, "err", lookupErr)
|
||
|
return d(u), lookupErr
|
||
|
} else {
|
||
|
slog.Info("Target.New", "target", t, "err", lookupErr)
|
||
|
}
|
||
|
|
||
|
if r, ok := t.registry[u.Scheme]; ok {
|
||
|
return r(u), nil
|
||
|
}
|
||
|
return nil, fmt.Errorf("%w: %s", ErrUnknownTargetType, u.Scheme)
|
||
|
}
|
||
|
|
||
|
func (t *Types) Has(typename string) bool {
|
||
|
if _, ok := t.registry[typename]; ok {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (t *Types) Get(typename string) TypeFactory {
|
||
|
if d, ok := t.registry[typename]; ok {
|
||
|
return d
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (n *TypeName) UnmarshalJSON(b []byte) error {
|
||
|
TargetTypeName := strings.Trim(string(b), "\"")
|
||
|
if TargetTypes.Has(TargetTypeName) {
|
||
|
*n = TypeName(TargetTypeName)
|
||
|
return nil
|
||
|
}
|
||
|
return fmt.Errorf("%w: %s", ErrUnknownTargetType, TargetTypeName)
|
||
|
}
|