feat: initial goget release — modern IPv6-first download utility

This commit is contained in:
2026-06-26 21:21:58 +02:00
commit 53db81e1f7
147 changed files with 45931 additions and 0 deletions
+132
View File
@@ -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)
}