mirror of
https://github.com/status-im/status-go.git
synced 2025-01-09 14:16:21 +00:00
f2c6fef64c
This change allows to connect to the mail server that we were using before the app was restarted. Separate loop is listening for whisper events, and when we receive event that request was completed we will update time on a peer record. Records are stored in leveldb. Body of the record is marshaled using json. At this point the only field is a timestamp when record was used. This loop doesn't control connections, it only tracks what mail server we ended up using. It works asynchronously to connection management loop. Which tracks events that are related to connection state and expiry of the requests. When app starts we look into the database and select the most recently used record. This record is added to connection management loop first. So if this server is available we will stick to using it. If we weren't able to connect to the same server in configured timeout (5s) we will try to connect to any other server from list of active servers. closes: #1285
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package mailservers
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
whisper "github.com/status-im/whisper/whisperv6"
|
|
)
|
|
|
|
// NewLastUsedConnectionMonitor returns pointer to the instance of LastUsedConnectionMonitor.
|
|
func NewLastUsedConnectionMonitor(ps *PeerStore, cache *Cache, whisper EnvelopeEventSubscbriber) *LastUsedConnectionMonitor {
|
|
return &LastUsedConnectionMonitor{
|
|
ps: ps,
|
|
cache: cache,
|
|
whisper: whisper,
|
|
}
|
|
}
|
|
|
|
// LastUsedConnectionMonitor watches relevant events and reflects it in cache.
|
|
type LastUsedConnectionMonitor struct {
|
|
ps *PeerStore
|
|
cache *Cache
|
|
|
|
whisper EnvelopeEventSubscbriber
|
|
|
|
quit chan struct{}
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
// Start spins a separate goroutine to watch connections.
|
|
func (mon *LastUsedConnectionMonitor) Start() {
|
|
mon.quit = make(chan struct{})
|
|
mon.wg.Add(1)
|
|
go func() {
|
|
events := make(chan whisper.EnvelopeEvent, whisperEventsBuffer)
|
|
sub := mon.whisper.SubscribeEnvelopeEvents(events)
|
|
defer sub.Unsubscribe()
|
|
defer mon.wg.Done()
|
|
for {
|
|
select {
|
|
case <-mon.quit:
|
|
return
|
|
case err := <-sub.Err():
|
|
log.Error("retry after error suscribing to whisper events", "error", err)
|
|
return
|
|
case ev := <-events:
|
|
node := mon.ps.Get(ev.Peer)
|
|
if node == nil {
|
|
continue
|
|
}
|
|
if ev.Event == whisper.EventMailServerRequestCompleted {
|
|
err := mon.updateRecord(ev.Peer)
|
|
if err != nil {
|
|
log.Error("unable to update storage", "peer", ev.Peer, "error", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (mon *LastUsedConnectionMonitor) updateRecord(nodeID enode.ID) error {
|
|
node := mon.ps.Get(nodeID)
|
|
if node == nil {
|
|
return nil
|
|
}
|
|
return mon.cache.UpdateRecord(PeerRecord{node: node, LastUsed: time.Now()})
|
|
}
|
|
|
|
// Stop closes channel to signal a quit and waits until all goroutines are stoppped.
|
|
func (mon *LastUsedConnectionMonitor) Stop() {
|
|
if mon.quit == nil {
|
|
return
|
|
}
|
|
select {
|
|
case <-mon.quit:
|
|
return
|
|
default:
|
|
}
|
|
close(mon.quit)
|
|
mon.wg.Wait()
|
|
mon.quit = nil
|
|
}
|