workgroups/vendor/gocloud.dev/internal/openurl/openurl.go
Marvin Preuss 1d4ae27878
All checks were successful
continuous-integration/drone/push Build is passing
ci: drone yaml with reusable anchors
2021-09-24 17:34:17 +02:00

106 lines
3.1 KiB
Go

// Copyright 2019 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package openurl provides helpers for URLMux and URLOpeners in portable APIs.
package openurl // import "gocloud.dev/internal/openurl"
import (
"fmt"
"net/url"
"sort"
"strings"
)
// SchemeMap maps URL schemes to values. The zero value is an empty map, ready for use.
type SchemeMap struct {
api string
m map[string]interface{}
}
// Register registers scheme for value; subsequent calls to FromString or
// FromURL with scheme will return value.
// api is the portable API name (e.g., "blob"); the same value should always
// be passed. It should be in all lowercase.
// typ is the portable type (e.g., "Bucket").
// Register panics if scheme has already been registered.
func (m *SchemeMap) Register(api, typ, scheme string, value interface{}) {
if m.m == nil {
m.m = map[string]interface{}{}
}
if api != strings.ToLower(api) {
panic(fmt.Errorf("api should be lowercase: %q", api))
}
if m.api == "" {
m.api = api
} else if m.api != api {
panic(fmt.Errorf("previously registered using api %q (now %q)", m.api, api))
}
if _, exists := m.m[scheme]; exists {
panic(fmt.Errorf("scheme %q already registered for %s.%s", scheme, api, typ))
}
m.m[scheme] = value
}
// FromString parses urlstr as an URL and looks up the value for the URL's scheme.
func (m *SchemeMap) FromString(typ, urlstr string) (interface{}, *url.URL, error) {
u, err := url.Parse(urlstr)
if err != nil {
return nil, nil, fmt.Errorf("open %s.%s: %v", m.api, typ, err)
}
val, err := m.FromURL(typ, u)
if err != nil {
return nil, nil, err
}
return val, u, nil
}
// FromURL looks up the value for u's scheme.
func (m *SchemeMap) FromURL(typ string, u *url.URL) (interface{}, error) {
scheme := u.Scheme
if scheme == "" {
return nil, fmt.Errorf("open %s.%s: no scheme in URL %q", m.api, typ, u)
}
for _, prefix := range []string{
fmt.Sprintf("%s+%s+", m.api, strings.ToLower(typ)),
fmt.Sprintf("%s+", m.api),
} {
scheme = strings.TrimPrefix(scheme, prefix)
}
v, ok := m.m[scheme]
if !ok {
return nil, fmt.Errorf("open %s.%s: no driver registered for %q for URL %q; available schemes: %v", m.api, typ, scheme, u, strings.Join(m.Schemes(), ", "))
}
return v, nil
}
// Schemes returns a sorted slice of the registered schemes.
func (m *SchemeMap) Schemes() []string {
var schemes []string
for s := range m.m {
schemes = append(schemes, s)
}
sort.Strings(schemes)
return schemes
}
// ValidScheme returns true iff scheme has been registered.
func (m *SchemeMap) ValidScheme(scheme string) bool {
for s := range m.m {
if scheme == s {
return true
}
}
return false
}