Fix start lifecycle

This commit is contained in:
世界
2026-07-15 20:50:36 +08:00
parent e34b57c3b0
commit 2392b176e2
18 changed files with 259 additions and 144 deletions
+17 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"net/http"
"os"
"runtime/debug"
"time"
@@ -43,6 +44,8 @@ var _ adapter.SimpleLifecycle = (*Box)(nil)
type Box struct {
createdAt time.Time
debugOptions option.DebugOptions
debugHTTPServer *http.Server
logFactory log.Factory
logger log.ContextLogger
network *route.NetworkManager
@@ -142,7 +145,8 @@ func New(options Options) (*Box, error) {
ctx = pause.WithDefaultManager(ctx)
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
err := applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
debugOptions := common.PtrValueOrDefault(experimentalOptions.Debug)
err := checkDebugOptions(debugOptions)
if err != nil {
return nil, err
}
@@ -470,6 +474,7 @@ func New(options Options) (*Box, error) {
router: router,
httpClientService: httpClientService,
createdAt: createdAt,
debugOptions: debugOptions,
logFactory: logFactory,
logger: logFactory.Logger(),
internalService: internalServices,
@@ -523,6 +528,11 @@ func (s *Box) preStart() error {
if err != nil {
return E.Cause(err, "start logger")
}
applyDebugOptions(s.debugOptions)
s.debugHTTPServer, err = startDebugHTTPServer(s.debugOptions)
if err != nil {
return err
}
err = adapter.StartNamed(s.logger, adapter.StartStateInitialize, s.internalService) // cache-file clash-api v2ray-api
if err != nil {
return err
@@ -594,6 +604,12 @@ func (s *Box) Close() error {
close(s.done)
}
var err error
if s.debugHTTPServer != nil {
err = E.Append(err, s.debugHTTPServer.Close(), func(err error) error {
return E.Cause(err, "close debug HTTP server")
})
s.debugHTTPServer = nil
}
for _, closeItem := range []struct {
name string
service adapter.Lifecycle
@@ -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) {
+8 -6
View File
@@ -7,8 +7,14 @@ import (
E "github.com/sagernet/sing/common/exceptions"
)
func applyDebugOptions(options option.DebugOptions) error {
applyDebugListenOption(options)
func checkDebugOptions(options option.DebugOptions) error {
if options.OOMKiller != nil {
return E.New("legacy oom_killer in debug options is removed, use oom-killer service instead")
}
return nil
}
func applyDebugOptions(options option.DebugOptions) {
if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent)
}
@@ -27,8 +33,4 @@ func applyDebugOptions(options option.DebugOptions) error {
if options.MemoryLimit.Value() != 0 {
debug.SetMemoryLimit(int64(float64(options.MemoryLimit.Value()) / 1.5))
}
if options.OOMKiller != nil {
return E.New("legacy oom_killer in debug options is removed, use oom-killer service instead")
}
return nil
}
+10 -10
View File
@@ -1,6 +1,7 @@
package box
import (
"net"
"net/http"
"net/http/pprof"
"runtime"
@@ -17,15 +18,9 @@ import (
"github.com/go-chi/chi/v5"
)
var debugHTTPServer *http.Server
func applyDebugListenOption(options option.DebugOptions) {
if debugHTTPServer != nil {
debugHTTPServer.Close()
debugHTTPServer = nil
}
func startDebugHTTPServer(options option.DebugOptions) (*http.Server, error) {
if options.Listen == "" {
return
return nil, nil
}
r := chi.NewMux()
r.Route("/debug", func(r chi.Router) {
@@ -63,14 +58,19 @@ func applyDebugListenOption(options option.DebugOptions) {
r.HandleFunc("/trace", pprof.Trace)
})
})
debugHTTPServer = &http.Server{
server := &http.Server{
Addr: options.Listen,
Handler: r,
}
listener, err := net.Listen("tcp", options.Listen)
if err != nil {
return nil, E.Cause(err, "listen debug HTTP server")
}
go func() {
err := debugHTTPServer.ListenAndServe()
err := server.Serve(listener)
if err != nil && !E.IsClosed(err) {
log.Error(E.Cause(err, "serve debug HTTP server"))
}
}()
return server, nil
}
+2 -5
View File
@@ -2,6 +2,7 @@ package main
import (
"context"
"slices"
"github.com/sagernet/sing-box/experimental/locale"
@@ -14,11 +15,7 @@ func setLocaleFromContext(ctx context.Context) {
if !loaded {
return
}
for _, localeID := range requestMetadata.Get("accept-language") {
if locale.Set(localeID) {
return
}
}
slices.ContainsFunc(requestMetadata.Get("accept-language"), locale.Set)
}
func unaryLocaleInterceptor(ctx context.Context, request any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
+2 -2
View File
@@ -5,7 +5,7 @@ func init() {
Locale: "fa",
DeprecatedMessage: "%s از sing-box %s منسوخ شده است و در sing-box %s حذف خواهد شد؛ لطفاً راهنمای مهاجرت را ببینید.",
DeprecatedMessageNoLink: "%s از sing-box %s منسوخ شده است و در sing-box %s حذف خواهد شد.",
InsecureFeatureMessage: "%s در کلاینت گرافیکی sing-box برای Windows ناامن تلقی میشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
ExternalPathFeature: "دسترسی به %s (خارج از پوشهٔ کاری) در کلاینت گرافیکی sing-box برای Windows ناامن تلقی میشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
InsecureFeatureMessage: "%s در کلاینت گرافیکی sing-box برای Windows ناامن تلقی می\u200cشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
ExternalPathFeature: "دسترسی به %s (خارج از پوشهٔ کاری) در کلاینت گرافیکی sing-box برای Windows ناامن تلقی می\u200cشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
}
}
+3 -3
View File
@@ -56,9 +56,6 @@ func NewDefaultFactory(
/*if platformWriter != nil {
factory.platformFormatter.DisableColors = platformWriter.DisableColors()
}*/
if needObservable {
factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
}
return factory
}
@@ -71,6 +68,9 @@ func (f *defaultFactory) Start() error {
f.writer = logFile
f.file = logFile
}
if f.needObservable {
f.observer = observable.NewObserver[Entry](f.subscriber, 64)
}
return nil
}
+24 -14
View File
@@ -27,17 +27,20 @@ func RegisterOutbound(registry *outbound.Registry) {
type Outbound struct {
outbound.Adapter
dialer tls.Dialer
server M.Socksaddr
tlsConfig tls.Config
client *anytls.Client
uotClient *uot.Client
logger log.ContextLogger
ctx context.Context
dialer tls.Dialer
server M.Socksaddr
tlsConfig tls.Config
clientOptions anytls.ClientConfig
client *anytls.Client
uotClient *uot.Client
logger log.ContextLogger
}
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSOutboundOptions) (adapter.Outbound, error) {
outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeAnyTLS, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
ctx: ctx,
server: options.ServerOptions.Build(),
logger: logger,
}
@@ -69,24 +72,31 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
outbound.dialer = tls.NewDialer(outboundDialer, tlsConfig)
client, err := anytls.NewClient(ctx, anytls.ClientConfig{
outbound.clientOptions = anytls.ClientConfig{
Password: options.Password,
IdleSessionCheckInterval: options.IdleSessionCheckInterval.Build(),
IdleSessionTimeout: options.IdleSessionTimeout.Build(),
MinIdleSession: options.MinIdleSession,
DialOut: outbound.dialOut,
Logger: logger,
})
if err != nil {
return nil, err
}
outbound.client = client
return outbound, nil
}
outbound.uotClient = &uot.Client{
func (h *Outbound) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateInitialize {
return nil
}
client, err := anytls.NewClient(h.ctx, h.clientOptions)
if err != nil {
return err
}
h.client = client
h.uotClient = &uot.Client{
Dialer: (anytlsDialer)(client.CreateProxy),
Version: uot.Version,
}
return outbound, nil
return nil
}
type anytlsDialer func(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
@@ -127,5 +137,5 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
func (h *Outbound) Close() error {
return common.Close(h.client)
return common.Close(common.PtrOrNil(h.client))
}
+4 -4
View File
@@ -151,10 +151,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
}
stateDirectory = filemanager.BasePath(ctx, os.ExpandEnv(stateDirectory))
stateDirectory, _ = filepath.Abs(stateDirectory)
mkdirErr := filemanager.MkdirAll(ctx, stateDirectory, 0o700)
if mkdirErr != nil {
return nil, E.Cause(mkdirErr, "create state directory")
}
if options.SSHServer != nil && options.SSHServer.Enabled {
err := adapter.CheckSecurityFeature(ctx, "Tailscale `ssh_server`")
if err != nil {
@@ -259,6 +255,10 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
func (t *Endpoint) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStateInitialize:
mkdirErr := filemanager.MkdirAll(t.ctx, t.server.Dir, 0o700)
if mkdirErr != nil {
return E.Cause(mkdirErr, "create state directory")
}
t.server.PeerDNSQueryHandler = (*peerDNSQueryHandler)(t)
case adapter.StartStateStart:
return t.start()
+41 -21
View File
@@ -35,6 +35,7 @@ type Outbound struct {
outbound.Adapter
ctx context.Context
logger logger.ContextLogger
dialer N.Dialer
proxy *proxybridge.Bridge
startConf *tor.StartConf
options map[string]string
@@ -51,10 +52,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
}
startConf.TempDataDirBase = filemanager.TempPath(ctx)
if startConf.DataDir != "" {
err := filemanager.MkdirAll(ctx, startConf.DataDir, 0o755)
if err != nil {
return nil, err
}
dataDirAbs, _ := filepath.Abs(startConf.DataDir)
geoIPPath := filepath.Join(dataDirAbs, "geoip")
geoIPInfo, err := filemanager.Stat(ctx, geoIPPath)
@@ -68,14 +65,9 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
}
torrcFile := filepath.Join(startConf.DataDir, "torrc")
torrcInfo, err := filemanager.Stat(ctx, torrcFile)
if os.IsNotExist(err) {
err = filemanager.WriteFile(ctx, torrcFile, []byte(""), 0o600)
if err != nil {
return nil, err
}
} else if err != nil {
if err != nil && !os.IsNotExist(err) {
return nil, err
} else if torrcInfo.IsDir() {
} else if err == nil && torrcInfo.IsDir() {
return nil, E.New("Tor configuration path is a directory: ", torrcFile)
}
startConf.TorrcFile = torrcFile
@@ -94,26 +86,54 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
if err != nil {
return nil, err
}
proxy, err := proxybridge.New(ctx, logger, "proxy", outboundDialer)
if err != nil {
return nil, err
}
return &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeTor, tag, []string{N.NetworkTCP}, options.DialerOptions),
ctx: ctx,
logger: logger,
proxy: proxy,
dialer: outboundDialer,
startConf: &startConf,
options: options.Options,
}, nil
}
func (t *Outbound) Start() error {
err := t.start()
if err != nil {
t.Close()
func (t *Outbound) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStateInitialize:
if t.startConf.DataDir == "" {
return nil
}
err := filemanager.MkdirAll(t.ctx, t.startConf.DataDir, 0o755)
if err != nil {
return err
}
torrcInfo, err := filemanager.Stat(t.ctx, t.startConf.TorrcFile)
if os.IsNotExist(err) {
err = filemanager.WriteFile(t.ctx, t.startConf.TorrcFile, []byte(""), 0o600)
if err != nil {
return err
}
} else if err != nil {
return err
} else if torrcInfo.IsDir() {
return E.New("Tor configuration path is a directory: ", t.startConf.TorrcFile)
}
case adapter.StartStateStart:
proxy, err := proxybridge.New(t.ctx, t.logger, "proxy", t.dialer)
if err != nil {
return err
}
t.proxy = proxy
err = proxy.Start()
if err != nil {
return err
}
err = t.start()
if err != nil {
t.Close()
return err
}
}
return err
return nil
}
var torLogEvents = []control.EventCode{
+1
View File
@@ -113,6 +113,7 @@ func (s *LocalRuleSet) reloadFile(path string) error {
if err != nil {
return err
}
defer setFile.Close()
ruleSet, err = srs.Read(setFile, false)
if err != nil {
return err
+40 -27
View File
@@ -48,11 +48,13 @@ var (
type Service struct {
certificate.Adapter
ctx context.Context
config *certmagic.Config
cache *certmagic.Cache
domain []string
nextProtos []string
ctx context.Context
config *certmagic.Config
cache *certmagic.Cache
zapLogger *zap.Logger
dataDirectory string
domain []string
nextProtos []string
}
func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag string, options option.ACMECertificateProviderOptions) (adapter.CertificateProviderService, error) {
@@ -78,13 +80,12 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
return nil, E.New("email is required to use the ZeroSSL ACME endpoint without external_account or account_key")
}
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, E.Cause(err, "create ACME data directory")
}
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
storage = &certmagic.FileStorage{Path: dataDirectory}
} else {
storage = certmagic.Default.Storage
@@ -169,33 +170,45 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
}
reflect.NewAt(httpClientField.Type(), unsafe.Pointer(httpClientField.UnsafeAddr())).Elem().Set(reflect.ValueOf(acmeHTTPClient))
config.Issuers = []certmagic.Issuer{certmagicIssuer}
cache := certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
return config, nil
},
Logger: zapLogger,
})
config = certmagic.New(cache, *config)
var nextProtos []string
if !acmeIssuer.DisableTLSALPNChallenge && acmeIssuer.DNS01Solver == nil {
nextProtos = []string{C.ACMETLS1Protocol}
}
return &Service{
Adapter: certificate.NewAdapter(C.TypeACME, tag),
ctx: ctx,
config: config,
cache: cache,
domain: options.Domain,
nextProtos: nextProtos,
Adapter: certificate.NewAdapter(C.TypeACME, tag),
ctx: ctx,
config: config,
zapLogger: zapLogger,
dataDirectory: dataDirectory,
domain: options.Domain,
nextProtos: nextProtos,
}, nil
}
func (s *Service) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
return nil
switch stage {
case adapter.StartStateInitialize:
if s.dataDirectory != "" {
err := filemanager.MkdirAll(s.ctx, s.dataDirectory, 0o700)
if err != nil {
return E.Cause(err, "create ACME data directory")
}
}
config := s.config
cache := certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
return config, nil
},
Logger: s.zapLogger,
})
config = certmagic.New(cache, *config)
s.config = config
s.cache = cache
case adapter.StartStateStart:
return s.config.ManageAsync(s.ctx, s.domain)
}
return s.config.ManageAsync(s.ctx, s.domain)
return nil
}
func (s *Service) Close() error {
+17 -8
View File
@@ -65,6 +65,7 @@ type Service struct {
timeFunc func() time.Time
httpClient *http.Client
storage certmagic.Storage
dataDirectory string
storageIssuerKey string
storageNamesKey string
storageLockKey string
@@ -109,14 +110,12 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
cancel()
return nil, err
}
var storage certmagic.Storage
var (
storage certmagic.Storage
dataDirectory string
)
if options.DataDirectory != "" {
dataDirectory := filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
mkdirErr := filemanager.MkdirAll(ctx, dataDirectory, 0o700)
if mkdirErr != nil {
cancel()
return nil, E.Cause(mkdirErr, "create data directory")
}
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
storage = &certmagic.FileStorage{Path: dataDirectory}
} else {
storage = certmagic.Default.Storage
@@ -140,6 +139,7 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
timeFunc: timeFunc,
httpClient: httpClient,
storage: storage,
dataDirectory: dataDirectory,
storageIssuerKey: storageIssuerKey,
storageNamesKey: storageNamesKey,
storageLockKey: storageLockKey,
@@ -162,7 +162,16 @@ func originCAHTTPClient(ctx context.Context, logger log.ContextLogger, options o
}
func (s *Service) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
if stage == adapter.StartStateInitialize {
if s.dataDirectory == "" {
return nil
}
err := filemanager.MkdirAll(s.ctx, s.dataDirectory, 0o700)
if err != nil {
return E.Cause(err, "create data directory")
}
return nil
} else if stage != adapter.StartStateStart {
return nil
}
cachedCertificate, cachedLeaf, err := s.loadCachedCertificate()