Persist swarm cache & make access modifiers explicit

pull/26/head
Niels Andriesse 5 years ago
parent cef9405473
commit 5af0ad03b9

@ -1204,6 +1204,8 @@ static NSTimeInterval launchStartedAt;
{
OWSAssertIsOnMainThread();
OWSLogInfo(@"storageIsReady");
[LokiAPI loadSwarmCache];
[self checkIfAppIsReady];
}

@ -1,6 +1,6 @@
import PromiseKit
extension LokiAPI {
public extension LokiAPI {
// MARK: Settings
private static let minimumSnodeCount = 2
@ -8,7 +8,26 @@ extension LokiAPI {
private static let defaultSnodePort: UInt16 = 8080
// MARK: Caching
fileprivate static var swarmCache: [String:[Target]] = [:] // TODO: Persist on disk
private static let swarmCacheKey = "swarmCacheKey"
private static let swarmCacheCollection = "swarmCacheCollection"
fileprivate static var swarmCache: [String:[Target]] = [:]
@objc public static func loadSwarmCache() {
var result: [String:[Target]]? = nil
storage.dbReadConnection.read { transaction in
let intermediate = transaction.object(forKey: swarmCacheKey, inCollection: swarmCacheCollection) as! [String:[TargetWrapper]]
result = intermediate.mapValues { $0.map { Target(from: $0) } }
}
swarmCache = result ?? [:]
}
private static func saveSwarmCache() {
let intermediate = swarmCache.mapValues { $0.map { TargetWrapper(from: $0) } }
storage.dbReadWriteConnection.readWrite { transaction in
transaction.setObject(intermediate, forKey: swarmCacheKey, inCollection: swarmCacheCollection)
}
}
// MARK: Internal API
private static func getRandomSnode() -> Promise<Target> {
@ -22,7 +41,10 @@ extension LokiAPI {
return Promise<[Target]> { $0.fulfill(cachedSwarm) }
} else {
let parameters: [String:Any] = [ "pubKey" : hexEncodedPublicKey ]
return getRandomSnode().then { invoke(.getSwarm, on: $0, associatedWith: hexEncodedPublicKey, parameters: parameters) }.map { parseTargets(from: $0) }.get { swarmCache[hexEncodedPublicKey] = $0 }
return getRandomSnode().then { invoke(.getSwarm, on: $0, associatedWith: hexEncodedPublicKey, parameters: parameters) }.map { parseTargets(from: $0) }.get { swarm in
swarmCache[hexEncodedPublicKey] = swarm
saveSwarmCache()
}
}
}
@ -46,9 +68,10 @@ extension LokiAPI {
}
}
// MARK: Error Handling
internal extension Promise {
func handlingSwarmSpecificErrorsIfNeeded(for target: LokiAPI.Target, associatedWith hexEncodedPublicKey: String) -> Promise<T> {
internal func handlingSwarmSpecificErrorsIfNeeded(for target: LokiAPI.Target, associatedWith hexEncodedPublicKey: String) -> Promise<T> {
return recover { error -> Promise<T> in
if let error = error as? NetworkManagerError {
switch error.statusCode {

@ -0,0 +1,26 @@
internal extension LokiAPI {
internal struct Target : Hashable {
internal let address: String
internal let port: UInt16
internal init(address: String, port: UInt16) {
self.address = address
self.port = port
}
internal init(from targetWrapper: TargetWrapper) {
self.address = targetWrapper.address
self.port = targetWrapper.port
}
internal enum Method : String {
/// Only supported by snode targets.
case getSwarm = "get_snodes_for_pubkey"
/// Only supported by snode targets.
case getMessages = "retrieve"
case sendMessage = "store"
}
}
}

@ -0,0 +1,22 @@
@objc internal final class TargetWrapper : NSObject, NSCoding {
internal let address: String
internal let port: UInt16
internal init(from target: LokiAPI.Target) {
address = target.address
port = target.port
super.init()
}
internal init?(coder: NSCoder) {
address = coder.decodeObject(forKey: "address") as! String
port = coder.decodeObject(forKey: "port") as! UInt16
super.init()
}
internal func encode(with coder: NSCoder) {
coder.encode(address, forKey: "address")
coder.encode(port, forKey: "port")
}
}

@ -1,26 +1,15 @@
import PromiseKit
@objc public final class LokiAPI : NSObject {
private static let storage = OWSPrimaryStorage.shared()
internal static let storage = OWSPrimaryStorage.shared()
// MARK: Settings
private static let version = "v1"
public static let defaultMessageTTL: UInt64 = 1 * 24 * 60 * 60
private static let receivedMessageHashValuesKey = "receivedMessageHashValuesKey"
private static let receivedMessageHashValuesCollection = "receivedMessageHashValuesCollection"
// MARK: Types
internal struct Target : Hashable {
let address: String
let port: UInt16
enum Method : String {
/// Only supported by snode targets.
case getSwarm = "get_snodes_for_pubkey"
/// Only supported by snode targets.
case getMessages = "retrieve"
case sendMessage = "store"
}
}
public typealias RawResponse = Any
public enum Error : LocalizedError {
@ -149,21 +138,21 @@ import PromiseKit
private static func getReceivedMessageHashValues() -> Set<String>? {
var result: Set<String>? = nil
storage.dbReadConnection.read { transaction in
result = storage.getReceivedMessageHashes(with: transaction)
result = transaction.object(forKey: receivedMessageHashValuesKey, inCollection: receivedMessageHashValuesCollection) as! Set<String>?
}
return result
}
private static func setReceivedMessageHashValues(to receivedMessageHashValues: Set<String>) {
storage.dbReadWriteConnection.readWrite { transaction in
storage.setReceivedMessageHashes(receivedMessageHashValues, with: transaction)
transaction.setObject(receivedMessageHashValues, forKey: receivedMessageHashValuesKey, inCollection: receivedMessageHashValuesCollection)
}
}
}
private extension AnyPromise {
static func from<T : Any>(_ promise: Promise<T>) -> AnyPromise {
fileprivate static func from<T : Any>(_ promise: Promise<T>) -> AnyPromise {
let result = AnyPromise(promise)
result.retainUntilComplete()
return result

@ -1,11 +1,11 @@
public extension ECKeyPair {
@objc var hexEncodedPrivateKey: String {
@objc public var hexEncodedPrivateKey: String {
return privateKey.map { String(format: "%02hhx", $0) }.joined()
}
@objc var hexEncodedPublicKey: String {
@objc public var hexEncodedPublicKey: String {
// Prefixing with "05" is necessary for what seems to be a sort of Signal public key versioning system
// Ref: [NSData prependKeyType] in AxolotKit
return "05" + publicKey.map { String(format: "%02hhx", $0) }.joined()

@ -4,7 +4,7 @@ import Curve25519Kit
private extension String {
// Convert hex string to Data
var hexData: Data {
fileprivate var hexData: Data {
var hex = self
var data = Data()
while(hex.count > 0) {

@ -95,9 +95,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)setLastMessageHashForServiceNode:(NSString *)serviceNode hash:(NSString *)hash expiresAt:(u_int64_t)expiresAt transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(setLastMessageHash(forServiceNode:hash:expiresAt:transaction:));
- (NSSet<NSString *> *_Nullable)getReceivedMessageHashesWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (void)setReceivedMessageHashes:(NSSet<NSString *> *)receivedMessageHashes withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
@end
NS_ASSUME_NONNULL_END

@ -153,12 +153,4 @@
[transaction removeObjectForKey:serviceNode inCollection:LKLastMessageHashCollection];
}
- (NSSet<NSString *> *_Nullable)getReceivedMessageHashesWithTransaction:(YapDatabaseReadTransaction *)transaction {
return (NSSet *)[[transaction objectForKey:LKReceivedMessageHashesKey inCollection:LKReceivedMessageHashesCollection] as:NSSet.class];
}
- (void)setReceivedMessageHashes:(NSSet<NSString *> *)receivedMessageHashes withTransaction:(YapDatabaseReadWriteTransaction *)transaction {
[transaction setObject:receivedMessageHashes forKey:LKReceivedMessageHashesKey inCollection:LKReceivedMessageHashesCollection];
}
@end

@ -2,12 +2,12 @@ import CryptoSwift
private extension UInt64 {
init(_ decimal: Decimal) {
fileprivate init(_ decimal: Decimal) {
self.init(truncating: decimal as NSDecimalNumber)
}
// Convert a UInt8 array to a UInt64
init(_ bytes: [UInt8]) {
fileprivate init(_ bytes: [UInt8]) {
precondition(bytes.count <= MemoryLayout<UInt64>.size)
var value: UInt64 = 0
for byte in bytes {
@ -24,7 +24,7 @@ private extension MutableCollection where Element == UInt8, Index == Int {
///
/// - Parameter amount: The amount to increment by
/// - Returns: The incremented collection
func increment(by amount: Int) -> Self {
fileprivate func increment(by amount: Int) -> Self {
var result = self
var increment = amount
for i in (0..<result.count).reversed() {

@ -156,7 +156,7 @@ public final class FriendRequestExpirationJob : NSObject {
// MARK: Events
private extension FriendRequestExpirationJob {
@objc func didBecomeActive() {
@objc fileprivate func didBecomeActive() {
AssertIsOnMainThread()
AppReadiness.runNowOrWhenAppDidBecomeReady {
FriendRequestExpirationJob.serialQueue.async {
@ -165,7 +165,7 @@ private extension FriendRequestExpirationJob {
}
}
@objc func willResignActive() {
@objc fileprivate func willResignActive() {
AssertIsOnMainThread()
resetNextExpireTimer()
}
@ -175,7 +175,7 @@ private extension FriendRequestExpirationJob {
// MARK: Asserts
private extension FriendRequestExpirationJob {
func AssertIsOnFriendRequestExpireQueue() {
fileprivate func AssertIsOnFriendRequestExpireQueue() {
#if DEBUG
guard #available(iOS 10.0, *) else { return }
dispatchPrecondition(condition: .onQueue(FriendRequestExpirationJob.serialQueue))

@ -1,6 +1,6 @@
import PromiseKit
extension Promise : Hashable {
public extension Promise : Hashable {
public func hash(into hasher: inout Hasher) {
let reference = ObjectIdentifier(self).hashValue

Loading…
Cancel
Save