Fixes from Cwtch UI Integration

This commit is contained in:
Sarah Jamie Lewis 2021-11-18 15:44:21 -08:00
parent b2da9fc54d
commit 3cc56fb011
7 changed files with 72 additions and 41 deletions

View File

@ -11,4 +11,3 @@ const (
// StatusError is an event response for event.Status signifying a call failed in error, ideally accompanied by a event.Error
StatusError = "error"
)

View File

@ -50,7 +50,7 @@ func (gf *GroupFunctionality) GetServerInfoList(profile peer.CwtchPeer) []Server
// GetServerInfo compiles all the information the UI might need regarding a particular server including any verified
// cryptographic keys
func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.CwtchPeer) Server {
serverInfo,_ := profile.FetchConversationInfo(serverOnion)
serverInfo, _ := profile.FetchConversationInfo(serverOnion)
keyTypes := []model.KeyType{model.KeyTypeServerOnion, model.KeyTypeTokenOnion, model.KeyTypePrivacyPass}
var serverKeys []ServerKey
@ -60,4 +60,4 @@ func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.Cwt
}
}
return Server{Onion: serverOnion, Status: connections.ConnectionStateName[profile.GetPeerState(serverInfo.Handle)], Keys: serverKeys}
}
}

View File

@ -18,7 +18,7 @@ const (
ZeroServersLoaded = event.Type("ZeroServersLoaded")
NewServer = event.Type("NewServer")
ServerIntentUpdate = event.Type("ServerIntentUpdate")
ServerDeleted = event.Type("ServerDeleted")
ServerDeleted = event.Type("ServerDeleted")
)
const (

58
lib.go
View File

@ -7,12 +7,12 @@ package main
import "C"
import (
// Import SQL Cipher
_ "github.com/mutecomm/go-sqlcipher/v4"
"crypto/rand"
constants2 "cwtch.im/cwtch/model/constants"
"encoding/json"
"fmt"
// Import SQL Cipher
_ "github.com/mutecomm/go-sqlcipher/v4"
"os/user"
"runtime"
"strconv"
@ -248,18 +248,18 @@ func ReconnectCwtchForeground() {
}
settings := utils.ReadGlobalSettings()
groupHandler,_ := groups.ExperimentGate(settings.Experiments)
groupHandler, _ := groups.ExperimentGate(settings.Experiments)
for _, profileOnion := range peerList {
// fix peerpeercontact message counts
profile := application.GetPeer(profileOnion)
conversations,_ := profile.FetchConversations()
conversations, _ := profile.FetchConversations()
for _, conversation := range conversations {
if (conversation.IsGroup() && groupHandler != nil) || conversation.IsServer() == false {
totalMessages,_ := profile.GetChannelMessageCount(conversation.ID, 0)
totalMessages, _ := profile.GetChannelMessageCount(conversation.ID, 0)
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
event.Identity: profileOnion,
event.Identity: profileOnion,
event.ConversationID: strconv.Itoa(conversation.ID),
event.Data: strconv.Itoa(totalMessages),
event.Data: strconv.Itoa(totalMessages),
}))
}
}
@ -504,6 +504,7 @@ func c_GetMessage(profile_ptr *C.char, profile_len C.int, conversation_id C.int,
// EnhancedMessage wraps a Cwtch model.Message with some additional data to reduce calls from the UI.
type EnhancedMessage struct {
model.Message
ID int // the actual ID of the message in the database (not the row number)
ContactImage string
}
@ -516,15 +517,18 @@ func GetMessage(profileOnion string, conversationID int, messageIndex int) strin
// these requests complete almost immediately v.s. being stalled for seconds to minutes on large groups.
if application != nil {
profile := application.GetPeer(profileOnion)
messages, err := profile.GetMostRecentMessages(conversationID,0, messageIndex, 1)
if err == nil && len (messages) == 1 {
messages, err := profile.GetMostRecentMessages(conversationID, 0, messageIndex, 1)
if err == nil && len(messages) == 1 {
time, _ := time.Parse(time.RFC3339Nano, messages[0].Attr[constants2.AttrSentTimestamp])
message.Message = model.Message{
Message: messages[0].Body,
Message: messages[0].Body,
Acknowledged: messages[0].Attr[constants2.AttrAck] == constants2.True,
Error: messages[0].Attr[constants2.AttrErr],
PeerID: messages[0].Attr["Author"],
Error: messages[0].Attr[constants2.AttrErr],
PeerID: messages[0].Attr[constants2.AttrAuthor],
Timestamp: time,
}
message.ContactImage = utils.RandomProfileImage(messages[0].Attr["Author"])
message.ID = messages[0].ID
message.ContactImage = utils.RandomProfileImage(message.PeerID)
}
}
bytes, _ := json.Marshal(message)
@ -542,7 +546,27 @@ func c_GetMessagesByContentHash(profile_ptr *C.char, profile_len C.int, conversa
func GetMessagesByContentHash(profileOnion string, handle int, contentHash string) string {
var indexedMessages []model.LocallyIndexedMessage
if application != nil {
// TODO
profile := application.GetPeer(profileOnion)
id, err := profile.GetChannelMessageByContentHash(handle, 0, contentHash)
if err == nil {
// TODO this is terrible
messages, err := profile.GetMostRecentMessages(handle, 0, 0, 100)
if err == nil {
for i, message := range messages {
if message.ID == id {
time, _ := time.Parse(time.RFC3339Nano, messages[0].Attr[constants2.AttrSentTimestamp])
msg := model.Message{
Message: messages[0].Body,
Acknowledged: messages[0].Attr[constants2.AttrAck] == constants2.True,
Error: messages[0].Attr[constants2.AttrErr],
PeerID: messages[0].Attr[constants2.AttrAuthor],
Timestamp: time,
}
indexedMessages = append(indexedMessages, model.LocallyIndexedMessage{LocalIndex: i, Message: msg})
}
}
}
}
}
bytes, _ := json.Marshal(indexedMessages)
return string(bytes)
@ -554,8 +578,6 @@ func c_FreePointer(ptr *C.char) {
C.free(unsafe.Pointer(ptr))
}
//export c_SendMessage
func c_SendMessage(profile_ptr *C.char, profile_len C.int, conversation_id C.int, msg_ptr *C.char, msg_len C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
@ -569,7 +591,7 @@ func SendMessage(profileOnion string, conversationID int, msg string) {
}
//export c_SendInvitation
func c_SendInvitation(profile_ptr *C.char, profile_len C.int, conversation_id C.int, target_id C.int) {
func c_SendInvitation(profile_ptr *C.char, profile_len C.int, conversation_id C.int, target_id C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
SendInvitation(profile, int(conversation_id), int(target_id))
}
@ -589,7 +611,7 @@ func c_ShareFile(profile_ptr *C.char, profile_len C.int, conversation_id C.int,
ShareFile(profile, int(conversation_id), sharefilepath)
}
func ShareFile(profileOnion string , conversationID int, sharefilepath string) {
func ShareFile(profileOnion string, conversationID int, sharefilepath string) {
profile := application.GetPeer(profileOnion)
fh, err := filesharing.FunctionalityGate(utils.ReadGlobalSettings().Experiments)
if err != nil {

View File

@ -13,5 +13,5 @@ type Contact struct {
IsGroup bool `json:"isGroup"`
GroupServer string `json:"groupServer"`
IsArchived bool `json:"isArchived"`
Identifier int `json:"identifier"`
Identifier int `json:"identifier"`
}

View File

@ -123,7 +123,6 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
}
}
online, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline)
// Name always exists
e.Data[constants.Name], _ = profile.GetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
@ -152,8 +151,19 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
continue
}
name,_ := conversationInfo.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
cpicPath := RandomProfileImage(conversationInfo.Handle)
name, exists := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.Name)
if !exists {
name, exists = conversationInfo.GetAttribute(attr.PeerScope, attr.ProfileZone, constants.Name)
if !exists {
name = conversationInfo.Handle
}
}
var cpicPath string
if conversationInfo.IsGroup() {
cpicPath = RandomGroupImage(conversationInfo.Handle)
} else {
cpicPath = RandomProfileImage(conversationInfo.Handle)
}
saveHistory, set := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, event.SaveHistoryKey)
if !set {
saveHistory = event.DeleteHistoryDefault
@ -177,19 +187,18 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
authorization = model.AuthBlocked
}
groupServer,_ := conversationInfo.GetAttribute(attr.LocalScope, attr.LegacyGroupZone, constants.GroupServer)
groupServer, _ := conversationInfo.GetAttribute(attr.LocalScope, attr.LegacyGroupZone, constants.GroupServer)
count, err := profile.GetChannelMessageCount(conversationInfo.ID, 0)
if err != nil {
log.Errorf("error fetching channel message count %v %v", conversationInfo.ID, err)
}
lastMessage,_ := profile.GetMostRecentMessages(conversationInfo.ID, 0, 0,1)
lastMessage, _ := profile.GetMostRecentMessages(conversationInfo.ID, 0, 0, 1)
contacts = append(contacts, Contact{
Name: name,
Identifier: conversationInfo.ID,
Identifier: conversationInfo.ID,
Onion: conversationInfo.Handle,
Status: connections.ConnectionStateName[state],
Picture: cpicPath,
@ -235,18 +244,19 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
profile.SetConversationAttribute(ci.ID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants2.Archived)), event.False)
} else {
// TODO This Conversation May Not Exist Yet...But we are not in charge of creating it...
log.Errorf("todo wait for contact to be added before processing this event...")
}
ev.Event.Data["Nick"],_ = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
ev.Event.Data["Nick"], _ = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
ev.Event.Data["Picture"] = RandomProfileImage(ev.Event.Data["RemotePeer"])
case event.NewMessageFromGroup:
// only needs contact nickname and picture, for displaying on popup notifications
ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"])
if ci != nil && err == nil {
ev.Event.Data["Nick"],_ = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
ev.Event.Data["Nick"], _ = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
}
ev.Event.Data["Picture"] = RandomProfileImage(ev.Event.Data[event.GroupID])
conversationID,_ := strconv.Atoi(ev.Event.Data[event.ConversationID])
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
profile.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants2.Archived)), event.False)
case event.PeerAcknowledgement:
ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"])
@ -254,14 +264,14 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
ev.Event.Data[event.ConversationID] = strconv.Itoa(ci.ID)
}
case event.ContactCreated:
conversationID,_ := strconv.Atoi(ev.Event.Data[event.ConversationID])
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
handle := ev.Event.Data[event.RemotePeer]
count, err := profile.GetChannelMessageCount(conversationID, 0)
if err != nil {
log.Errorf("error fetching channel message count %v %v", conversationID, err)
}
lastMessage,_ := profile.GetMostRecentMessages(conversationID, 0, 0,1)
lastMessage, _ := profile.GetMostRecentMessages(conversationID, 0, 0, 1)
ev.Event.Data["unread"] = strconv.Itoa(1) // we've just created this contact so by definition this must be 1...
ev.Event.Data["picture"] = RandomProfileImage(handle)
ev.Event.Data["numMessages"] = strconv.Itoa(count)
@ -288,7 +298,7 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
}
case event.PeerStateChange:
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
contact,_ := profile.FetchConversationInfo(ev.Event.Data[event.RemotePeer])
contact, _ := profile.FetchConversationInfo(ev.Event.Data[event.RemotePeer])
if cxnState == connections.AUTHENTICATED && contact == nil {
profile.NewContactConversation(ev.Event.Data[event.RemotePeer], model.AccessControl{Read: false, Append: false, Blocked: false}, false)
@ -307,13 +317,13 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
case event.NewRetValMessageFromPeer:
// auto handled event means the setting is already done, we're just deciding if we need to tell the UI
conversationID,_ := strconv.Atoi(ev.Event.Data[event.ConversationID])
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
scope := ev.Event.Data[event.Scope]
path := ev.Event.Data[event.Path]
exists, _ := strconv.ParseBool(ev.Event.Data[event.Exists])
if exists && attr.IntoScope(scope) == attr.PublicScope {
zone,path := attr.ParseZone(path)
zone, path := attr.ParseZone(path)
if _, err := profile.GetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(zone.ConstructZonedPath(path))); err != nil {
// we have a locally set override, don't pass this remote set public scope update to UI
return ""
@ -396,4 +406,4 @@ func getLastMessageTime(conversationMessages []model.ConversationMessage) int {
return 0
}
return int(time.Unix())
}
}

