platform: Add sleep support for NetworkExtension

This commit is contained in:
世界 2023-08-01 16:40:11 +08:00
parent 8d629ef323
commit 1983f54907
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
3 changed files with 87 additions and 24 deletions

43
common/sleep/manager.go Normal file
View file

@ -0,0 +1,43 @@
package sleep
import (
"sync"
)
type Manager struct {
access sync.Mutex
done chan struct{}
}
func NewManager() *Manager {
closedChan := make(chan struct{})
close(closedChan)
return &Manager{
done: closedChan,
}
}
func (m *Manager) Sleep() {
m.access.Lock()
defer m.access.Unlock()
select {
case <-m.done:
default:
return
}
m.done = make(chan struct{})
}
func (m *Manager) Wake() {
m.access.Lock()
defer m.access.Unlock()
select {
case <-m.done:
default:
close(m.done)
}
}
func (m *Manager) Active() <-chan struct{} {
return m.done
}

View file

@ -8,6 +8,7 @@ import (
"github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/common/sleep"
"github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing-box/common/urltest"
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs" "github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
"github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/experimental/libbox/platform"
@ -22,9 +23,10 @@ import (
) )
type BoxService struct { type BoxService struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
instance *box.Box instance *box.Box
sleepManager *sleep.Manager
} }
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) { func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
@ -35,6 +37,8 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID) ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
ctx = service.ContextWithPtr(ctx, urltest.NewHistoryStorage()) ctx = service.ContextWithPtr(ctx, urltest.NewHistoryStorage())
sleepManager := sleep.NewManager()
ctx = service.ContextWithPtr(ctx, sleepManager)
instance, err := box.New(box.Options{ instance, err := box.New(box.Options{
Context: ctx, Context: ctx,
Options: options, Options: options,
@ -45,9 +49,10 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
return nil, E.Cause(err, "create service") return nil, E.Cause(err, "create service")
} }
return &BoxService{ return &BoxService{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
instance: instance, instance: instance,
sleepManager: sleepManager,
}, nil }, nil
} }
@ -60,6 +65,15 @@ func (s *BoxService) Close() error {
return s.instance.Close() return s.instance.Close()
} }
func (s *BoxService) Sleep() {
s.sleepManager.Sleep()
_ = s.instance.Router().ResetNetwork()
}
func (s *BoxService) Wake() {
s.sleepManager.Wake()
}
var _ platform.Interface = (*platformInterfaceWrapper)(nil) var _ platform.Interface = (*platformInterfaceWrapper)(nil)
type platformInterfaceWrapper struct { type platformInterfaceWrapper struct {

View file

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/sleep"
"github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing-box/common/urltest"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
@ -143,15 +144,16 @@ func (s *URLTest) InterfaceUpdated() error {
} }
type URLTestGroup struct { type URLTestGroup struct {
ctx context.Context ctx context.Context
router adapter.Router router adapter.Router
logger log.Logger logger log.Logger
outbounds []adapter.Outbound outbounds []adapter.Outbound
link string link string
interval time.Duration interval time.Duration
tolerance uint16 tolerance uint16
history *urltest.HistoryStorage history *urltest.HistoryStorage
checking atomic.Bool checking atomic.Bool
sleepManager *sleep.Manager
access sync.Mutex access sync.Mutex
ticker *time.Ticker ticker *time.Ticker
@ -173,15 +175,16 @@ func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logg
history = urltest.NewHistoryStorage() history = urltest.NewHistoryStorage()
} }
return &URLTestGroup{ return &URLTestGroup{
ctx: ctx, ctx: ctx,
router: router, router: router,
logger: logger, logger: logger,
outbounds: outbounds, outbounds: outbounds,
link: link, link: link,
interval: interval, interval: interval,
tolerance: tolerance, tolerance: tolerance,
history: history, history: history,
close: make(chan struct{}), close: make(chan struct{}),
sleepManager: service.PtrFromContext[sleep.Manager](ctx),
} }
} }
@ -263,6 +266,9 @@ func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
func (g *URLTestGroup) loopCheck() { func (g *URLTestGroup) loopCheck() {
go g.CheckOutbounds(true) go g.CheckOutbounds(true)
for { for {
if g.sleepManager != nil {
<-g.sleepManager.Active()
}
select { select {
case <-g.close: case <-g.close:
return return