passepartout-apple/Passepartout/Library/Sources/CommonLibrary/Constants.swift

191 lines
5.2 KiB
Swift

//
// Constants.swift
// Passepartout
//
// Created by Davide De Rosa on 8/26/24.
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import PassepartoutKit
import SwiftUI
public struct Constants: Decodable, Sendable {
private static var bundleConfiguration: BundleConfiguration? {
.failableMain
}
public struct Identifiers: Decodable, Sendable {
public var appId: String {
bundleConfiguration?.string(for: .appId) ?? "1234567890"
}
public var appStoreId: String {
bundleConfiguration?.string(for: .appStoreId) ?? "11223344"
}
public var groupId: String {
bundleConfiguration?.string(for: .groupId) ?? "fake-group-id"
}
public var iapBundlePrefix: String {
bundleConfiguration?.string(for: .iapBundlePrefix) ?? "fake-iap-prefix"
}
public var displayName: String {
bundleConfiguration?.displayName ?? "DisplayName"
}
public var versionString: String {
bundleConfiguration?.versionString ?? "1.0.0 (1000)"
}
}
public struct Websites: Decodable, Sendable {
public let home: URL
public var faq: URL {
home.appendingPathComponent("faq/")
}
public var disclaimer: URL {
home.appendingPathComponent("disclaimer/")
}
public var privacyPolicy: URL {
home.appendingPathComponent("privacy/")
}
public var donate: URL {
home.appendingPathComponent("donate/")
}
public let subreddit: URL
public let githubSponsors: URL
}
public struct Emails: Decodable, Sendable {
private struct Recipients: Decodable, Sendable {
let issues: String
let beta: String
}
public let domain: String
private let recipients: Recipients
public var issues: String {
email(to: recipients.issues)
}
public var beta: String {
email(to: recipients.beta)
}
private func email(to: String) -> String {
[to, domain].joined(separator: "@")
}
}
public struct Formats: Decodable, Sendable {
public let timestamp: String
}
public struct Connection: Decodable, Sendable {
public let refreshInterval: TimeInterval
}
public struct Log: Decodable, Sendable {
public struct Formatter: Decodable, Sendable {
enum CodingKeys: CodingKey {
case timestamp
case message
}
private let timestampFormatter: DateFormatter
private let message: String
public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let timestampFormat = try container.decode(String.self, forKey: .timestamp)
timestampFormatter = DateFormatter()
timestampFormatter.dateFormat = timestampFormat
message = try container.decode(String.self, forKey: .message)
}
public func formattedLine(_ line: DebugLog.Line) -> String {
let formattedTimestamp = timestampFormatter.string(from: line.timestamp)
return String(format: message, formattedTimestamp, line.message)
}
}
public let formatter: Formatter
public let appPath: String
public let tunnelPath: String
public let sinceLast: TimeInterval
public let maxLevel: DebugLog.Level
public let maxNumberOfLines: Int
public let maxAge: TimeInterval?
}
public let identifiers: Identifiers
public let websites: Websites
public let emails: Emails
public let formats: Formats
public let connection: Connection
public let log: Log
}
extension Constants {
public var urlForReview: URL {
URL(string: "https://apps.apple.com/app/id\(identifiers.appStoreId)?action=write-review")!
}
public var urlForAppLog: URL {
cachesURL.appending(path: log.appPath)
}
public var urlForTunnelLog: URL {
cachesURL.appending(path: log.tunnelPath)
}
private var cachesURL: URL {
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: identifiers.groupId) else {
fatalError("Unable to access App Group container")
}
return url.appending(components: "Library", "Caches")
}
}