2021-03-04 23:57:48 +00:00
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cwtch.im/cwtch/app"
|
|
|
|
"cwtch.im/cwtch/app/plugins"
|
|
|
|
"cwtch.im/cwtch/model"
|
|
|
|
"cwtch.im/cwtch/model/attr"
|
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
|
|
|
"encoding/json"
|
|
|
|
"git.openprivacy.ca/flutter/libcwtch-go/constants"
|
2021-03-12 12:24:37 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
2021-03-04 23:57:48 +00:00
|
|
|
)
|
|
|
|
import "cwtch.im/cwtch/event"
|
|
|
|
|
|
|
|
type EventProfileEnvelope struct {
|
2021-03-12 12:24:37 +00:00
|
|
|
Event event.Event
|
|
|
|
Profile string
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type EventHandler struct {
|
2021-03-05 00:14:58 +00:00
|
|
|
app app.Application
|
|
|
|
appBusQueue event.Queue
|
2021-03-04 23:57:48 +00:00
|
|
|
profileEvents chan EventProfileEnvelope
|
|
|
|
|
|
|
|
profileQueues map[string]event.Queue
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEventHandler(application app.Application) *EventHandler {
|
|
|
|
appBusQueue := event.NewQueue()
|
|
|
|
application.GetPrimaryBus().Subscribe(event.NewPeer, appBusQueue)
|
|
|
|
application.GetPrimaryBus().Subscribe(event.PeerError, appBusQueue)
|
|
|
|
application.GetPrimaryBus().Subscribe(event.AppError, appBusQueue)
|
|
|
|
application.GetPrimaryBus().Subscribe(event.ACNStatus, appBusQueue)
|
|
|
|
application.GetPrimaryBus().Subscribe(event.ReloadDone, appBusQueue)
|
|
|
|
application.GetPrimaryBus().Subscribe(event.ACNVersion, appBusQueue)
|
2021-03-10 17:41:09 +00:00
|
|
|
application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, appBusQueue)
|
2021-03-09 00:53:49 +00:00
|
|
|
return &EventHandler{app: application, appBusQueue: appBusQueue, profileQueues: make(map[string]event.Queue), profileEvents: make(chan EventProfileEnvelope)}
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (eh *EventHandler) GetNextEvent() string {
|
|
|
|
appChan := eh.appBusQueue.OutChan()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case e := <-appChan:
|
|
|
|
return eh.handleAppBusEvent(&e)
|
|
|
|
case ev := <-eh.profileEvents:
|
|
|
|
return eh.handleProfileEvent(&ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleAppBusEvent enriches AppBus events so they are usable with out further data fetches
|
|
|
|
func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
|
|
|
|
switch e.EventType {
|
|
|
|
case event.NewPeer:
|
|
|
|
onion := e.Data[event.Identity]
|
|
|
|
profile := eh.app.GetPeer(e.Data[event.Identity])
|
|
|
|
|
|
|
|
eh.startHandlingPeer(onion)
|
|
|
|
|
|
|
|
if e.Data[event.Created] == event.True {
|
|
|
|
profile.SetAttribute(attr.GetPublicScope(constants.Name), profile.GetName())
|
|
|
|
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
|
|
|
|
}
|
|
|
|
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
|
|
|
|
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
|
|
|
|
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
|
|
|
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
|
|
|
}
|
|
|
|
|
|
|
|
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
|
|
|
|
if !exists {
|
|
|
|
nick = onion
|
|
|
|
}
|
|
|
|
|
|
|
|
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
|
|
|
|
if !ok {
|
|
|
|
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
|
|
|
|
}
|
|
|
|
pic, err := StringToImage(picVal)
|
|
|
|
if err != nil {
|
|
|
|
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
|
|
|
|
}
|
|
|
|
picPath := GetPicturePath(pic)
|
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
//tag, _ := profile.GetAttribute(app.AttributeTag)
|
2021-03-04 23:57:48 +00:00
|
|
|
|
|
|
|
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
|
|
|
|
|
|
|
|
e.Data[constants.Name] = nick
|
|
|
|
e.Data[constants.Picture] = picPath
|
|
|
|
e.Data["Online"] = online
|
2021-03-12 12:24:37 +00:00
|
|
|
|
|
|
|
var contacts []Contact
|
|
|
|
for _, contact := range profile.GetContacts() {
|
2021-03-15 22:24:49 +00:00
|
|
|
if profile.GetContact(contact).IsServer() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-03-12 12:24:37 +00:00
|
|
|
cpicVal, ok := profile.GetContactAttribute(contact, attr.GetPeerScope(constants.Picture))
|
|
|
|
if !ok {
|
|
|
|
cpicVal = ImageToString(NewImage(RandomProfileImage(contact), TypeImageDistro))
|
|
|
|
}
|
|
|
|
cpic, err := StringToImage(cpicVal)
|
|
|
|
if err != nil {
|
|
|
|
cpic = NewImage(RandomProfileImage(contact), TypeImageDistro)
|
|
|
|
}
|
|
|
|
cpicPath := GetPicturePath(cpic)
|
|
|
|
contactInfo := profile.GetContact(contact)
|
2021-03-17 21:46:51 +00:00
|
|
|
name, _ := contactInfo.GetAttribute(attr.GetLocalScope(constants.Name))
|
|
|
|
contacts = append(contacts, Contact{Name: name, Onion: contactInfo.Onion, Status: contactInfo.State, Picture: cpicPath, Authorization: string(contactInfo.Authorization)})
|
2021-03-12 12:24:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bytes, _ := json.Marshal(contacts)
|
|
|
|
e.Data["ContactsJson"] = string(bytes)
|
|
|
|
log.Infof("contactsJson %v", e.Data["ContactsJson"])
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
json, _ := json.Marshal(e)
|
|
|
|
return string(json)
|
|
|
|
}
|
|
|
|
|
2021-03-12 12:24:37 +00:00
|
|
|
// handleProfileEvent enriches Profile events so they are usable with out further data fetches
|
2021-03-04 23:57:48 +00:00
|
|
|
func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
|
|
|
|
|
2021-03-12 12:24:37 +00:00
|
|
|
peer := eh.app.GetPeer(ev.Profile)
|
2021-03-04 23:57:48 +00:00
|
|
|
ph := NewPeerHelper(peer)
|
|
|
|
|
2021-03-12 12:24:37 +00:00
|
|
|
switch ev.Event.EventType {
|
2021-03-04 23:57:48 +00:00
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
/*case event.NetworkStatus:
|
2021-03-05 00:14:58 +00:00
|
|
|
online, _ := peer.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
|
2021-03-16 20:16:45 +00:00
|
|
|
if e.Data[event.Status] == plugins.NetworkCheckSuccess && online == event.False {
|
|
|
|
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.True)
|
2021-03-05 00:14:58 +00:00
|
|
|
uiManager.UpdateNetworkStatus(true)
|
|
|
|
// TODO we may have to reinitialize the peer
|
2021-03-16 20:16:45 +00:00
|
|
|
} else if e.Data[event.Status] == plugins.NetworkCheckError && online == event.True {
|
|
|
|
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
|
2021-03-05 00:14:58 +00:00
|
|
|
uiManager.UpdateNetworkStatus(false)
|
|
|
|
}*/
|
2021-03-04 23:57:48 +00:00
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
2021-03-04 23:57:48 +00:00
|
|
|
// I Don't think we need to enrich
|
|
|
|
|
|
|
|
// TODO: deprecate and move to dart
|
|
|
|
/*func (p *PeerHelper) updateLastReadTime(id string) {
|
|
|
|
lastRead, _ := time.Now().MarshalText()
|
|
|
|
if p.IsGroup(id) {
|
|
|
|
p.peer.SetGroupAttribute(id, attr.GetLocalScope(constants.LastRead), string(lastRead))
|
|
|
|
} else {
|
|
|
|
p.peer.SetContactAttribute(id, attr.GetLocalScope(constants.LastRead), string(lastRead))
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
// legacy
|
2021-03-16 20:16:45 +00:00
|
|
|
//ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
2021-03-04 23:57:48 +00:00
|
|
|
|
|
|
|
case event.PeerAcknowledgement:
|
|
|
|
// No enrichement required
|
2021-03-16 20:16:45 +00:00
|
|
|
//Acknowledge(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.EventID])
|
2021-03-04 23:57:48 +00:00
|
|
|
/*
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
|
|
|
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
|
|
|
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true)
|
2021-03-05 00:14:58 +00:00
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.NewGroupInvite:
|
|
|
|
gid, err := peer.ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
2021-03-05 00:14:58 +00:00
|
|
|
group := peer.GetGroup(gid)
|
|
|
|
if err == nil && group != nil {
|
|
|
|
uiManager.AddContact(gid)
|
|
|
|
}
|
|
|
|
*/
|
2021-03-04 23:57:48 +00:00
|
|
|
case event.PeerCreated:
|
2021-03-12 12:24:37 +00:00
|
|
|
handle := ev.Event.Data[event.RemotePeer]
|
2021-03-04 23:57:48 +00:00
|
|
|
err := EnrichNewPeer(handle, ph, ev)
|
|
|
|
if err != nil {
|
2021-03-05 00:18:15 +00:00
|
|
|
return ""
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
/*
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.SendMessageToGroupError:
|
|
|
|
uiManager.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error])
|
|
|
|
case event.SendMessageToPeerError:
|
2021-03-16 20:44:20 +00:00
|
|
|
uiManager.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error])
|
2021-03-04 23:57:48 +00:00
|
|
|
*/
|
|
|
|
case event.PeerStateChange:
|
2021-03-12 12:24:37 +00:00
|
|
|
cxnState := connections.ConnectionStateToType[ev.Event.Data[event.ConnectionState]]
|
|
|
|
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
|
2021-03-04 23:57:48 +00:00
|
|
|
|
2021-03-05 00:18:15 +00:00
|
|
|
if cxnState == connections.AUTHENTICATED && contact == nil {
|
2021-03-16 20:16:45 +00:00
|
|
|
// Contact does not exist, change event to NewPeer
|
2021-03-12 12:24:37 +00:00
|
|
|
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
|
|
|
|
contact = peer.GetContact(ev.Event.Data[event.RemotePeer])
|
|
|
|
ev.Event.EventType = event.PeerCreated
|
|
|
|
err := EnrichNewPeer(ev.Event.Data[event.RemotePeer], ph, ev)
|
2021-03-05 00:18:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-04 23:57:48 +00:00
|
|
|
if contact != nil {
|
|
|
|
// No enrichment needed
|
|
|
|
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
|
|
|
if cxnState == connections.AUTHENTICATED {
|
|
|
|
// if known and authed, get vars
|
2021-03-12 12:24:37 +00:00
|
|
|
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
|
|
|
|
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
/*case event.NewRetValMessageFromPeer:
|
|
|
|
onion := e.Data[event.RemotePeer]
|
|
|
|
scope := e.Data[event.Scope]
|
|
|
|
path := e.Data[event.Path]
|
|
|
|
val := e.Data[event.Data]
|
|
|
|
exists, _ := strconv.ParseBool(e.Data[event.Exists])
|
2021-03-05 00:14:58 +00:00
|
|
|
|
|
|
|
if exists && scope == attr.PublicScope {
|
|
|
|
switch path {
|
|
|
|
case constants.Name:
|
|
|
|
peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Name), val)
|
|
|
|
uiManager.UpdateContactDisplayName(onion)
|
|
|
|
case constants.Picture:
|
|
|
|
peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Picture), val)
|
|
|
|
uiManager.UpdateContactPicture(onion)
|
|
|
|
}
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.ServerStateChange:
|
|
|
|
serverOnion := e.Data[event.GroupServer]
|
|
|
|
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
2021-03-05 00:14:58 +00:00
|
|
|
groups := peer.GetGroups()
|
|
|
|
for _, groupID := range groups {
|
|
|
|
group := peer.GetGroup(groupID)
|
|
|
|
if group != nil && group.GroupServer == serverOnion {
|
2021-03-16 20:16:45 +00:00
|
|
|
group.State = e.Data[event.ConnectionState]
|
2021-03-05 00:14:58 +00:00
|
|
|
loading := false
|
|
|
|
if state == connections.AUTHENTICATED {
|
|
|
|
loading = true
|
|
|
|
}
|
|
|
|
uiManager.UpdateContactStatus(groupID, int(state), loading)
|
|
|
|
uiManager.UpdateContactStatus(serverOnion, int(state), loading)
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-16 20:16:45 +00:00
|
|
|
case event.DeletePeer:
|
2021-03-05 00:14:58 +00:00
|
|
|
log.Infof("PeerHandler got DeletePeer, SHUTTING down!\n")
|
|
|
|
uiManager.ReloadProfiles()
|
|
|
|
return
|
|
|
|
*/
|
2021-03-04 23:57:48 +00:00
|
|
|
}
|
|
|
|
|
2021-03-16 22:16:04 +00:00
|
|
|
json, _ := json.Marshal(unwrap(ev))
|
2021-03-04 23:57:48 +00:00
|
|
|
return string(json)
|
|
|
|
}
|
|
|
|
|
2021-03-16 22:16:04 +00:00
|
|
|
func unwrap(original *EventProfileEnvelope) *event.Event {
|
2021-03-16 22:05:44 +00:00
|
|
|
unwrapped := &original.Event
|
|
|
|
unwrapped.Data["ProfileOnion"] = original.Profile
|
|
|
|
return unwrapped
|
|
|
|
}
|
|
|
|
|
2021-03-04 23:57:48 +00:00
|
|
|
func (eh *EventHandler) startHandlingPeer(onion string) {
|
|
|
|
eventBus := eh.app.GetEventBus(onion)
|
|
|
|
q := event.NewQueue()
|
|
|
|
eventBus.Subscribe(event.NewMessageFromPeer, q)
|
|
|
|
eventBus.Subscribe(event.PeerAcknowledgement, q)
|
|
|
|
eventBus.Subscribe(event.NewMessageFromGroup, q)
|
|
|
|
eventBus.Subscribe(event.NewGroupInvite, q)
|
|
|
|
eventBus.Subscribe(event.SendMessageToGroupError, q)
|
|
|
|
eventBus.Subscribe(event.SendMessageToPeerError, q)
|
|
|
|
eventBus.Subscribe(event.ServerStateChange, q)
|
|
|
|
eventBus.Subscribe(event.PeerStateChange, q)
|
|
|
|
eventBus.Subscribe(event.PeerCreated, q)
|
|
|
|
eventBus.Subscribe(event.NetworkStatus, q)
|
|
|
|
eventBus.Subscribe(event.ChangePasswordSuccess, q)
|
|
|
|
eventBus.Subscribe(event.ChangePasswordError, q)
|
|
|
|
eventBus.Subscribe(event.NewRetValMessageFromPeer, q)
|
|
|
|
|
|
|
|
eh.profileQueues[onion] = q
|
|
|
|
|
|
|
|
go eh.forwardProfileMessages(onion, q)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (eh *EventHandler) forwardProfileMessages(onion string, q event.Queue) {
|
2021-03-16 20:16:45 +00:00
|
|
|
// TODO: graceful shutdown, via an injected event of special QUIT type exiting loop/go routine
|
2021-03-05 00:14:58 +00:00
|
|
|
for {
|
2021-03-04 23:57:48 +00:00
|
|
|
e := q.Next()
|
2021-03-12 12:24:37 +00:00
|
|
|
ev := EventProfileEnvelope{Event: *e, Profile: onion}
|
2021-03-04 23:57:48 +00:00
|
|
|
eh.profileEvents <- ev
|
|
|
|
}
|
|
|
|
}
|