View File

@ -12,7 +12,7 @@ func RandomProfileImage(onion string) string {
choices := []string{"001-centaur", "002-kraken", "003-dinosaur", "004-tree-1", "005-hand", "006-echidna", "007-robot", "008-mushroom", "009-harpy", "010-phoenix", "011-dragon-1", "012-devil", "013-troll", "014-alien", "015-minotaur", "016-madre-monte", "017-satyr", "018-karakasakozou", "019-pirate", "020-werewolf", "021-scarecrow", "022-valkyrie", "023-curupira", "024-loch-ness-monster", "025-tree", "026-cerberus", "027-gryphon", "028-mermaid", "029-vampire", "030-goblin", "031-yeti", "032-leprechaun", "033-medusa", "034-chimera", "035-elf", "036-hydra", "037-cyclops", "038-pegasus", "039-narwhal", "040-woodcutter", "041-zombie", "042-dragon", "043-frankenstein", "044-witch", "045-fairy", "046-genie", "047-pinocchio", "048-ghost", "049-wizard", "050-unicorn"}
barr, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
if err != nil || len(barr) != 35 {
log.Errorf("error: %v %v %v\n", onion, err, barr)
log.Errorf("error finding image for profile: %v %v %v\n", onion, err, barr)
return "extra/openprivacy.png"
}
return "profiles/" + choices[int(barr[33])%len(choices)] + ".png"
@ -22,7 +22,7 @@ func RandomGroupImage(handle string) string {
choices := []string{"001-borobudur", "002-opera-house", "003-burj-al-arab", "004-chrysler", "005-acropolis", "006-empire-state-building", "007-temple", "008-indonesia-1", "009-new-zealand", "010-notre-dame", "011-space-needle", "012-seoul", "013-mosque", "014-milan", "015-statue", "016-pyramid", "017-cologne", "018-brandenburg-gate", "019-berlin-cathedral", "020-hungarian-parliament", "021-buckingham", "022-thailand", "023-independence", "024-angkor-wat", "025-vaticano", "026-christ-the-redeemer", "027-colosseum", "028-golden-gate-bridge", "029-sphinx", "030-statue-of-liberty", "031-cradle-of-humankind", "032-istanbul", "033-london-eye", "034-sagrada-familia", "035-tower-bridge", "036-burj-khalifa", "037-washington", "038-big-ben", "039-stonehenge", "040-white-house", "041-ahu-tongariki", "042-capitol", "043-eiffel-tower", "044-church-of-the-savior-on-spilled-blood", "045-arc-de-triomphe", "046-windmill", "047-louvre", "048-torii-gate", "049-petronas", "050-matsumoto-castle", "051-fuji", "052-temple-of-heaven", "053-pagoda", "054-chichen-itza", "055-forbidden-city", "056-merlion", "057-great-wall-of-china", "058-taj-mahal", "059-pisa", "060-indonesia"}
barr, err := hex.DecodeString(handle)
if err != nil || len(barr) == 0 {
log.Errorf("error: %v %v %v\n", handle, err, barr)
log.Errorf("error finding image for group: %v %v %v\n", handle, err, barr)
return "extra/openprivacy.png"
}
return "servers/" + choices[int(barr[0])%len(choices)] + ".png"