// // Copyright (c) 2023 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation import TIFoundationUtils import KeychainAccess import TILogging import UIKit public struct CoreDependencies { public var dateFormattersResusePool = DateFormattersReusePool() public var iso8601DateFormattersReusePool = ISO8601DateFormattersReusePool() public var jsonCodingConfigurator: JsonCodingConfigurator public var jsonKeyValueDecoder: JSONKeyValueDecoder public var jsonKeyValueEncoder: JSONKeyValueEncoder public var device: UIDevice = .current public var bundle: Bundle = .main public var fileManager: FileManager = .default public var logger: DefaultOSLogErrorLogger public var keychain: Keychain public var defaults: UserDefaults public var appGroupDefaults: UserDefaults? public var appGroupKeychain: Keychain? public var appGroupCacheDirectory: URL? public var networkCallbackQueue: DispatchQueue public init(bundleIdentifier: BundleIdentifier, customAppGroupIdentifier: String? = nil) { jsonCodingConfigurator = JsonCodingConfigurator(dateFormattersReusePool: dateFormattersResusePool, iso8601DateFormattersReusePool: iso8601DateFormattersReusePool) jsonKeyValueDecoder = JSONKeyValueDecoder(jsonDecoder: jsonCodingConfigurator.jsonDecoder) jsonKeyValueEncoder = JSONKeyValueEncoder(jsonEncoder: jsonCodingConfigurator.jsonEncoder) logger = DefaultOSLogErrorLogger(subsystem: bundleIdentifier.fullIdentifier, category: "general") keychain = Keychain(service: bundleIdentifier.fullIdentifier).accessibility(.whenUnlockedThisDeviceOnly) defaults = .standard let appGroupIdentifier = customAppGroupIdentifier ?? bundleIdentifier.defaultAppGroupIdenfier if let containerURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) { var appGroupCacheURL: URL if #available(iOS 16.0, *) { appGroupCacheURL = containerURL.appending(path: "Caches", directoryHint: .isDirectory) } else { appGroupCacheURL = containerURL.appendingPathComponent("Caches", isDirectory: true) } var resourceValues = URLResourceValues() resourceValues.isExcludedFromBackup = true do { try fileManager.createDirectory(at: appGroupCacheURL, withIntermediateDirectories: true) try appGroupCacheURL.setResourceValues(resourceValues) appGroupCacheDirectory = appGroupCacheURL } catch { logger.log(error: error, file: #file, line: #line) } appGroupDefaults = UserDefaults(suiteName: appGroupIdentifier) appGroupKeychain = Keychain(service: bundleIdentifier.appPrefix, accessGroup: appGroupIdentifier) .accessibility(.whenUnlockedThisDeviceOnly) } else { appGroupCacheDirectory = nil appGroupDefaults = nil appGroupKeychain = nil } networkCallbackQueue = DispatchQueue(label: bundleIdentifier.fullIdentifier + ".network-callback-queue", attributes: .concurrent) } public init?(bundle: Bundle = .main, customAppGroupIdentifier: String? = nil) { guard let bundleIdentifier = BundleIdentifier(bundle: bundle) else { return nil } self.init(bundleIdentifier: bundleIdentifier, customAppGroupIdentifier: customAppGroupIdentifier) } }