package storage
import (
"errors"
"net/url"
"path/filepath"
"strings"
"sync"
"github.com/navidrome/navidrome/utils/slice"
)
const LocalSchemaID = "file"
type constructor func(url.URL) Storage
var (
registry = map[string]constructor{}
lock sync.RWMutex
)
func Register(schema string, c constructor) {
lock.Lock()
defer lock.Unlock()
registry[schema] = c
}
func LocalPathToURL(osPath string) (url.URL, error) {
abs, _ := filepath.Abs(osPath)
abs = filepath.ToSlash(abs)
pathParts := strings.Split(abs, "/")
escapedParts := slice.Map(pathParts, func(s string) string {
return url.PathEscape(s)
})
u, err := url.Parse(LocalSchemaID + "://" + strings.Join(escapedParts, "/"))
if err != nil {
return url.URL{}, err
}
return *u, nil
}
func For(uri string) (Storage, error) {
lock.RLock()
defer lock.RUnlock()
parts := strings.Split(uri, "://")
var u *url.URL
if len(parts) < 2 {
parsed, err := LocalPathToURL(uri)
if err != nil {
return nil, err
}
u = &parsed
} else {
parsed, err := url.Parse(uri)
if err != nil {
return nil, err
}
u = parsed
}
c, ok := registry[u.Scheme]
if !ok {
return nil, errors.New("schema '" + u.Scheme + "' not registered")
}
return c(*u), nil
}