mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			123 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			123 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Swift
		
	
| 
											7 years ago
										 | // | ||
|  | //  Copyright (c) 2018 Open Whisper Systems. All rights reserved. | ||
|  | // | ||
|  | 
 | ||
|  | import Foundation | ||
|  | 
 | ||
|  | @objc(OWSBlockListCacheDelegate) | ||
|  | public protocol BlockListCacheDelegate: class { | ||
|  |     func blockListCacheDidUpdate(_ blocklistCache: BlockListCache) | ||
|  | } | ||
|  | 
 | ||
| 
											7 years ago
										 | /// A performant cache for which contacts/groups are blocked. | ||
|  | /// | ||
|  | /// The source of truth for which contacts and groups are blocked is the `blockingManager`, but because | ||
|  | /// those accessors are made to be thread safe, they can be slow in tight loops, e.g. when rendering table | ||
|  | /// view cells. | ||
|  | /// | ||
|  | /// Typically you'll want to create a Cache, update it to the latest state while simultaneously being informed | ||
|  | /// of any future changes to block list state. | ||
|  | /// | ||
|  | ///     class SomeViewController: BlockListCacheDelegate { | ||
|  | ///         let blockListCache = BlockListCache() | ||
|  | ///         func viewDidLoad() { | ||
|  | ///            super.viewDidLoad() | ||
|  | ///            blockListCache.startObservingAndSyncState(delegate: self) | ||
|  | ///            self.updateAnyViewsWhichDepondOnBlockListCache() | ||
|  | ///         } | ||
|  | /// | ||
|  | ///         func blockListCacheDidUpdate(_ blocklistCache: BlockListCache) { | ||
|  | ///             self.updateAnyViewsWhichDepondOnBlockListCache() | ||
|  | ///         } | ||
|  | /// | ||
|  | ///         ... | ||
|  | ///      } | ||
|  | /// | ||
| 
											7 years ago
										 | @objc(OWSBlockListCache) | ||
|  | public class BlockListCache: NSObject { | ||
|  | 
 | ||
|  |     private var blockedRecipientIds: Set<String> = Set() | ||
|  |     private var blockedGroupIds: Set<Data> = Set() | ||
|  |     private let serialQueue: DispatchQueue = DispatchQueue(label: "BlockListCache") | ||
|  |     weak var delegate: BlockListCacheDelegate? | ||
|  | 
 | ||
|  |     private var blockingManager: OWSBlockingManager { | ||
|  |         return OWSBlockingManager.shared() | ||
|  |     } | ||
|  | 
 | ||
|  |     /// Generally something which wants to use this cache wants to do 3 things | ||
|  |     ///   1. get the cache on the latest state | ||
|  |     ///   2. update the cache whenever the blockingManager's state changes | ||
|  |     ///   3. be notified when the cache updates | ||
|  |     /// This method does all three. | ||
|  |     @objc | ||
|  |     public func startObservingAndSyncState(delegate: BlockListCacheDelegate) { | ||
|  |         self.delegate = delegate | ||
|  |         NotificationCenter.default.addObserver(self, | ||
|  |                                                selector: #selector(blockListDidChange), | ||
|  |                                                name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange), | ||
|  |                                                object: nil) | ||
|  |         updateWithoutNotifyingDelegate() | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: - | ||
|  | 
 | ||
|  |     @objc | ||
|  |     func blockListDidChange() { | ||
|  |         self.update() | ||
|  |     } | ||
|  | 
 | ||
|  |     @objc(isRecipientIdBlocked:) | ||
|  |     public func isBlocked(recipientId: String) -> Bool { | ||
|  |         return serialQueue.sync { | ||
|  |             blockedRecipientIds.contains(recipientId) | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     @objc(isGroupIdBlocked:) | ||
|  |     public func isBlocked(groupId: Data) -> Bool { | ||
|  |         return serialQueue.sync { | ||
|  |             blockedGroupIds.contains(groupId) | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     @objc(isThreadBlocked:) | ||
|  |     public func isBlocked(thread: TSThread) -> Bool { | ||
|  |         switch thread { | ||
|  |         case let contactThread as TSContactThread: | ||
|  |             return serialQueue.sync { | ||
|  |                 blockedRecipientIds.contains(contactThread.contactIdentifier()) | ||
|  |             } | ||
|  |         case let groupThread as TSGroupThread: | ||
|  |             return serialQueue.sync { | ||
|  |                 blockedGroupIds.contains(groupThread.groupModel.groupId) | ||
|  |             } | ||
|  |         default: | ||
| 
											7 years ago
										 |             owsFailDebug("\(self.logTag) in \(#function) unexpected thread type: \(type(of: thread))") | ||
| 
											7 years ago
										 |             return false | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: - | ||
|  | 
 | ||
|  |     public func update() { | ||
|  |         updateWithoutNotifyingDelegate() | ||
|  |         DispatchQueue.main.async { | ||
|  |             self.delegate?.blockListCacheDidUpdate(self) | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     private func updateWithoutNotifyingDelegate() { | ||
|  |         let blockedRecipientIds = Set(blockingManager.blockedPhoneNumbers()) | ||
|  |         let blockedGroupIds = Set(blockingManager.blockedGroupIds) | ||
|  |         update(blockedRecipientIds: blockedRecipientIds, blockedGroupIds: blockedGroupIds) | ||
|  |     } | ||
|  | 
 | ||
|  |     private func update(blockedRecipientIds: Set<String>, blockedGroupIds: Set<Data>) { | ||
|  |         serialQueue.sync { | ||
|  |             self.blockedRecipientIds = blockedRecipientIds | ||
|  |             self.blockedGroupIds = blockedGroupIds | ||
|  |         } | ||
|  |     } | ||
|  | } |