cwtch/peer/connections/peerpeerconnection.go

156 lines
4.7 KiB
Go
Raw Normal View History

package connections
import (
2018-06-29 19:20:07 +00:00
"cwtch.im/cwtch/model"
2018-05-28 18:05:06 +00:00
"cwtch.im/cwtch/peer/peer"
"cwtch.im/cwtch/protocol"
2018-06-23 16:15:36 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go"
2018-10-29 19:19:30 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/application"
2018-06-23 16:15:36 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
2018-06-23 16:15:36 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
2018-12-04 02:52:11 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/log"
2018-03-14 22:23:35 +00:00
"time"
)
2018-10-06 03:50:55 +00:00
// PeerPeerConnection encapsulates a single outgoing cwtchPeer->cwtchPeer connection
type PeerPeerConnection struct {
connection.AutoConnectionHandler
PeerHostname string
state ConnectionState
2018-05-20 18:29:46 +00:00
connection *connection.Connection
2018-03-14 22:23:35 +00:00
profile *model.Profile
2018-10-04 19:15:03 +00:00
dataHandler func(string, []byte) []byte
aif application.ApplicationInstanceFactory
2018-11-22 18:01:04 +00:00
acn connectivity.ACN
}
// NewPeerPeerConnection creates a new peer connection for the given hostname and profile.
2018-11-22 18:01:04 +00:00
func NewPeerPeerConnection(acn connectivity.ACN, peerhostname string, profile *model.Profile, dataHandler func(string, []byte) []byte, aif application.ApplicationInstanceFactory) *PeerPeerConnection {
ppc := new(PeerPeerConnection)
2018-11-22 18:01:04 +00:00
ppc.acn = acn
ppc.PeerHostname = peerhostname
2018-03-11 19:05:35 +00:00
ppc.profile = profile
2018-10-04 19:15:03 +00:00
ppc.dataHandler = dataHandler
ppc.aif = aif
ppc.Init()
return ppc
}
// GetState returns the current connection state
func (ppc *PeerPeerConnection) GetState() ConnectionState {
return ppc.state
}
// HandleGroupInvite passes the given group invite tothe profile
2018-03-12 18:43:51 +00:00
func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite) {
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
2018-03-12 18:43:51 +00:00
}
2018-10-04 19:15:03 +00:00
// HandlePacket handles data packets on the optional data channel
func (ppc *PeerPeerConnection) HandlePacket(data []byte) []byte {
return ppc.dataHandler(ppc.PeerHostname, data)
}
// SendPacket sends data packets on the optional data channel
func (ppc *PeerPeerConnection) SendPacket(data []byte) {
ppc.WaitTilAuthenticated()
ppc.connection.Do(func() error {
channel := ppc.connection.Channel("im.cwtch.peer.data", channels.Outbound)
if channel != nil {
peerchannel, ok := channel.Handler.(*peer.CwtchPeerDataChannel)
if ok {
2018-12-04 02:52:11 +00:00
log.Debugf("Sending packet\n")
2018-10-04 19:15:03 +00:00
peerchannel.SendMessage(data)
}
}
return nil
})
}
2018-10-29 19:19:30 +00:00
// DoOnChannel performs an operation on the requested channel
func (ppc *PeerPeerConnection) DoOnChannel(ctype string, direction channels.Direction, doSomethingWith func(channel *channels.Channel)) {
ppc.WaitTilAuthenticated()
ppc.connection.Do(func() error {
channel := ppc.connection.Channel(ctype, direction)
if channel != nil {
doSomethingWith(channel)
}
return nil
})
}
// SendGroupInvite sends the given serialized invite packet to the Peer
2018-03-12 18:43:51 +00:00
func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) {
2018-10-04 19:15:03 +00:00
ppc.WaitTilAuthenticated()
2018-03-14 22:23:35 +00:00
ppc.connection.Do(func() error {
channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound)
if channel != nil {
peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel)
if ok {
2018-12-04 02:52:11 +00:00
log.Debugf("Sending group invite packet\n")
2018-03-14 22:23:35 +00:00
peerchannel.SendMessage(invite)
}
}
return nil
})
2018-03-11 19:05:35 +00:00
}
2018-10-04 19:15:03 +00:00
// WaitTilAuthenticated waits until the underlying connection is authenticated
func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
for {
if ppc.GetState() == AUTHENTICATED {
break
}
time.Sleep(time.Second * 1)
2018-10-04 19:15:03 +00:00
}
}
// Run manages the setup and teardown of a peer->peer connection
func (ppc *PeerPeerConnection) Run() error {
ppc.state = CONNECTING
2018-11-22 18:01:04 +00:00
rc, err := goricochet.Open(ppc.acn, ppc.PeerHostname)
if err == nil {
2018-05-20 18:29:46 +00:00
ppc.connection = rc
ppc.state = CONNECTED
2018-10-05 03:18:34 +00:00
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(identity.InitializeV3(ppc.profile.Name, &ppc.profile.Ed25519PrivateKey, &ppc.profile.Ed25519PublicKey))
2018-03-11 19:05:35 +00:00
if err == nil {
ppc.state = AUTHENTICATED
go func() {
ppc.connection.Do(func() error {
ppc.connection.RequestOpenChannel("im.cwtch.peer", &peer.CwtchPeerChannel{Handler: ppc})
return nil
})
2018-10-04 19:15:03 +00:00
if ppc.dataHandler != nil {
ppc.connection.Do(func() error {
ppc.connection.RequestOpenChannel("im.cwtch.peer.data", &peer.CwtchPeerDataChannel{Handler: ppc})
return nil
})
}
handlers := ppc.aif.GetHandlers()
for i := range handlers {
ppc.connection.Do(func() error {
ppc.connection.RequestOpenChannel(handlers[i], ppc.aif.GetHandler(handlers[i])(ppc.aif.GetApplicationInstance(ppc.connection))())
return nil
})
}
2018-03-11 19:05:35 +00:00
}()
ppc.connection.Process(ppc)
}
}
ppc.state = FAILED
return err
}
// Close closes the connection
func (ppc *PeerPeerConnection) Close() {
ppc.state = KILLED
if ppc.connection != nil {
ppc.connection.Conn.Close()
}
}