Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  FeatureMask.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import Foundation
import ThreemaEssentials
import ThreemaProtocols

enum FeatureMaskError: Error {
    case unknownError
}

public final class FeatureMask: NSObject, FeatureMaskProtocol {
    
    // MARK: - Local
    
    /// Updates local feature mask and sends it to server
    public static func updateLocal(completion: (() -> Void)? = nil, onError: ((Error) -> Void)? = nil) {

        let identityStore = MyIdentityStore.shared()

        let defaults = AppGroup.userDefaults()
        
        let lastUpdate = defaults?.object(forKey: "LastFeatureMaskSet") as? Date ?? .distantPast
        let updateThreshold = Calendar.current.date(byAdding: .day, value: -1, to: .now) ?? .now
        
        let newMask = FeatureMaskBuilder.current().build()
        let lastMask = identityStore.lastSentFeatureMask
        
        guard updateThreshold > lastUpdate || newMask != lastMask else {
            DDLogVerbose("Local feature mask is up-to-date.")
            completion?()
            return
        }
            
        DDLogNotice("[FeatureMask] Update feature mask on Server to: new=\(newMask) old=\(lastMask)")
        let serverAPIConnector = ServerAPIConnector()
        serverAPIConnector.setFeatureMask(NSNumber(integerLiteral: newMask), for: identityStore) {
            identityStore.lastSentFeatureMask = newMask
            defaults?.set(Date.now, forKey: "LastFeatureMaskSet")
            defaults?.synchronize()
            completion?()
        } onError: { error in
            identityStore.lastSentFeatureMask = 0
            
            let fullError: Error =
                if let error {
                    error
                }
                else {
                    FeatureMaskError.unknownError
                }
            
            if let onError {
                onError(fullError)
            }
            else {
                DDLogError("Update feature mask failed with error: \(fullError)")
                completion?()
            }
        }
    }

    /// Updates local feature mask and sends it to server
    ///
    /// Async version of `updateLocal(completion:)`
    public static func updateLocal() async throws {
        try await withCheckedThrowingContinuation { continuation in
            updateLocal {
                continuation.resume()
            } onError: { error in
                continuation.resume(throwing: error)
            }
        }
    }

    // MARK: - Contacts

    /// Get Feature Masks of given contacts from sever.
    /// - Parameter identities: Get Feature Masks for Identities
    /// - Returns: Dictionary with Identity and it's Feature Mask
    @objc static func getFeatureMask(for identities: [String]) async throws -> [String: Int] {
        guard !identities.isEmpty else {
            return [:]
        }

        return try await withCheckedThrowingContinuation { continuation in
            let serverAPIConnector = ServerAPIConnector()
            serverAPIConnector.getFeatureMasks(forIdentities: identities) { featureMasks in
                var values: [String: Int] = [:]
                if let masks = featureMasks as? [Int] {
                    var index = 0
                    for identity in identities {
                        values[identity] = masks[index]
                        index += 1
                    }
                }
                continuation.resume(returning: values)
            } onError: { error in
                continuation.resume(throwing: error!)
            }
        }
    }

    /// Gets feature mask of contacts from directory server and updates them.
    /// - Parameter identities: Identities to update Feature Mask for
    @MainActor
    public static func updateFeatureMask(for identities: [ThreemaIdentity]) async throws {
        let featureMasks = try await FeatureMask.getFeatureMask(for: identities.map(\.rawValue))

        let mediatorSyncableContacts = MediatorSyncableContacts()
        let entityManager = BusinessInjector.ui.entityManager

        await entityManager.performSave {
            for featureMask in featureMasks {
                guard featureMask.value >= 0 else {
                    continue
                }

                guard let contactEntity = entityManager.entityFetcher.contactEntity(for: featureMask.key) else {
                    continue
                }

                let oldFeatureMask = contactEntity.featureMask

                // Always update feature mask of local contact
                contactEntity.setFeatureMask(to: featureMask.value)

                if !oldFeatureMask.isEqual(to: contactEntity.featureMask) {
                    mediatorSyncableContacts.updateFeatureMask(
                        identity: featureMask.key,
                        value: contactEntity.featureMask
                    )
                }
            }
        }

        try await mediatorSyncableContacts.sync().async()
    }

