-
Notifications
You must be signed in to change notification settings - Fork 0
/
registry.go
155 lines (129 loc) · 3.54 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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package fs
import (
"cmp"
"fmt"
"slices"
"strings"
"sync"
)
const PrefixSeparator = "://"
var (
// Local is the local file system
Local = &LocalFileSystem{
DefaultCreatePermissions: UserAndGroupReadWrite,
DefaultCreateDirPermissions: UserAndGroupReadWrite,
}
Invalid InvalidFileSystem
)
type fsCount struct {
fs FileSystem
count int
}
var (
registry = make(map[string]*fsCount, 2)
registrySorted = make([]FileSystem, 0, 2)
registryMtx sync.RWMutex
)
func init() {
Register(Local)
Register(Invalid)
}
// Register adds a file system or increments its reference count
// if it is already registered.
// The function returns the reference file system's reference count.
func Register(fs FileSystem) int {
prefix := fs.Prefix()
if prefix == "" {
panic(fmt.Sprintf("file system with empty prefix: %#v", fs))
}
registryMtx.Lock()
defer registryMtx.Unlock()
if regFS, ok := registry[prefix]; ok {
regFS.count++
return regFS.count
}
registry[prefix] = &fsCount{fs, 1}
registrySorted = append(registrySorted, fs)
slices.SortFunc(registrySorted, func(a, b FileSystem) int { return cmp.Compare(a.Prefix(), b.Prefix()) })
return 1
}
// Unregister a file system decrements its reference count
// and removes it when the reference count reaches 0.
// If the file system is not registered, -1 is returned.
func Unregister(fs FileSystem) int {
prefix := fs.Prefix()
if prefix == "" {
panic(fmt.Sprintf("file system with empty prefix: %#v", fs))
}
registryMtx.Lock()
defer registryMtx.Unlock()
regFS, ok := registry[prefix]
if !ok {
return -1
}
if regFS.count <= 1 {
delete(registry, prefix)
registrySorted = slices.DeleteFunc(registrySorted, func(f FileSystem) bool { return f == regFS.fs })
return 0
}
regFS.count--
return regFS.count
}
// RegisteredFileSystems returns the registered file systems
// sorted by their prefix.
func RegisteredFileSystems() []FileSystem {
registryMtx.Lock()
defer registryMtx.Unlock()
return slices.Clone(registrySorted)
}
// IsRegistered returns true if the file system is registered
// with its prefix.
func IsRegistered(fs FileSystem) bool {
if fs == nil {
return false
}
registryMtx.Lock()
defer registryMtx.Unlock()
_, ok := registry[fs.Prefix()]
return ok
}
// GetFileSystemByPrefixOrNil returns the file system registered
// with the passed prefix, or nil if it can't be found.
func GetFileSystemByPrefixOrNil(prefix string) FileSystem {
registryMtx.Lock()
defer registryMtx.Unlock()
f, ok := registry[prefix]
if !ok {
return nil
}
return f.fs
}
// GetFileSystem returns a FileSystem for the passed URI.
// Returns the local file system if no other file system could be identified.
// The URI can be passed as parts that will be joined according to the file system.
func GetFileSystem(uriParts ...string) FileSystem {
if len(uriParts) == 0 {
return Invalid
}
fs, _ := ParseRawURI(uriParts[0])
return fs
}
// ParseRawURI returns a FileSystem for the passed URI and the path component within that file system.
// Returns the local file system if no other file system could be identified.
func ParseRawURI(uri string) (fs FileSystem, fsPath string) {
if uri == "" {
return Invalid, ""
}
registryMtx.RLock()
defer registryMtx.RUnlock()
// Find fs with longest matching prefix
// by iterating in reverse order of sorted registry
for i := len(registrySorted) - 1; i >= 0; i-- {
fs = registrySorted[i]
if strings.HasPrefix(uri, fs.Prefix()) {
return fs, fs.CleanPathFromURI(uri)
}
}
// No file system found, assume uri is for the local file system
return Local, uri
}