diff --git a/dns.xcodeproj/project.pbxproj b/dns.xcodeproj/project.pbxproj index 651cb4e..5eb3ebc 100644 --- a/dns.xcodeproj/project.pbxproj +++ b/dns.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + A051B5122FC9E0D700EACDC0 /* AsyncDNSResolver in Frameworks */ = {isa = PBXBuildFile; productRef = A051B5112FC9E0D700EACDC0 /* AsyncDNSResolver */; }; A08264132FC718790077B227 /* Stickers.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A082640C2FC718790077B227 /* Stickers.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ @@ -74,6 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A051B5122FC9E0D700EACDC0 /* AsyncDNSResolver in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +127,7 @@ ); name = dns; packageProductDependencies = ( + A051B5112FC9E0D700EACDC0 /* AsyncDNSResolver */, ); productName = dns; productReference = 069DCCFA2F8C0DCE00F1EB16 /* dns.app */; @@ -178,6 +181,9 @@ ); mainGroup = 069DCCF12F8C0DCD00F1EB16; minimizedProjectReferenceProxies = 1; + packageReferences = ( + A051B5102FC9E0D700EACDC0 /* XCRemoteSwiftPackageReference "swift-async-dns-resolver" */, + ); preferredProjectObjectVersion = 77; productRefGroup = 069DCCFB2F8C0DCE00F1EB16 /* Products */; projectDirPath = ""; @@ -529,6 +535,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + A051B5102FC9E0D700EACDC0 /* XCRemoteSwiftPackageReference "swift-async-dns-resolver" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-async-dns-resolver/"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.7.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + A051B5112FC9E0D700EACDC0 /* AsyncDNSResolver */ = { + isa = XCSwiftPackageProductDependency; + package = A051B5102FC9E0D700EACDC0 /* XCRemoteSwiftPackageReference "swift-async-dns-resolver" */; + productName = AsyncDNSResolver; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 069DCCF22F8C0DCD00F1EB16 /* Project object */; } diff --git a/dns.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dns.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..6e3a053 --- /dev/null +++ b/dns.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "8d197ac71cfa33d9e3396085f37fbee66795a894a6d74e24ff28bd887e01b9f2", + "pins" : [ + { + "identity" : "swift-async-dns-resolver", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-dns-resolver/", + "state" : { + "revision" : "9900d9b4113427a170d5f26075c2128be94984df", + "version" : "0.7.0" + } + } + ], + "version" : 3 +} diff --git a/dns/BlockedCount.swift b/dns/BlockedCount.swift index 892191e..3957fdf 100644 --- a/dns/BlockedCount.swift +++ b/dns/BlockedCount.swift @@ -1,9 +1,13 @@ import SwiftUI import Foundation +import AsyncDNSResolver struct BlockedCount: View { + @Environment(\.scenePhase) + private var scenePhase + @EnvironmentObject private var viewModel: ViewModel @@ -21,46 +25,32 @@ struct BlockedCount: View { var body: some View { Text(txtRecord) .onAppear { - fetchTXTRecord() + fetchTxtRecord() } .onChange(of: viewModel.blocklist) { _ in - fetchTXTRecord() + fetchTxtRecord() + } + .onChange(of: scenePhase) { newPhase in + if newPhase == .active { + fetchTxtRecord() + } } } - func parseResponse(data: Data) -> String? { - // This is a DNS wire format response and we make a lot of assumptions - // It is not critical functionality so just let it fail if it fails - - guard data.count > Self.startIndex else { - return nil - } - - // Find the first space character (ASCII 32). - guard let endIndex = data.suffix(from: Self.startIndex).firstIndex(of: 32) else { - return nil - } - - guard let numberString = String(data: data[Self.startIndex ..< endIndex], encoding: .utf8) - else { - return nil - } - - return Self.formatter.string(for: Int(numberString)) - } - - func fetchTXTRecord() { - let dohURL = URL(string: "https://\(viewModel.blocklist.server)/dns-query?dns=DoQBAAABAAAAAAAABXN0YXRzB2ludmFsaWQAABAAAQ")! - let request = URLRequest(url: dohURL) - - txtRecord = "…" - + private func fetchTxtRecord() { Task { do { - let (data, _) = try await URLSession.shared.data(for: request) + let resolver = try AsyncDNSResolver() - if let count = parseResponse(data: data) { - txtRecord = count + let records = try await resolver.queryTXT(name: "stats.invalid") + + let text = records.map { $0.txt }.joined() + + if let number = text.split(separator: " ").first, + let intValue = Int(number), + let formatted = Self.formatter.string(for: intValue) + { + txtRecord = formatted } else { txtRecord = NSLocalizedString("Error", comment: "")