    /// Checks whether contacts support a specific feature mask, returns unsupported contacts.
    /// - Parameters:
    ///   - identities: Identities of contacts to check
    ///   - mask: Mask to use
    ///   - completion: Array of contact identities that are not supported. Is called on main thread.
    @available(*, deprecated, renamed: "check(identities:for:force:)", message: "Use from Objective-C only")
    @objc public static func check(
        identities: Set<String>,
        for mask: Int,
        completion: @escaping ([String]) -> Void
    ) {
        Task { @MainActor in
            let unsupported = await FeatureMask.check(
                identities: Set(identities.map { ThreemaIdentity($0) }),
                for: mask,
                force: false
            )

            completion(unsupported.map(\.rawValue))
        }
    }
    
    /// Checks whether contacts support a specific feature mask, returns unsupported contacts.
    /// - Parameters:
    ///   - identities: Identities of contacts to check
    ///   - mask: Mask to use
    ///   - force: Force the update of the feature mask and sync to MD of all contacts
    /// - Returns: Array of contact identities that are not supported
    @MainActor
    public static func check(
        identities: Set<ThreemaIdentity>,
        for mask: Int,
        force: Bool = false
    ) async -> [ThreemaIdentity] {

        func filterUnsupported(identities: any Sequence<ThreemaIdentity>, for mask: Int) async -> [ThreemaIdentity] {
            let entityManager = BusinessInjector.ui.entityManager
            return await entityManager.perform {
                // Load contacts to check feature mask
                var contacts: Set<ContactEntity> = []
                for identity in identities {
                    guard let contact = entityManager.entityFetcher.contactEntity(for: identity.rawValue) else {
                        continue
                    }
                    contacts.insert(contact)
                }

                // Get contacts has not the feature mask
                return contacts.filter {
                    (mask & $0.featureMask.intValue) == 0
                }
                .map(\.threemaIdentity)
            }
        }

        let unsupported = force ? Array(identities) : await filterUnsupported(identities: identities, for: mask)

        guard !unsupported.isEmpty else {
            return []
        }

        do {
            try await updateFeatureMask(for: unsupported)

            return await filterUnsupported(identities: unsupported, for: mask)
        }
        catch {
            DDLogError("Failed to update/sync contacts feature masks: \(error)")
        }

        return unsupported
    }
    
    /// Checks if a `Contact` supports a given `Common_CspFeatureMaskFlag`
    /// - Parameters:
    ///   - contact: `Contact` to check
    ///   - mask: `Common_CspFeatureMaskFlag` to check contact for
    /// - Returns: `true` if `contact` supports `mask`, `false` otherwise
    public static func check(contact: Contact, for mask: ThreemaProtocols.Common_CspFeatureMaskFlag) -> Bool {
        mask.rawValue & contact.featureMask != 0
    }
    
    /// Check if the receiver(s) supports given `Common_CspFeatureMaskFlag`
    ///
    /// - Parameters:
    ///   - message: Message to check
    ///   - mask: `Common_CspFeatureMaskFlag` to check receiver(s) for
    ///   - Returns: `true` if min. one receiver supports the mask, all unsupported contacts
    public static func check(
        message: BaseMessageEntity,
        for mask: ThreemaProtocols.Common_CspFeatureMaskFlag
    ) -> (isSupported: Bool, unsupported: [Contact]) {
        guard let managedObjectContext = message.managedObjectContext else {
            return (false, [Contact]())
        }

        let contactsToCheck = managedObjectContext.performAndWait {
            var contactsToCheck = [Contact]()
            if message.conversation.isGroup {
                contactsToCheck
                    .append(contentsOf: message.conversation.unwrappedMembers.map { Contact(contactEntity: $0) })
            }
            else if let contactEntity = message.conversation.contact {
                contactsToCheck.append(Contact(contactEntity: contactEntity))
            }
            return contactsToCheck
        }

        var isSupported = false
        var unsupported = [Contact]()
        for contact in contactsToCheck {
            if FeatureMask.check(contact: contact, for: mask) {
                isSupported = true
            }
            else {
                unsupported.append(contact)
            }
        }
        return (isSupported, unsupported)
    }
}

Messung
CHZG
879310093

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104845
#Domains=499168