From 86dfe63a8fb45fcadb506394f4f0b64e17394fd1 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 6 Jan 2022 16:31:21 -0500 Subject: [PATCH] add caching and filtering of contact state change events; change logic from contact auth to approved/blocked --- go.mod | 3 +- go.sum | 9 +---- lib.go | 17 +++++++-- utils/contacts.go | 27 +++++++------- utils/eventHandler.go | 86 ++++++++++++++++++++++++++----------------- 5 files changed, 83 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index bf6dce7..c5b87a9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.openprivacy.ca/cwtch.im/libcwtch-go go 1.15 require ( - cwtch.im/cwtch v0.14.9 + cwtch.im/cwtch v0.14.10 git.openprivacy.ca/cwtch.im/server v1.4.2 git.openprivacy.ca/openprivacy/connectivity v1.5.0 git.openprivacy.ca/openprivacy/log v1.0.3 @@ -12,4 +12,3 @@ require ( golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect ) - diff --git a/go.sum b/go.sum index 50e8c98..7f13b02 100644 --- a/go.sum +++ b/go.sum @@ -10,17 +10,12 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cwtch.im/cwtch v0.14.1/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.1/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.8 h1:bybtnnCTp7utGvfIbQvdeffKmJQgGrkfgijrAfS8SQw= -cwtch.im/cwtch v0.14.8/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.9 h1:VYXbQG6f41fCoLpLEYDAeiJSG+9Gxstl1DOk1Hv4tjM= cwtch.im/cwtch v0.14.9/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= +cwtch.im/cwtch v0.14.10 h1:RA/hehCxeAE+J6YkUuEvS6n8blEAK2ixGnKbq23bN10= +cwtch.im/cwtch v0.14.10/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -git.openprivacy.ca/cwtch.im/server v1.4.1 h1:ZCySCYxt7rvCLdf2INFWK1xDoSexJD6sJRZ2yZ9iYHU= -git.openprivacy.ca/cwtch.im/server v1.4.1/go.mod h1:gJ57TXx0cnnKN7FZSzr210KNq+WtDtBUo1zHFZ/FbTw= git.openprivacy.ca/cwtch.im/server v1.4.2 h1:ZcRK1XuWvJzNjYdAvAISD8HcEITPwWbvRiIZGkMKu1k= git.openprivacy.ca/cwtch.im/server v1.4.2/go.mod h1:CeE/bThy2UVQ+gx+3ctNt65H9xvELDfcwBS9qJwOsOg= git.openprivacy.ca/cwtch.im/tapir v0.4.9 h1:LXonlztwvI1F1++0IyomIcDH1/Bxzo+oN8YjGonNvjM= diff --git a/lib.go b/lib.go index b2618b3..0f57850 100644 --- a/lib.go +++ b/lib.go @@ -10,16 +10,15 @@ import ( "crypto/rand" "encoding/json" "fmt" + "strconv" constants2 "cwtch.im/cwtch/model/constants" "git.openprivacy.ca/cwtch.im/libcwtch-go/features" - // Import SQL Cipher "os/user" "runtime" - "strconv" "strings" "unsafe" @@ -252,7 +251,7 @@ func ReconnectCwtchForeground() { // populate profile list peerList := application.ListProfiles() for _, onion := range peerList { - eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion, event.Created: event.False, "Reload": event.True})) + eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion})) } settings := utils.ReadGlobalSettings() @@ -489,6 +488,16 @@ func BlockContact(profileOnion string, conversationID int) { profile.BlockConversation(conversationID) } +//export c_UnblockContact +func c_UnblockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) { + UnblockContact(C.GoStringN(profilePtr, profileLen), int(conversation_id)) +} + +func UnblockContact(profileOnion string, conversationID int) { + profile := application.GetPeer(profileOnion) + profile.UnblockConversation(conversationID) +} + //export c_GetMessage // the pointer returned from this function **must** be Freed by c_Free func c_GetMessage(profile_ptr *C.char, profile_len C.int, conversation_id C.int, message_index C.int) *C.char { @@ -886,7 +895,7 @@ func SetMessageAttribute(profileOnion string, conversationID int, channelID int, } //export c_ChangePassword -func c_ChangePassword(profile_ptr *C.char, profile_len C.int, oldpassword_ptr *C.char, oldpassword_len C.int, newpassword_ptr *C.char, newpassword_len C.int, newpassword_again_ptr *C.char, newpassword_again_len C.int) { +func c_ChangePassword(profile_ptr *C.char, profile_len C.int, oldpassword_ptr *C.char, oldpassword_len C.int, newpassword_ptr *C.char, newpassword_len C.int, newpassword_again_ptr *C.char, newpassword_again_len C.int) { profileOnion := C.GoStringN(profile_ptr, profile_len) oldPassword := C.GoStringN(oldpassword_ptr, oldpassword_len) newPassword := C.GoStringN(newpassword_ptr, newpassword_len) diff --git a/utils/contacts.go b/utils/contacts.go index 1a5f2d1..9ddeabf 100644 --- a/utils/contacts.go +++ b/utils/contacts.go @@ -1,17 +1,18 @@ package utils type Contact struct { - Name string `json:"name"` - Onion string `json:"onion"` - Status string `json:"status"` - Picture string `json:"picture"` - Authorization string `json:"authorization"` - SaveHistory string `json:"saveConversationHistory"` - Messages int `json:"numMessages"` - Unread int `json:"numUnread"` - LastMessage string `json:"lastMsgTime"` - IsGroup bool `json:"isGroup"` - GroupServer string `json:"groupServer"` - IsArchived bool `json:"isArchived"` - Identifier int `json:"identifier"` + Name string `json:"name"` + Onion string `json:"onion"` + Status string `json:"status"` + Picture string `json:"picture"` + Accepted bool `json:"accepted"` + Blocked bool `json:"blocked"` + SaveHistory string `json:"saveConversationHistory"` + Messages int `json:"numMessages"` + Unread int `json:"numUnread"` + LastMessage string `json:"lastMsgTime"` + IsGroup bool `json:"isGroup"` + GroupServer string `json:"groupServer"` + IsArchived bool `json:"isArchived"` + Identifier int `json:"identifier"` } diff --git a/utils/eventHandler.go b/utils/eventHandler.go index 7a843d3..6bf4bfa 100644 --- a/utils/eventHandler.go +++ b/utils/eventHandler.go @@ -184,16 +184,9 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string { state = connections.DISCONNECTED } - // Resolve Conversation Auth State - // TODO: Align this with ACLs - authorization := model.AuthUnknown - if conversationInfo.Accepted { - authorization = model.AuthApproved - } - - // If ACL has blocked conversation then hide them... - if acl, exists := conversationInfo.ACL[conversationInfo.Handle]; exists && acl.Blocked { - authorization = model.AuthBlocked + blocked := false + if conversationInfo.ACL[conversationInfo.Handle].Blocked { + blocked = true } // Check if we are a server... @@ -208,19 +201,20 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string { lastMessage, _ := profile.GetMostRecentMessages(conversationInfo.ID, 0, 0, 1) contacts = append(contacts, Contact{ - Name: name, - Identifier: conversationInfo.ID, - Onion: conversationInfo.Handle, - Status: connections.ConnectionStateName[state], - Picture: cpicPath, - Authorization: string(authorization), - SaveHistory: saveHistory, - Messages: count, - Unread: 0, - LastMessage: strconv.Itoa(getLastMessageTime(lastMessage)), - IsGroup: conversationInfo.IsGroup(), - GroupServer: groupServer, - IsArchived: isArchived == event.True, + Name: name, + Identifier: conversationInfo.ID, + Onion: conversationInfo.Handle, + Status: connections.ConnectionStateName[state], + Picture: cpicPath, + Accepted: conversationInfo.Accepted, + Blocked: blocked, + SaveHistory: saveHistory, + Messages: count, + Unread: 0, + LastMessage: strconv.Itoa(getLastMessageTime(lastMessage)), + IsGroup: conversationInfo.IsGroup(), + GroupServer: groupServer, + IsArchived: isArchived == event.True, }) } } @@ -242,6 +236,9 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string { // handleProfileEvent enriches Profile events so they are usable with out further data fetches func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { + // cache of contact states to use to filter out events repeating known states + var contactStateCache = make(map[string]connections.ConnectionState) + if eh.app == nil { log.Errorf("eh.app == nil in handleProfileEvent... this shouldnt happen?") } else { @@ -312,16 +309,14 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { log.Errorf("error fetching conversation info for %v %v", conversationID, err) } - // Resolve Conversation Auth State - // TODO: Align this with ACLs - authorization := model.AuthUnknown - if conversationInfo.Accepted { - authorization = model.AuthApproved + blocked := constants.False + if conversationInfo.ACL[conversationInfo.Handle].Blocked { + blocked = constants.True } - // If ACL has blocked conversation then hide them... - if acl, exists := conversationInfo.ACL[conversationInfo.Handle]; exists && acl.Blocked { - authorization = model.AuthBlocked + accepted := constants.False + if conversationInfo.Accepted { + accepted = constants.True } lastMessage, _ := profile.GetMostRecentMessages(conversationID, 0, 0, 1) @@ -330,7 +325,8 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { ev.Event.Data["numMessages"] = strconv.Itoa(count) ev.Event.Data["nick"] = conversationInfo.Handle ev.Event.Data["status"] = connections.ConnectionStateName[profile.GetPeerState(conversationInfo.Handle)] - ev.Event.Data["authorization"] = string(authorization) + ev.Event.Data["accepted"] = accepted + ev.Event.Data["blocked"] = blocked ev.Event.Data["loading"] = "false" ev.Event.Data["lastMsgTime"] = strconv.Itoa(getLastMessageTime(lastMessage)) case event.GroupCreated: @@ -351,6 +347,12 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { } case event.PeerStateChange: cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]] + + // skip events the UI doesn't act on + if cxnState == connections.CONNECTING || cxnState == connections.CONNECTED { + return "" + } + contact, _ := profile.FetchConversationInfo(ev.Event.Data[event.RemotePeer]) if ev.Event.Data[event.RemotePeer] == profile.GetOnion() { @@ -363,15 +365,33 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { return "" } + // if we already know this state, suppress + if knownState, exists := contactStateCache[ev.Event.Data[event.RemotePeer]]; exists && cxnState == knownState { + return "" + } + contactStateCache[ev.Event.Data[event.RemotePeer]] = cxnState + if contact != nil { // No enrichment needed - //uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false) if cxnState == connections.AUTHENTICATED { // if known and authed, get vars profile.SendScopedZonedGetValToContact(contact.ID, attr.PublicScope, attr.ProfileZone, constants.Name) profile.SendScopedZonedGetValToContact(contact.ID, attr.PublicScope, attr.ProfileZone, constants2.Picture) } } + case event.ServerStateChange: + cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]] + + // skip events the UI doesn't act on + if cxnState == connections.CONNECTING || cxnState == connections.CONNECTED { + return "" + } + + // if we already know this state, suppress + if knownState, exists := contactStateCache[ev.Event.Data[event.RemotePeer]]; exists && cxnState == knownState { + return "" + } + contactStateCache[ev.Event.Data[event.RemotePeer]] = cxnState case event.NewRetValMessageFromPeer: // auto handled event means the setting is already done, we're just deciding if we need to tell the UI