Skip to content

Commit

Permalink
fix(POM-234): sdk configuration (#136)
Browse files Browse the repository at this point in the history
* Makes `DefaultPhoneNumberMetadataProvider` prewarm operation
asynchronous
  • Loading branch information
andrii-vysotskyi-cko authored Jul 17, 2023
1 parent 26ea718 commit 33aeedb
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,55 @@ final class DefaultPhoneNumberMetadataProvider: PhoneNumberMetadataProvider {

static let shared = DefaultPhoneNumberMetadataProvider()

/// - NOTE: Method is asynchronous.
func prewarm() {
loadMetadata(sync: false)
}

// MARK: - PhoneNumberMetadataProvider

func metadata(for countryCode: String) -> PhoneNumberMetadata? {
let transformedCountryCode = countryCode.applyingTransform(.toLatin, reverse: false) ?? countryCode
return metadata[transformedCountryCode]
if let metadata = metadata {
return metadata[transformedCountryCode]
}
loadMetadata(sync: true)
return metadata?[transformedCountryCode]
}

func prewarm() {
_ = metadata
}
// MARK: - Private Properties

private let dispatchQueue: DispatchQueue

@UnfairlyLocked
private var metadata: [String: PhoneNumberMetadata]?

// MARK: - Private Methods

private init() {
// NOP
dispatchQueue = DispatchQueue(label: "process-out.phone-number-metadata-provider", qos: .userInitiated)
}

// MARK: - Private Properties

private lazy var metadata: [String: PhoneNumberMetadata] = {
let metadata: [PhoneNumberMetadata]
do {
let data = try Data(contentsOf: Files.phoneNumberMetadata.url)
metadata = try JSONDecoder().decode([PhoneNumberMetadata].self, from: data)
} catch {
return [:]
}
return Dictionary(grouping: metadata, by: \.countryCode).compactMapValues { values in
let countryCode = values.first!.countryCode // swiftlint:disable:this force_unwrapping
return PhoneNumberMetadata(countryCode: countryCode, formats: values.flatMap(\.formats))
private func loadMetadata(sync: Bool) {
let dispatchWorkItem = DispatchWorkItem { [weak self] in
guard let self, self.metadata == nil else {
return
}
let groupedMetadata: [String: PhoneNumberMetadata]
do {
let data = try Data(contentsOf: Files.phoneNumberMetadata.url)
let metadata = try JSONDecoder().decode([PhoneNumberMetadata].self, from: data)
groupedMetadata = Dictionary(grouping: metadata, by: \.countryCode).compactMapValues { values in
let countryCode = values.first!.countryCode // swiftlint:disable:this force_unwrapping
return PhoneNumberMetadata(countryCode: countryCode, formats: values.flatMap(\.formats))
}
} catch {
assertionFailure("Failed to load metadata: \(error.localizedDescription)")
groupedMetadata = [:]
}
self.$metadata.withLock { $0 = groupedMetadata }
}
}()
let executor = sync ? dispatchQueue.sync : dispatchQueue.async
executor(dispatchWorkItem)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import Foundation
import os
@_implementationOnly import os

final class SystemLoggerDestination: LoggerDestination {

Expand Down
63 changes: 63 additions & 0 deletions Sources/ProcessOut/Sources/Core/Utils/UnfairlyLocked.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// UnfairlyLocked.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 14.07.2023.
//

@_implementationOnly import os

/// A thread-safe wrapper around a value.
@propertyWrapper
final class UnfairlyLocked<Value> {

init(wrappedValue: Value) {
value = wrappedValue
}

/// The contained value. Unsafe for anything more than direct read or write.
var wrappedValue: Value {
lock.withLock { value }
}

var projectedValue: UnfairlyLocked<Value> {
self
}

func withLock<R>(_ body: (inout Value) -> R) -> R {
lock.withLock {
body(&value)
}
}

// MARK: - Private Properties

private let lock = UnfairLock()
private var value: Value
}

/// An `os_unfair_lock` wrapper.
private final class UnfairLock {

init() {
unfairLock = .allocate(capacity: 1)
unfairLock.initialize(to: os_unfair_lock())
}

func withLock<R>(_ body: () -> R) -> R {
defer {
os_unfair_lock_unlock(unfairLock)
}
os_unfair_lock_lock(unfairLock)
return body()
}

deinit {
unfairLock.deinitialize(count: 1)
unfairLock.deallocate()
}

// MARK: - Private Properties

private let unfairLock: os_unfair_lock_t
}

0 comments on commit 33aeedb

Please sign in to comment.