// Copyright 2024 Matthew Rich . 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) }