Fix/connection listener (#777)

Fix add/remove connection listener

In case we call the RemoveConnListener from Java then
we lose the reference from the original instance
This commit is contained in:
Zoltan Papp 2023-04-03 16:59:13 +02:00 committed by GitHub
parent 769388cd21
commit 86f9051a30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 44 deletions

View File

@ -118,12 +118,12 @@ func (c *Client) PeersList() *PeerInfoArray {
return &PeerInfoArray{items: peerInfos} return &PeerInfoArray{items: peerInfos}
} }
// AddConnectionListener add new network connection listener // SetConnectionListener set the network connection listener
func (c *Client) AddConnectionListener(listener ConnectionListener) { func (c *Client) SetConnectionListener(listener ConnectionListener) {
c.recorder.AddConnectionListener(listener) c.recorder.SetConnectionListener(listener)
} }
// RemoveConnectionListener remove connection listener // RemoveConnectionListener remove connection listener
func (c *Client) RemoveConnectionListener(listener ConnectionListener) { func (c *Client) RemoveConnectionListener() {
c.recorder.RemoveConnectionListener(listener) c.recorder.RemoveConnectionListener()
} }

View File

@ -14,32 +14,31 @@ const (
type notifier struct { type notifier struct {
serverStateLock sync.Mutex serverStateLock sync.Mutex
listenersLock sync.Mutex listenersLock sync.Mutex
listeners map[Listener]struct{} listener Listener
currentServerState bool currentServerState bool
currentClientState bool currentClientState bool
lastNotification int lastNotification int
} }
func newNotifier() *notifier { func newNotifier() *notifier {
return &notifier{ return &notifier{}
listeners: make(map[Listener]struct{}),
}
} }
func (n *notifier) addListener(listener Listener) { func (n *notifier) setListener(listener Listener) {
n.listenersLock.Lock() n.listenersLock.Lock()
defer n.listenersLock.Unlock() defer n.listenersLock.Unlock()
n.serverStateLock.Lock() n.serverStateLock.Lock()
go n.notifyListener(listener, n.lastNotification) n.notifyListener(listener, n.lastNotification)
n.serverStateLock.Unlock() n.serverStateLock.Unlock()
n.listeners[listener] = struct{}{}
n.listener = listener
} }
func (n *notifier) removeListener(listener Listener) { func (n *notifier) removeListener() {
n.listenersLock.Lock() n.listenersLock.Lock()
defer n.listenersLock.Unlock() defer n.listenersLock.Unlock()
delete(n.listeners, listener) n.listener = nil
} }
func (n *notifier) updateServerStates(mgmState bool, signalState bool) { func (n *notifier) updateServerStates(mgmState bool, signalState bool) {
@ -64,7 +63,7 @@ func (n *notifier) updateServerStates(mgmState bool, signalState bool) {
} }
n.lastNotification = n.calculateState(newState, n.currentClientState) n.lastNotification = n.calculateState(newState, n.currentClientState)
go n.notifyAll(n.lastNotification) n.notify(n.lastNotification)
} }
func (n *notifier) clientStart() { func (n *notifier) clientStart() {
@ -72,7 +71,7 @@ func (n *notifier) clientStart() {
defer n.serverStateLock.Unlock() defer n.serverStateLock.Unlock()
n.currentClientState = true n.currentClientState = true
n.lastNotification = n.calculateState(n.currentServerState, true) n.lastNotification = n.calculateState(n.currentServerState, true)
go n.notifyAll(n.lastNotification) n.notify(n.lastNotification)
} }
func (n *notifier) clientStop() { func (n *notifier) clientStop() {
@ -80,7 +79,7 @@ func (n *notifier) clientStop() {
defer n.serverStateLock.Unlock() defer n.serverStateLock.Unlock()
n.currentClientState = false n.currentClientState = false
n.lastNotification = n.calculateState(n.currentServerState, false) n.lastNotification = n.calculateState(n.currentServerState, false)
go n.notifyAll(n.lastNotification) n.notify(n.lastNotification)
} }
func (n *notifier) clientTearDown() { func (n *notifier) clientTearDown() {
@ -88,23 +87,24 @@ func (n *notifier) clientTearDown() {
defer n.serverStateLock.Unlock() defer n.serverStateLock.Unlock()
n.currentClientState = false n.currentClientState = false
n.lastNotification = stateDisconnecting n.lastNotification = stateDisconnecting
go n.notifyAll(n.lastNotification) n.notify(n.lastNotification)
} }
func (n *notifier) isServerStateChanged(newState bool) bool { func (n *notifier) isServerStateChanged(newState bool) bool {
return n.currentServerState != newState return n.currentServerState != newState
} }
func (n *notifier) notifyAll(state int) { func (n *notifier) notify(state int) {
n.listenersLock.Lock() n.listenersLock.Lock()
defer n.listenersLock.Unlock() defer n.listenersLock.Unlock()
if n.listener == nil {
for l := range n.listeners { return
n.notifyListener(l, state)
} }
n.notifyListener(n.listener, state)
} }
func (n *notifier) notifyListener(l Listener, state int) { func (n *notifier) notifyListener(l Listener, state int) {
go func() {
switch state { switch state {
case stateDisconnected: case stateDisconnected:
l.OnDisconnected() l.OnDisconnected()
@ -115,6 +115,7 @@ func (n *notifier) notifyListener(l Listener, state int) {
case stateDisconnecting: case stateDisconnecting:
l.OnDisconnecting() l.OnDisconnecting()
} }
}()
} }
func (n *notifier) calculateState(serverState bool, clientState bool) int { func (n *notifier) calculateState(serverState bool, clientState bool) int {
@ -132,17 +133,17 @@ func (n *notifier) calculateState(serverState bool, clientState bool) int {
func (n *notifier) peerListChanged(numOfPeers int) { func (n *notifier) peerListChanged(numOfPeers int) {
n.listenersLock.Lock() n.listenersLock.Lock()
defer n.listenersLock.Unlock() defer n.listenersLock.Unlock()
if n.listener == nil {
for l := range n.listeners { return
l.OnPeersListChanged(numOfPeers)
} }
n.listener.OnPeersListChanged(numOfPeers)
} }
func (n *notifier) localAddressChanged(fqdn, address string) { func (n *notifier) localAddressChanged(fqdn, address string) {
n.listenersLock.Lock() n.listenersLock.Lock()
defer n.listenersLock.Unlock() defer n.listenersLock.Unlock()
if n.listener == nil {
for l := range n.listeners { return
l.OnAddressChanged(fqdn, address)
} }
n.listener.OnAddressChanged(fqdn, address)
} }

View File

@ -1,9 +1,48 @@
package peer package peer
import ( import (
"sync"
"testing" "testing"
) )
type mocListener struct {
lastState int
wg sync.WaitGroup
peers int
}
func (l *mocListener) OnConnected() {
l.lastState = stateConnected
l.wg.Done()
}
func (l *mocListener) OnDisconnected() {
l.lastState = stateDisconnected
l.wg.Done()
}
func (l *mocListener) OnConnecting() {
l.lastState = stateConnecting
l.wg.Done()
}
func (l *mocListener) OnDisconnecting() {
l.lastState = stateDisconnecting
l.wg.Done()
}
func (l *mocListener) OnAddressChanged(host, addr string) {
}
func (l *mocListener) OnPeersListChanged(size int) {
l.peers = size
}
func (l *mocListener) setWaiter() {
l.wg.Add(1)
}
func (l *mocListener) wait() {
l.wg.Wait()
}
func Test_notifier_serverState(t *testing.T) { func Test_notifier_serverState(t *testing.T) {
type scenario struct { type scenario struct {
@ -30,3 +69,30 @@ func Test_notifier_serverState(t *testing.T) {
}) })
} }
} }
func Test_notifier_SetListener(t *testing.T) {
listener := &mocListener{}
listener.setWaiter()
n := newNotifier()
n.lastNotification = stateConnecting
n.setListener(listener)
listener.wait()
if listener.lastState != n.lastNotification {
t.Errorf("invalid state: %d, expected: %d", listener.lastState, n.lastNotification)
}
}
func Test_notifier_RemoveListener(t *testing.T) {
listener := &mocListener{}
listener.setWaiter()
n := newNotifier()
n.lastNotification = stateConnecting
n.setListener(listener)
n.removeListener()
n.peerListChanged(1)
if listener.peers != 0 {
t.Errorf("invalid state: %d", listener.peers)
}
}

View File

@ -293,14 +293,14 @@ func (d *Status) ClientTeardown() {
d.notifier.clientTearDown() d.notifier.clientTearDown()
} }
// AddConnectionListener add a listener to the notifier // SetConnectionListener set a listener to the notifier
func (d *Status) AddConnectionListener(listener Listener) { func (d *Status) SetConnectionListener(listener Listener) {
d.notifier.addListener(listener) d.notifier.setListener(listener)
} }
// RemoveConnectionListener remove a listener from the notifier // RemoveConnectionListener remove the listener from the notifier
func (d *Status) RemoveConnectionListener(listener Listener) { func (d *Status) RemoveConnectionListener() {
d.notifier.removeListener(listener) d.notifier.removeListener()
} }
func (d *Status) onConnectionChanged() { func (d *Status) onConnectionChanged() {