diff --git a/common/taggedfeatures/holder.go b/common/taggedfeatures/holder.go new file mode 100644 index 000000000..e8057b5e9 --- /dev/null +++ b/common/taggedfeatures/holder.go @@ -0,0 +1,84 @@ +package taggedfeatures + +import ( + "context" + "github.com/v2fly/v2ray-core/v4/common/task" + "github.com/v2fly/v2ray-core/v4/features" + "reflect" + "sync" +) + +type Holder struct { + access *sync.RWMutex + features map[string]features.Feature + memberType reflect.Type + ctx context.Context +} + +func NewHolder(ctx context.Context, memberType interface{}) *Holder { + return &Holder{ + ctx: ctx, + access: &sync.RWMutex{}, + features: make(map[string]features.Feature), + memberType: reflect.TypeOf(memberType), + } +} + +func (h *Holder) GetFeaturesByTag(tag string) (features.Feature, error) { + h.access.RLock() + defer h.access.RUnlock() + feature, ok := h.features[tag] + if !ok { + return nil, newError("unable to find feature with tag") + } + return feature, nil +} + +func (h *Holder) AddFeaturesByTag(tag string, feature features.Feature) error { + h.access.Lock() + defer h.access.Unlock() + featureType := reflect.TypeOf(feature.Type()) + if !featureType.AssignableTo(h.memberType) { + return newError("feature is not assignable to the base type") + } + h.features[tag] = feature + return nil +} + +func (h *Holder) RemoveFeaturesByTag(tag string) error { + h.access.Lock() + defer h.access.Unlock() + delete(h.features, tag) + return nil +} + +func (h *Holder) GetFeaturesTag() ([]string, error) { + h.access.RLock() + defer h.access.RUnlock() + var ret []string + for key, _ := range h.features { + ret = append(ret, key) + } + return ret, nil +} + +func (h *Holder) Start() error { + h.access.Lock() + defer h.access.Unlock() + var startTasks []func() error + for _, v := range h.features { + startTasks = append(startTasks, v.Start) + } + return task.Run(h.ctx, startTasks...) +} + +func (h *Holder) Close() error { + h.access.Lock() + defer h.access.Unlock() + + var closeTasks []func() error + for _, v := range h.features { + closeTasks = append(closeTasks, v.Close) + } + return task.Run(h.ctx, closeTasks...) +} diff --git a/common/taggedfeatures/taggedfeatures.go b/common/taggedfeatures/taggedfeatures.go new file mode 100644 index 000000000..450e72b66 --- /dev/null +++ b/common/taggedfeatures/taggedfeatures.go @@ -0,0 +1,3 @@ +package taggedfeatures + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen diff --git a/features/feature.go b/features/feature.go index a609f3b44..b6987d20e 100644 --- a/features/feature.go +++ b/features/feature.go @@ -15,3 +15,7 @@ type Feature interface { func PrintDeprecatedFeatureWarning(feature string) { newError("You are using a deprecated feature: " + feature + ". Please update your config file with latest configuration format, or update your client software.").WriteToLog() } + +type TaggedFeatures interface { + GetFeaturesByTag(tag string) (Feature, error) +}