mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
97 lines
2.8 KiB
Swift
97 lines
2.8 KiB
Swift
// The MIT License (MIT)
|
|
//
|
|
// Copyright (c) 2020-2024 Alexander Grebenyuk (github.com/kean).
|
|
|
|
import Foundation
|
|
import CoreData
|
|
import Combine
|
|
import Pulse
|
|
|
|
/// Keeps track of hosts, paths, etc.
|
|
final class LoggerStoreIndex: ObservableObject {
|
|
@Published private(set) var labels: Set<String> = []
|
|
@Published private(set) var files: Set<String> = []
|
|
@Published private(set) var hosts: Set<String> = []
|
|
@Published private(set) var paths: Set<String> = []
|
|
|
|
private let context: NSManagedObjectContext
|
|
private var cancellable: AnyCancellable?
|
|
|
|
convenience init(store: LoggerStore) {
|
|
self.init(context: store.backgroundContext)
|
|
|
|
store.backgroundContext.perform {
|
|
self.prepopulate()
|
|
}
|
|
cancellable = store.events.receive(on: DispatchQueue.main).sink { [weak self] in
|
|
self?.handle($0)
|
|
}
|
|
}
|
|
|
|
init(context: NSManagedObjectContext) {
|
|
self.context = context
|
|
context.perform {
|
|
self.prepopulate()
|
|
}
|
|
}
|
|
|
|
private func handle(_ event: LoggerStore.Event) {
|
|
switch event {
|
|
case .messageStored(let event):
|
|
self.files.insert(event.file)
|
|
self.labels.insert(event.label)
|
|
case .networkTaskCompleted(let event):
|
|
if let host = event.originalRequest.url.flatMap(getHost) {
|
|
var hosts = self.hosts
|
|
let (isInserted, _) = hosts.insert(host)
|
|
if isInserted { self.hosts = hosts }
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
private func prepopulate() {
|
|
let files = context.getDistinctValues(entityName: "LoggerMessageEntity", property: "file")
|
|
let labels = context.getDistinctValues(entityName: "LoggerMessageEntity", property: "label")
|
|
let urls = context.getDistinctValues(entityName: "NetworkTaskEntity", property: "url")
|
|
|
|
var hosts = Set<String>()
|
|
var paths = Set<String>()
|
|
|
|
for url in urls {
|
|
guard let components = URLComponents(string: url) else {
|
|
continue
|
|
}
|
|
if let host = components.host, !host.isEmpty {
|
|
hosts.insert(host)
|
|
}
|
|
paths.insert(components.path)
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
self.labels = labels
|
|
self.files = files
|
|
self.hosts = hosts
|
|
self.paths = paths
|
|
}
|
|
}
|
|
|
|
func clear() {
|
|
self.labels = []
|
|
self.files = []
|
|
self.paths = []
|
|
self.hosts = []
|
|
}
|
|
}
|
|
|
|
private func getHost(for url: URL) -> String? {
|
|
if let host = url.host {
|
|
return host
|
|
}
|
|
if url.scheme == nil, let url = URL(string: "https://" + url.absoluteString) {
|
|
return url.host ?? "" // URL(string: "example.com")?.host with not scheme returns host: ""
|
|
}
|
|
return nil
|
|
}
|