diff --git a/service/pause/default.go b/service/pause/default.go index beb7e0f..0b5d85f 100644 --- a/service/pause/default.go +++ b/service/pause/default.go @@ -3,13 +3,19 @@ package pause import ( "context" "sync" + + "github.com/sagernet/sing/common/atomic" + "github.com/sagernet/sing/common/x/list" ) type defaultManager struct { - ctx context.Context - access sync.Mutex - devicePause chan struct{} - networkPause chan struct{} + ctx context.Context + access sync.Mutex + devicePause chan struct{} + devicePaused atomic.Bool + networkPause chan struct{} + networkPaused atomic.Bool + callbacks list.List[Callback] } func NewDefaultManager(ctx context.Context) Manager { @@ -29,7 +35,9 @@ func (d *defaultManager) DevicePause() { defer d.access.Unlock() select { case <-d.devicePause: + d.devicePaused.Store(true) d.devicePause = make(chan struct{}) + d.emit(EventDevicePaused) default: } } @@ -40,20 +48,20 @@ func (d *defaultManager) DeviceWake() { select { case <-d.devicePause: default: + d.devicePaused.Store(false) close(d.devicePause) + d.emit(EventDeviceWake) } } -func (d *defaultManager) DevicePauseChan() <-chan struct{} { - return d.devicePause -} - func (d *defaultManager) NetworkPause() { d.access.Lock() defer d.access.Unlock() select { case <-d.networkPause: + d.networkPaused.Store(true) d.networkPause = make(chan struct{}) + d.emit(EventNetworkPause) default: } } @@ -64,12 +72,30 @@ func (d *defaultManager) NetworkWake() { select { case <-d.networkPause: default: + d.networkPaused.Store(false) close(d.networkPause) + d.emit(EventNetworkWake) } } -func (d *defaultManager) NetworkPauseChan() <-chan struct{} { - return d.networkPause +func (d *defaultManager) RegisterCallback(callback Callback) *list.Element[Callback] { + d.access.Lock() + defer d.access.Unlock() + return d.callbacks.PushBack(callback) +} + +func (d *defaultManager) UnregisterCallback(element *list.Element[Callback]) { + d.access.Lock() + defer d.access.Unlock() + d.callbacks.Remove(element) +} + +func (d *defaultManager) IsDevicePaused() bool { + return d.devicePaused.Load() +} + +func (d *defaultManager) IsNetworkPaused() bool { + return d.networkPaused.Load() } func (d *defaultManager) IsPaused() bool { @@ -99,3 +125,9 @@ func (d *defaultManager) WaitActive() { case <-d.ctx.Done(): } } + +func (d *defaultManager) emit(event int) { + for element := d.callbacks.Front(); element != nil; element = element.Next() { + element.Value(event) + } +} diff --git a/service/pause/manager.go b/service/pause/manager.go index 9f7df65..6f5058e 100644 --- a/service/pause/manager.go +++ b/service/pause/manager.go @@ -1,12 +1,25 @@ package pause +import "github.com/sagernet/sing/common/x/list" + type Manager interface { DevicePause() DeviceWake() - DevicePauseChan() <-chan struct{} NetworkPause() NetworkWake() - NetworkPauseChan() <-chan struct{} + IsDevicePaused() bool + IsNetworkPaused() bool IsPaused() bool WaitActive() + RegisterCallback(callback Callback) *list.Element[Callback] + UnregisterCallback(element *list.Element[Callback]) } + +const ( + EventDevicePaused int = iota + EventDeviceWake + EventNetworkPause + EventNetworkWake +) + +type Callback = func(event int)