Improve pause management

This commit is contained in:
世界 2025-04-06 16:35:18 +08:00
parent 24af0766ac
commit 97d41ffde8
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
8 changed files with 60 additions and 67 deletions

View File

@ -40,7 +40,7 @@ type BoxService struct {
clashServer adapter.ClashServer
pauseManager pause.Manager
servicePauseFields
iOSPauseFields
}
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {

View File

@ -1,31 +1,33 @@
package libbox
import (
"sync"
"time"
C "github.com/sagernet/sing-box/constant"
)
type servicePauseFields struct {
pauseAccess sync.Mutex
pauseTimer *time.Timer
type iOSPauseFields struct {
endPauseTimer *time.Timer
}
func (s *BoxService) Pause() {
s.pauseAccess.Lock()
defer s.pauseAccess.Unlock()
if s.pauseTimer != nil {
s.pauseTimer.Stop()
s.pauseManager.DevicePause()
if !C.IsIos {
s.instance.Router().ResetNetwork()
} else {
if s.endPauseTimer == nil {
s.endPauseTimer = time.AfterFunc(time.Minute, s.pauseManager.DeviceWake)
} else {
s.endPauseTimer.Reset(time.Minute)
}
}
s.pauseTimer = time.AfterFunc(3*time.Second, s.ResetNetwork)
}
func (s *BoxService) Wake() {
s.pauseAccess.Lock()
defer s.pauseAccess.Unlock()
if s.pauseTimer != nil {
s.pauseTimer.Stop()
if !C.IsIos {
s.pauseManager.DeviceWake()
s.instance.Router().ResetNetwork()
}
s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork)
}
func (s *BoxService) ResetNetwork() {

View File

@ -19,6 +19,7 @@ import (
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/x/list"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/pause"
)
@ -27,10 +28,7 @@ func RegisterURLTest(registry *outbound.Registry) {
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
}
var (
_ adapter.OutboundGroup = (*URLTest)(nil)
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
)
var _ adapter.OutboundGroup = (*URLTest)(nil)
type URLTest struct {
outbound.Adapter
@ -172,15 +170,12 @@ func (s *URLTest) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
}
func (s *URLTest) InterfaceUpdated() {
go s.group.CheckOutbounds(true)
return
}
type URLTestGroup struct {
ctx context.Context
router adapter.Router
outboundManager adapter.OutboundManager
outbound adapter.OutboundManager
pause pause.Manager
pauseCallback *list.Element[pause.Callback]
logger log.Logger
outbounds []adapter.Outbound
link string
@ -189,17 +184,15 @@ type URLTestGroup struct {
idleTimeout time.Duration
history *urltest.HistoryStorage
checking atomic.Bool
pauseManager pause.Manager
selectedOutboundTCP adapter.Outbound
selectedOutboundUDP adapter.Outbound
interruptGroup *interrupt.Group
interruptExternalConnections bool
access sync.Mutex
ticker *time.Ticker
close chan struct{}
started bool
lastActive atomic.TypedValue[time.Time]
access sync.Mutex
ticker *time.Ticker
close chan struct{}
started bool
lastActive atomic.TypedValue[time.Time]
}
func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManager, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16, idleTimeout time.Duration, interruptExternalConnections bool) (*URLTestGroup, error) {
@ -224,7 +217,7 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
}
return &URLTestGroup{
ctx: ctx,
outboundManager: outboundManager,
outbound: outboundManager,
logger: logger,
outbounds: outbounds,
link: link,
@ -233,13 +226,15 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
idleTimeout: idleTimeout,
history: history,
close: make(chan struct{}),
pauseManager: service.FromContext[pause.Manager](ctx),
pause: service.FromContext[pause.Manager](ctx),
interruptGroup: interrupt.NewGroup(),
interruptExternalConnections: interruptExternalConnections,
}, nil
}
func (g *URLTestGroup) PostStart() {
g.access.Lock()
defer g.access.Unlock()
g.started = true
g.lastActive.Store(time.Now())
go g.CheckOutbounds(false)
@ -249,24 +244,25 @@ func (g *URLTestGroup) Touch() {
if !g.started {
return
}
g.access.Lock()
defer g.access.Unlock()
if g.ticker != nil {
g.lastActive.Store(time.Now())
return
}
g.access.Lock()
defer g.access.Unlock()
if g.ticker != nil {
return
}
g.ticker = time.NewTicker(g.interval)
go g.loopCheck()
g.pauseCallback = pause.RegisterTicker(g.pause, g.ticker, g.interval, nil)
}
func (g *URLTestGroup) Close() error {
g.access.Lock()
defer g.access.Unlock()
if g.ticker == nil {
return nil
}
g.ticker.Stop()
g.pause.UnregisterCallback(g.pauseCallback)
close(g.close)
return nil
}
@ -330,10 +326,11 @@ func (g *URLTestGroup) loopCheck() {
g.access.Lock()
g.ticker.Stop()
g.ticker = nil
g.pause.UnregisterCallback(g.pauseCallback)
g.pauseCallback = nil
g.access.Unlock()
return
}
g.pauseManager.WaitActive()
g.CheckOutbounds(false)
}
}
@ -366,7 +363,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
continue
}
checked[realTag] = true
p, loaded := g.outboundManager.Outbound(realTag)
p, loaded := g.outbound.Outbound(realTag)
if !loaded {
continue
}

View File

@ -120,7 +120,6 @@ func (w *Endpoint) Close() error {
func (w *Endpoint) InterfaceUpdated() {
w.endpoint.BindUpdate()
return
}
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {

View File

@ -126,7 +126,6 @@ func (o *Outbound) Close() error {
func (o *Outbound) InterfaceUpdated() {
o.endpoint.BindUpdate()
return
}
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {

View File

@ -60,10 +60,6 @@ func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata
}
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
if r.pauseManager.IsDevicePaused() {
return E.New("reject connection to ", metadata.Destination, " while device paused")
}
//nolint:staticcheck
if metadata.InboundDetour != "" {
if metadata.LastInbound == metadata.InboundDetour {
@ -186,9 +182,6 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn,
}
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
if r.pauseManager.IsDevicePaused() {
return E.New("reject packet connection to ", metadata.Destination, " while device paused")
}
//nolint:staticcheck
if metadata.InboundDetour != "" {
if metadata.LastInbound == metadata.InboundDetour {

View File

@ -103,7 +103,7 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
}
}
if s.lastUpdated.IsZero() {
err := s.fetchOnce(ctx, startContext)
err := s.fetch(ctx, startContext)
if err != nil {
return E.Cause(err, "initial rule-set: ", s.options.Tag)
}
@ -198,7 +198,7 @@ func (s *RemoteRuleSet) loadBytes(content []byte) error {
func (s *RemoteRuleSet) loopUpdate() {
if time.Since(s.lastUpdated) > s.updateInterval {
err := s.fetchOnce(s.ctx, nil)
err := s.fetch(s.ctx, nil)
if err != nil {
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
} else if s.refs.Load() == 0 {
@ -211,18 +211,21 @@ func (s *RemoteRuleSet) loopUpdate() {
case <-s.ctx.Done():
return
case <-s.updateTicker.C:
s.pauseManager.WaitActive()
err := s.fetchOnce(s.ctx, nil)
if err != nil {
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
} else if s.refs.Load() == 0 {
s.rules = nil
}
s.updateOnce()
}
}
}
func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTTPStartContext) error {
func (s *RemoteRuleSet) updateOnce() {
err := s.fetch(s.ctx, nil)
if err != nil {
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
} else if s.refs.Load() == 0 {
s.rules = nil
}
}
func (s *RemoteRuleSet) fetch(ctx context.Context, startContext *adapter.HTTPStartContext) error {
s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL)
var httpClient *http.Client
if startContext != nil {

View File

@ -30,7 +30,7 @@ type Endpoint struct {
allowedAddress []netip.Prefix
tunDevice Device
device *device.Device
pauseManager pause.Manager
pause pause.Manager
pauseCallback *list.Element[pause.Callback]
}
@ -187,9 +187,9 @@ func (e *Endpoint) Start(resolve bool) error {
return E.Cause(err, "setup wireguard: \n", ipcConf)
}
e.device = wgDevice
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
if e.pauseManager != nil {
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
e.pause = service.FromContext[pause.Manager](e.options.Context)
if e.pause != nil {
e.pauseCallback = e.pause.RegisterCallback(e.onPauseUpdated)
}
return nil
}
@ -217,16 +217,16 @@ func (e *Endpoint) Close() error {
e.device.Close()
}
if e.pauseCallback != nil {
e.pauseManager.UnregisterCallback(e.pauseCallback)
e.pause.UnregisterCallback(e.pauseCallback)
}
return nil
}
func (e *Endpoint) onPauseUpdated(event int) {
switch event {
case pause.EventDevicePaused:
case pause.EventDevicePaused, pause.EventNetworkPause:
e.device.Down()
case pause.EventDeviceWake:
case pause.EventDeviceWake, pause.EventNetworkWake:
e.device.Up()
}
}