mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
core, ios: try to get next ntf message to get expected (#4962)
This commit is contained in:
@@ -26,7 +26,7 @@ enum NSENotification {
|
||||
case nse(UNMutableNotificationContent)
|
||||
case callkit(RcvCallInvitation)
|
||||
case empty
|
||||
case msgInfo(NtfMsgInfo)
|
||||
case msgInfo(NtfMsgAckInfo)
|
||||
|
||||
var isCallInvitation: Bool {
|
||||
switch self {
|
||||
@@ -119,7 +119,9 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
var threadId: UUID? = NSEThreads.shared.newThread()
|
||||
var notificationInfo: NtfMessages?
|
||||
var receiveEntityId: String?
|
||||
var receiveConnId: String?
|
||||
var expectedMessage: String?
|
||||
var allowedGetNextAttempts: Int = 3
|
||||
// return true if the message is taken - it prevents sending it to another NotificationService instance for processing
|
||||
var shouldProcessNtf = false
|
||||
var appSubscriber: AppSubscriber?
|
||||
@@ -191,17 +193,21 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
let dbStatus = startChat()
|
||||
if case .ok = dbStatus,
|
||||
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
|
||||
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessage_ == nil ? 0 : 1))")
|
||||
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.receivedMsg_ == nil ? 0 : 1))")
|
||||
if let connEntity = ntfInfo.connEntity_ {
|
||||
setBestAttemptNtf(
|
||||
ntfInfo.ntfsEnabled
|
||||
? .nse(createConnectionEventNtf(ntfInfo.user, connEntity))
|
||||
: .empty
|
||||
)
|
||||
if let id = connEntity.id, ntfInfo.msgTs != nil {
|
||||
if let id = connEntity.id, ntfInfo.expectedMsg_ != nil {
|
||||
notificationInfo = ntfInfo
|
||||
receiveEntityId = id
|
||||
expectedMessage = ntfInfo.ntfMessage_.flatMap { $0.msgId }
|
||||
receiveConnId = connEntity.conn.agentConnId
|
||||
let expectedMsgId = ntfInfo.expectedMsg_?.msgId
|
||||
let receivedMsgId = ntfInfo.receivedMsg_?.msgId
|
||||
logger.debug("NotificationService: receiveNtfMessages: expectedMsgId = \(expectedMsgId ?? "nil", privacy: .private), receivedMsgId = \(receivedMsgId ?? "nil", privacy: .private)")
|
||||
expectedMessage = expectedMsgId
|
||||
shouldProcessNtf = true
|
||||
return
|
||||
}
|
||||
@@ -219,22 +225,34 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
|
||||
func processReceivedNtf(_ ntf: NSENotification) -> Bool {
|
||||
guard let ntfInfo = notificationInfo, let msgTs = ntfInfo.msgTs else { return false }
|
||||
guard let ntfInfo = notificationInfo, let expectedMsgTs = ntfInfo.expectedMsg_?.msgTs else { return false }
|
||||
if !ntfInfo.user.showNotifications {
|
||||
self.setBestAttemptNtf(.empty)
|
||||
}
|
||||
if case let .msgInfo(info) = ntf {
|
||||
if info.msgId == expectedMessage {
|
||||
expectedMessage = nil
|
||||
logger.debug("NotificationService processNtf: msgInfo")
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): expected")
|
||||
self.deliverBestAttemptNtf()
|
||||
return true
|
||||
} else if info.msgTs > msgTs {
|
||||
logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one")
|
||||
} else if let msgTs = info.msgTs_, msgTs > expectedMsgTs {
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, let other instance to process it, stopping this one")
|
||||
self.deliverBestAttemptNtf()
|
||||
return false
|
||||
} else if allowedGetNextAttempts > 0, let receiveConnId = receiveConnId {
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, get next message")
|
||||
allowedGetNextAttempts -= 1
|
||||
if let receivedMsg = apiGetConnNtfMessage(connId: receiveConnId) {
|
||||
logger.debug("NotificationService processNtf, on apiGetConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private), receivedMsg msgId = \(receivedMsg.msgId, privacy: .private)")
|
||||
return true
|
||||
} else {
|
||||
logger.debug("NotificationService processNtf, on apiGetConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private): no next message, deliver best attempt")
|
||||
self.deliverBestAttemptNtf()
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
logger.debug("NotificationService processNtf: unknown message, let other instance to process it")
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unknown message, let other instance to process it")
|
||||
self.deliverBestAttemptNtf()
|
||||
return false
|
||||
}
|
||||
} else if ntfInfo.user.showNotifications {
|
||||
@@ -692,9 +710,9 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
|
||||
return nil
|
||||
}
|
||||
let r = sendSimpleXCmd(.apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo))
|
||||
if case let .ntfMessages(user, connEntity_, msgTs, ntfMessage_) = r, let user = user {
|
||||
logger.debug("apiGetNtfMessage response ntfMessages: \(ntfMessage_ == nil ? 0 : 1)")
|
||||
return NtfMessages(user: user, connEntity_: connEntity_, msgTs: msgTs, ntfMessage_: ntfMessage_)
|
||||
if case let .ntfMessages(user, connEntity_, expectedMsg_, receivedMsg_) = r, let user = user {
|
||||
logger.debug("apiGetNtfMessage response ntfMessages: \(receivedMsg_ == nil ? 0 : 1)")
|
||||
return NtfMessages(user: user, connEntity_: connEntity_, expectedMsg_: expectedMsg_, receivedMsg_: receivedMsg_)
|
||||
} else if case let .chatCmdError(_, error) = r {
|
||||
logger.debug("apiGetNtfMessage error response: \(String.init(describing: error))")
|
||||
} else {
|
||||
@@ -703,6 +721,20 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiGetConnNtfMessage(connId: String) -> NtfMsgInfo? {
|
||||
guard apiGetActiveUser() != nil else {
|
||||
logger.debug("no active user")
|
||||
return nil
|
||||
}
|
||||
let r = sendSimpleXCmd(.apiGetConnNtfMessage(connId: connId))
|
||||
if case let .connNtfMessage(receivedMsg_) = r {
|
||||
logger.debug("apiGetConnNtfMessage response receivedMsg_: \(receivedMsg_ == nil ? 0 : 1)")
|
||||
return receivedMsg_
|
||||
}
|
||||
logger.debug("apiGetConnNtfMessage error: \(responseError(r))")
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
|
||||
let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
|
||||
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
|
||||
@@ -740,8 +772,8 @@ func setNetworkConfig(_ cfg: NetCfg) throws {
|
||||
struct NtfMessages {
|
||||
var user: User
|
||||
var connEntity_: ConnectionEntity?
|
||||
var msgTs: Date?
|
||||
var ntfMessage_: NtfMsgInfo?
|
||||
var expectedMsg_: NtfMsgInfo?
|
||||
var receivedMsg_: NtfMsgInfo?
|
||||
|
||||
var ntfsEnabled: Bool {
|
||||
user.showNotifications && (connEntity_?.ntfsEnabled ?? false)
|
||||
|
||||
@@ -169,6 +169,11 @@
|
||||
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
|
||||
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
|
||||
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
|
||||
64BAB0852CB417A500D7D8FD /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BAB0802CB417A500D7D8FD /* libgmp.a */; };
|
||||
64BAB0862CB417A500D7D8FD /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BAB0812CB417A500D7D8FD /* libgmpxx.a */; };
|
||||
64BAB0872CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BAB0822CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a */; };
|
||||
64BAB0882CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BAB0832CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a */; };
|
||||
64BAB0892CB417A500D7D8FD /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BAB0842CB417A500D7D8FD /* libffi.a */; };
|
||||
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
@@ -217,11 +222,6 @@
|
||||
D741547A29AF90B00022400A /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547929AF90B00022400A /* PushKit.framework */; };
|
||||
D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; };
|
||||
D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; };
|
||||
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */; };
|
||||
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92372CAB2B8800C212F2 /* libgmp.a */; };
|
||||
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92382CAB2B8800C212F2 /* libffi.a */; };
|
||||
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */; };
|
||||
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B923A2CAB2B8800C212F2 /* libgmpxx.a */; };
|
||||
E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; };
|
||||
E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
|
||||
E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; };
|
||||
@@ -511,6 +511,11 @@
|
||||
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
|
||||
64BAB0802CB417A500D7D8FD /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64BAB0812CB417A500D7D8FD /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64BAB0822CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64BAB0832CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a"; sourceTree = "<group>"; };
|
||||
64BAB0842CB417A500D7D8FD /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
@@ -557,11 +562,6 @@
|
||||
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a"; sourceTree = "<group>"; };
|
||||
E51B92372CAB2B8800C212F2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
E51B92382CAB2B8800C212F2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = "<group>"; };
|
||||
E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@@ -653,14 +653,14 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */,
|
||||
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */,
|
||||
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */,
|
||||
64BAB0882CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */,
|
||||
64BAB0862CB417A500D7D8FD /* libgmpxx.a in Frameworks */,
|
||||
64BAB0892CB417A500D7D8FD /* libffi.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
64BAB0852CB417A500D7D8FD /* libgmp.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */,
|
||||
64BAB0872CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -737,11 +737,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E51B92382CAB2B8800C212F2 /* libffi.a */,
|
||||
E51B92372CAB2B8800C212F2 /* libgmp.a */,
|
||||
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */,
|
||||
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */,
|
||||
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */,
|
||||
64BAB0842CB417A500D7D8FD /* libffi.a */,
|
||||
64BAB0802CB417A500D7D8FD /* libgmp.a */,
|
||||
64BAB0812CB417A500D7D8FD /* libgmpxx.a */,
|
||||
64BAB0822CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15-ghc9.6.3.a */,
|
||||
64BAB0832CB417A500D7D8FD /* libHSsimplex-chat-6.1.0.5-KYQ48Wt5wtN69vfbmNbu15.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -56,6 +56,7 @@ public enum ChatCommand {
|
||||
case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
|
||||
case apiDeleteToken(token: DeviceToken)
|
||||
case apiGetNtfMessage(nonce: String, encNtfInfo: String)
|
||||
case apiGetConnNtfMessage(connId: String)
|
||||
case apiNewGroup(userId: Int64, incognito: Bool, groupProfile: GroupProfile)
|
||||
case apiAddMember(groupId: Int64, contactId: Int64, memberRole: GroupMemberRole)
|
||||
case apiJoinGroup(groupId: Int64)
|
||||
@@ -214,6 +215,7 @@ public enum ChatCommand {
|
||||
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
|
||||
case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)"
|
||||
case let .apiGetNtfMessage(nonce, encNtfInfo): return "/_ntf message \(nonce) \(encNtfInfo)"
|
||||
case let .apiGetConnNtfMessage(connId): return "/_ntf conn message \(connId)"
|
||||
case let .apiNewGroup(userId, incognito, groupProfile): return "/_group \(userId) incognito=\(onOff(incognito)) \(encodeJSON(groupProfile))"
|
||||
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
|
||||
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
|
||||
@@ -368,6 +370,7 @@ public enum ChatCommand {
|
||||
case .apiVerifyToken: return "apiVerifyToken"
|
||||
case .apiDeleteToken: return "apiDeleteToken"
|
||||
case .apiGetNtfMessage: return "apiGetNtfMessage"
|
||||
case .apiGetConnNtfMessage: return "apiGetConnNtfMessage"
|
||||
case .apiNewGroup: return "apiNewGroup"
|
||||
case .apiAddMember: return "apiAddMember"
|
||||
case .apiJoinGroup: return "apiJoinGroup"
|
||||
@@ -679,8 +682,9 @@ public enum ChatResponse: Decodable, Error {
|
||||
case callInvitations(callInvitations: [RcvCallInvitation])
|
||||
case ntfTokenStatus(status: NtfTknStatus)
|
||||
case ntfToken(token: DeviceToken, status: NtfTknStatus, ntfMode: NotificationsMode, ntfServer: String)
|
||||
case ntfMessages(user_: User?, connEntity_: ConnectionEntity?, msgTs: Date?, ntfMessage_: NtfMsgInfo?)
|
||||
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgInfo)
|
||||
case ntfMessages(user_: User?, connEntity_: ConnectionEntity?, expectedMsg_: NtfMsgInfo?, receivedMsg_: NtfMsgInfo?)
|
||||
case connNtfMessage(receivedMsg_: NtfMsgInfo?)
|
||||
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgAckInfo)
|
||||
case contactConnectionDeleted(user: UserRef, connection: PendingContactConnection)
|
||||
case contactDisabled(user: UserRef, contact: Contact)
|
||||
// remote desktop responses/events
|
||||
@@ -848,6 +852,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .ntfTokenStatus: return "ntfTokenStatus"
|
||||
case .ntfToken: return "ntfToken"
|
||||
case .ntfMessages: return "ntfMessages"
|
||||
case .connNtfMessage: return "connNtfMessage"
|
||||
case .ntfMessage: return "ntfMessage"
|
||||
case .contactConnectionDeleted: return "contactConnectionDeleted"
|
||||
case .contactDisabled: return "contactDisabled"
|
||||
@@ -1024,7 +1029,8 @@ public enum ChatResponse: Decodable, Error {
|
||||
case let .callInvitations(invs): return String(describing: invs)
|
||||
case let .ntfTokenStatus(status): return String(describing: status)
|
||||
case let .ntfToken(token, status, ntfMode, ntfServer): return "token: \(token)\nstatus: \(status.rawValue)\nntfMode: \(ntfMode.rawValue)\nntfServer: \(ntfServer)"
|
||||
case let .ntfMessages(u, connEntity, msgTs, ntfMessages): return withUser(u, "connEntity: \(String(describing: connEntity))\nmsgTs: \(String(describing: msgTs))\nntfMessages: \(String(describing: ntfMessages))")
|
||||
case let .ntfMessages(u, connEntity, expectedMsg_, receivedMsg_): return withUser(u, "connEntity: \(String(describing: connEntity))\nexpectedMsg_: \(String(describing: expectedMsg_))\nreceivedMsg_: \(String(describing: receivedMsg_))")
|
||||
case let .connNtfMessage(receivedMsg_): return "receivedMsg_: \(String(describing: receivedMsg_))"
|
||||
case let .ntfMessage(u, connEntity, ntfMessage): return withUser(u, "connEntity: \(String(describing: connEntity))\nntfMessage: \(String(describing: ntfMessage))")
|
||||
case let .contactConnectionDeleted(u, connection): return withUser(u, String(describing: connection))
|
||||
case let .contactDisabled(u, contact): return withUser(u, String(describing: contact))
|
||||
|
||||
@@ -2240,32 +2240,42 @@ public struct MemberSubError: Decodable, Hashable {
|
||||
}
|
||||
|
||||
public enum ConnectionEntity: Decodable, Hashable {
|
||||
case rcvDirectMsgConnection(contact: Contact?)
|
||||
case rcvGroupMsgConnection(groupInfo: GroupInfo, groupMember: GroupMember)
|
||||
case sndFileConnection(sndFileTransfer: SndFileTransfer)
|
||||
case rcvFileConnection(rcvFileTransfer: RcvFileTransfer)
|
||||
case userContactConnection(userContact: UserContact)
|
||||
case rcvDirectMsgConnection(entityConnection: Connection, contact: Contact?)
|
||||
case rcvGroupMsgConnection(entityConnection: Connection, groupInfo: GroupInfo, groupMember: GroupMember)
|
||||
case sndFileConnection(entityConnection: Connection, sndFileTransfer: SndFileTransfer)
|
||||
case rcvFileConnection(entityConnection: Connection, rcvFileTransfer: RcvFileTransfer)
|
||||
case userContactConnection(entityConnection: Connection, userContact: UserContact)
|
||||
|
||||
public var id: String? {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(contact):
|
||||
case let .rcvDirectMsgConnection(_, contact):
|
||||
return contact?.id
|
||||
case let .rcvGroupMsgConnection(_, groupMember):
|
||||
case let .rcvGroupMsgConnection(_, _, groupMember):
|
||||
return groupMember.id
|
||||
case let .userContactConnection(userContact):
|
||||
case let .userContactConnection(_, userContact):
|
||||
return userContact.id
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var conn: Connection {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(entityConnection, _): entityConnection
|
||||
case let .rcvGroupMsgConnection(entityConnection, _, _): entityConnection
|
||||
case let .sndFileConnection(entityConnection, _): entityConnection
|
||||
case let .rcvFileConnection(entityConnection, _): entityConnection
|
||||
case let .userContactConnection(entityConnection, _): entityConnection
|
||||
}
|
||||
}
|
||||
|
||||
public var ntfsEnabled: Bool {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(contact): return contact?.chatSettings.enableNtfs == .all
|
||||
case let .rcvGroupMsgConnection(groupInfo, _): return groupInfo.chatSettings.enableNtfs == .all
|
||||
case let .rcvDirectMsgConnection(_, contact): return contact?.chatSettings.enableNtfs == .all
|
||||
case let .rcvGroupMsgConnection(_, groupInfo, _): return groupInfo.chatSettings.enableNtfs == .all
|
||||
case .sndFileConnection: return false
|
||||
case .rcvFileConnection: return false
|
||||
case let .userContactConnection(userContact): return userContact.groupId == nil
|
||||
case let .userContactConnection(_, userContact): return userContact.groupId == nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2275,6 +2285,11 @@ public struct NtfMsgInfo: Decodable, Hashable {
|
||||
public var msgTs: Date
|
||||
}
|
||||
|
||||
public struct NtfMsgAckInfo: Decodable, Hashable {
|
||||
public var msgId: String
|
||||
public var msgTs_: Date?
|
||||
}
|
||||
|
||||
public struct ChatItemDeletion: Decodable, Hashable {
|
||||
public var deletedChatItem: AChatItem
|
||||
public var toChatItem: AChatItem? = nil
|
||||
|
||||
@@ -94,7 +94,7 @@ public func createConnectionEventNtf(_ user: User, _ connEntity: ConnectionEntit
|
||||
var body: String? = nil
|
||||
var targetContentIdentifier: String? = nil
|
||||
switch connEntity {
|
||||
case let .rcvDirectMsgConnection(contact):
|
||||
case let .rcvDirectMsgConnection(_, contact):
|
||||
if let contact = contact {
|
||||
title = hideContent ? contactHidden : "\(contact.chatViewName):"
|
||||
targetContentIdentifier = contact.id
|
||||
@@ -102,7 +102,7 @@ public func createConnectionEventNtf(_ user: User, _ connEntity: ConnectionEntit
|
||||
title = NSLocalizedString("New contact:", comment: "notification")
|
||||
}
|
||||
body = NSLocalizedString("message received", comment: "notification")
|
||||
case let .rcvGroupMsgConnection(groupInfo, groupMember):
|
||||
case let .rcvGroupMsgConnection(_, groupInfo, groupMember):
|
||||
title = groupMsgNtfTitle(groupInfo, groupMember, hideContent: hideContent)
|
||||
body = NSLocalizedString("message received", comment: "notification")
|
||||
targetContentIdentifier = groupInfo.id
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: da79d544cf990fb0638ae5434407d6a30724fb87
|
||||
tag: b8971a31bcb82fffabcb792c9afd6bc4a96ec649
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."da79d544cf990fb0638ae5434407d6a30724fb87" = "11rxpcg2g781rbr5d20fw6zpv81q06w3c9bh6qh5cpnza230yvl3";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."b8971a31bcb82fffabcb792c9afd6bc4a96ec649" = "1p6m390ngcsp7i7vy0m0zxh167gkbciavva9a00l6pxwzaz9qmpi";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||
|
||||
+17
-6
@@ -54,7 +54,6 @@ import qualified Data.Text as T
|
||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||
import Data.Time (NominalDiffTime, addUTCTime, defaultTimeLocale, formatTime)
|
||||
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime, nominalDay, nominalDiffTimeToSeconds)
|
||||
import Data.Time.Clock.System (systemToUTCTime)
|
||||
import qualified Data.UUID as UUID
|
||||
import qualified Data.UUID.V4 as V4
|
||||
import Data.Word (Word32)
|
||||
@@ -1452,14 +1451,25 @@ processChatCommand' vr = \case
|
||||
APIVerifyToken token nonce code -> withUser $ \_ -> withAgent (\a -> verifyNtfToken a token nonce code) >> ok_
|
||||
APIDeleteToken token -> withUser $ \_ -> withAgent (`deleteNtfToken` token) >> ok_
|
||||
APIGetNtfMessage nonce encNtfInfo -> withUser $ \_ -> do
|
||||
(NotificationInfo {ntfConnId, ntfMsgMeta}, msg) <- withAgent $ \a -> getNotificationMessage a nonce encNtfInfo
|
||||
let msgTs' = systemToUTCTime . (\SMP.NMsgMeta {msgTs} -> msgTs) <$> ntfMsgMeta
|
||||
agentConnId = AgentConnId ntfConnId
|
||||
(NotificationInfo {ntfConnId, ntfMsgMeta = nMsgMeta}, msg) <- withAgent $ \a -> getNotificationMessage a nonce encNtfInfo
|
||||
let agentConnId = AgentConnId ntfConnId
|
||||
user_ <- withStore' (`getUserByAConnId` agentConnId)
|
||||
connEntity_ <-
|
||||
pure user_ $>>= \user ->
|
||||
withStore (\db -> Just <$> getConnectionEntity db vr user agentConnId) `catchChatError` (\e -> toView (CRChatError (Just user) e) $> Nothing)
|
||||
pure CRNtfMessages {user_, connEntity_, msgTs = msgTs', ntfMessage_ = ntfMsgInfo <$> msg}
|
||||
pure
|
||||
CRNtfMessages
|
||||
{ user_,
|
||||
connEntity_,
|
||||
-- Decrypted ntf meta of the expected message (the one notification was sent for)
|
||||
expectedMsg_ = expectedMsgInfo <$> nMsgMeta,
|
||||
-- Info of the first message retrieved by agent using GET
|
||||
-- (may differ from the expected message due to, for example, coalescing or loss of notifications)
|
||||
receivedMsg_ = receivedMsgInfo <$> msg
|
||||
}
|
||||
ApiGetConnNtfMessage (AgentConnId connId) -> withUser $ \_ -> do
|
||||
msg <- withAgent $ \a -> getConnectionMessage a connId
|
||||
pure $ CRConnNtfMessage (receivedMsgInfo <$> msg)
|
||||
APIGetUserProtoServers userId (AProtocolType p) -> withUserId userId $ \user -> withServerProtocol p $ do
|
||||
cfg@ChatConfig {defaultServers} <- asks config
|
||||
servers <- withFastStore' (`getProtocolServers` user)
|
||||
@@ -4343,7 +4353,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
END -> case entity of
|
||||
RcvDirectMsgConnection _ (Just ct) -> toView $ CRContactAnotherClient user ct
|
||||
_ -> toView $ CRSubscriptionEnd user entity
|
||||
MSGNTF smpMsgInfo -> toView $ CRNtfMessage user entity $ ntfMsgInfo smpMsgInfo
|
||||
MSGNTF msgId msgTs_ -> toView $ CRNtfMessage user entity $ ntfMsgAckInfo msgId msgTs_
|
||||
_ -> case entity of
|
||||
RcvDirectMsgConnection conn contact_ ->
|
||||
processDirectMessage agentMessage entity conn contact_
|
||||
@@ -8012,6 +8022,7 @@ chatCommandP =
|
||||
"/_ntf verify " *> (APIVerifyToken <$> strP <* A.space <*> strP <* A.space <*> strP),
|
||||
"/_ntf delete " *> (APIDeleteToken <$> strP),
|
||||
"/_ntf message " *> (APIGetNtfMessage <$> strP <* A.space <*> strP),
|
||||
"/_ntf conn message " *> (ApiGetConnNtfMessage <$> strP),
|
||||
"/_add #" *> (APIAddMember <$> A.decimal <* A.space <*> A.decimal <*> memberRole),
|
||||
"/_join #" *> (APIJoinGroup <$> A.decimal),
|
||||
"/_member role #" *> (APIMemberRole <$> A.decimal <* A.space <*> A.decimal <*> memberRole),
|
||||
|
||||
@@ -44,7 +44,7 @@ import Data.String
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Encoding (decodeLatin1)
|
||||
import Data.Time (NominalDiffTime, UTCTime)
|
||||
import Data.Time.Clock.System (systemToUTCTime)
|
||||
import Data.Time.Clock.System (SystemTime (..), systemToUTCTime)
|
||||
import Data.Version (showVersion)
|
||||
import Data.Word (Word16)
|
||||
import Database.SQLite.Simple (SQLError)
|
||||
@@ -84,7 +84,7 @@ import Simplex.Messaging.Crypto.Ratchet (PQEncryption)
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
|
||||
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
|
||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtocolType (..), ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol)
|
||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, MsgId, NMsgMeta (..), NtfServer, ProtocolType (..), ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol)
|
||||
import Simplex.Messaging.TMap (TMap)
|
||||
import Simplex.Messaging.Transport (TLS, simplexMQVersion)
|
||||
import Simplex.Messaging.Transport.Client (SocksProxyWithAuth, TransportHost)
|
||||
@@ -331,6 +331,7 @@ data ChatCommand
|
||||
| APIVerifyToken DeviceToken C.CbNonce ByteString
|
||||
| APIDeleteToken DeviceToken
|
||||
| APIGetNtfMessage {nonce :: C.CbNonce, encNtfInfo :: ByteString}
|
||||
| ApiGetConnNtfMessage {connId :: AgentConnId}
|
||||
| APIAddMember GroupId ContactId GroupMemberRole
|
||||
| APIJoinGroup GroupId
|
||||
| APIMemberRole GroupId GroupMemberId GroupMemberRole
|
||||
@@ -744,8 +745,9 @@ data ChatResponse
|
||||
| CRUserContactLinkSubError {chatError :: ChatError} -- TODO delete
|
||||
| CRNtfTokenStatus {status :: NtfTknStatus}
|
||||
| CRNtfToken {token :: DeviceToken, status :: NtfTknStatus, ntfMode :: NotificationsMode, ntfServer :: NtfServer}
|
||||
| CRNtfMessages {user_ :: Maybe User, connEntity_ :: Maybe ConnectionEntity, msgTs :: Maybe UTCTime, ntfMessage_ :: Maybe NtfMsgInfo}
|
||||
| CRNtfMessage {user :: User, connEntity :: ConnectionEntity, ntfMessage :: NtfMsgInfo}
|
||||
| CRNtfMessages {user_ :: Maybe User, connEntity_ :: Maybe ConnectionEntity, expectedMsg_ :: Maybe NtfMsgInfo, receivedMsg_ :: Maybe NtfMsgInfo}
|
||||
| CRConnNtfMessage {receivedMsg_ :: Maybe NtfMsgInfo}
|
||||
| CRNtfMessage {user :: User, connEntity :: ConnectionEntity, ntfMessage :: NtfMsgAckInfo}
|
||||
| CRContactConnectionDeleted {user :: User, connection :: PendingContactConnection}
|
||||
| CRRemoteHostList {remoteHosts :: [RemoteHostInfo]}
|
||||
| CRCurrentRemoteHost {remoteHost_ :: Maybe RemoteHostInfo}
|
||||
@@ -1052,8 +1054,21 @@ instance FromJSON ComposedMessage where
|
||||
data NtfMsgInfo = NtfMsgInfo {msgId :: Text, msgTs :: UTCTime}
|
||||
deriving (Show)
|
||||
|
||||
ntfMsgInfo :: SMPMsgMeta -> NtfMsgInfo
|
||||
ntfMsgInfo SMPMsgMeta {msgId, msgTs} = NtfMsgInfo {msgId = decodeLatin1 $ strEncode msgId, msgTs = systemToUTCTime msgTs}
|
||||
receivedMsgInfo :: SMPMsgMeta -> NtfMsgInfo
|
||||
receivedMsgInfo SMPMsgMeta {msgId, msgTs} = ntfMsgInfo_ msgId msgTs
|
||||
|
||||
expectedMsgInfo :: NMsgMeta -> NtfMsgInfo
|
||||
expectedMsgInfo NMsgMeta {msgId, msgTs} = ntfMsgInfo_ msgId msgTs
|
||||
|
||||
ntfMsgInfo_ :: MsgId -> SystemTime -> NtfMsgInfo
|
||||
ntfMsgInfo_ msgId msgTs = NtfMsgInfo {msgId = decodeLatin1 $ strEncode msgId, msgTs = systemToUTCTime msgTs}
|
||||
|
||||
-- Acknowledged message info - used to correlate with expected message
|
||||
data NtfMsgAckInfo = NtfMsgAckInfo {msgId :: Text, msgTs_ :: Maybe UTCTime}
|
||||
deriving (Show)
|
||||
|
||||
ntfMsgAckInfo :: MsgId -> Maybe UTCTime -> NtfMsgAckInfo
|
||||
ntfMsgAckInfo msgId msgTs_ = NtfMsgAckInfo {msgId = decodeLatin1 $ strEncode msgId, msgTs_}
|
||||
|
||||
crNtfToken :: (DeviceToken, NtfTknStatus, NotificationsMode, NtfServer) -> ChatResponse
|
||||
crNtfToken (token, status, ntfMode, ntfServer) = CRNtfToken {token, status, ntfMode, ntfServer}
|
||||
@@ -1504,6 +1519,8 @@ $(JQ.deriveJSON defaultJSON ''UserProfileUpdateSummary)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''NtfMsgInfo)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''NtfMsgAckInfo)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''SwitchProgress)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''RatchetSyncProgress)
|
||||
|
||||
@@ -326,6 +326,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
|
||||
CRNtfTokenStatus status -> ["device token status: " <> plain (smpEncode status)]
|
||||
CRNtfToken _ status mode srv -> ["device token status: " <> plain (smpEncode status) <> ", notifications mode: " <> plain (strEncode mode) <> ", server: " <> sShow srv]
|
||||
CRNtfMessages {} -> []
|
||||
CRConnNtfMessage {} -> []
|
||||
CRNtfMessage {} -> []
|
||||
CRCurrentRemoteHost rhi_ ->
|
||||
[ maybe
|
||||
|
||||
Reference in New Issue
Block a user