191 lines
5.2 KiB
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")
|
||
|
}
|
||
|
}
|