mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-15 07:27:30 +00:00
types/mapx, ipn/ipnext: add ordered map, akin to set.Slice
We had an ordered set type (set.Slice) already but we occasionally want to do the same thing with a map, preserving the order things were added, so add that too, as mapsx.OrderedMap[K, V], and then use in ipnext. Updates #12614 Change-Id: I85e6f5e11035571a28316441075e952aef9a0863 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
3bc10ea585
commit
dbf13976d3
@@ -8,6 +8,7 @@ package ipnext
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"iter"
|
||||
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/feature"
|
||||
@@ -16,8 +17,7 @@ import (
|
||||
"tailscale.com/tsd"
|
||||
"tailscale.com/tstime"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/mak"
|
||||
"tailscale.com/types/mapx"
|
||||
)
|
||||
|
||||
// Extension augments LocalBackend with additional functionality.
|
||||
@@ -91,13 +91,9 @@ func (d *Definition) MakeExtension(logf logger.Logf, sb SafeBackend) (Extension,
|
||||
return ext, nil
|
||||
}
|
||||
|
||||
// extensionsByName is a map of registered extensions,
|
||||
// extensions is a map of registered extensions,
|
||||
// where the key is the name of the extension.
|
||||
var extensionsByName map[string]*Definition
|
||||
|
||||
// extensionsByOrder is a slice of registered extensions,
|
||||
// in the order they were registered.
|
||||
var extensionsByOrder []*Definition
|
||||
var extensions mapx.OrderedMap[string, *Definition]
|
||||
|
||||
// RegisterExtension registers a function that instantiates an [Extension].
|
||||
// The name must be the same as returned by the extension's [Extension.Name].
|
||||
@@ -111,19 +107,16 @@ func RegisterExtension(name string, newExt NewExtensionFn) {
|
||||
if newExt == nil {
|
||||
panic(fmt.Sprintf("ipnext: newExt is nil: %q", name))
|
||||
}
|
||||
if _, ok := extensionsByName[name]; ok {
|
||||
if extensions.Contains(name) {
|
||||
panic(fmt.Sprintf("ipnext: duplicate extensions: %q", name))
|
||||
}
|
||||
ext := &Definition{name, newExt}
|
||||
mak.Set(&extensionsByName, name, ext)
|
||||
extensionsByOrder = append(extensionsByOrder, ext)
|
||||
extensions.Set(name, &Definition{name, newExt})
|
||||
}
|
||||
|
||||
// Extensions returns a read-only view of the extensions
|
||||
// registered via [RegisterExtension]. It preserves the order
|
||||
// in which the extensions were registered.
|
||||
func Extensions() views.Slice[*Definition] {
|
||||
return views.SliceOf(extensionsByOrder)
|
||||
// Extensions iterates over the extensions in the order they were registered
|
||||
// via [RegisterExtension].
|
||||
func Extensions() iter.Seq[*Definition] {
|
||||
return extensions.Values()
|
||||
}
|
||||
|
||||
// DefinitionForTest returns a [Definition] for the specified [Extension].
|
||||
|
@@ -162,17 +162,14 @@ func newExtensionHost(logf logger.Logf, b Backend, overrideExts ...*ipnext.Defin
|
||||
}
|
||||
|
||||
// Use registered extensions.
|
||||
exts := ipnext.Extensions().All()
|
||||
numExts := ipnext.Extensions().Len()
|
||||
extDef := ipnext.Extensions()
|
||||
if overrideExts != nil {
|
||||
// Use the provided, potentially empty, overrideExts
|
||||
// instead of the registered ones.
|
||||
exts = slices.All(overrideExts)
|
||||
numExts = len(overrideExts)
|
||||
extDef = slices.Values(overrideExts)
|
||||
}
|
||||
|
||||
host.allExtensions = make([]ipnext.Extension, 0, numExts)
|
||||
for _, d := range exts {
|
||||
for d := range extDef {
|
||||
ext, err := d.MakeExtension(logf, b)
|
||||
if errors.Is(err, ipnext.SkipExtension) {
|
||||
// The extension wants to be skipped.
|
||||
|
Reference in New Issue
Block a user