seekia/internal/messaging/myChatConversations/myChatConversations.go

825 lines
30 KiB
Go
Raw Normal View History

// myChatConversations provides functions to generate and retrieve a user's chat conversations
// These conversations can be filtered and sorted based on the recipient's qualities
// Examples: Sort recipients by age, filter recipients who do not fulfill our desires
package myChatConversations
import "seekia/internal/appMemory"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/messaging/myChatFilters"
import "seekia/internal/messaging/myChatMessages"
import "seekia/internal/messaging/myReadStatus"
import "seekia/internal/myBlockedUsers"
import "seekia/internal/myDatastores/myMapList"
import "seekia/internal/myIdentity"
import "seekia/internal/mySettings"
import "seekia/internal/profiles/viewableProfiles"
import "slices"
import "sync"
import "errors"
// This mutex will be locked whenever we update chat conversations
var updatingMyChatConversationsMutex sync.Mutex
var myMateChatConversationsMapListDatastore *myMapList.MyMapList
var myModeratorChatConversationsMapListDatastore *myMapList.MyMapList
// This function must be called whenever an app user signs in
func InitializeMyChatConversationsDatastores()error{
updatingMyChatConversationsMutex.Lock()
defer updatingMyChatConversationsMutex.Unlock()
newMyMateChatConversationsMapListDatastore, err := myMapList.CreateNewMapList("MyMateChatConversations")
if (err != nil) { return err }
newMyModeratorChatConversationsMapListDatastore, err := myMapList.CreateNewMapList("MyModeratorChatConversations")
if (err != nil) { return err }
myMateChatConversationsMapListDatastore = newMyMateChatConversationsMapListDatastore
myModeratorChatConversationsMapListDatastore = newMyModeratorChatConversationsMapListDatastore
return nil
}
func getMyConversationsMapListDatastore(identityType string)(*myMapList.MyMapList, error) {
if (identityType == "Mate"){
return myMateChatConversationsMapListDatastore, nil
}
if (identityType == "Moderator"){
return myModeratorChatConversationsMapListDatastore, nil
}
return nil, errors.New("getMyConversationsMapListDatastore called with invalid identity type: " + identityType)
}
// This function checks if conversations are generated and sorted
func GetMyChatConversationsReadyStatus(identityType string, networkType byte)(bool, error){
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, errors.New("GetMyChatConversationsReadyStatus called with invalid networkType: " + networkTypeString)
}
generatedStatus, err := getMyChatConversationsGeneratedStatus(identityType)
if (err != nil) { return false, err }
if (generatedStatus == false) {
return false, nil
}
exists, sortedStatus, err := mySettings.GetSetting(identityType + "ChatConversationsSortedStatus")
if (err != nil) { return false, err }
if (exists == false || sortedStatus != "Yes") {
return false, nil
}
exists, conversationsNetworkTypeString, err := mySettings.GetSetting(identityType + "ChatConversationsNetworkType")
if (err != nil) { return false, err }
if (exists == false){
// This should not happen, because ...ChatConversationsNetworkType is set whenever conversations are generated
return false, errors.New("mySettings is missing " + identityType + "ChatConversationsNetworkType when " + identityType + "ChatConversationsGeneratedStatus exists.")
}
conversationsNetworkType, err := helpers.ConvertNetworkTypeStringToByte(conversationsNetworkTypeString)
if (err != nil) {
return false, errors.New("MySettings contains invalid " + identityType + "ChatConversationsNetworkType: " + conversationsNetworkTypeString)
}
if (conversationsNetworkType != networkType) {
// Conversations must have been generated for a different networkType.
// This should not happen, because we should only call this function using our current appNetworkType
// Whenever we change network types, we reset the ChatConversationsGeneratedStatus to No.
//TODO: Log this.
err := mySettings.SetSetting(identityType + "ChatConversationsGeneratedStatus", "No")
if (err != nil) { return false, err }
return false, nil
}
return true, nil
}
// Our conversations will need a refresh any time a new message sent to the user's inboxes is downloaded
func CheckIfMyChatConversationsNeedRefresh(identityType string)(bool, error){
exists, needsRefresh, err := mySettings.GetSetting(identityType + "ChatConversationsNeedRefreshYesNo")
if (err != nil) { return true, err }
if (exists == true && needsRefresh == "No") {
return false, nil
}
return true, nil
}
func getMyChatConversationsGeneratedStatus(identityType string)(bool, error){
chatMessagesReady, err := myChatMessages.GetMyChatMessagesReadyStatus(identityType)
if (err != nil) { return false, err }
if (chatMessagesReady == false) {
return false, nil
}
exists, readyStatus, err := mySettings.GetSetting(identityType + "ChatConversationsGeneratedStatus")
if (err != nil) { return false, err }
if (exists == false || readyStatus != "Yes"){
return false, nil
}
return true, nil
}
// This function returns the ready (generated and sorted) chat conversations map list
//Outputs:
// -bool: Chat conversations are ready
// -[]map[string]string
// -error
func GetMyChatConversationsMapList(identityType string, networkType byte)(bool, []map[string]string, error){
if (identityType != "Mate" && identityType != "Moderator"){
return false, nil, errors.New("GetMyChatConversationsMapList called with invalid identityType: " + identityType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, nil, errors.New("GetMyChatConversationsMapList called with invalid networkType: " + networkTypeString)
}
conversationsReady, err := GetMyChatConversationsReadyStatus(identityType, networkType)
if (err != nil) { return false, nil, err }
if (conversationsReady == false) {
return false, nil, nil
}
myReadyConversationsMapListDatastore, err := getMyConversationsMapListDatastore(identityType)
if (err != nil) { return false, nil, err }
myReadyChatConversationsMapList, err := myReadyConversationsMapListDatastore.GetMapList()
if (err != nil) { return false, nil, err }
return true, myReadyChatConversationsMapList, nil
}
//Outputs:
// -bool: Conversations ready
// -string: Number of conversations
// -error
func GetNumberOfConversations(identityType string, networkType byte)(bool, int, error){
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, 0, errors.New("GetNumberOfConversations called with invalid networkType: " + networkTypeString)
}
conversationsReady, conversationsMap, err := GetMyChatConversationsMapList(identityType, networkType)
if (err != nil) { return false, 0, err }
if (conversationsReady == false){
return false, 0, nil
}
numberOfConversations := len(conversationsMap)
return true, numberOfConversations, nil
}
func GetConversationsSortByAttribute(identityType string) (string, error){
exists, currentAttribute, err := mySettings.GetSetting(identityType + "ChatConversations_SortByAttribute")
if (err != nil) { return "", err }
if (exists == false){
return "MatchScore", nil
}
return currentAttribute, nil
}
func GetConversationsSortDirection(identityType string) (string, error){
exists, sortDirection, err := mySettings.GetSetting(identityType + "ChatConversations_SortDirection")
if (err != nil) { return "", err }
if (exists == false){
return "Descending", nil
}
if (sortDirection != "Ascending" && sortDirection != "Descending"){
return "", errors.New("MySettings malformed: Invalid ChatConversations_SortDirection: " + sortDirection)
}
return sortDirection, nil
}
//Outputs:
// -bool: Conversations ready
// -string: Number of unread conversations
// -error
func GetNumberOfUnreadConversations(identityType string, networkType byte)(bool, int, error){
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, 0, errors.New("GetNumberOfUnreadConversations called with invalid networkType: " + networkTypeString)
}
conversationsReady, conversationsMapList, err := GetMyChatConversationsMapList(identityType, networkType)
if (err != nil) { return false, 0, err }
if (conversationsReady == false){
return false, 0, nil
}
numberOfUnreadConversations := 0
for _, conversationMap := range conversationsMapList {
myIdentityHashString, exists := conversationMap["MyIdentityHash"]
if (exists == false) {
return false, 0, errors.New("Invalid conversation map: Item missing MyIdentityHash")
}
theirIdentityHashString, exists := conversationMap["TheirIdentityHash"]
if (exists == false) {
return false, 0, errors.New("Invalid conversation map: Item missing TheirIdentityHash")
}
myIdentityHash, myIdentityType, err := identity.ReadIdentityHashString(myIdentityHashString)
if (err != nil){
return false, 0, errors.New("Invalid conversation map: Item contains invalid MyIdentityHash: " + myIdentityHashString)
}
theirIdentityHash, theirIdentityType, err := identity.ReadIdentityHashString(theirIdentityHashString)
if (err != nil){
return false, 0, errors.New("Invalid conversation map: Item contains invalid TheirIdentityHash: " + theirIdentityHashString)
}
if (myIdentityType != theirIdentityType){
return false, 0, errors.New("Invalid conversation map: Item contains mismatched My and Their identityTypes.")
}
if (myIdentityType != identityType){
return false, 0, errors.New("GetMyChatConversationsMapList returning conversation map for different identityType participants.")
}
readUnreadStatus, err := myReadStatus.GetConversationReadUnreadStatus(myIdentityHash, theirIdentityHash, networkType)
if (err != nil) { return false, 0, err }
if (readUnreadStatus == "Unread"){
numberOfUnreadConversations += 1
}
}
return true, numberOfUnreadConversations, nil
}
//Outputs:
// -bool: Build encountered error
// -string: Error encountered
// -bool: Build is stopped (will be stopped if user went to different page)
// -bool: Conversations are ready
// -float64: Percentage Progress (0 - 1)
// -error
func GetChatConversationsBuildStatus(identityType string, networkType byte)(bool, string, bool, bool, float64, error){
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, "", false, false, 0, errors.New("GetChatConversationsBuildStatus called with invalid networkType: " + networkTypeString)
}
exists, encounteredError := appMemory.GetMemoryEntry(identityType + "ChatConversationsBuildEncounteredError")
if (exists == false){
// No build exists. A build has not been started since Seekia was started
return false, "", false, false, 0, nil
}
if (encounteredError == "Yes"){
exists, errorEncountered := appMemory.GetMemoryEntry(identityType + "ChatConversationsBuildError")
if (exists == false){
return false, "", false, false, 0, errors.New("Chat conversations build error encountered error is yes, but no error exists.")
}
return true, errorEncountered, false, false, 0, nil
}
isStopped := CheckIfBuildMyConversationsIsStopped()
if (isStopped == true){
return false, "", true, false, 0, nil
}
conversationsReadyBool, err := GetMyChatConversationsReadyStatus(identityType, networkType)
if (err != nil) { return false, "", false, false, 0, err }
if (conversationsReadyBool == true){
return false, "", false, true, 1, nil
}
exists, currentPercentageString := appMemory.GetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus")
if (exists == false){
// No build exists. A build has not been started since Seekia was started
return false, "", false, false, 0, nil
}
currentPercentageFloat, err := helpers.ConvertStringToFloat64(currentPercentageString)
if (err != nil){
return false, "", false, false, 0, errors.New("ChatConversationsReadyProgressStatus is invalid: Not a float: " + currentPercentageString)
}
return false, "", false, false, currentPercentageFloat, nil
}
func CheckIfBuildMyConversationsIsStopped()bool{
exists, buildStoppedStatus := appMemory.GetMemoryEntry("StopBuildMyConversationsYesNo")
if (exists == false || buildStoppedStatus != "No") {
return true
}
return false
}
// This function will cancel the current build (if one is running)
// It will then start updating our chat messages and conversations list
func StartUpdatingMyConversations(identityType string, networkType byte) error{
if (identityType != "Mate" && identityType != "Moderator") {
return errors.New("StartUpdatingMyConversations called with invalid identity type: " + identityType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("StartUpdatingMyConversations called with invalid networkType: " + networkTypeString)
}
networkTypeString := helpers.ConvertByteToString(networkType)
appMemory.SetMemoryEntry("StopBuildMyConversationsYesNo", "Yes")
// We wait for any existing build to stop
updatingMyChatConversationsMutex.Lock()
appMemory.SetMemoryEntry(identityType + "ChatConversationsBuildEncounteredError", "No")
appMemory.SetMemoryEntry(identityType + "ChatConversationsBuildError", "")
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", "0")
appMemory.SetMemoryEntry("StopBuildMyConversationsYesNo", "No")
updateMyChatConversations := func()error{
myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(identityType)
if (err != nil) { return err }
if (myIdentityExists == false){
// Our identity does not exist.
// We first update our myChatMessagesMapList ready status by running the below function
updateProgressFunction := func(_ int)error{
return nil
}
_, err := myChatMessages.GetUpdatedMyChatMessagesMapList(identityType, networkType, updateProgressFunction)
if (err != nil) { return err }
// Now we overwrite our conversation datastores with empty map lists.
// Using the DeleteMapList function achieves this.
myChatConversationsMapListDatastore, err := getMyConversationsMapListDatastore(identityType)
if (err != nil) { return err }
err = myChatConversationsMapListDatastore.DeleteMapList()
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsGeneratedStatus", "Yes")
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsNetworkType", networkTypeString)
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsSortedStatus", "Yes")
if (err != nil) { return err }
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", "1")
err = mySettings.SetSetting(identityType + "ChatConversationsNeedRefreshYesNo", "No")
if (err != nil) { return err }
return nil
}
isStopped := CheckIfBuildMyConversationsIsStopped()
if (isStopped == true) {
// User has moved to a different page. Stop generating.
return nil
}
getConversationsNeedToBeGeneratedStatus := func()(bool, error){
messagesReadyStatus, err := myChatMessages.GetMyChatMessagesReadyStatus(identityType)
if (err != nil) { return false, err }
if (messagesReadyStatus == false){
return true, nil
}
conversationsGenerated, err := getMyChatConversationsGeneratedStatus(identityType)
if (err != nil) { return false, err }
if (conversationsGenerated == false){
return true, nil
}
exists, chatConversationsNetworkTypeString, err := mySettings.GetSetting(identityType + "ChatConversationsNetworkType")
if (err != nil) { return false, err }
if (exists == false){
// This should not happen, because MatchesNetworkType is set to Yes whenever matches are generated
return false, errors.New("...ChatConversationsNetworkType missing when ...ChatConversationsGeneratedStatus exists.")
}
chatConversationsNetworkType, err := helpers.ConvertNetworkTypeStringToByte(chatConversationsNetworkTypeString)
if (err != nil) {
return false, errors.New("mySettings contains invalid ...ChatConversationsNetworkType: " + chatConversationsNetworkTypeString)
}
if (chatConversationsNetworkType != networkType){
// This should not happen, because ...ChatConversationsGeneratedStatus should be set to No whenever app network
// type is changed, and StartUpdatingMyConversations should only be called with the current app network type.
return true, nil
}
return false, nil
}
conversationsNeedToBeGenerated, err := getConversationsNeedToBeGeneratedStatus()
if (err != nil) { return err }
if (conversationsNeedToBeGenerated == true){
// We generate conversations
err := mySettings.SetSetting(identityType + "ChatConversationsGeneratedStatus", "No")
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsSortedStatus", "No")
if (err != nil) { return err }
updatePercentageProgressFunction := func(input int)error{
// Input is a value between 0-100
// We reduce it down to a value between 0-50
newProgressInt, err := helpers.ScaleNumberProportionally(true, input, 0, 100, 0, 50)
if (err != nil) { return err }
newPercentageProgressFloat := float64(newProgressInt)/100
newPercentageProgressString := helpers.ConvertFloat64ToString(newPercentageProgressFloat)
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", newPercentageProgressString)
return nil
}
myChatMessagesMapList, err := myChatMessages.GetUpdatedMyChatMessagesMapList(identityType, networkType, updatePercentageProgressFunction)
if (err != nil) { return err }
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", ".50")
// Conversations map stores data as TheirIdentityHash -> MostRecentMessageTime
conversationsMap := make(map[[16]byte]int64)
for _, messageMap := range myChatMessagesMapList {
isStopped := CheckIfBuildMyConversationsIsStopped()
if (isStopped == true) {
// User has moved to a different page. Stop generating.
return nil
}
messageMyIdentityHashString, exists := messageMap["MyIdentityHash"]
if (exists == false){
return errors.New("Malformed message map: missing MyIdentityHash.")
}
messageMyIdentityHash, messageMyIdentityHashIdentityType, err := identity.ReadIdentityHashString(messageMyIdentityHashString)
if (err != nil){
return errors.New("Malformed message map: contains invalid MyIdentityHash: " + messageMyIdentityHashString)
}
if (messageMyIdentityHashIdentityType != identityType){
return errors.New("GetUpdatedMyChatMessagesMapList returning message with different identity type.")
}
if (messageMyIdentityHash != myIdentityHash){
// This should not happen, because our old identity's messages should have been deleted.
return errors.New("GetUpdatedMyChatMessagesMapList returning map list containing message from a different identityHash than our current one for provided identityType.")
}
messageTheirIdentityHashString, exists := messageMap["TheirIdentityHash"]
if (exists == false){
return errors.New("Malformed message map: Missing TheirIdentityHash.")
}
messageTheirIdentityHash, theirIdentityType, err := identity.ReadIdentityHashString(messageTheirIdentityHashString)
if (err != nil) {
return errors.New("Malformed message map: Contains invalid TheirIdentityHash: " + messageTheirIdentityHashString)
}
if (theirIdentityType != identityType){
return errors.New("myChatMessagesMapList contains message map between different identity types.")
}
messageNetworkType, exists := messageMap["NetworkType"]
if (exists == false){
return errors.New("myChatMessagesMapList returning messageMap missing NetworkType.")
}
if (messageNetworkType != networkTypeString){
return errors.New("myChatMessagesMapList returning messageMap with different NetworkType")
}
messageSentTimeString, exists := messageMap["TimeSent"]
if (exists == false){
return errors.New("Malformed message map: Missing TimeSent.")
}
currentMessageSentTimeInt64, err := helpers.ConvertStringToInt64(messageSentTimeString)
if (err != nil) {
return errors.New("Malformed message map: Contains invalid TimeSent: " + messageSentTimeString)
}
existingMostRecentMessageSentTime, exists := conversationsMap[messageTheirIdentityHash]
if (exists == false || currentMessageSentTimeInt64 > existingMostRecentMessageSentTime){
conversationsMap[messageTheirIdentityHash] = currentMessageSentTimeInt64
}
}
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", ".60")
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return errors.New("GetMyIdentityHash returning invalid myIdentityHash: " + myIdentityHashHex)
}
newConversationsMapList := make([]map[string]string, 0)
for theirIdentityHash, conversationMostRecentMessageTime := range conversationsMap {
isStopped := CheckIfBuildMyConversationsIsStopped()
if (isStopped == true) {
// User has moved to a different page. Stop generating.
return nil
}
theyAreBlocked, _, _, _, err := myBlockedUsers.CheckIfUserIsBlocked(theirIdentityHash)
if (err != nil) { return err }
if (theyAreBlocked == true) {
continue
}
userPassesChatFilters, err := myChatFilters.CheckIfUserPassesAllMyChatFilters(theirIdentityHash, networkType)
if (err != nil) { return err }
if (userPassesChatFilters == false){
continue
}
theirIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(theirIdentityHash)
if (err != nil){
theirIdentityHashHex := encoding.EncodeBytesToHexString(theirIdentityHash[:])
return errors.New("conversationsMap contains invalid theirIdentityHash: " + theirIdentityHashHex)
}
mostRecentMessageSentTimeString := helpers.ConvertInt64ToString(conversationMostRecentMessageTime)
newConversationMap := map[string]string{
"MyIdentityHash": myIdentityHashString,
"TheirIdentityHash": theirIdentityHashString,
"NetworkType": networkTypeString,
"MostRecentMessageTime": mostRecentMessageSentTimeString,
}
newConversationsMapList = append(newConversationsMapList, newConversationMap)
}
myChatConversationsMapListDatastore, err := getMyConversationsMapListDatastore(identityType)
if (err != nil) { return err }
err = myChatConversationsMapListDatastore.OverwriteMapList(newConversationsMapList)
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsGeneratedStatus", "Yes")
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsNetworkType", networkTypeString)
if (err != nil) { return err }
}
isStopped = CheckIfBuildMyConversationsIsStopped()
if (isStopped == true) {
// User has moved to a different page. Stop generating.
return nil
}
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", ".70")
conversationsReady, err := GetMyChatConversationsReadyStatus(identityType, networkType)
if (err != nil) { return err }
if (conversationsReady == false){
// Now we sort conversations.
currentSortByAttribute, err := GetConversationsSortByAttribute(identityType)
if (err != nil) { return err }
currentSortDirection, err := GetConversationsSortDirection(identityType)
if (err != nil) { return err }
myChatConversationsMapListDatastore, err := getMyConversationsMapListDatastore(identityType)
if (err != nil) { return err }
currentConversationsMapList, err := myChatConversationsMapListDatastore.GetMapList()
if (err != nil) { return err }
// We use this map to make sure there are no duplicate recipients
// This should never happen, unless the user's stored map list was edited or there is a bug
recipientsMap := make(map[[16]byte]struct{})
// Map structure: Their Identity Hash -> Sort By Attribute Value
recipientAttributeValuesMap := make(map[string]float64)
getAllowUnknownViewableStatusBool := func()bool{
if (identityType == "Mate"){
return false
}
return true
}
allowUnknownViewableStatusBool := getAllowUnknownViewableStatusBool()
maximumIndex := len(currentConversationsMapList) - 1
for index, conversationMap := range currentConversationsMapList{
conversationMyIdentityHashString, exists := conversationMap["MyIdentityHash"]
if (exists == false) {
return errors.New("Malformed conversation map during sort: item missing MyIdentityHash.")
}
conversationMyIdentityHash, conversationMyIdentityHashIdentityType, err := identity.ReadIdentityHashString(conversationMyIdentityHashString)
if (err != nil){
return errors.New("Malformed conversation map during sort: contains invalid MyIdentityHash: " + conversationMyIdentityHashString)
}
if (conversationMyIdentityHashIdentityType != identityType){
return errors.New("Malformed conversation map during sort: contains conversation with different identity type.")
}
if (conversationMyIdentityHash != myIdentityHash){
// This should not happen, because our conversations should be regenerated whenever we change our identity
return errors.New("Malformed conversation map during sort: Contains different identity hash.")
}
theirIdentityHashString, exists := conversationMap["TheirIdentityHash"]
if (exists == false) {
return errors.New("ChatConversations map list item missing TheirIdentityHash")
}
theirIdentityHash, theirIdentityType, err := identity.ReadIdentityHashString(theirIdentityHashString)
if (err != nil){
return errors.New("ChatConversations map list item contains invalid theirIdentityHash: " + theirIdentityHashString)
}
if (theirIdentityType != identityType){
return errors.New("ChatConversations map list item contains invalid theirIdentityHash: Different identityType: " + theirIdentityType)
}
_, exists = recipientsMap[theirIdentityHash]
if (exists == true){
return errors.New("ChatConversations map list is malformed: Contains two conversation maps with the same recipient")
}
recipientsMap[theirIdentityHash] = struct{}{}
profileExists, _, attributeExists, attributeValue, err := viewableProfiles.GetAnyAttributeFromNewestViewableUserProfile(theirIdentityHash, networkType, currentSortByAttribute, true, allowUnknownViewableStatusBool, true)
if (err != nil) { return err }
if (profileExists == true && attributeExists == true){
attributeValueFloat, err := helpers.ConvertStringToFloat64(attributeValue)
if (err != nil) {
return errors.New("User attribute cannot be converted to float during conversation build: " + attributeValue)
}
recipientAttributeValuesMap[theirIdentityHashString] = attributeValueFloat
}
isStopped := CheckIfBuildMyConversationsIsStopped()
if (isStopped == true){
// User has moved to a different page. Stop generating.
return nil
}
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 70, 85)
if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100
newProgressString := helpers.ConvertFloat64ToString(newProgressFloat)
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", newProgressString)
}
compareConversationMapsFunction := func(conversationMapA map[string]string, conversationMapB map[string]string) int {
identityHashA, exists := conversationMapA["TheirIdentityHash"]
if (exists == false) {
panic("Malformed conversations map list: Item missing TheirIdentityHash")
}
identityHashB, exists := conversationMapB["TheirIdentityHash"]
if (exists == false) {
panic("Malformed conversations map list: Item missing TheirIdentityHash")
}
if (identityHashA == identityHashB){
panic("Malformed conversations map list: Two conversations contain the same TheirIdentityHash.")
}
attributeValueA, attributeValueAExists := recipientAttributeValuesMap[identityHashA]
attributeValueB, attributeValueBExists := recipientAttributeValuesMap[identityHashB]
if (attributeValueAExists == false && attributeValueBExists == false){
// We don't know the attribute value for either recipient
// We sort recipients in unicode order
if (identityHashA < identityHashB){
return -1
}
return 1
} else if (attributeValueAExists == true && attributeValueBExists == false){
// We sort unknown attribute recipient conversations to the back of the list
return -1
} else if (attributeValueAExists == false && attributeValueBExists == true){
return 1
}
// Both recipient attribute values exist
if (attributeValueA == attributeValueB){
// If values are equal, we want the result to be the same with each refresh
// We sort the identity hashses in unicode order
if (identityHashA < identityHashB){
return -1
}
return 1
}
if (attributeValueA < attributeValueB){
if (currentSortDirection == "Ascending"){
return -1
}
return 1
}
if (currentSortDirection == "Ascending"){
return 1
}
return -1
}
slices.SortFunc(currentConversationsMapList, compareConversationMapsFunction)
err = myChatConversationsMapListDatastore.OverwriteMapList(currentConversationsMapList)
if (err != nil) { return err }
err = mySettings.SetSetting(identityType + "ChatConversationsSortedStatus", "Yes")
if (err != nil) { return err }
}
appMemory.SetMemoryEntry(identityType + "ChatConversationsReadyProgressStatus", "1")
err = mySettings.SetSetting(identityType + "ChatConversationsNeedRefreshYesNo", "No")
if (err != nil) { return err }
return nil
}
updateFunction := func(){
err := updateMyChatConversations()
if (err != nil){
appMemory.SetMemoryEntry(identityType + "ChatConversationsBuildEncounteredError", "Yes")
appMemory.SetMemoryEntry(identityType + "ChatConversationsBuildError", err.Error())
}
updatingMyChatConversationsMutex.Unlock()
}
go updateFunction()
return nil
}