2026-04-13 14:18:42 +01:00
|
|
|
|
|
|
|
|
import SwiftUI
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
|
|
struct BlockedCount: View {
|
2026-04-14 17:53:22 +02:00
|
|
|
|
2026-04-14 18:21:00 +02:00
|
|
|
@EnvironmentObject
|
|
|
|
|
private var viewModel: ViewModel
|
|
|
|
|
|
|
|
|
|
@State private var txtRecord: String = "…"
|
2026-04-13 14:18:42 +01:00
|
|
|
|
2026-04-14 17:53:22 +02:00
|
|
|
private static let startIndex = 44
|
|
|
|
|
|
|
|
|
|
private static let formatter: NumberFormatter = {
|
|
|
|
|
let formatter = NumberFormatter()
|
|
|
|
|
formatter.numberStyle = .decimal
|
|
|
|
|
|
|
|
|
|
return formatter
|
|
|
|
|
}()
|
|
|
|
|
|
2026-04-13 14:18:42 +01:00
|
|
|
var body: some View {
|
|
|
|
|
Text(txtRecord)
|
|
|
|
|
.onAppear {
|
|
|
|
|
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
|
|
|
|
|
|
2026-04-14 17:53:22 +02:00
|
|
|
guard data.count > Self.startIndex else {
|
|
|
|
|
return nil
|
2026-04-13 14:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 17:53:22 +02:00
|
|
|
// Find the first space character (ASCII 32).
|
|
|
|
|
guard let endIndex = data.suffix(from: Self.startIndex).firstIndex(of: 32) else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2026-04-13 14:18:42 +01:00
|
|
|
|
2026-04-14 17:53:22 +02:00
|
|
|
guard let numberString = String(data: data[Self.startIndex ..< endIndex], encoding: .utf8)
|
|
|
|
|
else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2026-04-13 14:18:42 +01:00
|
|
|
|
2026-04-14 17:53:22 +02:00
|
|
|
return Self.formatter.string(for: Int(numberString))
|
2026-04-13 14:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func fetchTXTRecord() {
|
2026-04-14 18:21:00 +02:00
|
|
|
let dohURL = URL(string: "https://\(viewModel.blocklist.server)/dns-query?dns=DoQBAAABAAAAAAAABXN0YXRzB2ludmFsaWQAABAAAQ")!
|
2026-04-13 14:18:42 +01:00
|
|
|
|
|
|
|
|
let request = URLRequest(url: dohURL)
|
|
|
|
|
|
2026-04-14 18:18:26 +02:00
|
|
|
Task {
|
|
|
|
|
do {
|
|
|
|
|
let (data, _) = try await URLSession.shared.data(for: request)
|
2026-04-13 14:18:42 +01:00
|
|
|
|
2026-04-14 18:18:26 +02:00
|
|
|
if let count = parseResponse(data: data) {
|
|
|
|
|
txtRecord = count
|
2026-04-13 14:18:42 +01:00
|
|
|
}
|
2026-04-14 18:18:26 +02:00
|
|
|
else {
|
2026-04-13 14:18:42 +01:00
|
|
|
txtRecord = "Error"
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-14 18:18:26 +02:00
|
|
|
catch {
|
|
|
|
|
txtRecord = "Error"
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-13 14:18:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#Preview {
|
|
|
|
|
BlockedCount()
|
2026-04-14 18:21:00 +02:00
|
|
|
.environmentObject(ViewModel())
|
2026-04-13 14:18:42 +01:00
|
|
|
}
|