-
-
Notifications
You must be signed in to change notification settings - Fork 480
/
registry.go
121 lines (98 loc) · 2.62 KB
/
registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package backend
import (
"context"
"fmt"
"sort"
"golang.org/x/exp/maps"
)
var (
// CryptoRegistry is the global registry of available crypto backends.
CryptoRegistry = NewRegistry[CryptoBackend, CryptoLoader]()
// StorageRegistry is the global registry of available storage backends.
StorageRegistry = NewRegistry[StorageBackend, StorageLoader]()
// ErrNotFound is returned if the requested backend was not found.
ErrNotFound = fmt.Errorf("backend not found")
)
// Prioritized is the interface for prioritized items.
type Prioritized interface {
Priority() int
}
// CryptoLoader is the interface for creating a new crypto backend.
type CryptoLoader interface {
fmt.Stringer
Prioritized
New(context.Context) (Crypto, error)
Handles(context.Context, Storage) error
}
// StorageLoader is the interface for creating a new storage backend.
type StorageLoader interface {
fmt.Stringer
Prioritized
New(context.Context, string) (Storage, error)
Init(context.Context, string) (Storage, error)
Clone(context.Context, string, string) (Storage, error)
Handles(context.Context, string) error
}
// NewRegistry returns a new registry.
func NewRegistry[K comparable, V Prioritized]() *Registry[K, V] {
return &Registry[K, V]{
backends: map[K]V{},
nameToBackend: map[string]K{},
backendToName: map[K]string{},
}
}
// Registry is a registry of backends.
type Registry[K comparable, V Prioritized] struct {
backends map[K]V
nameToBackend map[string]K
backendToName map[K]string
}
func (r *Registry[K, V]) Register(backend K, name string, loader V) {
r.backends[backend] = loader
r.nameToBackend[name] = backend
r.backendToName[backend] = name
}
func (r *Registry[K, V]) BackendNames() []string {
names := maps.Keys(r.nameToBackend)
sort.Strings(names)
return names
}
func (r *Registry[K, V]) Backends() []V {
bes := make([]V, 0, len(r.backends))
for _, be := range r.backends {
bes = append(bes, be)
}
return bes
}
func (r *Registry[K, V]) Prioritized() []V {
bes := maps.Values(r.backends)
sort.Slice(bes, func(i, j int) bool {
return bes[i].Priority() < bes[j].Priority()
})
return bes
}
func (r *Registry[K, V]) Get(key K) (V, error) {
if be, found := r.backends[key]; found {
return be, nil
}
var zero V
return zero, ErrNotFound
}
func (r *Registry[K, V]) Backend(name string) (K, error) {
if name == "gpg" {
name = "gpgcli"
}
backend, ok := r.nameToBackend[name]
if !ok {
var zero K
return zero, ErrNotFound
}
return backend, nil
}
func (r *Registry[K, V]) BackendName(backend K) (string, error) {
name, ok := r.backendToName[backend]
if !ok {
return "", ErrNotFound
}
return name, nil
}