Fix start lifecycle

This commit is contained in:
世界
2026-08-30 17:41:43 +08:00
parent 0a4e4c8061
commit b9572e5812
17 changed files with 254 additions and 140 deletions
@@ -96,6 +96,15 @@ type appleTransport struct {
closed bool
}
func validateAppleTransport(ctx context.Context, options option.HTTPClientOptions) error {
sessionConfig, err := newAppleSessionConfig(ctx, options)
if err != nil {
return err
}
sessionConfig.close()
return nil
}
func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDialer N.Dialer, options option.HTTPClientOptions) (innerTransport, error) {
sessionConfig, err := newAppleSessionConfig(ctx, options)
if err != nil {
@@ -111,6 +120,10 @@ func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDial
if err != nil {
return nil, err
}
err = bridge.Start()
if err != nil {
return nil, err
}
shared := &appleTransportShared{
logger: logger,
bridge: bridge,
@@ -11,6 +11,10 @@ import (
N "github.com/sagernet/sing/common/network"
)
func validateAppleTransport(ctx context.Context, options option.HTTPClientOptions) error {
return E.New("Apple HTTP engine is not available on non-Apple platforms")
}
func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDialer N.Dialer, options option.HTTPClientOptions) (innerTransport, error) {
return nil, E.New("Apple HTTP engine is not available on non-Apple platforms")
}
+5 -7
View File
@@ -35,11 +35,11 @@ func NewTransport(ctx context.Context, logger logger.ContextLogger, tag string,
var cheapRebuild bool
switch options.Engine {
case C.TLSEngineApple:
inner, transportErr := newAppleTransport(ctx, logger, rawDialer, options)
if transportErr != nil {
return nil, transportErr
err = validateAppleTransport(ctx, options)
if err != nil {
return nil, err
}
managedTransport := &ManagedTransport{
return &ManagedTransport{
dialer: rawDialer,
headers: headers,
host: host,
@@ -47,9 +47,7 @@ func NewTransport(ctx context.Context, logger logger.ContextLogger, tag string,
factory: func() (innerTransport, error) {
return newAppleTransport(ctx, logger, rawDialer, options)
},
}
managedTransport.epoch.Store(&transportEpoch{transport: inner})
return managedTransport, nil
}, nil
case "", C.TLSEngineGo:
cheapRebuild = true
default:
+12 -9
View File
@@ -34,23 +34,26 @@ type Bridge struct {
func New(ctx context.Context, logger logger.ContextLogger, tag string, dialer N.Dialer) (*Bridge, error) {
username := randomHex(16)
password := randomHex(16)
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)})
if err != nil {
return nil, err
}
bridge := &Bridge{
return &Bridge{
ctx: ctx,
logger: logger,
tag: tag,
dialer: dialer,
connection: service.FromContext[adapter.ConnectionManager](ctx),
tcpListener: tcpListener,
username: username,
password: password,
authenticator: auth.NewAuthenticator([]auth.User{{Username: username, Password: password}}),
}, nil
}
func (b *Bridge) Start() error {
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)})
if err != nil {
return err
}
go bridge.acceptLoop()
return bridge, nil
b.tcpListener = tcpListener
go b.acceptLoop()
return nil
}
func randomHex(size int) string {
@@ -72,7 +75,7 @@ func (b *Bridge) Password() string {
}
func (b *Bridge) Close() error {
return common.Close(b.tcpListener)
return common.Close(common.PtrOrNil(b.tcpListener))
}
func (b *Bridge) acceptLoop() {
+44 -21
View File
@@ -26,21 +26,45 @@ import (
)
type acmeWrapper struct {
ctx context.Context
cfg *certmagic.Config
cache *certmagic.Cache
domain []string
ctx context.Context
cfg *certmagic.Config
cache *certmagic.Cache
zapLogger *zap.Logger
dataDirectory string
domain []string
}
func (w *acmeWrapper) Start() error {
if w.dataDirectory != "" {
err := filemanager.MkdirAll(w.ctx, w.dataDirectory, 0o700)
if err != nil {
return E.Cause(err, "create ACME data directory")
}
}
config := w.cfg
cache := certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
return config, nil
},
Logger: w.zapLogger,
})
config = certmagic.New(cache, *config)
w.cfg = config
w.cache = cache
return w.cfg.ManageSync(w.ctx, w.domain)
}
func (w *acmeWrapper) Close() error {
w.cache.Stop()
if w.cache != nil {
w.cache.Stop()
}
return nil
}
func (w *acmeWrapper) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return w.cfg.GetCertificate(hello)
}
func startACME(ctx context.Context, logger logger.Logger, options option.InboundACMEOptions) (*tls.Config, adapter.SimpleLifecycle, error) {
var acmeServer string
switch options.Provider {
@@ -54,13 +78,12 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
}
acmeServer = options.Provider
}
var storage certmagic.Storage
var (
storage certmagic.Storage
dataDirectory string
)
if options.DataDirectory != "" {
dataDirectory := filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
err := filemanager.MkdirAll(ctx, dataDirectory, 0o700)
if err != nil {
return nil, nil, E.Cause(err, "create ACME data directory")
}
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
storage = &certmagic.FileStorage{
Path: dataDirectory,
}
@@ -126,23 +149,23 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
acmeConfig.ExternalAccount = (*acme.EAB)(options.ExternalAccount)
}
config.Issuers = []certmagic.Issuer{certmagic.NewACMEIssuer(config, acmeConfig)}
cache := certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
return config, nil
},
Logger: zapLogger,
})
config = certmagic.New(cache, *config)
wrapper := &acmeWrapper{
ctx: ctx,
cfg: config,
zapLogger: zapLogger,
dataDirectory: dataDirectory,
domain: options.Domain,
}
var tlsConfig *tls.Config
if acmeConfig.DisableTLSALPNChallenge || acmeConfig.DNS01Solver != nil {
tlsConfig = &tls.Config{
GetCertificate: config.GetCertificate,
GetCertificate: wrapper.GetCertificate,
}
} else {
tlsConfig = &tls.Config{
GetCertificate: config.GetCertificate,
GetCertificate: wrapper.GetCertificate,
NextProtos: []string{C.ACMETLS1Protocol},
}
}
return tlsConfig, &acmeWrapper{ctx: ctx, cfg: config, cache: cache, domain: options.Domain}, nil
return tlsConfig, wrapper, nil
}
+12 -6
View File
@@ -50,13 +50,10 @@ type Manager struct {
}
func NewManager(outbound adapter.OutboundManager) *Manager {
manager := &Manager{
return &Manager{
outbound: outbound,
eventSubscriber: observable.NewSubscriber[ConnectionEvent](256),
}
manager.eventObserver = observable.NewObserver(manager.eventSubscriber, 64)
manager.cleaner = cleanup.Add(manager.Clear)
return manager
}
func (m *Manager) Name() string {
@@ -64,12 +61,21 @@ func (m *Manager) Name() string {
}
func (m *Manager) Start(stage adapter.StartStage) error {
if stage == adapter.StartStateInitialize {
m.eventObserver = observable.NewObserver(m.eventSubscriber, 64)
m.cleaner = cleanup.Add(m.Clear)
}
return nil
}
func (m *Manager) Close() error {
m.cleaner.Close()
return m.eventObserver.Close()
if m.cleaner != nil {
m.cleaner.Close()
}
if m.eventObserver != nil {
return m.eventObserver.Close()
}
return nil
}
func (m *Manager) SubscribeEvents() (observable.Subscription[ConnectionEvent], <-chan struct{}, error) {