From 22f89370985125f456dc9487b3cd584890a20bf3 Mon Sep 17 00:00:00 2001 From: u Date: Mon, 27 Feb 2023 16:21:17 +0100 Subject: [PATCH 1/6] feat: netmanager Signed-off-by: u --- pkg/logutil/logger_native_darwin.go | 2 +- pkg/netmanager/connectivity.go | 117 ++++++++++++++++++++++++++++ pkg/netmanager/netmanager.go | 79 +++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 pkg/netmanager/connectivity.go create mode 100644 pkg/netmanager/netmanager.go diff --git a/pkg/logutil/logger_native_darwin.go b/pkg/logutil/logger_native_darwin.go index fdf90fe3..a84a29d2 100644 --- a/pkg/logutil/logger_native_darwin.go +++ b/pkg/logutil/logger_native_darwin.go @@ -49,7 +49,7 @@ func NativeLog(logLevel zapcore.Level, namespace string, message string) { level = C.INFO } - log := C.os_log_create(C.CString(namespace), C.CString("")) + log := C.os_log_create(C.CString(namespace), C.CString(namespace)) C.os_log_wrapper(level, log, C.CString(fmt.Sprintf("[%s] %s", logLevel.CapitalString(), message))) } diff --git a/pkg/netmanager/connectivity.go b/pkg/netmanager/connectivity.go new file mode 100644 index 00000000..d3e7a4c2 --- /dev/null +++ b/pkg/netmanager/connectivity.go @@ -0,0 +1,117 @@ +package netmanager + +import ( + "fmt" +) + +type ConnectivityState int +const ( + ConnectivityStateUnknown ConnectivityState = iota + ConnectivityStateOff + ConnectivityStateOn +) +func (cs ConnectivityState) ToString() string { + switch cs { + case ConnectivityStateUnknown: + return "unknown" + case ConnectivityStateOff: + return "off" + case ConnectivityStateOn: + return "on" + default: + return "error" + } +} + +type ConnectivityNetType int +const ( + ConnectivityNetUnknown ConnectivityNetType = iota + ConnectivityNetNone + ConnectivityNetWifi + ConnectivityNetEthernet + ConnectivityNetCellular +) +func (cnt ConnectivityNetType) ToString() string { + switch cnt { + case ConnectivityNetUnknown: + return "unknown" + case ConnectivityNetNone: + return "none" + case ConnectivityNetWifi: + return "wifi" + case ConnectivityNetEthernet: + return "ethernet" + case ConnectivityNetCellular: + return "cellular" + default: + return "error" + } +} + +type ConnectivityCellularType int +const ( + ConnectivityCellularUnknown ConnectivityCellularType = iota + ConnectivityCellularNone + ConnectivityCellular2G + ConnectivityCellular3G + ConnectivityCellular4G + ConnectivityCellular5G +) +func (cct ConnectivityCellularType) ToString() string { + switch cct { + case ConnectivityCellularUnknown: + return "unknown" + case ConnectivityCellularNone: + return "none" + case ConnectivityCellular2G: + return "2G" + case ConnectivityCellular3G: + return "3G" + case ConnectivityCellular4G: + return "4G" + case ConnectivityCellular5G: + return "5G" + default: + return "error" + } +} + +type ConnectivityInfo struct { + State ConnectivityState + Metering ConnectivityState + Bluetooth ConnectivityState + NetType ConnectivityNetType + CellularType ConnectivityCellularType +} + +func NewConnectivityInfo() *ConnectivityInfo { + return &ConnectivityInfo{ + State: ConnectivityState(ConnectivityStateUnknown), + Metering: ConnectivityState(ConnectivityStateUnknown), + Bluetooth: ConnectivityState(ConnectivityStateUnknown), + NetType: ConnectivityNetType(ConnectivityNetUnknown), + CellularType: ConnectivityCellularType(ConnectivityCellularUnknown), + } +} + +func (ci *ConnectivityInfo) GetState() ConnectivityState { return ci.State } +func (ci *ConnectivityInfo) GetMetering() ConnectivityState { return ci.Metering } +func (ci *ConnectivityInfo) GetBluetooth() ConnectivityState { return ci.Bluetooth } +func (ci *ConnectivityInfo) GetNetType() ConnectivityNetType { return ci.NetType } +func (ci *ConnectivityInfo) GetCellularType() ConnectivityCellularType { return ci.CellularType } + +func (ci *ConnectivityInfo) SetState(state ConnectivityState) { ci.State = state } +func (ci *ConnectivityInfo) SetMetering(metering ConnectivityState) { ci.Metering = metering } +func (ci *ConnectivityInfo) SetBluetooth(bluetooth ConnectivityState) { ci.Bluetooth = bluetooth } +func (ci *ConnectivityInfo) SetNetType(netType ConnectivityNetType) { ci.NetType = netType } +func (ci *ConnectivityInfo) SetCellularType(cellularType ConnectivityCellularType) { ci.CellularType = cellularType } + +func (ci *ConnectivityInfo) ToString() string { + return fmt.Sprint("ConnectivityInfo{ ", + "State: ", ci.State.ToString(), ", ", + "Metering: ", ci.Metering.ToString(), ", ", + "Bluetooth: ", ci.Bluetooth.ToString(), ", ", + "NetType: ", ci.NetType.ToString(), ", ", + "CellularType: ", ci.CellularType.ToString(), + " }") +} \ No newline at end of file diff --git a/pkg/netmanager/netmanager.go b/pkg/netmanager/netmanager.go new file mode 100644 index 00000000..f037d55c --- /dev/null +++ b/pkg/netmanager/netmanager.go @@ -0,0 +1,79 @@ +package netmanager + +import ( + "context" + "sync" + + "berty.tech/weshnet/internal/notify" +) + +type NetManager struct { + currentState *ConnectivityInfo + + locker *sync.RWMutex + notify *notify.Notify +} + +type NetManagerEventType uint +const ( + NetManagerConnectivityStateChanged NetManagerEventType = 1 << iota + NetManagerConnectivityMeteringChanged + NetManagerConnectivityBluetoothChanged + NetManagerConnectivityNetTypeChanged + NetManagerConnectivityCellularTypeChanged + + NetManagerConnectivityChanged = 0 | + NetManagerConnectivityStateChanged | + NetManagerConnectivityMeteringChanged | + NetManagerConnectivityBluetoothChanged | + NetManagerConnectivityNetTypeChanged | + NetManagerConnectivityCellularTypeChanged +) + +func NewNetManager(initialState *ConnectivityInfo) *NetManager { + var locker sync.RWMutex + return &NetManager{ + currentState: initialState, + locker: &locker, + notify: notify.New(&locker), + } +} + +// UpdateState update the current state of the Manager +func (m *NetManager) UpdateState(state *ConnectivityInfo) { + m.locker.Lock() + if m.currentState != state { + m.currentState = state + m.notify.Broadcast() + } + m.locker.Unlock() +} + +// WaitForStateChange waits until the currentState changes from sourceState or ctx expires. A true value is returned in former case and false in latter. +func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType NetManagerEventType) bool { + m.locker.Lock() + + ok := true + for ok { + if (eventType & NetManagerConnectivityStateChanged != 0 && sourceState.State != m.currentState.State) || + (eventType & NetManagerConnectivityMeteringChanged != 0 && sourceState.Metering != m.currentState.Metering) || + (eventType & NetManagerConnectivityBluetoothChanged != 0 && sourceState.Bluetooth != m.currentState.Bluetooth) || + (eventType & NetManagerConnectivityNetTypeChanged != 0 && sourceState.NetType != m.currentState.NetType) || + (eventType & NetManagerConnectivityCellularTypeChanged != 0 && sourceState.CellularType != m.currentState.CellularType) { + break + } + // wait until state has been changed or context has been cancel + ok = m.notify.Wait(ctx) + } + + m.locker.Unlock() + return ok +} + +// GetCurrentState return the current state of the Manager +func (m *NetManager) GetCurrentState() (state *ConnectivityInfo) { + m.locker.RLock() + state = m.currentState + m.locker.RUnlock() + return +} From 137dd81935356afcb53b838ea49638792b217192 Mon Sep 17 00:00:00 2001 From: u Date: Tue, 28 Feb 2023 17:48:32 +0100 Subject: [PATCH 2/6] test: added unit test for connectivity driver --- pkg/netmanager/connectivity.go | 41 ++++---------- pkg/netmanager/netmanager.go | 21 ++++---- pkg/netmanager/netmanager_test.go | 89 +++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 41 deletions(-) create mode 100644 pkg/netmanager/netmanager_test.go diff --git a/pkg/netmanager/connectivity.go b/pkg/netmanager/connectivity.go index d3e7a4c2..c9fa8d1c 100644 --- a/pkg/netmanager/connectivity.go +++ b/pkg/netmanager/connectivity.go @@ -10,7 +10,7 @@ const ( ConnectivityStateOff ConnectivityStateOn ) -func (cs ConnectivityState) ToString() string { +func (cs ConnectivityState) String() string { switch cs { case ConnectivityStateUnknown: return "unknown" @@ -31,7 +31,7 @@ const ( ConnectivityNetEthernet ConnectivityNetCellular ) -func (cnt ConnectivityNetType) ToString() string { +func (cnt ConnectivityNetType) String() string { switch cnt { case ConnectivityNetUnknown: return "unknown" @@ -57,7 +57,7 @@ const ( ConnectivityCellular4G ConnectivityCellular5G ) -func (cct ConnectivityCellularType) ToString() string { +func (cct ConnectivityCellularType) String() string { switch cct { case ConnectivityCellularUnknown: return "unknown" @@ -83,35 +83,12 @@ type ConnectivityInfo struct { NetType ConnectivityNetType CellularType ConnectivityCellularType } - -func NewConnectivityInfo() *ConnectivityInfo { - return &ConnectivityInfo{ - State: ConnectivityState(ConnectivityStateUnknown), - Metering: ConnectivityState(ConnectivityStateUnknown), - Bluetooth: ConnectivityState(ConnectivityStateUnknown), - NetType: ConnectivityNetType(ConnectivityNetUnknown), - CellularType: ConnectivityCellularType(ConnectivityCellularUnknown), - } -} - -func (ci *ConnectivityInfo) GetState() ConnectivityState { return ci.State } -func (ci *ConnectivityInfo) GetMetering() ConnectivityState { return ci.Metering } -func (ci *ConnectivityInfo) GetBluetooth() ConnectivityState { return ci.Bluetooth } -func (ci *ConnectivityInfo) GetNetType() ConnectivityNetType { return ci.NetType } -func (ci *ConnectivityInfo) GetCellularType() ConnectivityCellularType { return ci.CellularType } - -func (ci *ConnectivityInfo) SetState(state ConnectivityState) { ci.State = state } -func (ci *ConnectivityInfo) SetMetering(metering ConnectivityState) { ci.Metering = metering } -func (ci *ConnectivityInfo) SetBluetooth(bluetooth ConnectivityState) { ci.Bluetooth = bluetooth } -func (ci *ConnectivityInfo) SetNetType(netType ConnectivityNetType) { ci.NetType = netType } -func (ci *ConnectivityInfo) SetCellularType(cellularType ConnectivityCellularType) { ci.CellularType = cellularType } - -func (ci *ConnectivityInfo) ToString() string { +func (ci ConnectivityInfo) String() string { return fmt.Sprint("ConnectivityInfo{ ", - "State: ", ci.State.ToString(), ", ", - "Metering: ", ci.Metering.ToString(), ", ", - "Bluetooth: ", ci.Bluetooth.ToString(), ", ", - "NetType: ", ci.NetType.ToString(), ", ", - "CellularType: ", ci.CellularType.ToString(), + "State: ", ci.State.String(), ", ", + "Metering: ", ci.Metering.String(), ", ", + "Bluetooth: ", ci.Bluetooth.String(), ", ", + "NetType: ", ci.NetType.String(), ", ", + "CellularType: ", ci.CellularType.String(), " }") } \ No newline at end of file diff --git a/pkg/netmanager/netmanager.go b/pkg/netmanager/netmanager.go index f037d55c..a999985e 100644 --- a/pkg/netmanager/netmanager.go +++ b/pkg/netmanager/netmanager.go @@ -8,7 +8,7 @@ import ( ) type NetManager struct { - currentState *ConnectivityInfo + currentState ConnectivityInfo locker *sync.RWMutex notify *notify.Notify @@ -29,8 +29,11 @@ const ( NetManagerConnectivityNetTypeChanged | NetManagerConnectivityCellularTypeChanged ) +func (t NetManagerEventType) has(other NetManagerEventType) bool { + return (t & other) == other +} -func NewNetManager(initialState *ConnectivityInfo) *NetManager { +func NewNetManager(initialState ConnectivityInfo) *NetManager { var locker sync.RWMutex return &NetManager{ currentState: initialState, @@ -40,7 +43,7 @@ func NewNetManager(initialState *ConnectivityInfo) *NetManager { } // UpdateState update the current state of the Manager -func (m *NetManager) UpdateState(state *ConnectivityInfo) { +func (m *NetManager) UpdateState(state ConnectivityInfo) { m.locker.Lock() if m.currentState != state { m.currentState = state @@ -55,11 +58,11 @@ func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *Connec ok := true for ok { - if (eventType & NetManagerConnectivityStateChanged != 0 && sourceState.State != m.currentState.State) || - (eventType & NetManagerConnectivityMeteringChanged != 0 && sourceState.Metering != m.currentState.Metering) || - (eventType & NetManagerConnectivityBluetoothChanged != 0 && sourceState.Bluetooth != m.currentState.Bluetooth) || - (eventType & NetManagerConnectivityNetTypeChanged != 0 && sourceState.NetType != m.currentState.NetType) || - (eventType & NetManagerConnectivityCellularTypeChanged != 0 && sourceState.CellularType != m.currentState.CellularType) { + if (eventType.has(NetManagerConnectivityStateChanged) && sourceState.State != m.currentState.State) || + (eventType.has(NetManagerConnectivityMeteringChanged) && sourceState.Metering != m.currentState.Metering) || + (eventType.has(NetManagerConnectivityBluetoothChanged) && sourceState.Bluetooth != m.currentState.Bluetooth) || + (eventType.has(NetManagerConnectivityNetTypeChanged) && sourceState.NetType != m.currentState.NetType) || + (eventType.has(NetManagerConnectivityCellularTypeChanged) && sourceState.CellularType != m.currentState.CellularType) { break } // wait until state has been changed or context has been cancel @@ -71,7 +74,7 @@ func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *Connec } // GetCurrentState return the current state of the Manager -func (m *NetManager) GetCurrentState() (state *ConnectivityInfo) { +func (m *NetManager) GetCurrentState() (state ConnectivityInfo) { m.locker.RLock() state = m.currentState m.locker.RUnlock() diff --git a/pkg/netmanager/netmanager_test.go b/pkg/netmanager/netmanager_test.go new file mode 100644 index 00000000..fa0d2cdf --- /dev/null +++ b/pkg/netmanager/netmanager_test.go @@ -0,0 +1,89 @@ +package netmanager + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewNetManager(t *testing.T) { + initial := ConnectivityInfo{ + State: ConnectivityStateOn, + NetType: ConnectivityNetWifi, + Bluetooth: ConnectivityStateOn, + } + + netmanager := NewNetManager(initial) + + require.Equal(t, initial, netmanager.GetCurrentState()) + initial.State = ConnectivityStateOff + require.NotEqual(t, initial, netmanager.GetCurrentState()) +} + +func TestNetManagerSingleUpdate(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + a := ConnectivityInfo{ + State: ConnectivityStateOn, + } + state := ConnectivityInfo{} + + netmanager := NewNetManager(state) + + netmanager.UpdateState(a) + require.Equal(t, a, netmanager.GetCurrentState()) + + netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityChanged) + + require.Equal(t, a, netmanager.GetCurrentState()) +} + +func TestNetManagerDoubleUpdate(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + a := ConnectivityInfo{ + State: ConnectivityStateOn, + } + b := ConnectivityInfo{ + State: ConnectivityStateOff, + } + state := ConnectivityInfo{} + + netmanager := NewNetManager(state) + + netmanager.UpdateState(a) + require.Equal(t, a, netmanager.GetCurrentState()) + netmanager.UpdateState(b) + require.Equal(t, b, netmanager.GetCurrentState()) + + netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityChanged) + require.Equal(t, b, netmanager.GetCurrentState()) +} + +func TestNetManagerFilterUpdate(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + a := ConnectivityInfo{ + State: ConnectivityStateOff, + } + b := ConnectivityInfo{ + State: ConnectivityStateOn, + NetType: ConnectivityNetCellular, + CellularType: ConnectivityCellular3G, + } + state := ConnectivityInfo{} + + netmanager := NewNetManager(state) + + netmanager.UpdateState(a) + require.Equal(t, a, netmanager.GetCurrentState()) + netmanager.UpdateState(b) + require.Equal(t, b, netmanager.GetCurrentState()) + + netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityCellularTypeChanged) + require.Equal(t, b, netmanager.GetCurrentState()) +} From 81d8f4d8c39c1a08597e50abfd5cdf06c504efd9 Mon Sep 17 00:00:00 2001 From: u Date: Wed, 1 Mar 2023 10:17:46 +0100 Subject: [PATCH 3/6] style: fix lint --- pkg/netmanager/connectivity.go | 11 +++++++-- pkg/netmanager/netmanager.go | 40 ++++++++++++++++--------------- pkg/netmanager/netmanager_test.go | 14 +++++------ 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/pkg/netmanager/connectivity.go b/pkg/netmanager/connectivity.go index c9fa8d1c..3277fcd2 100644 --- a/pkg/netmanager/connectivity.go +++ b/pkg/netmanager/connectivity.go @@ -5,11 +5,13 @@ import ( ) type ConnectivityState int + const ( ConnectivityStateUnknown ConnectivityState = iota ConnectivityStateOff ConnectivityStateOn ) + func (cs ConnectivityState) String() string { switch cs { case ConnectivityStateUnknown: @@ -24,6 +26,7 @@ func (cs ConnectivityState) String() string { } type ConnectivityNetType int + const ( ConnectivityNetUnknown ConnectivityNetType = iota ConnectivityNetNone @@ -31,6 +34,7 @@ const ( ConnectivityNetEthernet ConnectivityNetCellular ) + func (cnt ConnectivityNetType) String() string { switch cnt { case ConnectivityNetUnknown: @@ -49,6 +53,7 @@ func (cnt ConnectivityNetType) String() string { } type ConnectivityCellularType int + const ( ConnectivityCellularUnknown ConnectivityCellularType = iota ConnectivityCellularNone @@ -57,6 +62,7 @@ const ( ConnectivityCellular4G ConnectivityCellular5G ) + func (cct ConnectivityCellularType) String() string { switch cct { case ConnectivityCellularUnknown: @@ -83,6 +89,7 @@ type ConnectivityInfo struct { NetType ConnectivityNetType CellularType ConnectivityCellularType } + func (ci ConnectivityInfo) String() string { return fmt.Sprint("ConnectivityInfo{ ", "State: ", ci.State.String(), ", ", @@ -90,5 +97,5 @@ func (ci ConnectivityInfo) String() string { "Bluetooth: ", ci.Bluetooth.String(), ", ", "NetType: ", ci.NetType.String(), ", ", "CellularType: ", ci.CellularType.String(), - " }") -} \ No newline at end of file + " }") +} diff --git a/pkg/netmanager/netmanager.go b/pkg/netmanager/netmanager.go index a999985e..699a6d93 100644 --- a/pkg/netmanager/netmanager.go +++ b/pkg/netmanager/netmanager.go @@ -14,22 +14,24 @@ type NetManager struct { notify *notify.Notify } -type NetManagerEventType uint +type EventType uint + const ( - NetManagerConnectivityStateChanged NetManagerEventType = 1 << iota - NetManagerConnectivityMeteringChanged - NetManagerConnectivityBluetoothChanged - NetManagerConnectivityNetTypeChanged - NetManagerConnectivityCellularTypeChanged + ConnectivityStateChanged EventType = 1 << iota + ConnectivityMeteringChanged + ConnectivityBluetoothChanged + ConnectivityNetTypeChanged + ConnectivityCellularTypeChanged - NetManagerConnectivityChanged = 0 | - NetManagerConnectivityStateChanged | - NetManagerConnectivityMeteringChanged | - NetManagerConnectivityBluetoothChanged | - NetManagerConnectivityNetTypeChanged | - NetManagerConnectivityCellularTypeChanged + ConnectivityChanged = 0 | + ConnectivityStateChanged | + ConnectivityMeteringChanged | + ConnectivityBluetoothChanged | + ConnectivityNetTypeChanged | + ConnectivityCellularTypeChanged ) -func (t NetManagerEventType) has(other NetManagerEventType) bool { + +func (t EventType) has(other EventType) bool { return (t & other) == other } @@ -53,16 +55,16 @@ func (m *NetManager) UpdateState(state ConnectivityInfo) { } // WaitForStateChange waits until the currentState changes from sourceState or ctx expires. A true value is returned in former case and false in latter. -func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType NetManagerEventType) bool { +func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType EventType) bool { m.locker.Lock() ok := true for ok { - if (eventType.has(NetManagerConnectivityStateChanged) && sourceState.State != m.currentState.State) || - (eventType.has(NetManagerConnectivityMeteringChanged) && sourceState.Metering != m.currentState.Metering) || - (eventType.has(NetManagerConnectivityBluetoothChanged) && sourceState.Bluetooth != m.currentState.Bluetooth) || - (eventType.has(NetManagerConnectivityNetTypeChanged) && sourceState.NetType != m.currentState.NetType) || - (eventType.has(NetManagerConnectivityCellularTypeChanged) && sourceState.CellularType != m.currentState.CellularType) { + if (eventType.has(ConnectivityStateChanged) && sourceState.State != m.currentState.State) || + (eventType.has(ConnectivityMeteringChanged) && sourceState.Metering != m.currentState.Metering) || + (eventType.has(ConnectivityBluetoothChanged) && sourceState.Bluetooth != m.currentState.Bluetooth) || + (eventType.has(ConnectivityNetTypeChanged) && sourceState.NetType != m.currentState.NetType) || + (eventType.has(ConnectivityCellularTypeChanged) && sourceState.CellularType != m.currentState.CellularType) { break } // wait until state has been changed or context has been cancel diff --git a/pkg/netmanager/netmanager_test.go b/pkg/netmanager/netmanager_test.go index fa0d2cdf..1a803e7c 100644 --- a/pkg/netmanager/netmanager_test.go +++ b/pkg/netmanager/netmanager_test.go @@ -9,8 +9,8 @@ import ( func TestNewNetManager(t *testing.T) { initial := ConnectivityInfo{ - State: ConnectivityStateOn, - NetType: ConnectivityNetWifi, + State: ConnectivityStateOn, + NetType: ConnectivityNetWifi, Bluetooth: ConnectivityStateOn, } @@ -35,7 +35,7 @@ func TestNetManagerSingleUpdate(t *testing.T) { netmanager.UpdateState(a) require.Equal(t, a, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityChanged) + netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) require.Equal(t, a, netmanager.GetCurrentState()) } @@ -59,7 +59,7 @@ func TestNetManagerDoubleUpdate(t *testing.T) { netmanager.UpdateState(b) require.Equal(t, b, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityChanged) + netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) require.Equal(t, b, netmanager.GetCurrentState()) } @@ -71,8 +71,8 @@ func TestNetManagerFilterUpdate(t *testing.T) { State: ConnectivityStateOff, } b := ConnectivityInfo{ - State: ConnectivityStateOn, - NetType: ConnectivityNetCellular, + State: ConnectivityStateOn, + NetType: ConnectivityNetCellular, CellularType: ConnectivityCellular3G, } state := ConnectivityInfo{} @@ -84,6 +84,6 @@ func TestNetManagerFilterUpdate(t *testing.T) { netmanager.UpdateState(b) require.Equal(t, b, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, NetManagerConnectivityCellularTypeChanged) + netmanager.WaitForStateChange(ctx, &state, ConnectivityCellularTypeChanged) require.Equal(t, b, netmanager.GetCurrentState()) } From 15510a0fd997016b0f17fec2d6f77416811a5755 Mon Sep 17 00:00:00 2001 From: u Date: Thu, 2 Mar 2023 10:06:32 +0100 Subject: [PATCH 4/6] feat: return eventType and added comments --- pkg/netmanager/connectivity.go | 10 +++++++++ pkg/netmanager/netmanager.go | 37 +++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/pkg/netmanager/connectivity.go b/pkg/netmanager/connectivity.go index 3277fcd2..0308a250 100644 --- a/pkg/netmanager/connectivity.go +++ b/pkg/netmanager/connectivity.go @@ -83,10 +83,20 @@ func (cct ConnectivityCellularType) String() string { } type ConnectivityInfo struct { + // False when the device is not connected to a network. State ConnectivityState + + // True when the device is connected to a metered network. Metering ConnectivityState + + // True when the device is connected to a bluetooth network. Bluetooth ConnectivityState + + // The type of the network the device is connected to: wifi/ethernet/cellular. NetType ConnectivityNetType + + // If the device is connected to a cellular network: + // The type of the cellular network the device is connected to: 2G/3G/4G/5G. CellularType ConnectivityCellularType } diff --git a/pkg/netmanager/netmanager.go b/pkg/netmanager/netmanager.go index 699a6d93..f15becc9 100644 --- a/pkg/netmanager/netmanager.go +++ b/pkg/netmanager/netmanager.go @@ -31,7 +31,7 @@ const ( ConnectivityCellularTypeChanged ) -func (t EventType) has(other EventType) bool { +func (t EventType) Has(other EventType) bool { return (t & other) == other } @@ -54,17 +54,36 @@ func (m *NetManager) UpdateState(state ConnectivityInfo) { m.locker.Unlock() } -// WaitForStateChange waits until the currentState changes from sourceState or ctx expires. A true value is returned in former case and false in latter. -func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType EventType) bool { +// WaitForStateChange waits until the currentState changes from sourceState or ctx expires. +// The eventType argument allow you to filter out the event you want to wait for. +// A true value is returned in former case and false in latter. +// The EventType is also returned to know which events has been triggered. +func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType EventType) (bool, EventType) { m.locker.Lock() + var currentEventType EventType ok := true + for ok { - if (eventType.has(ConnectivityStateChanged) && sourceState.State != m.currentState.State) || - (eventType.has(ConnectivityMeteringChanged) && sourceState.Metering != m.currentState.Metering) || - (eventType.has(ConnectivityBluetoothChanged) && sourceState.Bluetooth != m.currentState.Bluetooth) || - (eventType.has(ConnectivityNetTypeChanged) && sourceState.NetType != m.currentState.NetType) || - (eventType.has(ConnectivityCellularTypeChanged) && sourceState.CellularType != m.currentState.CellularType) { + currentEventType = 0 + + if (sourceState.State != m.currentState.State) { + currentEventType |= ConnectivityStateChanged + } + if (sourceState.Metering != m.currentState.Metering) { + currentEventType |= ConnectivityMeteringChanged + } + if (sourceState.Bluetooth != m.currentState.Bluetooth) { + currentEventType |= ConnectivityBluetoothChanged + } + if (sourceState.NetType != m.currentState.NetType) { + currentEventType |= ConnectivityNetTypeChanged + } + if (sourceState.CellularType != m.currentState.CellularType) { + currentEventType |= ConnectivityCellularTypeChanged + } + + if ((eventType & currentEventType) != 0) { break } // wait until state has been changed or context has been cancel @@ -72,7 +91,7 @@ func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *Connec } m.locker.Unlock() - return ok + return ok, currentEventType } // GetCurrentState return the current state of the Manager From 101336a083fffa46c3ffe70a05605859add19694 Mon Sep 17 00:00:00 2001 From: u Date: Thu, 2 Mar 2023 10:14:43 +0100 Subject: [PATCH 5/6] chore: lint --- pkg/netmanager/connectivity.go | 8 ++++---- pkg/netmanager/netmanager.go | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/netmanager/connectivity.go b/pkg/netmanager/connectivity.go index 0308a250..0efd28f4 100644 --- a/pkg/netmanager/connectivity.go +++ b/pkg/netmanager/connectivity.go @@ -84,16 +84,16 @@ func (cct ConnectivityCellularType) String() string { type ConnectivityInfo struct { // False when the device is not connected to a network. - State ConnectivityState + State ConnectivityState // True when the device is connected to a metered network. - Metering ConnectivityState + Metering ConnectivityState // True when the device is connected to a bluetooth network. - Bluetooth ConnectivityState + Bluetooth ConnectivityState // The type of the network the device is connected to: wifi/ethernet/cellular. - NetType ConnectivityNetType + NetType ConnectivityNetType // If the device is connected to a cellular network: // The type of the cellular network the device is connected to: 2G/3G/4G/5G. diff --git a/pkg/netmanager/netmanager.go b/pkg/netmanager/netmanager.go index f15becc9..da3819d4 100644 --- a/pkg/netmanager/netmanager.go +++ b/pkg/netmanager/netmanager.go @@ -67,23 +67,23 @@ func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *Connec for ok { currentEventType = 0 - if (sourceState.State != m.currentState.State) { + if sourceState.State != m.currentState.State { currentEventType |= ConnectivityStateChanged } - if (sourceState.Metering != m.currentState.Metering) { + if sourceState.Metering != m.currentState.Metering { currentEventType |= ConnectivityMeteringChanged } - if (sourceState.Bluetooth != m.currentState.Bluetooth) { + if sourceState.Bluetooth != m.currentState.Bluetooth { currentEventType |= ConnectivityBluetoothChanged } - if (sourceState.NetType != m.currentState.NetType) { + if sourceState.NetType != m.currentState.NetType { currentEventType |= ConnectivityNetTypeChanged } - if (sourceState.CellularType != m.currentState.CellularType) { + if sourceState.CellularType != m.currentState.CellularType { currentEventType |= ConnectivityCellularTypeChanged } - if ((eventType & currentEventType) != 0) { + if (eventType & currentEventType) != 0 { break } // wait until state has been changed or context has been cancel From 295f8d0d412ae978d8cb42d63a8f894bd7655d2b Mon Sep 17 00:00:00 2001 From: u Date: Thu, 2 Mar 2023 10:23:22 +0100 Subject: [PATCH 6/6] test: updated netmanager tests --- pkg/netmanager/netmanager_test.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/netmanager/netmanager_test.go b/pkg/netmanager/netmanager_test.go index 1a803e7c..2df0baa9 100644 --- a/pkg/netmanager/netmanager_test.go +++ b/pkg/netmanager/netmanager_test.go @@ -35,9 +35,11 @@ func TestNetManagerSingleUpdate(t *testing.T) { netmanager.UpdateState(a) require.Equal(t, a, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) + ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) require.Equal(t, a, netmanager.GetCurrentState()) + require.True(t, ok) + require.Equal(t, ConnectivityStateChanged, eventType) } func TestNetManagerDoubleUpdate(t *testing.T) { @@ -59,8 +61,11 @@ func TestNetManagerDoubleUpdate(t *testing.T) { netmanager.UpdateState(b) require.Equal(t, b, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) + ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged) + require.Equal(t, b, netmanager.GetCurrentState()) + require.True(t, ok) + require.Equal(t, ConnectivityStateChanged, eventType) } func TestNetManagerFilterUpdate(t *testing.T) { @@ -84,6 +89,9 @@ func TestNetManagerFilterUpdate(t *testing.T) { netmanager.UpdateState(b) require.Equal(t, b, netmanager.GetCurrentState()) - netmanager.WaitForStateChange(ctx, &state, ConnectivityCellularTypeChanged) + ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityCellularTypeChanged) + require.Equal(t, b, netmanager.GetCurrentState()) + require.True(t, ok) + require.Equal(t, ConnectivityStateChanged | ConnectivityNetTypeChanged | ConnectivityCellularTypeChanged, eventType) }