Files
sing-box-extended-mirror/adapter/provider/manager.go
T
2026-10-19 01:05:55 +03:00

126 lines
3.0 KiB
Go

package provider
import (
"context"
"os"
"sync"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
var _ adapter.ProviderManager = (*Manager)(nil)
type Manager struct {
registry adapter.ProviderRegistry
access sync.Mutex
startAccess sync.Mutex
scope *adapter.Scope
stage adapter.StartStage
providers []adapter.Provider
providerByTag map[string]adapter.Provider
}
func NewManager(registry adapter.ProviderRegistry) *Manager {
return &Manager{
registry: registry,
providerByTag: make(map[string]adapter.Provider),
}
}
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
m.startAccess.Lock()
defer m.startAccess.Unlock()
m.access.Lock()
m.scope = scope
m.stage = stage
providers := m.providers
m.access.Unlock()
for _, provider := range providers {
err := scope.Start("provider/"+provider.Type()+"["+provider.Tag()+"]", provider, stage)
if err != nil {
return err
}
}
return nil
}
func (m *Manager) Providers() []adapter.Provider {
m.access.Lock()
defer m.access.Unlock()
return m.providers
}
func (m *Manager) Get(tag string) (adapter.Provider, bool) {
m.access.Lock()
provider, found := m.providerByTag[tag]
m.access.Unlock()
return provider, found
}
func (m *Manager) Remove(tag string) error {
m.startAccess.Lock()
defer m.startAccess.Unlock()
m.access.Lock()
provider, found := m.providerByTag[tag]
if !found {
m.access.Unlock()
return os.ErrInvalid
}
delete(m.providerByTag, tag)
m.providers = common.Filter(m.providers, func(it adapter.Provider) bool {
return it != provider
})
scope := m.scope
m.access.Unlock()
if scope == nil {
return nil
}
return scope.Remove(provider)
}
func (m *Manager) Create(ctx context.Context, router adapter.Router, logFactory log.Factory, tag string, providerType string, options any) error {
if tag == "" {
return os.ErrInvalid
}
provider, err := m.registry.CreateProvider(ctx, router, logFactory, tag, providerType, options)
if err != nil {
return err
}
m.startAccess.Lock()
defer m.startAccess.Unlock()
m.access.Lock()
scope := m.scope
stage := m.stage
m.access.Unlock()
if scope != nil {
name := "provider/" + provider.Type() + "[" + provider.Tag() + "]"
for _, startStage := range adapter.ListStartStages[:stage+1] {
err = scope.Start(name, provider, startStage)
if err != nil {
return E.Errors(err, scope.Remove(provider))
}
}
}
m.access.Lock()
existsProvider, loaded := m.providerByTag[tag]
if loaded {
m.providers = common.Filter(m.providers, func(it adapter.Provider) bool {
return it != existsProvider
})
}
m.providers = append(m.providers, provider)
m.providerByTag[tag] = provider
m.access.Unlock()
if !loaded || scope == nil {
return nil
}
err = scope.Remove(existsProvider)
if err != nil {
return E.Cause(err, "close provider/", existsProvider.Type(), "[", existsProvider.Tag(), "]")
}
return nil
}