make engine a interface and private struct, private most methods

This commit is contained in:
Dan Ballard 2019-05-15 12:58:57 -07:00
parent 475073f9f6
commit 1e1cbe6cd8
5 changed files with 80 additions and 49 deletions

View File

@ -24,7 +24,7 @@ type cwtchPeer struct {
shutdown bool shutdown bool
started bool started bool
engine *connections.Engine engine connections.Engine
queue *event.Queue queue *event.Queue
eventBus *event.Manager eventBus *event.Manager
} }
@ -101,8 +101,8 @@ func (cp *cwtchPeer) Init(acn connectivity.ACN, eventBus *event.Manager) {
} }
// TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key. // TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
cp.engine = connections.NewProtocolEngine(cp.Profile.Ed25519PrivateKey, acn, eventBus, blockedPeers) identity := identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey)
cp.engine.Identity = identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey) cp.engine = connections.NewProtocolEngine(identity, cp.Profile.Ed25519PrivateKey, acn, eventBus, blockedPeers)
} }
// ImportGroup intializes a group from an imported source rather than a peer invite // ImportGroup intializes a group from an imported source rather than a peer invite

View File

@ -27,7 +27,7 @@ func NewConnectionsManager(acn connectivity.ACN) *Manager {
} }
// ManagePeerConnection creates a new PeerConnection for the given Host and Profile. // ManagePeerConnection creates a new PeerConnection for the given Host and Profile.
func (m *Manager) ManagePeerConnection(host string, engine *Engine) *PeerPeerConnection { func (m *Manager) ManagePeerConnection(host string, engine Engine) *PeerPeerConnection {
m.lock.Lock() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()

View File

@ -17,15 +17,13 @@ import (
"time" "time"
) )
// Engine (ProtocolEngine) encapsulates the logic necessary to make and receive Cwtch connections. type engine struct {
// Note: ProtocolEngine doesn't have access to any information necessary to encrypt or decrypt GroupMessages
type Engine struct {
queue *event.Queue queue *event.Queue
connectionsManager *Manager connectionsManager *Manager
// Engine Attributes // Engine Attributes
Identity identity.Identity identity identity.Identity
ACN connectivity.ACN acn connectivity.ACN
app *application.RicochetApplication app *application.RicochetApplication
@ -37,18 +35,39 @@ type Engine struct {
// Pointer to the Global Event Manager // Pointer to the Global Event Manager
eventManager *event.Manager eventManager *event.Manager
privateKey ed25519.PrivateKey
// Required for listen(), inaccessible from identity
privateKey ed25519.PrivateKey
}
// Engine (ProtocolEngine) encapsulates the logic necessary to make and receive Cwtch connections.
// Note: ProtocolEngine doesn't have access to any information necessary to encrypt or decrypt GroupMessages
type Engine interface {
Identity() identity.Identity
ACN() connectivity.ACN
GetPeerHandler(string) *CwtchPeerHandler
ContactRequest(string, string) string
LookupContact(string, rsa.PublicKey) (bool, bool)
LookupContactV3(string, ed25519.PublicKey) (bool, bool)
GetPeers() map[string]ConnectionState
GetServers() map[string]ConnectionState
Shutdown()
} }
// NewProtocolEngine initializes a new engine that runs Cwtch using the given parameters // NewProtocolEngine initializes a new engine that runs Cwtch using the given parameters
func NewProtocolEngine(privateKey ed25519.PrivateKey, acn connectivity.ACN, eventManager *event.Manager, blockedPeers []string) *Engine { func NewProtocolEngine(identity identity.Identity, privateKey ed25519.PrivateKey, acn connectivity.ACN, eventManager *event.Manager, blockedPeers []string) Engine {
engine := new(Engine) engine := new(engine)
engine.identity = identity
engine.privateKey = privateKey engine.privateKey = privateKey
engine.queue = event.NewEventQueue(100) engine.queue = event.NewEventQueue(100)
go engine.eventHandler() go engine.eventHandler()
engine.ACN = acn engine.acn = acn
engine.connectionsManager = NewConnectionsManager(engine.ACN) engine.connectionsManager = NewConnectionsManager(engine.acn)
go engine.connectionsManager.AttemptReconnections() go engine.connectionsManager.AttemptReconnections()
engine.eventManager = eventManager engine.eventManager = eventManager
@ -67,21 +86,29 @@ func NewProtocolEngine(privateKey ed25519.PrivateKey, acn connectivity.ACN, even
return engine return engine
} }
func (e *engine) ACN() connectivity.ACN {
return e.acn
}
func (e *engine) Identity() identity.Identity {
return e.identity
}
// eventHandler process events from other subsystems // eventHandler process events from other subsystems
func (e *Engine) eventHandler() { func (e *engine) eventHandler() {
for { for {
ev := e.queue.Next() ev := e.queue.Next()
switch ev.EventType { switch ev.EventType {
case event.StatusRequest: case event.StatusRequest:
e.eventManager.Publish(event.Event{EventType: event.ProtocolEngineStatus, EventID: ev.EventID}) e.eventManager.Publish(event.Event{EventType: event.ProtocolEngineStatus, EventID: ev.EventID})
case event.PeerRequest: case event.PeerRequest:
e.PeerWithOnion(ev.Data[event.RemotePeer]) e.peerWithOnion(ev.Data[event.RemotePeer])
case event.InvitePeerToGroup: case event.InvitePeerToGroup:
e.InviteOnionToGroup(ev.Data[event.RemotePeer], []byte(ev.Data[event.GroupInvite])) e.inviteOnionToGroup(ev.Data[event.RemotePeer], []byte(ev.Data[event.GroupInvite]))
case event.JoinServer: case event.JoinServer:
e.JoinServer(ev.Data[event.GroupServer]) e.joinServer(ev.Data[event.GroupServer])
case event.SendMessageToGroup: case event.SendMessageToGroup:
e.SendMessageToGroup(ev.Data[event.GroupServer], []byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature])) e.sendMessageToGroup(ev.Data[event.GroupServer], []byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature]))
case event.SendMessageToPeer: case event.SendMessageToPeer:
log.Debugf("Sending Message to Peer.....") log.Debugf("Sending Message to Peer.....")
ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(ev.Data[event.RemotePeer]) ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(ev.Data[event.RemotePeer])
@ -110,16 +137,16 @@ func (e *Engine) eventHandler() {
// GetPeerHandler is an external interface function that allows callers access to a CwtchPeerHandler // GetPeerHandler is an external interface function that allows callers access to a CwtchPeerHandler
// TODO: There is likely a slightly better way to encapsulate this behavior // TODO: There is likely a slightly better way to encapsulate this behavior
func (e *Engine) GetPeerHandler(remotePeerHostname string) *CwtchPeerHandler { func (e *engine) GetPeerHandler(remotePeerHostname string) *CwtchPeerHandler {
return &CwtchPeerHandler{Onion: remotePeerHostname, EventBus: e.eventManager} return &CwtchPeerHandler{Onion: remotePeerHostname, EventBus: e.eventManager}
} }
// Listen sets up an onion listener to process incoming cwtch messages // Listen sets up an onion listener to process incoming cwtch messages
func (e *Engine) listenFn() { func (e *engine) listenFn() {
ra := new(application.RicochetApplication) ra := new(application.RicochetApplication)
onionService, err := e.ACN.Listen(e.privateKey, application.RicochetPort) onionService, err := e.acn.Listen(e.privateKey, application.RicochetPort)
if err != nil /*&& fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision"*/ { if err != nil /*&& fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision"*/ {
e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.Identity.Hostname(), event.Error: err.Error()})) e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.identity.Hostname(), event.Error: err.Error()}))
return return
} }
@ -145,29 +172,29 @@ func (e *Engine) listenFn() {
} }
}) })
ra.Init(e.ACN, e.Identity.Name, e.Identity, af, e) ra.Init(e.ACN(), e.identity.Name, e.identity, af, e)
log.Infof("Running cwtch peer on %v", onionService.AddressFull()) log.Infof("Running cwtch peer on %v", onionService.AddressFull())
e.started = true e.started = true
e.app = ra e.app = ra
ra.Run(onionService) ra.Run(onionService)
e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.Identity.Hostname()})) e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.identity.Hostname()}))
return return
} }
// LookupContact is a V2 API Call, we want to reject all V2 Peers // LookupContact is a V2 API Call, we want to reject all V2 Peers
// TODO Deprecate // TODO Deprecate
func (e *Engine) LookupContact(hostname string, publicKey rsa.PublicKey) (allowed, known bool) { func (e *engine) LookupContact(hostname string, publicKey rsa.PublicKey) (allowed, known bool) {
return false, false return false, false
} }
// ContactRequest is a V2 API Call needed to implement ContactRequestHandler Interface // ContactRequest is a V2 API Call needed to implement ContactRequestHandler Interface
// TODO Deprecate // TODO Deprecate
func (e *Engine) ContactRequest(name string, message string) string { func (e *engine) ContactRequest(name string, message string) string {
return "Rejected" return "Rejected"
} }
// LookupContactV3 returns that a contact is known and allowed to communicate for all cases. // LookupContactV3 returns that a contact is known and allowed to communicate for all cases.
func (e *Engine) LookupContactV3(hostname string, publicKey ed25519.PublicKey) (allowed, known bool) { func (e *engine) LookupContactV3(hostname string, publicKey ed25519.PublicKey) (allowed, known bool) {
// TODO: We want to autoblock those that are blocked, The known parameter has no use anymore and should be // TODO: We want to autoblock those that are blocked, The known parameter has no use anymore and should be
// disregarded by peers, so we set it to false. // disregarded by peers, so we set it to false.
if _, blocked := e.blocked.Load(hostname); blocked { if _, blocked := e.blocked.Load(hostname); blocked {
@ -177,19 +204,19 @@ func (e *Engine) LookupContactV3(hostname string, publicKey ed25519.PublicKey) (
} }
// Shutdown tears down the eventHandler goroutine // Shutdown tears down the eventHandler goroutine
func (e *Engine) Shutdown() { func (e *engine) Shutdown() {
e.connectionsManager.Shutdown() e.connectionsManager.Shutdown()
e.app.Shutdown() e.app.Shutdown()
e.queue.Shutdown() e.queue.Shutdown()
} }
// PeerWithOnion is the entry point for cwtchPeer relationships // peerWithOnion is the entry point for cwtchPeer relationships
func (e *Engine) PeerWithOnion(onion string) *PeerPeerConnection { func (e *engine) peerWithOnion(onion string) *PeerPeerConnection {
return e.connectionsManager.ManagePeerConnection(onion, e) return e.connectionsManager.ManagePeerConnection(onion, e)
} }
// InviteOnionToGroup kicks off the invite process // inviteOnionToGroup kicks off the invite process
func (e *Engine) InviteOnionToGroup(onion string, invite []byte) error { func (e *engine) inviteOnionToGroup(onion string, invite []byte) error {
ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(onion) ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(onion)
if ppc == nil { if ppc == nil {
return errors.New("peer connection not setup for onion. peers must be trusted before sending") return errors.New("peer connection not setup for onion. peers must be trusted before sending")
@ -203,25 +230,25 @@ func (e *Engine) InviteOnionToGroup(onion string, invite []byte) error {
return nil return nil
} }
// ReceiveGroupMessage is a callback function that processes GroupMessages from a given server // receiveGroupMessage is a callback function that processes GroupMessages from a given server
func (e *Engine) ReceiveGroupMessage(server string, gm *protocol.GroupMessage) { func (e *engine) receiveGroupMessage(server string, gm *protocol.GroupMessage) {
// Publish Event so that a Profile Engine can deal with it. // Publish Event so that a Profile Engine can deal with it.
// Note: This technically means that *multiple* Profile Engines could listen to the same ProtocolEngine! // Note: This technically means that *multiple* Profile Engines could listen to the same ProtocolEngine!
e.eventManager.Publish(event.NewEvent(event.EncryptedGroupMessage, map[event.Field]string{event.Ciphertext: string(gm.GetCiphertext()), event.Signature: string(gm.GetSignature())})) e.eventManager.Publish(event.NewEvent(event.EncryptedGroupMessage, map[event.Field]string{event.Ciphertext: string(gm.GetCiphertext()), event.Signature: string(gm.GetSignature())}))
} }
// FinishedFetch is a callback function the processes the termination of a fetch channel from a given server // finishedFetch is a callback function the processes the termination of a fetch channel from a given server
func (e *Engine) FinishedFetch(server string) { func (e *engine) finishedFetch(server string) {
e.eventManager.Publish(event.NewEvent(event.FinishedFetch, map[event.Field]string{event.GroupServer: server})) e.eventManager.Publish(event.NewEvent(event.FinishedFetch, map[event.Field]string{event.GroupServer: server}))
} }
// JoinServer manages a new server connection with the given onion address // joinServer manages a new server connection with the given onion address
func (e *Engine) JoinServer(onion string) { func (e *engine) joinServer(onion string) {
e.connectionsManager.ManageServerConnection(onion, e.ReceiveGroupMessage, e.FinishedFetch) e.connectionsManager.ManageServerConnection(onion, e.receiveGroupMessage, e.finishedFetch)
} }
// SendMessageToGroup attempts to sent the given message to the given group id. // sendMessageToGroup attempts to sent the given message to the given group id.
func (e *Engine) SendMessageToGroup(server string, ct []byte, sig []byte) { func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) {
psc := e.connectionsManager.GetPeerServerConnectionForOnion(server) psc := e.connectionsManager.GetPeerServerConnectionForOnion(server)
if psc == nil { if psc == nil {
e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupServer: server, event.Signature: string(sig), event.Error: "server is offline or the connection has yet to finalize"})) e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupServer: server, event.Signature: string(sig), event.Error: "server is offline or the connection has yet to finalize"}))
@ -238,12 +265,12 @@ func (e *Engine) SendMessageToGroup(server string, ct []byte, sig []byte) {
} }
// GetPeers returns a list of peer connections. // GetPeers returns a list of peer connections.
func (e *Engine) GetPeers() map[string]ConnectionState { func (e *engine) GetPeers() map[string]ConnectionState {
return e.connectionsManager.GetPeers() return e.connectionsManager.GetPeers()
} }
// GetServers returns a list of server connections // GetServers returns a list of server connections
func (e *Engine) GetServers() map[string]ConnectionState { func (e *engine) GetServers() map[string]ConnectionState {
return e.connectionsManager.GetServers() return e.connectionsManager.GetServers()
} }

View File

@ -16,11 +16,11 @@ type PeerPeerConnection struct {
PeerHostname string PeerHostname string
state ConnectionState state ConnectionState
connection *connection.Connection connection *connection.Connection
protocolEngine *Engine protocolEngine Engine
} }
// NewPeerPeerConnection creates a new peer connection for the given hostname and profile. // NewPeerPeerConnection creates a new peer connection for the given hostname and profile.
func NewPeerPeerConnection(peerhostname string, protocolEngine *Engine) *PeerPeerConnection { func NewPeerPeerConnection(peerhostname string, protocolEngine Engine) *PeerPeerConnection {
ppc := new(PeerPeerConnection) ppc := new(PeerPeerConnection)
ppc.PeerHostname = peerhostname ppc.PeerHostname = peerhostname
ppc.protocolEngine = protocolEngine ppc.protocolEngine = protocolEngine
@ -79,11 +79,11 @@ func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
// Run manages the setup and teardown of a peer->peer connection // Run manages the setup and teardown of a peer->peer connection
func (ppc *PeerPeerConnection) Run() error { func (ppc *PeerPeerConnection) Run() error {
ppc.state = CONNECTING ppc.state = CONNECTING
rc, err := goricochet.Open(ppc.protocolEngine.ACN, ppc.PeerHostname) rc, err := goricochet.Open(ppc.protocolEngine.ACN(), ppc.PeerHostname)
if err == nil { if err == nil {
ppc.connection = rc ppc.connection = rc
ppc.state = CONNECTED ppc.state = CONNECTED
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(ppc.protocolEngine.Identity) _, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(ppc.protocolEngine.Identity())
if err == nil { if err == nil {
ppc.state = AUTHENTICATED ppc.state = AUTHENTICATED
go func() { go func() {

View File

@ -2,6 +2,7 @@ package connections
import ( import (
"crypto/rand" "crypto/rand"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model" "cwtch.im/cwtch/model"
"cwtch.im/cwtch/protocol" "cwtch.im/cwtch/protocol"
"cwtch.im/cwtch/protocol/connections/peer" "cwtch.im/cwtch/protocol/connections/peer"
@ -60,7 +61,10 @@ func TestPeerPeerConnection(t *testing.T) {
profile := model.GenerateNewProfile("alice") profile := model.GenerateNewProfile("alice")
hostname := identity.Hostname() hostname := identity.Hostname()
ppc := NewPeerPeerConnection("127.0.0.1:5452|"+hostname, &Engine{ACN: connectivity.LocalProvider(), Identity: identity}) manager := &event.Manager{}
manager.Initialize()
engine := NewProtocolEngine(identity, priv, connectivity.LocalProvider(), manager, nil)
ppc := NewPeerPeerConnection("127.0.0.1:5452|"+hostname, engine)
tp := new(TestPeer) tp := new(TestPeer)
tp.Init() tp.Init()