From d0a3758ff4befc471850575fe0137b7063646345 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 12 Jun 2020 09:49:49 +1000 Subject: [PATCH] Fix thread safety issues --- .../src/Loki/API/LokiAPI+SwarmAPI.swift | 53 +++++++++++++++++-- SignalServiceKit/src/Loki/API/LokiAPI.swift | 1 + .../Protocol/Mentions/MentionsManager.swift | 17 +++++- .../Multi Device/MultiDeviceProtocol.swift | 16 +++++- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift index a69158a1f..16b698809 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift @@ -1,13 +1,58 @@ import PromiseKit public extension LokiAPI { - private static var snodeVersion: [LokiAPITarget:String] = [:] fileprivate static let seedNodePool: Set = [ "https://storage.seed1.loki.network", "https://storage.seed3.loki.network", "https://public.loki.foundation" ] - internal static var snodeFailureCount: [LokiAPITarget:UInt] = [:] - internal static var snodePool: Set = [] - internal static var swarmCache: [String:[LokiAPITarget]] = [:] // TODO: Make this set based? + internal static var _snodeFailureCount: [LokiAPITarget:UInt] = [:] + internal static var snodeFailureCount: [LokiAPITarget:UInt] { + get { + let (promise, seal) = Promise<[LokiAPITarget:UInt]>.pending() + stateQueue.async { + seal.fulfill(_snodeFailureCount) + } + return try! promise.wait() + } + set { + LokiAPI.stateQueue.async { + _snodeFailureCount = newValue + } + } + } + + // TODO: Read/write this directly from/to the database + internal static var _snodePool: Set = [] + internal static var snodePool: Set { + get { + let (promise, seal) = Promise>.pending() + stateQueue.async { + seal.fulfill(_snodePool) + } + return try! promise.wait() + } + set { + LokiAPI.stateQueue.async { + _snodePool = newValue + } + } + } + + // TODO: Read/write this directly from/to the database + internal static var _swarmCache: [String:[LokiAPITarget]] = [:] + internal static var swarmCache: [String:[LokiAPITarget]] { + get { + let (promise, seal) = Promise<[String:[LokiAPITarget]]>.pending() + stateQueue.async { + seal.fulfill(_swarmCache) + } + return try! promise.wait() + } + set { + LokiAPI.stateQueue.async { + _swarmCache = newValue + } + } + } // MARK: Settings private static let minimumSnodePoolCount = 32 diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index e3c63db67..5dd1a9c8a 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -2,6 +2,7 @@ import PromiseKit @objc(LKAPI) public final class LokiAPI : NSObject { + internal static let stateQueue = DispatchQueue(label: "LokiAPI.stateQueue", qos: .userInitiated) internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } diff --git a/SignalServiceKit/src/Loki/Protocol/Mentions/MentionsManager.swift b/SignalServiceKit/src/Loki/Protocol/Mentions/MentionsManager.swift index d5a9f3454..3842eee81 100644 --- a/SignalServiceKit/src/Loki/Protocol/Mentions/MentionsManager.swift +++ b/SignalServiceKit/src/Loki/Protocol/Mentions/MentionsManager.swift @@ -1,9 +1,24 @@ +import PromiseKit @objc(LKMentionsManager) public final class MentionsManager : NSObject { + @objc public static var _userPublicKeyCache: [String:Set] = [:] /// A mapping from thread ID to set of user hex encoded public keys. - @objc public static var userPublicKeyCache: [String:Set] = [:] + @objc public static var userPublicKeyCache: [String:Set] { + get { + let (promise, seal) = Promise<[String:Set]>.pending() + LokiAPI.stateQueue.async { + seal.fulfill(_userPublicKeyCache) + } + return try! promise.wait() + } + set { + LokiAPI.stateQueue.async { + _userPublicKeyCache = newValue + } + } + } internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index 1a8bb43cc..aaaff3aec 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -15,8 +15,22 @@ import PromiseKit @objc(LKMultiDeviceProtocol) public final class MultiDeviceProtocol : NSObject { + public static var _lastDeviceLinkUpdate: [String:Date] = [:] /// A mapping from hex encoded public key to date updated. - public static var lastDeviceLinkUpdate: [String:Date] = [:] + public static var lastDeviceLinkUpdate: [String:Date] { + get { + let (promise, seal) = Promise<[String:Date]>.pending() + LokiAPI.stateQueue.async { + seal.fulfill(_lastDeviceLinkUpdate) + } + return try! promise.wait() + } + set { + LokiAPI.stateQueue.async { + _lastDeviceLinkUpdate = newValue + } + } + } internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() }