mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-20 16:24:25 +00:00
126 lines
3.0 KiB
Go
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
|
|
}
|