|
|
|
@ -8,7 +8,6 @@ import (
|
|
|
|
|
model3 "cwtch.im/cwtch/protocol/model"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"git.openprivacy.ca/cwtch.im/tapir"
|
|
|
|
|
"git.openprivacy.ca/cwtch.im/tapir/applications"
|
|
|
|
|
"git.openprivacy.ca/cwtch.im/tapir/networks/tor"
|
|
|
|
@ -135,7 +134,10 @@ func (e *engine) eventHandler() {
|
|
|
|
|
go e.peerWithOnion(ev.Data[event.RemotePeer])
|
|
|
|
|
}
|
|
|
|
|
case event.InvitePeerToGroup:
|
|
|
|
|
e.sendMessageToPeer(ev.EventID, ev.Data[event.RemotePeer], event.ContextInvite, []byte(ev.Data[event.GroupInvite]))
|
|
|
|
|
err := e.sendPeerMessage(ev.Data[event.RemotePeer], model3.PeerMessage{ID: ev.EventID, Context: event.ContextInvite, Data: []byte(ev.Data[event.GroupInvite])})
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
case event.JoinServer:
|
|
|
|
|
signature, err := base64.StdEncoding.DecodeString(ev.Data[event.Signature])
|
|
|
|
|
if err != nil {
|
|
|
|
@ -162,14 +164,17 @@ func (e *engine) eventHandler() {
|
|
|
|
|
if !ok {
|
|
|
|
|
context = event.ContextRaw
|
|
|
|
|
}
|
|
|
|
|
err := e.sendMessageToPeer(ev.EventID, ev.Data[event.RemotePeer], context, []byte(ev.Data[event.Data]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err := e.sendPeerMessage(ev.Data[event.RemotePeer], model3.PeerMessage{ID: ev.EventID, Context: context, Data: []byte(ev.Data[event.Data])}); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: "peer is offline or the connection has yet to finalize"}))
|
|
|
|
|
}
|
|
|
|
|
case event.SendGetValMessageToPeer:
|
|
|
|
|
e.sendGetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Scope], ev.Data[event.Path])
|
|
|
|
|
if err := e.sendGetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Scope], ev.Data[event.Path]); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
case event.SendRetValMessageToPeer:
|
|
|
|
|
e.sendRetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Data], ev.Data[event.Exists])
|
|
|
|
|
if err := e.sendRetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Data], ev.Data[event.Exists]); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
case event.SetPeerAuthorization:
|
|
|
|
|
auth := model.Authorization(ev.Data[event.Authorization])
|
|
|
|
|
e.authorizations.Store(ev.Data[event.RemotePeer], auth)
|
|
|
|
@ -197,13 +202,20 @@ func (e *engine) eventHandler() {
|
|
|
|
|
handle := ev.Data[event.Handle]
|
|
|
|
|
key := ev.Data[event.FileKey]
|
|
|
|
|
size, _ := strconv.Atoi(ev.Data[event.ManifestSize])
|
|
|
|
|
go e.sendPeerMessage(handle, e.filesharingSubSystem.FetchManifest(key, uint64(size)))
|
|
|
|
|
if err := e.sendPeerMessage(handle, e.filesharingSubSystem.FetchManifest(key, uint64(size))); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
case event.ManifestSaved:
|
|
|
|
|
handle := ev.Data[event.Handle]
|
|
|
|
|
key := ev.Data[event.FileKey]
|
|
|
|
|
serializedManifest := ev.Data[event.SerializedManifest]
|
|
|
|
|
// NOTE: for now there will probably only ever be a single chunk request. When we enable group
|
|
|
|
|
// sharing and rehosting then this loop will serve as a a way of splitting the request among multiple
|
|
|
|
|
// contacts
|
|
|
|
|
for _, message := range e.filesharingSubSystem.CompileChunkRequests(key, serializedManifest) {
|
|
|
|
|
go e.sendPeerMessage(handle, message)
|
|
|
|
|
if err := e.sendPeerMessage(handle, message); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return
|
|
|
|
@ -211,7 +223,6 @@ func (e *engine) eventHandler() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (e *engine) isBlocked(onion string) bool {
|
|
|
|
|
authorization, known := e.authorizations.Load(onion)
|
|
|
|
|
if !known {
|
|
|
|
@ -429,20 +440,6 @@ func (e *engine) peerDisconnected(onion string) {
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sendMessageToPeer sends a message to a peer under a given context
|
|
|
|
|
func (e *engine) sendMessageToPeer(eventID string, onion string, context string, message []byte) error {
|
|
|
|
|
conn, err := e.service.WaitForCapabilityOrClose(onion, cwtchCapability)
|
|
|
|
|
if err == nil {
|
|
|
|
|
peerApp, ok := (conn.App()).(*PeerApp)
|
|
|
|
|
if ok {
|
|
|
|
|
peerApp.SendMessage(model3.PeerMessage{ID: eventID, Context: context, Data: message})
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return errors.New("failed type assertion conn.App != PeerApp")
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *engine) sendGetValToPeer(eventID, onion, scope, path string) error {
|
|
|
|
|
log.Debugf("sendGetValMessage to peer %v %v.%v\n", onion, scope, path)
|
|
|
|
|
getVal := peerGetVal{Scope: scope, Path: path}
|
|
|
|
@ -450,7 +447,7 @@ func (e *engine) sendGetValToPeer(eventID, onion, scope, path string) error {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return e.sendMessageToPeer(eventID, onion, event.ContextGetVal, message)
|
|
|
|
|
return e.sendPeerMessage(onion, model3.PeerMessage{ID: eventID, Context: event.ContextGetVal, Data: message})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *engine) sendRetValToPeer(eventID, onion, val, existsStr string) error {
|
|
|
|
@ -461,7 +458,7 @@ func (e *engine) sendRetValToPeer(eventID, onion, val, existsStr string) error {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return e.sendMessageToPeer(eventID, onion, event.ContextRetVal, message)
|
|
|
|
|
return e.sendPeerMessage(onion, model3.PeerMessage{ID: eventID, Context: event.ContextRetVal, Data: message})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *engine) deleteConnection(id string) {
|
|
|
|
@ -501,7 +498,7 @@ func (e *engine) sendMessageToGroup(groupID string, server string, ct []byte, si
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupID: groupID, event.GroupServer: server, event.Error: err.Error(), event.Signature: base64.StdEncoding.EncodeToString(sig)}))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Broadast the token error
|
|
|
|
|
// Broadcast the token error
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupID: groupID, event.GroupServer: server, event.Error: err.Error(), event.Signature: base64.StdEncoding.EncodeToString(sig)}))
|
|
|
|
|
}
|
|
|
|
|
} else if numtokens < 5 {
|
|
|
|
@ -526,7 +523,9 @@ func (e *engine) handlePeerMessage(hostname string, eventID string, context stri
|
|
|
|
|
}
|
|
|
|
|
} else if context == event.ContextRequestManifest {
|
|
|
|
|
for _, message := range e.filesharingSubSystem.RequestManifestParts(eventID) {
|
|
|
|
|
e.sendPeerMessage(hostname, message)
|
|
|
|
|
if err := e.sendPeerMessage(hostname, message); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: hostname, event.EventID: eventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if context == event.ContextSendManifest {
|
|
|
|
|
if fileKey, manifest := e.filesharingSubSystem.ReceiveManifestPart(eventID, message); len(manifest) != 0 {
|
|
|
|
@ -535,7 +534,9 @@ func (e *engine) handlePeerMessage(hostname string, eventID string, context stri
|
|
|
|
|
}
|
|
|
|
|
} else if context == event.ContextRequestFile {
|
|
|
|
|
for _, message := range e.filesharingSubSystem.ProcessChunkRequest(eventID, message) {
|
|
|
|
|
e.sendPeerMessage(hostname, message)
|
|
|
|
|
if err := e.sendPeerMessage(hostname, message); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: hostname, event.EventID: eventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if context == event.ContextSendFile {
|
|
|
|
|
fileKey, downloaded, progress, totalChunks, _ := e.filesharingSubSystem.ProcessChunk(eventID, message)
|
|
|
|
@ -547,7 +548,14 @@ func (e *engine) handlePeerMessage(hostname string, eventID string, context stri
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.FileDownloadProgressUpdate, map[event.Field]string{event.FileKey: fileKey, event.Progress: strconv.Itoa(int(progress)), event.FileSizeInChunks: strconv.Itoa(int(totalChunks))}))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Fall through handler for the default text conversation.
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.NewMessageFromPeer, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.Data: string(message)}))
|
|
|
|
|
|
|
|
|
|
// Send an explicit acknowledgement
|
|
|
|
|
// Every other protocol should have a explicit acknowledgement message e.g. value lookups have responses, and file handling has an explicit flow
|
|
|
|
|
if err := e.sendPeerMessage(hostname, model3.PeerMessage{ID: eventID, Context: event.ContextAck, Data: []byte{}}); err != nil {
|
|
|
|
|
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: hostname, event.EventID: eventID, event.Error: err.Error()}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -578,12 +586,15 @@ func (e *engine) leaveServer(server string) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *engine) sendPeerMessage(handle string, message model3.PeerMessage) {
|
|
|
|
|
func (e *engine) sendPeerMessage(handle string, message model3.PeerMessage) error {
|
|
|
|
|
conn, err := e.service.WaitForCapabilityOrClose(handle, cwtchCapability)
|
|
|
|
|
if err == nil {
|
|
|
|
|
peerApp, ok := (conn.App()).(*PeerApp)
|
|
|
|
|
if ok {
|
|
|
|
|
peerApp.SendMessage(message)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.Errorf("could not send peer message: %v", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|