feat: initial goget release — modern IPv6-first download utility
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
//go:build linux || freebsd
|
||||
// +build linux freebsd
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"codeberg.org/petrbalvin/goget/internal/core"
|
||||
)
|
||||
|
||||
// Registry manages all registered protocols
|
||||
type Registry struct {
|
||||
mu sync.RWMutex
|
||||
protocols map[string]core.Protocol
|
||||
}
|
||||
|
||||
// NewRegistry creates a new registry
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
protocols: make(map[string]core.Protocol),
|
||||
}
|
||||
}
|
||||
|
||||
// Register registers a protocol under its primary scheme
|
||||
func (r *Registry) Register(p core.Protocol) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
scheme := p.Scheme()
|
||||
if scheme == "" {
|
||||
return fmt.Errorf("protocol scheme cannot be empty")
|
||||
}
|
||||
|
||||
if _, exists := r.protocols[scheme]; exists {
|
||||
return fmt.Errorf("protocol already registered: %s", scheme)
|
||||
}
|
||||
|
||||
r.protocols[scheme] = p
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeScheme normalizes a scheme for lookup (https -> http, webdavs -> webdav, etc.)
|
||||
func normalizeScheme(scheme string) string {
|
||||
scheme = strings.ToLower(scheme)
|
||||
switch scheme {
|
||||
case "https":
|
||||
return "http"
|
||||
case "webdavs":
|
||||
return "webdav"
|
||||
case "ftps":
|
||||
return "ftp"
|
||||
default:
|
||||
return scheme
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a protocol for a given URL with scheme normalization
|
||||
func (r *Registry) Get(u *url.URL) (core.Protocol, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
if u == nil {
|
||||
return nil, fmt.Errorf("url cannot be nil")
|
||||
}
|
||||
|
||||
scheme := normalizeScheme(u.Scheme)
|
||||
p, exists := r.protocols[scheme]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("unsupported protocol: %s", u.Scheme)
|
||||
}
|
||||
|
||||
// Additional validation via CanHandle
|
||||
if !p.CanHandle(u) {
|
||||
return nil, fmt.Errorf("protocol %s cannot handle url: %s", scheme, u.String())
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// List returns a list of all registered protocols
|
||||
func (r *Registry) List() []string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
schemes := make([]string, 0, len(r.protocols))
|
||||
for scheme := range r.protocols {
|
||||
schemes = append(schemes, scheme)
|
||||
}
|
||||
|
||||
sort.Strings(schemes)
|
||||
return schemes
|
||||
}
|
||||
|
||||
// Supports determines whether a protocol is supported (with normalization)
|
||||
func (r *Registry) Supports(scheme string) bool {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
_, exists := r.protocols[normalizeScheme(scheme)]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Capabilities returns the capabilities of all protocols
|
||||
func (r *Registry) Capabilities() map[string][]string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
caps := make(map[string][]string)
|
||||
for scheme, p := range r.protocols {
|
||||
caps[scheme] = p.Capabilities()
|
||||
}
|
||||
|
||||
return caps
|
||||
}
|
||||
|
||||
// GlobalRegistry is the global registry instance
|
||||
var GlobalRegistry = NewRegistry()
|
||||
|
||||
// Register is a helper for registering in the global registry
|
||||
func Register(p core.Protocol) error {
|
||||
return GlobalRegistry.Register(p)
|
||||
}
|
||||
|
||||
// Get is a helper for getting a protocol from the global registry
|
||||
func Get(u *url.URL) (core.Protocol, error) {
|
||||
return GlobalRegistry.Get(u)
|
||||
}
|
||||
Reference in New Issue
Block a user