Merge branch 'reconncect' of dan/cwtch into master
the build failed
Details
the build failed
Details
This commit is contained in:
commit
832c4c28d5
22
app/app.go
22
app/app.go
|
@ -44,6 +44,7 @@ type Application interface {
|
||||||
|
|
||||||
GetPrimaryBus() event.Manager
|
GetPrimaryBus() event.Manager
|
||||||
GetEventBus(onion string) event.Manager
|
GetEventBus(onion string) event.Manager
|
||||||
|
QueryACNStatus()
|
||||||
|
|
||||||
ShutdownPeer(string)
|
ShutdownPeer(string)
|
||||||
Shutdown()
|
Shutdown()
|
||||||
|
@ -67,11 +68,7 @@ func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
||||||
app := &application{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationCore: *newAppCore(appDirectory), appBus: event.NewEventManager()}
|
app := &application{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationCore: *newAppCore(appDirectory), appBus: event.NewEventManager()}
|
||||||
app.appletPeers.init()
|
app.appletPeers.init()
|
||||||
|
|
||||||
fn := func(progress int, status string) {
|
app.appletACN.init(acn, app.getACNStatusHandler())
|
||||||
progStr := strconv.Itoa(progress)
|
|
||||||
app.appBus.Publish(event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status))
|
|
||||||
}
|
|
||||||
app.appletACN.init(acn, fn)
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +193,21 @@ func (ac *applicationCore) GetEventBus(onion string) event.Manager {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *application) getACNStatusHandler() func(int, string) {
|
||||||
|
return func(progress int, status string) {
|
||||||
|
progStr := strconv.Itoa(progress)
|
||||||
|
app.appBus.Publish(event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status))
|
||||||
|
for _, bus := range app.eventBuses {
|
||||||
|
bus.Publish(event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *application) QueryACNStatus() {
|
||||||
|
prog, status := app.acn.GetBootstrapStatus()
|
||||||
|
app.getACNStatusHandler()(prog, status)
|
||||||
|
}
|
||||||
|
|
||||||
// ShutdownPeer shuts down a peer and removes it from the app's management
|
// ShutdownPeer shuts down a peer and removes it from the app's management
|
||||||
func (app *application) ShutdownPeer(onion string) {
|
func (app *application) ShutdownPeer(onion string) {
|
||||||
app.mutex.Lock()
|
app.mutex.Lock()
|
||||||
|
|
|
@ -107,6 +107,11 @@ func (ac *applicationClient) LoadProfiles(password string) {
|
||||||
ac.bridge.Write(&message)
|
ac.bridge.Write(&message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ac *applicationClient) QueryACNStatus() {
|
||||||
|
message := event.IPCMessage{Dest: DestApp, Message: event.NewEvent(event.GetACNStatus, map[event.Field]string{})}
|
||||||
|
ac.bridge.Write(&message)
|
||||||
|
}
|
||||||
|
|
||||||
// ShutdownPeer shuts down a peer and removes it from the app's management
|
// ShutdownPeer shuts down a peer and removes it from the app's management
|
||||||
func (ac *applicationClient) ShutdownPeer(onion string) {
|
func (ac *applicationClient) ShutdownPeer(onion string) {
|
||||||
ac.mutex.Lock()
|
ac.mutex.Lock()
|
||||||
|
|
|
@ -31,11 +31,7 @@ type ApplicationService interface {
|
||||||
func NewAppService(acn connectivity.ACN, appDirectory string, bridge event.IPCBridge) ApplicationService {
|
func NewAppService(acn connectivity.ACN, appDirectory string, bridge event.IPCBridge) ApplicationService {
|
||||||
appService := &applicationService{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationBridge: applicationBridge{applicationCore: *newAppCore(appDirectory), bridge: bridge}}
|
appService := &applicationService{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationBridge: applicationBridge{applicationCore: *newAppCore(appDirectory), bridge: bridge}}
|
||||||
|
|
||||||
fn := func(progress int, status string) {
|
appService.appletACN.init(acn, appService.getACNStatusHandler())
|
||||||
progStr := strconv.Itoa(progress)
|
|
||||||
appService.bridge.Write(&event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status)})
|
|
||||||
}
|
|
||||||
appService.appletACN.init(acn, fn)
|
|
||||||
appService.handle = appService.handleEvent
|
appService.handle = appService.handleEvent
|
||||||
|
|
||||||
go appService.listen()
|
go appService.listen()
|
||||||
|
@ -74,6 +70,9 @@ func (as *applicationService) handleEvent(ev *event.Event) {
|
||||||
message := event.IPCMessage{Dest: onion, Message: *ev}
|
message := event.IPCMessage{Dest: onion, Message: *ev}
|
||||||
as.bridge.Write(&message)
|
as.bridge.Write(&message)
|
||||||
}
|
}
|
||||||
|
case event.GetACNStatus:
|
||||||
|
prog, status := as.acn.GetBootstrapStatus()
|
||||||
|
as.getACNStatusHandler()(prog, status)
|
||||||
case event.ShutdownPeer:
|
case event.ShutdownPeer:
|
||||||
onion := ev.Data[event.Identity]
|
onion := ev.Data[event.Identity]
|
||||||
as.ShutdownPeer(onion)
|
as.ShutdownPeer(onion)
|
||||||
|
@ -127,6 +126,16 @@ func (as *applicationService) loadProfiles(password string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (as *applicationService) getACNStatusHandler() func(int, string) {
|
||||||
|
return func(progress int, status string) {
|
||||||
|
progStr := strconv.Itoa(progress)
|
||||||
|
as.bridge.Write(&event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status)})
|
||||||
|
for _, bus := range as.eventBuses {
|
||||||
|
bus.Publish(event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (as *applicationService) ShutdownPeer(onion string) {
|
func (as *applicationService) ShutdownPeer(onion string) {
|
||||||
as.engines[onion].Shutdown()
|
as.engines[onion].Shutdown()
|
||||||
delete(as.engines, onion)
|
delete(as.engines, onion)
|
||||||
|
|
|
@ -10,26 +10,35 @@ import (
|
||||||
const tickTime = 10 * time.Second
|
const tickTime = 10 * time.Second
|
||||||
const maxBakoff int = 32 // 320 seconds or ~5 min
|
const maxBakoff int = 32 // 320 seconds or ~5 min
|
||||||
|
|
||||||
type peer struct {
|
type connectionType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
peerConn connectionType = iota
|
||||||
|
serverConn
|
||||||
|
)
|
||||||
|
|
||||||
|
type contact struct {
|
||||||
id string
|
id string
|
||||||
state connections.ConnectionState
|
state connections.ConnectionState
|
||||||
|
ctype connectionType
|
||||||
|
|
||||||
ticks int
|
ticks int
|
||||||
backoff int
|
backoff int
|
||||||
}
|
}
|
||||||
|
|
||||||
type contactRetry struct {
|
type contactRetry struct {
|
||||||
bus event.Manager
|
bus event.Manager
|
||||||
queue event.Queue
|
queue event.Queue
|
||||||
|
networkUp bool
|
||||||
|
|
||||||
breakChan chan bool
|
breakChan chan bool
|
||||||
|
|
||||||
peers sync.Map //[string]*peer
|
connections sync.Map //[string]*contact
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContactRetry returns a Plugin that when started will retry connecting to contacts with a backoff timing
|
// NewConnectionRetry returns a Plugin that when started will retry connecting to contacts with a backoff timing
|
||||||
func NewContactRetry(bus event.Manager) Plugin {
|
func NewConnectionRetry(bus event.Manager) Plugin {
|
||||||
cr := &contactRetry{bus: bus, queue: event.NewQueue(), breakChan: make(chan bool), peers: sync.Map{}}
|
cr := &contactRetry{bus: bus, queue: event.NewQueue(), breakChan: make(chan bool), connections: sync.Map{}, networkUp: false}
|
||||||
return cr
|
return cr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +48,9 @@ func (cr *contactRetry) Start() {
|
||||||
|
|
||||||
func (cr *contactRetry) run() {
|
func (cr *contactRetry) run() {
|
||||||
cr.bus.Subscribe(event.PeerStateChange, cr.queue)
|
cr.bus.Subscribe(event.PeerStateChange, cr.queue)
|
||||||
|
cr.bus.Subscribe(event.ACNStatus, cr.queue)
|
||||||
|
cr.bus.Subscribe(event.ServerStateChange, cr.queue)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-cr.queue.OutChan():
|
case e := <-cr.queue.OutChan():
|
||||||
|
@ -46,21 +58,46 @@ func (cr *contactRetry) run() {
|
||||||
case event.PeerStateChange:
|
case event.PeerStateChange:
|
||||||
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
peer := e.Data[event.RemotePeer]
|
peer := e.Data[event.RemotePeer]
|
||||||
cr.handleEvent(peer, state)
|
cr.handleEvent(peer, state, peerConn)
|
||||||
|
|
||||||
|
case event.ServerStateChange:
|
||||||
|
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
|
server := e.Data[event.GroupServer]
|
||||||
|
cr.handleEvent(server, state, serverConn)
|
||||||
|
|
||||||
|
case event.ACNStatus:
|
||||||
|
prog := e.Data[event.Progreess]
|
||||||
|
if prog == "100" && cr.networkUp == false {
|
||||||
|
cr.networkUp = true
|
||||||
|
cr.connections.Range(func(k, v interface{}) bool {
|
||||||
|
p := v.(*contact)
|
||||||
|
p.ticks = 0
|
||||||
|
p.backoff = 1
|
||||||
|
cr.bus.Publish(event.NewEvent(event.RetryPeerRequest, map[event.Field]string{event.RemotePeer: p.id}))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
} else if prog != "100" {
|
||||||
|
cr.networkUp = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-time.After(tickTime):
|
case <-time.After(tickTime):
|
||||||
cr.peers.Range(func(k, v interface{}) bool {
|
cr.connections.Range(func(k, v interface{}) bool {
|
||||||
p := v.(*peer)
|
p := v.(*contact)
|
||||||
|
|
||||||
if p.state == connections.DISCONNECTED {
|
if p.state == connections.DISCONNECTED {
|
||||||
p.ticks++
|
p.ticks++
|
||||||
if p.ticks == p.backoff {
|
if p.ticks == p.backoff {
|
||||||
p.ticks = 0
|
p.ticks = 0
|
||||||
cr.bus.Publish(event.NewEvent(event.RetryPeerRequest, map[event.Field]string{event.RemotePeer: p.id}))
|
if cr.networkUp {
|
||||||
|
if p.ctype == peerConn {
|
||||||
|
cr.bus.Publish(event.NewEvent(event.RetryPeerRequest, map[event.Field]string{event.RemotePeer: p.id}))
|
||||||
|
} else {
|
||||||
|
cr.bus.Publish(event.NewEventList(event.JoinServer, event.GroupServer, p.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -70,15 +107,15 @@ func (cr *contactRetry) run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr *contactRetry) handleEvent(id string, state connections.ConnectionState) {
|
func (cr *contactRetry) handleEvent(id string, state connections.ConnectionState, ctype connectionType) {
|
||||||
if _, exists := cr.peers.Load(id); !exists {
|
if _, exists := cr.connections.Load(id); !exists {
|
||||||
p := &peer{id: id, state: connections.DISCONNECTED, backoff: 1, ticks: 0}
|
p := &contact{id: id, state: connections.DISCONNECTED, backoff: 1, ticks: 0, ctype: ctype}
|
||||||
cr.peers.Store(id, p)
|
cr.connections.Store(id, p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pinf, _ := cr.peers.Load(id)
|
pinf, _ := cr.connections.Load(id)
|
||||||
p := pinf.(*peer)
|
p := pinf.(*contact)
|
||||||
if state == connections.DISCONNECTED || state == connections.FAILED || state == connections.KILLED {
|
if state == connections.DISCONNECTED || state == connections.FAILED || state == connections.KILLED {
|
||||||
p.state = connections.DISCONNECTED
|
p.state = connections.DISCONNECTED
|
||||||
if p.backoff < maxBakoff {
|
if p.backoff < maxBakoff {
|
||||||
|
|
|
@ -9,7 +9,7 @@ type PluginID int
|
||||||
|
|
||||||
// These are the plugin IDs for the supplied plugins
|
// These are the plugin IDs for the supplied plugins
|
||||||
const (
|
const (
|
||||||
CONTACTRETRY PluginID = iota
|
CONNECTIONRETRY PluginID = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// Plugin is the interface for a plugin
|
// Plugin is the interface for a plugin
|
||||||
|
@ -21,8 +21,8 @@ type Plugin interface {
|
||||||
// Get is a plugin factory for the requested plugin
|
// Get is a plugin factory for the requested plugin
|
||||||
func Get(id PluginID, bus event.Manager) Plugin {
|
func Get(id PluginID, bus event.Manager) Plugin {
|
||||||
switch id {
|
switch id {
|
||||||
case CONTACTRETRY:
|
case CONNECTIONRETRY:
|
||||||
return NewContactRetry(bus)
|
return NewConnectionRetry(bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -29,6 +29,7 @@ const (
|
||||||
BlockUnknownPeers = Type("BlockUnknownPeers")
|
BlockUnknownPeers = Type("BlockUnknownPeers")
|
||||||
AllowUnknownPeers = Type("AllowUnknownPeers")
|
AllowUnknownPeers = Type("AllowUnknownPeers")
|
||||||
|
|
||||||
|
// GroupServer
|
||||||
JoinServer = Type("JoinServer")
|
JoinServer = Type("JoinServer")
|
||||||
|
|
||||||
ProtocolEngineStartListen = Type("ProtocolEngineStartListen")
|
ProtocolEngineStartListen = Type("ProtocolEngineStartListen")
|
||||||
|
@ -160,6 +161,8 @@ const (
|
||||||
// Error(err)
|
// Error(err)
|
||||||
AppError = Type("AppError")
|
AppError = Type("AppError")
|
||||||
|
|
||||||
|
GetACNStatus = Type("GetACNStatus")
|
||||||
|
|
||||||
// Progress, Status
|
// Progress, Status
|
||||||
ACNStatus = Type("ACNStatus")
|
ACNStatus = Type("ACNStatus")
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func TestProfileIdentity(t *testing.T) {
|
func TestProfileIdentity(t *testing.T) {
|
||||||
sarah := GenerateNewProfile("Sarah")
|
sarah := GenerateNewProfile("Sarah")
|
||||||
alice := GenerateNewProfile("Alice")
|
alice := GenerateNewProfile("Alice")
|
||||||
|
|
|
@ -6,14 +6,12 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manager encapsulates all the logic necessary to manage outgoing peer and server connections.
|
// Manager encapsulates all the logic necessary to manage outgoing peer and server connections.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
serverConnections map[string]*PeerServerConnection
|
serverConnections map[string]*PeerServerConnection
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
breakChannel chan bool
|
|
||||||
acn connectivity.ACN
|
acn connectivity.ACN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +20,6 @@ func NewConnectionsManager(acn connectivity.ACN) *Manager {
|
||||||
m := new(Manager)
|
m := new(Manager)
|
||||||
m.acn = acn
|
m.acn = acn
|
||||||
m.serverConnections = make(map[string]*PeerServerConnection)
|
m.serverConnections = make(map[string]*PeerServerConnection)
|
||||||
m.breakChannel = make(chan bool)
|
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,36 +63,8 @@ func (m *Manager) GetPeerServerConnectionForOnion(host string) (psc *PeerServerC
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttemptReconnections repeatedly attempts to reconnect with failed peers and servers.
|
|
||||||
func (m *Manager) AttemptReconnections() {
|
|
||||||
maxTimeout := time.Minute * 5
|
|
||||||
// nearly instant first run, next few runs will prolly be too quick to have any FAILED and will gracefully slow to MAX after that
|
|
||||||
timeout := time.Millisecond * 500
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-time.After(timeout):
|
|
||||||
m.lock.Lock()
|
|
||||||
for _, psc := range m.serverConnections {
|
|
||||||
if psc.GetState() == FAILED {
|
|
||||||
go psc.Run()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.lock.Unlock()
|
|
||||||
|
|
||||||
if timeout < maxTimeout {
|
|
||||||
timeout = timeout * 2
|
|
||||||
} else {
|
|
||||||
timeout = maxTimeout
|
|
||||||
}
|
|
||||||
case <-m.breakChannel:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown closes all connections under management (freeing their goroutines)
|
// Shutdown closes all connections under management (freeing their goroutines)
|
||||||
func (m *Manager) Shutdown() {
|
func (m *Manager) Shutdown() {
|
||||||
m.breakChannel <- true
|
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
for onion, psc := range m.serverConnections {
|
for onion, psc := range m.serverConnections {
|
||||||
psc.Close()
|
psc.Close()
|
||||||
|
|
|
@ -63,7 +63,6 @@ func NewProtocolEngine(identity primitives.Identity, privateKey ed25519.PrivateK
|
||||||
|
|
||||||
engine.acn = acn
|
engine.acn = acn
|
||||||
engine.connectionsManager = NewConnectionsManager(engine.acn)
|
engine.connectionsManager = NewConnectionsManager(engine.acn)
|
||||||
go engine.connectionsManager.AttemptReconnections()
|
|
||||||
|
|
||||||
// Init the Server running the Simple App.
|
// Init the Server running the Simple App.
|
||||||
engine.service = new(tor.BaseOnionService)
|
engine.service = new(tor.BaseOnionService)
|
||||||
|
|
Loading…
Reference in New Issue