Merge branch 'fix/tweaks-to-config-message-generation' of https://github.com/mpretty-cyro/session-ios into bug-fix-for-call
This commit is contained in:
commit
fdde7e4fe0
|
@ -177,6 +177,7 @@
|
|||
7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
7BC707F227290ACB002817AD /* SessionCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC707F127290ACB002817AD /* SessionCallManager.swift */; };
|
||||
7BCD116C27016062006330F1 /* WebRTCSession+DataChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BCD116B27016062006330F1 /* WebRTCSession+DataChannel.swift */; };
|
||||
7BD477A827EC39F5004E2822 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477A727EC39F5004E2822 /* Atomic.swift */; };
|
||||
7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; };
|
||||
7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; };
|
||||
7BFD1A8A2745C4F000FB91B9 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFD1A892745C4F000FB91B9 /* Permissions.swift */; };
|
||||
|
@ -1198,6 +1199,7 @@
|
|||
7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
7BC707F127290ACB002817AD /* SessionCallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionCallManager.swift; sourceTree = "<group>"; };
|
||||
7BCD116B27016062006330F1 /* WebRTCSession+DataChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebRTCSession+DataChannel.swift"; sourceTree = "<group>"; };
|
||||
7BD477A727EC39F5004E2822 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
|
||||
7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
|
||||
7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = "<group>"; };
|
||||
7BFD1A892745C4F000FB91B9 /* Permissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = "<group>"; };
|
||||
|
@ -2433,6 +2435,7 @@
|
|||
B8A582B0258C66C900AFD84C /* General */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7BD477A727EC39F5004E2822 /* Atomic.swift */,
|
||||
7BAF54D527ACD0E2003D12F8 /* ReusableView.swift */,
|
||||
7BAF54D627ACD0E3003D12F8 /* String+Localization.swift */,
|
||||
7BAF54D727ACD0E3003D12F8 /* UITableView+ReusableView.swift */,
|
||||
|
@ -4796,6 +4799,7 @@
|
|||
C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */,
|
||||
B8F5F58325EC94A6003BF8D4 /* Collection+Subscripting.swift in Sources */,
|
||||
C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */,
|
||||
7BD477A827EC39F5004E2822 /* Atomic.swift in Sources */,
|
||||
B8BC00C0257D90E30032E807 /* General.swift in Sources */,
|
||||
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */,
|
||||
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */,
|
||||
|
|
|
@ -283,10 +283,8 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
let linkPreviewDraft = snInputView.linkPreviewInfo?.draft
|
||||
let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread)
|
||||
|
||||
Storage.write(with: { transaction in
|
||||
let promise: Promise<Void> = self.approveMessageRequestIfNeeded(
|
||||
for: self.thread,
|
||||
with: transaction,
|
||||
isNewThread: !oldThreadShouldBeVisible,
|
||||
timestamp: (sentTimestamp - 1) // Set 1ms earlier as this is used for sorting
|
||||
)
|
||||
|
@ -325,7 +323,6 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
}
|
||||
|
||||
promise.retainUntilComplete()
|
||||
})
|
||||
}
|
||||
|
||||
func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) {
|
||||
|
@ -349,10 +346,8 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
let oldThreadShouldBeVisible: Bool = thread.shouldBeVisible
|
||||
let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread)
|
||||
|
||||
Storage.write(with: { transaction in
|
||||
let promise: Promise<Void> = self.approveMessageRequestIfNeeded(
|
||||
for: self.thread,
|
||||
with: transaction,
|
||||
isNewThread: !oldThreadShouldBeVisible,
|
||||
timestamp: (sentTimestamp - 1) // Set 1ms earlier as this is used for sorting
|
||||
)
|
||||
|
@ -386,7 +381,6 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
}
|
||||
|
||||
promise.retainUntilComplete()
|
||||
})
|
||||
}
|
||||
|
||||
func handleMessageSent() {
|
||||
|
@ -1128,7 +1122,7 @@ extension ConversationVC: UIDocumentInteractionControllerDelegate {
|
|||
|
||||
extension ConversationVC {
|
||||
|
||||
fileprivate func approveMessageRequestIfNeeded(for thread: TSThread?, with transaction: YapDatabaseReadWriteTransaction, isNewThread: Bool, timestamp: UInt64) -> Promise<Void> {
|
||||
fileprivate func approveMessageRequestIfNeeded(for thread: TSThread?, isNewThread: Bool, timestamp: UInt64) -> Promise<Void> {
|
||||
guard let contactThread: TSContactThread = thread as? TSContactThread else { return Promise.value(()) }
|
||||
|
||||
// If the contact doesn't exist then we should create it so we can store the 'isApproved' state
|
||||
|
@ -1159,7 +1153,17 @@ extension ConversationVC {
|
|||
}
|
||||
|
||||
return promise
|
||||
.then { MessageSender.sendNonDurably(messageRequestResponse, in: contactThread, using: transaction) }
|
||||
.then { _ -> Promise<Void> in
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
Storage.writeSync { transaction in
|
||||
MessageSender.sendNonDurably(messageRequestResponse, in: contactThread, using: transaction)
|
||||
.done { seal.fulfill(()) }
|
||||
.catch { _ in seal.fulfill(()) } // Fulfill even if this failed; the configuration in the swarm should be at most 2 days old
|
||||
.retainUntilComplete()
|
||||
}
|
||||
|
||||
return promise
|
||||
}
|
||||
.map { _ in
|
||||
if self?.presentedViewController is ModalActivityIndicatorViewController {
|
||||
self?.dismiss(animated: true, completion: nil) // Dismiss the loader
|
||||
|
@ -1168,9 +1172,11 @@ extension ConversationVC {
|
|||
}
|
||||
.map { _ in
|
||||
// Default 'didApproveMe' to true for the person approving the message request
|
||||
Storage.write { transaction in
|
||||
contact.isApproved = true
|
||||
contact.didApproveMe = (contact.didApproveMe || !isNewThread)
|
||||
Storage.shared.setContact(contact, using: transaction)
|
||||
}
|
||||
|
||||
// Hide the 'messageRequestView' since the request has been approved and force a config
|
||||
// sync to propagate the contact approval state (both must run on the main thread)
|
||||
|
@ -1208,17 +1214,15 @@ extension ConversationVC {
|
|||
|
||||
// Send a sync message with the details of the contact
|
||||
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
|
||||
appDelegate.forceSyncConfigurationNowIfNeeded(with: transaction).retainUntilComplete()
|
||||
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func acceptMessageRequest() {
|
||||
Storage.write { transaction in
|
||||
let promise: Promise<Void> = self.approveMessageRequestIfNeeded(
|
||||
for: self.thread,
|
||||
with: transaction,
|
||||
isNewThread: false,
|
||||
timestamp: NSDate.millisecondTimestamp()
|
||||
)
|
||||
|
@ -1232,7 +1236,6 @@ extension ConversationVC {
|
|||
|
||||
promise.retainUntilComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func deleteMessageRequest() {
|
||||
guard let uniqueId: String = thread.uniqueId else { return }
|
||||
|
|
|
@ -144,10 +144,11 @@ extension AppDelegate {
|
|||
guard Storage.shared.getUser()?.name != nil else { return }
|
||||
let userDefaults = UserDefaults.standard
|
||||
let lastSync = userDefaults[.lastConfigurationSync] ?? .distantPast
|
||||
guard Date().timeIntervalSince(lastSync) > 7 * 24 * 60 * 60,
|
||||
let configurationMessage = ConfigurationMessage.getCurrent() else { return } // Sync every 2 days
|
||||
guard Date().timeIntervalSince(lastSync) > 7 * 24 * 60 * 60 else { return } // Sync every 2 days
|
||||
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
|
||||
Storage.shared.write { transaction in
|
||||
Storage.write { transaction in
|
||||
guard let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else { return }
|
||||
|
||||
let job = MessageSendJob(message: configurationMessage, destination: destination)
|
||||
JobQueue.shared.add(job, using: transaction)
|
||||
}
|
||||
|
@ -159,14 +160,17 @@ extension AppDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
func forceSyncConfigurationNowIfNeeded(with transaction: YapDatabaseReadWriteTransaction? = nil) -> Promise<Void> {
|
||||
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
|
||||
return Promise.value(())
|
||||
}
|
||||
|
||||
func forceSyncConfigurationNowIfNeeded() -> Promise<Void> {
|
||||
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
|
||||
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
|
||||
Storage.writeSync { transaction in
|
||||
guard Storage.shared.getUser(using: transaction)?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
|
||||
seal.fulfill(())
|
||||
return
|
||||
}
|
||||
|
||||
MessageSender.send(configurationMessage, to: destination, using: transaction).done {
|
||||
seal.fulfill(())
|
||||
}.catch { _ in
|
||||
|
|
|
@ -135,7 +135,7 @@ final class NukeDataModal : Modal {
|
|||
appDelegate.forceSyncConfigurationNowIfNeeded().ensure(on: DispatchQueue.main) {
|
||||
self?.dismiss(animated: true, completion: nil) // Dismiss the loader
|
||||
UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later
|
||||
General.Cache.cachedEncodedPublicKey = nil // Remove the cached key so it gets re-cached on next access
|
||||
General.Cache.cachedEncodedPublicKey.mutate { $0 = nil } // Remove the cached key so it gets re-cached on next access
|
||||
NotificationCenter.default.post(name: .dataNukeRequested, object: nil)
|
||||
}.retainUntilComplete()
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ final class NukeDataModal : Modal {
|
|||
self?.dismiss(animated: true, completion: nil) // Dismiss the loader
|
||||
let potentiallyMaliciousSnodes = confirmations.compactMap { $0.value == false ? $0.key : nil }
|
||||
if potentiallyMaliciousSnodes.isEmpty {
|
||||
General.Cache.cachedEncodedPublicKey = nil // Remove the cached key so it gets re-cached on next access
|
||||
General.Cache.cachedEncodedPublicKey.mutate { $0 = nil } // Remove the cached key so it gets re-cached on next access
|
||||
UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later
|
||||
NotificationCenter.default.post(name: .dataNukeRequested, object: nil)
|
||||
} else {
|
||||
|
|
|
@ -40,7 +40,7 @@ extension Storage {
|
|||
}
|
||||
|
||||
public func getUser(using transaction: YapDatabaseReadTransaction?) -> Contact? {
|
||||
guard let userPublicKey = getUserPublicKey() else { return nil }
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
var result: Contact?
|
||||
|
||||
if let transaction = transaction {
|
||||
|
|
|
@ -2,7 +2,7 @@ import SessionUtilitiesKit
|
|||
|
||||
extension ConfigurationMessage {
|
||||
|
||||
public static func getCurrent(with transaction: YapDatabaseReadWriteTransaction? = nil) -> ConfigurationMessage? {
|
||||
public static func getCurrent(with transaction: YapDatabaseReadTransaction) -> ConfigurationMessage? {
|
||||
let storage = Storage.shared
|
||||
guard let user = storage.getUser(using: transaction) else { return nil }
|
||||
|
||||
|
@ -13,7 +13,6 @@ extension ConfigurationMessage {
|
|||
var openGroups: Set<String> = []
|
||||
var contacts: Set<ConfigurationMessage.Contact> = []
|
||||
|
||||
let populateDataClosure: (YapDatabaseReadTransaction) -> () = { transaction in
|
||||
TSGroupThread.enumerateCollectionObjects(with: transaction) { object, _ in
|
||||
guard let thread = object as? TSGroupThread else { return }
|
||||
|
||||
|
@ -53,10 +52,10 @@ extension ConfigurationMessage {
|
|||
let currentUserPublicKey: String = getUserHexEncodedPublicKey()
|
||||
|
||||
contacts = storage.getAllContacts(with: transaction)
|
||||
.filter { contact -> Bool in
|
||||
.compactMap { contact -> ConfigurationMessage.Contact? in
|
||||
let threadID = TSContactThread.threadID(fromContactSessionID: contact.sessionID)
|
||||
|
||||
return (
|
||||
guard
|
||||
// Skip the current user
|
||||
contact.sessionID != currentUserPublicKey &&
|
||||
// Contacts which have visible threads
|
||||
|
@ -69,9 +68,10 @@ extension ConfigurationMessage {
|
|||
// Sync blocked contacts
|
||||
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID)
|
||||
)
|
||||
)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
.map { contact -> ConfigurationMessage.Contact in
|
||||
|
||||
// Can just default the 'hasX' values to true as they will be set to this
|
||||
// when converting to proto anyway
|
||||
let profilePictureURL = contact.profilePictureURL
|
||||
|
@ -91,16 +91,6 @@ extension ConfigurationMessage {
|
|||
)
|
||||
}
|
||||
.asSet()
|
||||
}
|
||||
|
||||
// If we are provided with a transaction then read the data based on the state of the database
|
||||
// from within the transaction rather than the state in disk
|
||||
if let transaction: YapDatabaseReadWriteTransaction = transaction {
|
||||
populateDataClosure(transaction)
|
||||
}
|
||||
else {
|
||||
Storage.read { transaction in populateDataClosure(transaction) }
|
||||
}
|
||||
|
||||
return ConfigurationMessage(
|
||||
displayName: displayName,
|
||||
|
|
|
@ -869,7 +869,8 @@ extension MessageReceiver {
|
|||
// a new configuration message (otherwise the `contact` will be loaded direct from the database and the
|
||||
// `didApproveMe` value won't have been updated)
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent() else {
|
||||
Storage.write { transaction in
|
||||
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -877,6 +878,7 @@ extension MessageReceiver {
|
|||
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func handleMessageRequestResponse(_ message: MessageRequestResponse, using transaction: Any) {
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
|
||||
public enum General {
|
||||
public enum Cache {
|
||||
public static var cachedEncodedPublicKey: String? = nil
|
||||
public static var cachedEncodedPublicKey: Atomic<String?> = Atomic(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,10 @@ public class GeneralUtilities: NSObject {
|
|||
}
|
||||
|
||||
public func getUserHexEncodedPublicKey() -> String {
|
||||
if let cachedKey: String = General.Cache.cachedEncodedPublicKey { return cachedKey }
|
||||
if let cachedKey: String = General.Cache.cachedEncodedPublicKey.wrappedValue { return cachedKey }
|
||||
|
||||
if let keyPair = OWSIdentityManager.shared().identityKeyPair() { // Can be nil under some circumstances
|
||||
General.Cache.cachedEncodedPublicKey = keyPair.hexEncodedPublicKey
|
||||
General.Cache.cachedEncodedPublicKey.mutate { $0 = keyPair.hexEncodedPublicKey }
|
||||
return keyPair.hexEncodedPublicKey
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
import Foundation
|
||||
|
||||
// MARK: - Atomic<Value>
|
||||
/// The `Atomic<Value>` wrapper is a generic wrapper providing a thread-safe way to get and set a value
|
||||
///
|
||||
/// A write-up on the need for this class and it's approach can be found here:
|
||||
/// https://www.vadimbulavin.com/swift-atomic-properties-with-property-wrappers/
|
||||
/// there is also another approach which can be taken but it requires separate types for collections and results in
|
||||
/// a somewhat inconsistent interface between different `Atomic` wrappers
|
||||
@propertyWrapper
|
||||
public class Atomic<Value> {
|
||||
private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)")
|
||||
private var value: Value
|
||||
|
||||
/// In order to change the value you **must** use the `mutate` function
|
||||
public var wrappedValue: Value {
|
||||
return queue.sync { return value }
|
||||
}
|
||||
|
||||
/// For more information see https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#projections
|
||||
public var projectedValue: Atomic<Value> {
|
||||
return self
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
public init(_ initialValue: Value) {
|
||||
self.value = initialValue
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public func mutate(_ mutation: (inout Value) -> Void) {
|
||||
return queue.sync {
|
||||
mutation(&value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Atomic where Value: CustomDebugStringConvertible {
|
||||
var debugDescription: String {
|
||||
return value.debugDescription
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue