From fc5cdc5eb1f1bca6275e293b5ca41f20f87a7dd9 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 26 Apr 2022 07:51:06 +0100 Subject: [PATCH] mobile: use batched DOWN/UP events, core: include pending contacts (#573) * mobile: use batched DOWN/UP events, core: include pending contacts * query style --- .../java/chat/simplex/app/model/ChatModel.kt | 12 +++++- .../java/chat/simplex/app/model/SimpleXAPI.kt | 38 ++++++++++--------- apps/ios/Shared/Model/ChatModel.swift | 13 +++++-- apps/ios/Shared/Model/SimpleXAPI.swift | 35 ++++++++--------- src/Simplex/Chat/Store.hs | 6 +-- 5 files changed, 61 insertions(+), 43 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt index a379e1a00a..346f8ce8ad 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt @@ -67,8 +67,8 @@ class ChatModel(val controller: ChatController) { } } - fun updateNetworkStatus(contact: Contact, status: Chat.NetworkStatus) { - val i = getChatIndex(contact.id) + fun updateNetworkStatus(id: ChatId, status: Chat.NetworkStatus) { + val i = getChatIndex(id) if (i >= 0) { val chat = chats[i] chats[i] = chat.copy(serverInfo = chat.serverInfo.copy(networkStatus = status)) @@ -389,6 +389,14 @@ class Contact( } } +@Serializable +class ContactRef( + val contactId: Long, + var localDisplayName: String +) { + val id: ChatId get() = "@$contactId" +} + @Serializable class ContactSubStatus( val contact: Contact, diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index db708aaf06..6e6f172f4e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -352,7 +352,7 @@ open class ChatController(private val ctrl: ChatCtrl, private val ntfManager: Nt is CR.ContactConnected -> { chatModel.updateContact(r.contact) chatModel.removeChat(r.contact.activeConn.id) - chatModel.updateNetworkStatus(r.contact, Chat.NetworkStatus.Connected()) + chatModel.updateNetworkStatus(r.contact.id, Chat.NetworkStatus.Connected()) // NtfManager.shared.notifyContactConnected(contact) } is CR.ContactConnecting -> { @@ -371,17 +371,18 @@ open class ChatController(private val ctrl: ChatCtrl, private val ntfManager: Nt chatModel.updateChatInfo(cInfo) } } - is CR.ContactSubscribed -> processContactSubscribed(r.contact) - is CR.ContactDisconnected -> { - chatModel.updateContact(r.contact) - chatModel.updateNetworkStatus(r.contact, Chat.NetworkStatus.Disconnected()) - } + is CR.ContactsSubscribed -> updateContactsStatus(r.contactRefs, Chat.NetworkStatus.Connected()) + is CR.ContactsDisconnected -> updateContactsStatus(r.contactRefs, Chat.NetworkStatus.Disconnected()) is CR.ContactSubError -> processContactSubError(r.contact, r.chatError) is CR.ContactSubSummary -> { for (sub in r.contactSubscriptions) { val err = sub.contactError - if (err == null) processContactSubscribed(sub.contact) - else processContactSubError(sub.contact, sub.contactError) + if (err == null) { + chatModel.updateContact(sub.contact) + chatModel.updateNetworkStatus(sub.contact.id, Chat.NetworkStatus.Connected()) + } else { + processContactSubError(sub.contact, sub.contactError) + } } } is CR.NewChatItem -> { @@ -436,9 +437,10 @@ open class ChatController(private val ctrl: ChatCtrl, private val ntfManager: Nt } } - fun processContactSubscribed(contact: Contact) { - chatModel.updateContact(contact) - chatModel.updateNetworkStatus(contact, Chat.NetworkStatus.Connected()) + fun updateContactsStatus(contactRefs: List, status: Chat.NetworkStatus) { + for (c in contactRefs) { + chatModel.updateNetworkStatus(c.id, status) + } } fun processContactSubError(contact: Contact, chatError: ChatError) { @@ -454,7 +456,7 @@ open class ChatController(private val ctrl: ChatCtrl, private val ntfManager: Nt } } else e.string - chatModel.updateNetworkStatus(contact, Chat.NetworkStatus.Error(err)) + chatModel.updateNetworkStatus(contact.id, Chat.NetworkStatus.Error(err)) } fun showBackgroundServiceNotice() { @@ -667,8 +669,8 @@ sealed class CR { @Serializable @SerialName("acceptingContactRequest") class AcceptingContactRequest(val contact: Contact): CR() @Serializable @SerialName("contactRequestRejected") class ContactRequestRejected: CR() @Serializable @SerialName("contactUpdated") class ContactUpdated(val toContact: Contact): CR() - @Serializable @SerialName("contactSubscribed") class ContactSubscribed(val contact: Contact): CR() - @Serializable @SerialName("contactDisconnected") class ContactDisconnected(val contact: Contact): CR() + @Serializable @SerialName("contactsSubscribed") class ContactsSubscribed(val server: String, val contactRefs: List): CR() + @Serializable @SerialName("contactsDisconnected") class ContactsDisconnected(val server: String, val contactRefs: List): CR() @Serializable @SerialName("contactSubError") class ContactSubError(val contact: Contact, val chatError: ChatError): CR() @Serializable @SerialName("contactSubSummary") class ContactSubSummary(val contactSubscriptions: List): CR() @Serializable @SerialName("groupSubscribed") class GroupSubscribed(val group: GroupInfo): CR() @@ -713,8 +715,8 @@ sealed class CR { is AcceptingContactRequest -> "acceptingContactRequest" is ContactRequestRejected -> "contactRequestRejected" is ContactUpdated -> "contactUpdated" - is ContactSubscribed -> "contactSubscribed" - is ContactDisconnected -> "contactDisconnected" + is ContactsSubscribed -> "contactsSubscribed" + is ContactsDisconnected -> "contactsDisconnected" is ContactSubError -> "contactSubError" is ContactSubSummary -> "contactSubSummary" is GroupSubscribed -> "groupSubscribed" @@ -760,8 +762,8 @@ sealed class CR { is AcceptingContactRequest -> json.encodeToString(contact) is ContactRequestRejected -> noDetails() is ContactUpdated -> json.encodeToString(toContact) - is ContactSubscribed -> json.encodeToString(contact) - is ContactDisconnected -> json.encodeToString(contact) + is ContactsSubscribed -> "server: $server\ncontacts:\n${json.encodeToString(contactRefs)}" + is ContactsDisconnected -> "server: $server\ncontacts:\n${json.encodeToString(contactRefs)}" is ContactSubError -> "error:\n${chatError.string}\ncontact:\n${json.encodeToString(contact)}" is ContactSubSummary -> json.encodeToString(contactSubscriptions) is GroupSubscribed -> json.encodeToString(group) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index e2960a6ea0..4e21969b70 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -70,9 +70,9 @@ final class ChatModel: ObservableObject { } } - func updateNetworkStatus(_ contact: Contact, _ status: Chat.NetworkStatus) { - if let ix = getChatIndex(contact.id) { - chats[ix].serverInfo.networkStatus = status + func updateNetworkStatus(_ id: ChatId, _ status: Chat.NetworkStatus) { + if let i = getChatIndex(id) { + chats[i].serverInfo.networkStatus = status } } @@ -488,6 +488,13 @@ struct Contact: Identifiable, Decodable, NamedChat { ) } +struct ContactRef: Decodable { + var contactId: Int64 + var localDisplayName: ContactName + + var id: ChatId { get { "@\(contactId)" } } +} + struct ContactSubStatus: Decodable { var contact: Contact var contactError: ChatError? diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 674d047374..e719956a66 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -159,8 +159,8 @@ enum ChatResponse: Decodable, Error { case acceptingContactRequest(contact: Contact) case contactRequestRejected case contactUpdated(toContact: Contact) - case contactSubscribed(contact: Contact) - case contactDisconnected(contact: Contact) + case contactsSubscribed(server: String, contactRefs: [ContactRef]) + case contactsDisconnected(server: String, contactRefs: [ContactRef]) case contactSubError(contact: Contact, chatError: ChatError) case contactSubSummary(contactSubscriptions: [ContactSubStatus]) case groupSubscribed(groupInfo: GroupInfo) @@ -207,8 +207,8 @@ enum ChatResponse: Decodable, Error { case .acceptingContactRequest: return "acceptingContactRequest" case .contactRequestRejected: return "contactRequestRejected" case .contactUpdated: return "contactUpdated" - case .contactSubscribed: return "contactSubscribed" - case .contactDisconnected: return "contactDisconnected" + case .contactsSubscribed: return "contactsSubscribed" + case .contactsDisconnected: return "contactsDisconnected" case .contactSubError: return "contactSubError" case .contactSubSummary: return "contactSubSummary" case .groupSubscribed: return "groupSubscribed" @@ -258,8 +258,8 @@ enum ChatResponse: Decodable, Error { case let .acceptingContactRequest(contact): return String(describing: contact) case .contactRequestRejected: return noDetails case let .contactUpdated(toContact): return String(describing: toContact) - case let .contactSubscribed(contact): return String(describing: contact) - case let .contactDisconnected(contact): return String(describing: contact) + case let .contactsSubscribed(server, contactRefs): return "server: \(server)\ncontacts:\n\(String(describing: contactRefs))" + case let .contactsDisconnected(server, contactRefs): return "server: \(server)\ncontacts:\n\(String(describing: contactRefs))" case let .contactSubError(contact, chatError): return "contact:\n\(String(describing: contact))\nerror:\n\(String(describing: chatError))" case let .contactSubSummary(contactSubscriptions): return String(describing: contactSubscriptions) case let .groupSubscribed(groupInfo): return String(describing: groupInfo) @@ -720,7 +720,7 @@ func processReceivedMsg(_ res: ChatResponse) { case let .contactConnected(contact): m.updateContact(contact) m.removeChat(contact.activeConn.id) - m.updateNetworkStatus(contact, .connected) + m.updateNetworkStatus(contact.id, .connected) NtfManager.shared.notifyContactConnected(contact) case let .contactConnecting(contact): m.updateContact(contact) @@ -736,11 +736,10 @@ func processReceivedMsg(_ res: ChatResponse) { if m.hasChat(toContact.id) { m.updateChatInfo(cInfo) } - case let .contactSubscribed(contact): - processContactSubscribed(contact) - case let .contactDisconnected(contact): - m.updateContact(contact) - m.updateNetworkStatus(contact, .disconnected) + case let .contactsSubscribed(_, contactRefs): + updateContactsStatus(contactRefs, status: .connected) + case let .contactsDisconnected(_, contactRefs): + updateContactsStatus(contactRefs, status: .disconnected) case let .contactSubError(contact, chatError): processContactSubError(contact, chatError) case let .contactSubSummary(contactSubscriptions): @@ -748,7 +747,8 @@ func processReceivedMsg(_ res: ChatResponse) { if let err = sub.contactError { processContactSubError(sub.contact, err) } else { - processContactSubscribed(sub.contact) + m.updateContact(sub.contact) + m.updateNetworkStatus(sub.contact.id, .connected) } } case let .newChatItem(aChatItem): @@ -810,10 +810,11 @@ func processReceivedMsg(_ res: ChatResponse) { } } -func processContactSubscribed(_ contact: Contact) { +func updateContactsStatus(_ contactRefs: [ContactRef], status: Chat.NetworkStatus) { let m = ChatModel.shared - m.updateContact(contact) - m.updateNetworkStatus(contact, .connected) + for c in contactRefs { + m.updateNetworkStatus(c.id, status) + } } func processContactSubError(_ contact: Contact, _ chatError: ChatError) { @@ -825,7 +826,7 @@ func processContactSubError(_ contact: Contact, _ chatError: ChatError) { case .errorAgent(agentError: .SMP(smpErr: .AUTH)): err = "contact deleted" default: err = String(describing: chatError) } - m.updateNetworkStatus(contact, .error(err)) + m.updateNetworkStatus(contact.id, .error(err)) } private struct UserResponse: Decodable { diff --git a/src/Simplex/Chat/Store.hs b/src/Simplex/Chat/Store.hs index 9c381a7764..03760fe3d9 100644 --- a/src/Simplex/Chat/Store.hs +++ b/src/Simplex/Chat/Store.hs @@ -1209,11 +1209,11 @@ getConnectionsContacts st userId agentConnIds = SELECT ct.contact_id, ct.local_display_name FROM contacts ct JOIN connections c ON c.contact_id = ct.contact_id - WHERE ct.user_id = ? AND c.agent_conn_id IN (SELECT conn_id FROM temp.conn_ids) + WHERE ct.user_id = ? + AND c.agent_conn_id IN (SELECT conn_id FROM temp.conn_ids) AND c.conn_type = ? - AND (c.conn_status = ? OR c.conn_status = ?) |] - (userId, ConnContact, ConnReady, ConnSndReady) + (userId, ConnContact) DB.execute_ db "DROP TABLE temp.conn_ids" pure conns