-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b910428
commit 2a2d5d8
Showing
76 changed files
with
1,639 additions
and
674 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package adapter | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/sagernet/sing-box/log" | ||
"github.com/sagernet/sing-box/option" | ||
) | ||
|
||
type Endpoint interface { | ||
Lifecycle | ||
Type() string | ||
Tag() string | ||
Outbound | ||
} | ||
|
||
type EndpointRegistry interface { | ||
option.EndpointOptionsRegistry | ||
Create(ctx context.Context, router Router, logger log.ContextLogger, tag string, endpointType string, options any) (Endpoint, error) | ||
} | ||
|
||
type EndpointManager interface { | ||
Lifecycle | ||
Endpoints() []Endpoint | ||
Get(tag string) (Endpoint, bool) | ||
Remove(tag string) error | ||
Create(ctx context.Context, router Router, logger log.ContextLogger, tag string, endpointType string, options any) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package endpoint | ||
|
||
import "github.com/sagernet/sing-box/option" | ||
|
||
type Adapter struct { | ||
endpointType string | ||
endpointTag string | ||
network []string | ||
dependencies []string | ||
} | ||
|
||
func NewAdapter(endpointType string, endpointTag string, network []string, dependencies []string) Adapter { | ||
return Adapter{ | ||
endpointType: endpointType, | ||
endpointTag: endpointTag, | ||
network: network, | ||
dependencies: dependencies, | ||
} | ||
} | ||
|
||
func NewAdapterWithDialerOptions(endpointType string, endpointTag string, network []string, dialOptions option.DialerOptions) Adapter { | ||
var dependencies []string | ||
if dialOptions.Detour != "" { | ||
dependencies = []string{dialOptions.Detour} | ||
} | ||
return NewAdapter(endpointType, endpointTag, network, dependencies) | ||
} | ||
|
||
func (a *Adapter) Type() string { | ||
return a.endpointType | ||
} | ||
|
||
func (a *Adapter) Tag() string { | ||
return a.endpointTag | ||
} | ||
|
||
func (a *Adapter) Network() []string { | ||
return a.network | ||
} | ||
|
||
func (a *Adapter) Dependencies() []string { | ||
return a.dependencies | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package endpoint | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"sync" | ||
|
||
"github.com/sagernet/sing-box/adapter" | ||
"github.com/sagernet/sing-box/common/taskmonitor" | ||
C "github.com/sagernet/sing-box/constant" | ||
"github.com/sagernet/sing-box/log" | ||
"github.com/sagernet/sing/common" | ||
E "github.com/sagernet/sing/common/exceptions" | ||
) | ||
|
||
var _ adapter.EndpointManager = (*Manager)(nil) | ||
|
||
type Manager struct { | ||
logger log.ContextLogger | ||
registry adapter.EndpointRegistry | ||
access sync.Mutex | ||
started bool | ||
stage adapter.StartStage | ||
endpoints []adapter.Endpoint | ||
endpointByTag map[string]adapter.Endpoint | ||
} | ||
|
||
func NewManager(logger log.ContextLogger, registry adapter.EndpointRegistry) *Manager { | ||
return &Manager{ | ||
logger: logger, | ||
registry: registry, | ||
endpointByTag: make(map[string]adapter.Endpoint), | ||
} | ||
} | ||
|
||
func (m *Manager) Start(stage adapter.StartStage) error { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
if m.started && m.stage >= stage { | ||
panic("already started") | ||
} | ||
m.started = true | ||
m.stage = stage | ||
if stage == adapter.StartStateStart { | ||
// started with outbound manager | ||
return nil | ||
} | ||
for _, endpoint := range m.endpoints { | ||
err := adapter.LegacyStart(endpoint, stage) | ||
if err != nil { | ||
return E.Cause(err, stage, " endpoint/", endpoint.Type(), "[", endpoint.Tag(), "]") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (m *Manager) Close() error { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
if !m.started { | ||
return nil | ||
} | ||
m.started = false | ||
endpoints := m.endpoints | ||
m.endpoints = nil | ||
monitor := taskmonitor.New(m.logger, C.StopTimeout) | ||
var err error | ||
for _, endpoint := range endpoints { | ||
monitor.Start("close endpoint/", endpoint.Type(), "[", endpoint.Tag(), "]") | ||
err = E.Append(err, endpoint.Close(), func(err error) error { | ||
return E.Cause(err, "close endpoint/", endpoint.Type(), "[", endpoint.Tag(), "]") | ||
}) | ||
monitor.Finish() | ||
} | ||
return nil | ||
} | ||
|
||
func (m *Manager) Endpoints() []adapter.Endpoint { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
return m.endpoints | ||
} | ||
|
||
func (m *Manager) Get(tag string) (adapter.Endpoint, bool) { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
endpoint, found := m.endpointByTag[tag] | ||
return endpoint, found | ||
} | ||
|
||
func (m *Manager) Remove(tag string) error { | ||
m.access.Lock() | ||
endpoint, found := m.endpointByTag[tag] | ||
if !found { | ||
m.access.Unlock() | ||
return os.ErrInvalid | ||
} | ||
delete(m.endpointByTag, tag) | ||
index := common.Index(m.endpoints, func(it adapter.Endpoint) bool { | ||
return it == endpoint | ||
}) | ||
if index == -1 { | ||
panic("invalid endpoint index") | ||
} | ||
m.endpoints = append(m.endpoints[:index], m.endpoints[index+1:]...) | ||
started := m.started | ||
m.access.Unlock() | ||
if started { | ||
return endpoint.Close() | ||
} | ||
return nil | ||
} | ||
|
||
func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, outboundType string, options any) error { | ||
endpoint, err := m.registry.Create(ctx, router, logger, tag, outboundType, options) | ||
if err != nil { | ||
return err | ||
} | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
if m.started { | ||
for _, stage := range adapter.ListStartStages { | ||
err = adapter.LegacyStart(endpoint, stage) | ||
if err != nil { | ||
return E.Cause(err, stage, " endpoint/", endpoint.Type(), "[", endpoint.Tag(), "]") | ||
} | ||
} | ||
} | ||
if existsEndpoint, loaded := m.endpointByTag[tag]; loaded { | ||
if m.started { | ||
err = existsEndpoint.Close() | ||
if err != nil { | ||
return E.Cause(err, "close endpoint/", existsEndpoint.Type(), "[", existsEndpoint.Tag(), "]") | ||
} | ||
} | ||
existsIndex := common.Index(m.endpoints, func(it adapter.Endpoint) bool { | ||
return it == existsEndpoint | ||
}) | ||
if existsIndex == -1 { | ||
panic("invalid endpoint index") | ||
} | ||
m.endpoints = append(m.endpoints[:existsIndex], m.endpoints[existsIndex+1:]...) | ||
} | ||
m.endpoints = append(m.endpoints, endpoint) | ||
m.endpointByTag[tag] = endpoint | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package endpoint | ||
|
||
import ( | ||
"context" | ||
"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" | ||
) | ||
|
||
type ConstructorFunc[T any] func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options T) (adapter.Endpoint, error) | ||
|
||
func Register[Options any](registry *Registry, outboundType string, constructor ConstructorFunc[Options]) { | ||
registry.register(outboundType, func() any { | ||
return new(Options) | ||
}, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, rawOptions any) (adapter.Endpoint, error) { | ||
var options *Options | ||
if rawOptions != nil { | ||
options = rawOptions.(*Options) | ||
} | ||
return constructor(ctx, router, logger, tag, common.PtrValueOrDefault(options)) | ||
}) | ||
} | ||
|
||
var _ adapter.EndpointRegistry = (*Registry)(nil) | ||
|
||
type ( | ||
optionsConstructorFunc func() any | ||
constructorFunc func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options any) (adapter.Endpoint, error) | ||
) | ||
|
||
type Registry struct { | ||
access sync.Mutex | ||
optionsType map[string]optionsConstructorFunc | ||
constructor map[string]constructorFunc | ||
} | ||
|
||
func NewRegistry() *Registry { | ||
return &Registry{ | ||
optionsType: make(map[string]optionsConstructorFunc), | ||
constructor: make(map[string]constructorFunc), | ||
} | ||
} | ||
|
||
func (m *Registry) CreateOptions(outboundType string) (any, bool) { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
optionsConstructor, loaded := m.optionsType[outboundType] | ||
if !loaded { | ||
return nil, false | ||
} | ||
return optionsConstructor(), true | ||
} | ||
|
||
func (m *Registry) Create(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, outboundType string, options any) (adapter.Endpoint, error) { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
constructor, loaded := m.constructor[outboundType] | ||
if !loaded { | ||
return nil, E.New("outbound type not found: " + outboundType) | ||
} | ||
return constructor(ctx, router, logger, tag, options) | ||
} | ||
|
||
func (m *Registry) register(outboundType string, optionsConstructor optionsConstructorFunc, constructor constructorFunc) { | ||
m.access.Lock() | ||
defer m.access.Unlock() | ||
m.optionsType[outboundType] = optionsConstructor | ||
m.constructor[outboundType] = constructor | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ import ( | |
) | ||
|
||
type Inbound interface { | ||
Service | ||
Lifecycle | ||
Type() string | ||
Tag() string | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.