cwtch/protocol/connections/peerapp.go

96 lines
2.7 KiB
Go
Raw Normal View History

2019-07-17 19:10:52 +00:00
package connections
import (
2019-07-23 17:57:04 +00:00
"cwtch.im/cwtch/event"
2019-07-17 19:10:52 +00:00
"cwtch.im/tapir"
"cwtch.im/tapir/applications"
"encoding/json"
2019-07-17 19:10:52 +00:00
"git.openprivacy.ca/openprivacy/libricochet-go/log"
)
// PeerApp encapsulates the behaviour of a Cwtch Peer
type PeerApp struct {
applications.AuthApp
2019-08-08 18:39:38 +00:00
connection tapir.Connection
2019-07-30 23:47:12 +00:00
MessageHandler func(string, string, []byte)
IsBlocked func(string) bool
2019-07-29 20:21:58 +00:00
OnAcknowledgement func(string, string)
OnAuth func(string)
OnClose func(string)
2019-07-23 17:57:04 +00:00
OnConnecting func(string)
}
// PeerMessage is an encapsulation that can be used by higher level applications
type PeerMessage struct {
ID string // A unique Message ID (primarily used for acknowledgments)
Context string // A unique context identifier i.e. im.cwtch.chat
Data []byte // The serialized data packet.
2019-07-17 19:10:52 +00:00
}
// NewInstance should always return a new instantiation of the application.
func (pa PeerApp) NewInstance() tapir.Application {
newApp := new(PeerApp)
newApp.MessageHandler = pa.MessageHandler
newApp.IsBlocked = pa.IsBlocked
2019-07-23 17:57:04 +00:00
newApp.OnAcknowledgement = pa.OnAcknowledgement
2019-07-17 19:10:52 +00:00
newApp.OnAuth = pa.OnAuth
newApp.OnClose = pa.OnClose
2019-07-23 17:57:04 +00:00
newApp.OnConnecting = pa.OnConnecting
2019-07-17 19:10:52 +00:00
return newApp
}
// Init is run when the connection is first started.
2019-08-08 18:39:38 +00:00
func (pa *PeerApp) Init(connection tapir.Connection) {
2019-07-23 17:57:04 +00:00
2019-07-17 19:10:52 +00:00
// First run the Authentication App
pa.AuthApp.Init(connection)
if connection.HasCapability(applications.AuthCapability) {
2019-07-17 19:10:52 +00:00
pa.connection = connection
2019-08-08 18:39:38 +00:00
if pa.IsBlocked(connection.Hostname()) {
pa.connection.Close()
2019-08-08 18:39:38 +00:00
pa.OnClose(connection.Hostname())
} else {
2019-08-08 18:39:38 +00:00
pa.OnAuth(connection.Hostname())
go pa.listen()
}
2019-07-17 19:10:52 +00:00
} else {
2019-08-08 18:39:38 +00:00
pa.OnClose(connection.Hostname())
2019-07-17 19:10:52 +00:00
}
}
func (pa PeerApp) listen() {
for {
message := pa.connection.Expect()
if len(message) == 0 {
log.Errorf("0 byte read, socket has likely failed. Closing the listen goroutine")
2019-08-08 18:39:38 +00:00
pa.OnClose(pa.connection.Hostname())
2019-07-17 19:10:52 +00:00
return
}
var peerMessage PeerMessage
err := json.Unmarshal(message, &peerMessage)
if err == nil {
2019-07-23 17:57:04 +00:00
if peerMessage.Context == event.ContextAck {
2019-08-08 18:39:38 +00:00
pa.OnAcknowledgement(pa.connection.Hostname(), peerMessage.ID)
} else {
2019-08-08 18:39:38 +00:00
pa.MessageHandler(pa.connection.Hostname(), peerMessage.Context, peerMessage.Data)
2019-07-30 23:47:12 +00:00
// Acknowledge the message
// TODO Should this be in the ui?
pa.SendMessage(PeerMessage{peerMessage.ID, event.ContextAck, []byte{}})
}
} else {
log.Errorf("Error unmarshalling PeerMessage package: %x %v", message, err)
}
2019-07-17 19:10:52 +00:00
}
}
// SendMessage sends the peer a preformatted message
// NOTE: This is a stub, we will likely want to extend this to better reflect the desired protocol
func (pa PeerApp) SendMessage(message PeerMessage) {
serialized, _ := json.Marshal(message)
pa.connection.Send(serialized)
2019-07-17 19:10:52 +00:00
}