package connections import ( "cwtch.im/cwtch/event" "cwtch.im/tapir" "cwtch.im/tapir/applications" "encoding/json" "git.openprivacy.ca/openprivacy/libricochet-go/log" ) // PeerApp encapsulates the behaviour of a Cwtch Peer type PeerApp struct { applications.AuthApp connection *tapir.Connection MessageHandler func(string, []byte) OnAcknowledgement func(string) OnAuth func(string) OnClose func(string) 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. } // NewInstance should always return a new instantiation of the application. func (pa PeerApp) NewInstance() tapir.Application { newApp := new(PeerApp) newApp.MessageHandler = pa.MessageHandler newApp.OnAcknowledgement = pa.OnAcknowledgement newApp.OnAuth = pa.OnAuth newApp.OnClose = pa.OnClose newApp.OnConnecting = pa.OnConnecting return newApp } // Init is run when the connection is first started. func (pa *PeerApp) Init(connection *tapir.Connection) { // First run the Authentication App pa.AuthApp.Init(connection) if connection.HasCapability(applications.AuthCapability) { pa.connection = connection pa.OnAuth(connection.Hostname) go pa.listen() } else { pa.OnClose(connection.Hostname) } } 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") pa.OnClose(pa.connection.Hostname) return } var peerMessage PeerMessage err := json.Unmarshal(message, &peerMessage) if err == nil { if peerMessage.Context == event.ContextAck { pa.OnAcknowledgement(peerMessage.ID) } else { pa.MessageHandler(pa.connection.Hostname, peerMessage.Data) } } else { log.Errorf("Error unmarshalling PeerMessage package: %x %v", message, err) } } } // 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) }