Fine-tune important logging categories (#825)
- .App.profiles for profiles management - .App.iap for in-app purchases
This commit is contained in:
parent
5949ff1508
commit
c32dcd6565
|
@ -46,7 +46,7 @@ public final class InMemoryProfileRepository: ProfileRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func saveProfile(_ profile: Profile) {
|
public func saveProfile(_ profile: Profile) {
|
||||||
pp_log(.app, .info, "Save profile: \(profile.id))")
|
pp_log(.App.profiles, .info, "Save profile: \(profile.id))")
|
||||||
if let index = profiles.firstIndex(where: { $0.id == profile.id }) {
|
if let index = profiles.firstIndex(where: { $0.id == profile.id }) {
|
||||||
profiles[index] = profile
|
profiles[index] = profile
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,7 +55,7 @@ public final class InMemoryProfileRepository: ProfileRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeProfiles(withIds ids: [Profile.ID]) {
|
public func removeProfiles(withIds ids: [Profile.ID]) {
|
||||||
pp_log(.app, .info, "Remove profiles: \(ids)")
|
pp_log(.App.profiles, .info, "Remove profiles: \(ids)")
|
||||||
profiles = profiles.filter {
|
profiles = profiles.filter {
|
||||||
!ids.contains($0.id)
|
!ids.contains($0.id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,10 +92,10 @@ private extension NEProfileRepository {
|
||||||
let profiles = managers.values.compactMap {
|
let profiles = managers.values.compactMap {
|
||||||
do {
|
do {
|
||||||
let profile = try repository.profile(from: $0)
|
let profile = try repository.profile(from: $0)
|
||||||
pp_log(.app, .debug, "Attributes for profile \(profile.id): \(profile.attributes)")
|
pp_log(.App.profiles, .debug, "Attributes for profile \(profile.id): \(profile.attributes)")
|
||||||
return profile
|
return profile
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .error, "Unable to decode profile from NE manager '\($0.localizedDescription ?? "")': \(error)")
|
pp_log(.App.profiles, .error, "Unable to decode profile from NE manager '\($0.localizedDescription ?? "")': \(error)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ private extension NEProfileRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !removedProfilesDescription.isEmpty {
|
if !removedProfilesDescription.isEmpty {
|
||||||
pp_log(.app, .info, "Sync profiles removed externally: \(removedProfilesDescription)")
|
pp_log(.App.profiles, .info, "Sync profiles removed externally: \(removedProfilesDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
profilesSubject.send(profiles)
|
profilesSubject.send(profiles)
|
||||||
|
|
|
@ -144,7 +144,7 @@ extension ProfileManager {
|
||||||
profile = originalProfile
|
profile = originalProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_log(.app, .notice, "Save profile \(profile.id)...")
|
pp_log(.App.profiles, .notice, "Save profile \(profile.id)...")
|
||||||
do {
|
do {
|
||||||
let existingProfile = allProfiles[profile.id]
|
let existingProfile = allProfiles[profile.id]
|
||||||
if existingProfile == nil || profile != existingProfile {
|
if existingProfile == nil || profile != existingProfile {
|
||||||
|
@ -157,27 +157,27 @@ extension ProfileManager {
|
||||||
allProfiles[profile.id] = profile
|
allProfiles[profile.id] = profile
|
||||||
didChange.send(.save(profile))
|
didChange.send(.save(profile))
|
||||||
} else {
|
} else {
|
||||||
pp_log(.app, .notice, "\tProfile \(profile.id) not modified, not saving")
|
pp_log(.App.profiles, .notice, "\tProfile \(profile.id) not modified, not saving")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .fault, "\tUnable to save profile \(profile.id): \(error)")
|
pp_log(.App.profiles, .fault, "\tUnable to save profile \(profile.id): \(error)")
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
if let isShared, let remoteRepository {
|
if let isShared, let remoteRepository {
|
||||||
if isShared {
|
if isShared {
|
||||||
pp_log(.app, .notice, "\tEnable remote sharing of profile \(profile.id)...")
|
pp_log(.App.profiles, .notice, "\tEnable remote sharing of profile \(profile.id)...")
|
||||||
try await remoteRepository.saveProfile(profile)
|
try await remoteRepository.saveProfile(profile)
|
||||||
} else {
|
} else {
|
||||||
pp_log(.app, .notice, "\tDisable remote sharing of profile \(profile.id)...")
|
pp_log(.App.profiles, .notice, "\tDisable remote sharing of profile \(profile.id)...")
|
||||||
try await remoteRepository.removeProfiles(withIds: [profile.id])
|
try await remoteRepository.removeProfiles(withIds: [profile.id])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .fault, "\tUnable to save/remove remote profile \(profile.id): \(error)")
|
pp_log(.App.profiles, .fault, "\tUnable to save/remove remote profile \(profile.id): \(error)")
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
pp_log(.app, .notice, "Finished saving profile \(profile.id)")
|
pp_log(.App.profiles, .notice, "Finished saving profile \(profile.id)")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func remove(withId profileId: Profile.ID) async {
|
public func remove(withId profileId: Profile.ID) async {
|
||||||
|
@ -185,7 +185,7 @@ extension ProfileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func remove(withIds profileIds: [Profile.ID]) async {
|
public func remove(withIds profileIds: [Profile.ID]) async {
|
||||||
pp_log(.app, .notice, "Remove profiles \(profileIds)...")
|
pp_log(.App.profiles, .notice, "Remove profiles \(profileIds)...")
|
||||||
do {
|
do {
|
||||||
// remove local profiles
|
// remove local profiles
|
||||||
var newAllProfiles = allProfiles
|
var newAllProfiles = allProfiles
|
||||||
|
@ -204,7 +204,7 @@ extension ProfileManager {
|
||||||
allProfiles = newAllProfiles
|
allProfiles = newAllProfiles
|
||||||
didChange.send(.remove(profileIds))
|
didChange.send(.remove(profileIds))
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .fault, "Unable to remove profiles \(profileIds): \(error)")
|
pp_log(.App.profiles, .fault, "Unable to remove profiles \(profileIds): \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ extension ProfileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func eraseRemotelySharedProfiles() async throws {
|
public func eraseRemotelySharedProfiles() async throws {
|
||||||
pp_log(.app, .notice, "Erase remotely shared profiles...")
|
pp_log(.App.profiles, .notice, "Erase remotely shared profiles...")
|
||||||
try await remoteRepository?.removeProfiles(withIds: Array(allRemoteProfiles.keys))
|
try await remoteRepository?.removeProfiles(withIds: Array(allRemoteProfiles.keys))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +250,7 @@ extension ProfileManager {
|
||||||
|
|
||||||
var builder = profile.builder(withNewId: true)
|
var builder = profile.builder(withNewId: true)
|
||||||
builder.name = firstUniqueName(from: profile.name)
|
builder.name = firstUniqueName(from: profile.name)
|
||||||
pp_log(.app, .notice, "Duplicate profile [\(profileId), \(profile.name)] -> [\(builder.id), \(builder.name)]...")
|
pp_log(.App.profiles, .notice, "Duplicate profile [\(profileId), \(profile.name)] -> [\(builder.id), \(builder.name)]...")
|
||||||
let copy = try builder.tryBuild()
|
let copy = try builder.tryBuild()
|
||||||
|
|
||||||
try await save(copy)
|
try await save(copy)
|
||||||
|
@ -316,7 +316,7 @@ extension ProfileManager {
|
||||||
|
|
||||||
private extension ProfileManager {
|
private extension ProfileManager {
|
||||||
func reloadLocalProfiles(_ result: [Profile]) {
|
func reloadLocalProfiles(_ result: [Profile]) {
|
||||||
pp_log(.app, .info, "Reload local profiles: \(result.map(\.id))")
|
pp_log(.App.profiles, .info, "Reload local profiles: \(result.map(\.id))")
|
||||||
allProfiles = result.reduce(into: [:]) {
|
allProfiles = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$0[$1.id] = $1
|
||||||
}
|
}
|
||||||
|
@ -330,7 +330,7 @@ private extension ProfileManager {
|
||||||
.map(\.key)
|
.map(\.key)
|
||||||
|
|
||||||
if !idsToRemove.isEmpty {
|
if !idsToRemove.isEmpty {
|
||||||
pp_log(.app, .info, "Delete non-included local profiles: \(idsToRemove)")
|
pp_log(.App.profiles, .info, "Delete non-included local profiles: \(idsToRemove)")
|
||||||
Task.detached {
|
Task.detached {
|
||||||
try await self.repository.removeProfiles(withIds: idsToRemove)
|
try await self.repository.removeProfiles(withIds: idsToRemove)
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ private extension ProfileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadInitialRemoteProfiles(_ result: [Profile]) {
|
func loadInitialRemoteProfiles(_ result: [Profile]) {
|
||||||
pp_log(.app, .info, "Load initial remote profiles: \(result.map(\.id))")
|
pp_log(.App.profiles, .info, "Load initial remote profiles: \(result.map(\.id))")
|
||||||
allRemoteProfiles = result.reduce(into: [:]) {
|
allRemoteProfiles = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$0[$1.id] = $1
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ private extension ProfileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
func reloadRemoteProfiles(_ result: [Profile]) {
|
func reloadRemoteProfiles(_ result: [Profile]) {
|
||||||
pp_log(.app, .info, "Reload remote profiles: \(result.map(\.id))")
|
pp_log(.App.profiles, .info, "Reload remote profiles: \(result.map(\.id))")
|
||||||
allRemoteProfiles = result.reduce(into: [:]) {
|
allRemoteProfiles = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$0[$1.id] = $1
|
||||||
}
|
}
|
||||||
|
@ -358,17 +358,17 @@ private extension ProfileManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_log(.app, .info, "Start importing remote profiles...")
|
pp_log(.App.profiles, .info, "Start importing remote profiles...")
|
||||||
|
|
||||||
pp_log(.app, .debug, "Local fingerprints:")
|
pp_log(.App.profiles, .debug, "Local fingerprints:")
|
||||||
let localFingerprints: [Profile.ID: UUID] = await allProfiles.values.reduce(into: [:]) {
|
let localFingerprints: [Profile.ID: UUID] = await allProfiles.values.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1.attributes.fingerprint
|
$0[$1.id] = $1.attributes.fingerprint
|
||||||
pp_log(.app, .debug, "\t\($1.id) = \($1.attributes.fingerprint?.description ?? "nil")")
|
pp_log(.App.profiles, .debug, "\t\($1.id) = \($1.attributes.fingerprint?.description ?? "nil")")
|
||||||
}
|
}
|
||||||
pp_log(.app, .debug, "Remote fingerprints:")
|
pp_log(.App.profiles, .debug, "Remote fingerprints:")
|
||||||
let remoteFingerprints: [Profile.ID: UUID] = result.reduce(into: [:]) {
|
let remoteFingerprints: [Profile.ID: UUID] = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1.attributes.fingerprint
|
$0[$1.id] = $1.attributes.fingerprint
|
||||||
pp_log(.app, .debug, "\t\($1.id) = \($1.attributes.fingerprint?.description ?? "nil")")
|
pp_log(.App.profiles, .debug, "\t\($1.id) = \($1.attributes.fingerprint?.description ?? "nil")")
|
||||||
}
|
}
|
||||||
|
|
||||||
let profilesToImport = result
|
let profilesToImport = result
|
||||||
|
@ -377,7 +377,7 @@ private extension ProfileManager {
|
||||||
|
|
||||||
var idsToRemove: [Profile.ID] = []
|
var idsToRemove: [Profile.ID] = []
|
||||||
if !remotelyDeletedIds.isEmpty {
|
if !remotelyDeletedIds.isEmpty {
|
||||||
pp_log(.app, .info, "Will \(deletingRemotely ? "delete" : "retain") local profiles not present in remote repository: \(remotelyDeletedIds)")
|
pp_log(.App.profiles, .info, "Will \(deletingRemotely ? "delete" : "retain") local profiles not present in remote repository: \(remotelyDeletedIds)")
|
||||||
|
|
||||||
if deletingRemotely {
|
if deletingRemotely {
|
||||||
idsToRemove.append(contentsOf: remotelyDeletedIds)
|
idsToRemove.append(contentsOf: remotelyDeletedIds)
|
||||||
|
@ -386,27 +386,27 @@ private extension ProfileManager {
|
||||||
for remoteProfile in profilesToImport {
|
for remoteProfile in profilesToImport {
|
||||||
do {
|
do {
|
||||||
guard processor?.isIncluded(remoteProfile) ?? true else {
|
guard processor?.isIncluded(remoteProfile) ?? true else {
|
||||||
pp_log(.app, .info, "Will delete non-included remote profile \(remoteProfile.id)")
|
pp_log(.App.profiles, .info, "Will delete non-included remote profile \(remoteProfile.id)")
|
||||||
idsToRemove.append(remoteProfile.id)
|
idsToRemove.append(remoteProfile.id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
guard remoteFingerprints[remoteProfile.id] != localFingerprints[remoteProfile.id] else {
|
guard remoteFingerprints[remoteProfile.id] != localFingerprints[remoteProfile.id] else {
|
||||||
pp_log(.app, .info, "Skip re-importing local profile \(remoteProfile.id)")
|
pp_log(.App.profiles, .info, "Skip re-importing local profile \(remoteProfile.id)")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pp_log(.app, .notice, "Import remote profile \(remoteProfile.id)...")
|
pp_log(.App.profiles, .notice, "Import remote profile \(remoteProfile.id)...")
|
||||||
try await save(remoteProfile)
|
try await save(remoteProfile)
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .error, "Unable to import remote profile: \(error)")
|
pp_log(.App.profiles, .error, "Unable to import remote profile: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pp_log(.app, .notice, "Finished importing remote profiles, delete stale profiles: \(idsToRemove)")
|
pp_log(.App.profiles, .notice, "Finished importing remote profiles, delete stale profiles: \(idsToRemove)")
|
||||||
try? await repository.removeProfiles(withIds: idsToRemove)
|
try? await repository.removeProfiles(withIds: idsToRemove)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func performSearch(_ search: String) {
|
func performSearch(_ search: String) {
|
||||||
pp_log(.app, .notice, "Filter profiles with '\(search)'")
|
pp_log(.App.profiles, .notice, "Filter profiles with '\(search)'")
|
||||||
reloadFilteredProfiles(with: search)
|
reloadFilteredProfiles(with: search)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ extension ProfileAttributes: ProfileUserInfoTransformable {
|
||||||
let data = try JSONEncoder().encode(self)
|
let data = try JSONEncoder().encode(self)
|
||||||
return try JSONSerialization.jsonObject(with: data) as? [String: AnyHashable] ?? [:]
|
return try JSONSerialization.jsonObject(with: data) as? [String: AnyHashable] ?? [:]
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .error, "Unable to encode ProfileAttributes to dictionary: \(error)")
|
pp_log(.App.profiles, .error, "Unable to encode ProfileAttributes to dictionary: \(error)")
|
||||||
return [:]
|
return [:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ extension ProfileAttributes: ProfileUserInfoTransformable {
|
||||||
let data = try JSONSerialization.data(withJSONObject: userInfo ?? [:])
|
let data = try JSONSerialization.data(withJSONObject: userInfo ?? [:])
|
||||||
self = try JSONDecoder().decode(ProfileAttributes.self, from: data)
|
self = try JSONDecoder().decode(ProfileAttributes.self, from: data)
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.app, .error, "Unable to decode ProfileAttributes from dictionary: \(error)")
|
pp_log(.App.profiles, .error, "Unable to decode ProfileAttributes from dictionary: \(error)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,14 +60,14 @@ private extension FallbackReceiptReader {
|
||||||
func asyncReceipt(at userLevel: AppUserLevel) async -> InAppReceipt? {
|
func asyncReceipt(at userLevel: AppUserLevel) async -> InAppReceipt? {
|
||||||
let localURL = Bundle.main.appStoreReceiptURL
|
let localURL = Bundle.main.appStoreReceiptURL
|
||||||
|
|
||||||
pp_log(.iap, .debug, "\tParse receipt for user level \(userLevel)")
|
pp_log(.App.iap, .debug, "\tParse receipt for user level \(userLevel)")
|
||||||
|
|
||||||
// 1. TestFlight, look for release receipt
|
// 1. TestFlight, look for release receipt
|
||||||
let releaseReceipt: InAppReceipt? = await {
|
let releaseReceipt: InAppReceipt? = await {
|
||||||
guard userLevel == .beta, let localURL else {
|
guard userLevel == .beta, let localURL else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pp_log(.iap, .debug, "\tTestFlight, look for release receipt")
|
pp_log(.App.iap, .debug, "\tTestFlight, look for release receipt")
|
||||||
let releaseURL = localURL
|
let releaseURL = localURL
|
||||||
.deletingLastPathComponent()
|
.deletingLastPathComponent()
|
||||||
.appendingPathComponent("receipt")
|
.appendingPathComponent("receipt")
|
||||||
|
@ -83,7 +83,7 @@ private extension FallbackReceiptReader {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if let releaseReceipt {
|
if let releaseReceipt {
|
||||||
pp_log(.iap, .debug, "\tTestFlight, return release receipt")
|
pp_log(.App.iap, .debug, "\tTestFlight, return release receipt")
|
||||||
return releaseReceipt
|
return releaseReceipt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,18 +95,18 @@ private extension FallbackReceiptReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. primary receipt + build from local receipt
|
// 2. primary receipt + build from local receipt
|
||||||
pp_log(.iap, .debug, "\tNo release receipt, read primary receipt")
|
pp_log(.App.iap, .debug, "\tNo release receipt, read primary receipt")
|
||||||
if let receipt = await reader?.receipt() {
|
if let receipt = await reader?.receipt() {
|
||||||
if let build = await localReceiptBlock()?.originalBuildNumber {
|
if let build = await localReceiptBlock()?.originalBuildNumber {
|
||||||
pp_log(.iap, .debug, "\tReturn primary receipt with local build: \(build)")
|
pp_log(.App.iap, .debug, "\tReturn primary receipt with local build: \(build)")
|
||||||
return receipt.withBuildNumber(build)
|
return receipt.withBuildNumber(build)
|
||||||
}
|
}
|
||||||
pp_log(.iap, .debug, "\tReturn primary receipt without local build")
|
pp_log(.App.iap, .debug, "\tReturn primary receipt without local build")
|
||||||
return receipt
|
return receipt
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. fall back to local receipt
|
// 3. fall back to local receipt
|
||||||
pp_log(.iap, .debug, "\tReturn local receipt")
|
pp_log(.App.iap, .debug, "\tReturn local receipt")
|
||||||
return await localReceiptBlock()
|
return await localReceiptBlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ extension IAPManager {
|
||||||
inAppProducts[$0]
|
inAppProducts[$0]
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.iap, .error, "Unable to fetch in-app products: \(error)")
|
pp_log(.App.iap, .error, "Unable to fetch in-app products: \(error)")
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ extension IAPManager {
|
||||||
|
|
||||||
private extension IAPManager {
|
private extension IAPManager {
|
||||||
func asyncReloadReceipt() async {
|
func asyncReloadReceipt() async {
|
||||||
pp_log(.iap, .notice, "Start reloading in-app receipt...")
|
pp_log(.App.iap, .notice, "Start reloading in-app receipt...")
|
||||||
|
|
||||||
purchasedAppBuild = nil
|
purchasedAppBuild = nil
|
||||||
purchasedProducts.removeAll()
|
purchasedProducts.removeAll()
|
||||||
|
@ -171,41 +171,41 @@ private extension IAPManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let purchasedAppBuild {
|
if let purchasedAppBuild {
|
||||||
pp_log(.iap, .info, "Original purchased build: \(purchasedAppBuild)")
|
pp_log(.App.iap, .info, "Original purchased build: \(purchasedAppBuild)")
|
||||||
|
|
||||||
// assume some purchases by build number
|
// assume some purchases by build number
|
||||||
let entitled = productsAtBuild?(purchasedAppBuild) ?? []
|
let entitled = productsAtBuild?(purchasedAppBuild) ?? []
|
||||||
pp_log(.iap, .notice, "Entitled features: \(entitled.map(\.rawValue))")
|
pp_log(.App.iap, .notice, "Entitled features: \(entitled.map(\.rawValue))")
|
||||||
|
|
||||||
entitled.forEach {
|
entitled.forEach {
|
||||||
purchasedProducts.insert($0)
|
purchasedProducts.insert($0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let iapReceipts = receipt.purchaseReceipts {
|
if let iapReceipts = receipt.purchaseReceipts {
|
||||||
pp_log(.iap, .info, "Process in-app purchase receipts...")
|
pp_log(.App.iap, .info, "Process in-app purchase receipts...")
|
||||||
|
|
||||||
let products: [AppProduct] = iapReceipts.compactMap {
|
let products: [AppProduct] = iapReceipts.compactMap {
|
||||||
guard let pid = $0.productIdentifier else {
|
guard let pid = $0.productIdentifier else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
guard let product = AppProduct(rawValue: pid) else {
|
guard let product = AppProduct(rawValue: pid) else {
|
||||||
pp_log(.iap, .debug, "\tDiscard unknown product identifier: \(pid)")
|
pp_log(.App.iap, .debug, "\tDiscard unknown product identifier: \(pid)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let expirationDate = $0.expirationDate {
|
if let expirationDate = $0.expirationDate {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
pp_log(.iap, .debug, "\t\(pid) [expiration date: \(expirationDate), now: \(now)]")
|
pp_log(.App.iap, .debug, "\t\(pid) [expiration date: \(expirationDate), now: \(now)]")
|
||||||
if now >= expirationDate {
|
if now >= expirationDate {
|
||||||
pp_log(.iap, .info, "\t\(pid) [expired on: \(expirationDate)]")
|
pp_log(.App.iap, .info, "\t\(pid) [expired on: \(expirationDate)]")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let cancellationDate = $0.cancellationDate {
|
if let cancellationDate = $0.cancellationDate {
|
||||||
pp_log(.iap, .info, "\t\(pid) [cancelled on: \(cancellationDate)]")
|
pp_log(.App.iap, .info, "\t\(pid) [cancelled on: \(cancellationDate)]")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let purchaseDate = $0.originalPurchaseDate {
|
if let purchaseDate = $0.originalPurchaseDate {
|
||||||
pp_log(.iap, .info, "\t\(pid) [purchased on: \(purchaseDate)]")
|
pp_log(.App.iap, .info, "\t\(pid) [purchased on: \(purchaseDate)]")
|
||||||
}
|
}
|
||||||
return product
|
return product
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ private extension IAPManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pp_log(.iap, .error, "Could not parse App Store receipt!")
|
pp_log(.App.iap, .error, "Could not parse App Store receipt!")
|
||||||
}
|
}
|
||||||
|
|
||||||
userLevel.features.forEach {
|
userLevel.features.forEach {
|
||||||
|
@ -231,10 +231,10 @@ private extension IAPManager {
|
||||||
eligibleFeatures.insert($0)
|
eligibleFeatures.insert($0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_log(.iap, .notice, "Finished reloading in-app receipt for user level \(userLevel)")
|
pp_log(.App.iap, .notice, "Finished reloading in-app receipt for user level \(userLevel)")
|
||||||
pp_log(.iap, .notice, "\tPurchased build number: \(purchasedAppBuild?.description ?? "unknown")")
|
pp_log(.App.iap, .notice, "\tPurchased build number: \(purchasedAppBuild?.description ?? "unknown")")
|
||||||
pp_log(.iap, .notice, "\tPurchased products: \(purchasedProducts.map(\.rawValue))")
|
pp_log(.App.iap, .notice, "\tPurchased products: \(purchasedProducts.map(\.rawValue))")
|
||||||
pp_log(.iap, .notice, "\tEligible features: \(eligibleFeatures)")
|
pp_log(.App.iap, .notice, "\tEligible features: \(eligibleFeatures)")
|
||||||
|
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ private extension IAPManager {
|
||||||
await reloadReceipt()
|
await reloadReceipt()
|
||||||
do {
|
do {
|
||||||
let products = try await inAppHelper.fetchProducts()
|
let products = try await inAppHelper.fetchProducts()
|
||||||
pp_log(.iap, .info, "Available in-app products: \(products.map(\.key))")
|
pp_log(.App.iap, .info, "Available in-app products: \(products.map(\.key))")
|
||||||
|
|
||||||
inAppHelper
|
inAppHelper
|
||||||
.didUpdate
|
.didUpdate
|
||||||
|
@ -262,7 +262,7 @@ private extension IAPManager {
|
||||||
.store(in: &subscriptions)
|
.store(in: &subscriptions)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
pp_log(.iap, .error, "Unable to fetch in-app products: \(error)")
|
pp_log(.App.iap, .error, "Unable to fetch in-app products: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,11 +273,11 @@ private extension IAPManager {
|
||||||
}
|
}
|
||||||
if let customUserLevel {
|
if let customUserLevel {
|
||||||
userLevel = customUserLevel
|
userLevel = customUserLevel
|
||||||
pp_log(.iap, .info, "App level (custom): \(userLevel)")
|
pp_log(.App.iap, .info, "App level (custom): \(userLevel)")
|
||||||
} else {
|
} else {
|
||||||
let isBeta = await SandboxChecker().isBeta
|
let isBeta = await SandboxChecker().isBeta
|
||||||
userLevel = isBeta ? .beta : .freemium
|
userLevel = isBeta ? .beta : .freemium
|
||||||
pp_log(.iap, .info, "App level: \(userLevel)")
|
pp_log(.App.iap, .info, "App level: \(userLevel)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,13 @@ import PassepartoutKit
|
||||||
import PassepartoutWireGuardGo
|
import PassepartoutWireGuardGo
|
||||||
|
|
||||||
extension LoggerDestination {
|
extension LoggerDestination {
|
||||||
public static let app = Self(category: "app")
|
public static let app = LoggerDestination(category: "app")
|
||||||
|
|
||||||
public static let iap = Self(category: "iap")
|
public enum App {
|
||||||
|
public static let iap = LoggerDestination(category: "app.iap")
|
||||||
|
|
||||||
|
public static let profiles = LoggerDestination(category: "app.profiles")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension WireGuard.Configuration.Builder {
|
extension WireGuard.Configuration.Builder {
|
||||||
|
|
Loading…
Reference in New Issue