Files
iOS/Sources/App/Onboarding/API/Bonjour.swift
Bruno Pantaleão Gonçalves 16f5a1bc75 Simplify and migrate onboarding screens to SwiftUI (#3527)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->



https://github.com/user-attachments/assets/e79c6e4d-13ff-405a-9463-02e597ce4996
2025-04-08 23:54:34 +02:00

109 lines
3.5 KiB
Swift

import Foundation
public protocol BonjourObserver: AnyObject {
func bonjour(_ bonjour: Bonjour, didAdd instance: DiscoveredHomeAssistant)
func bonjour(_ bonjour: Bonjour, didRemoveInstanceWithName name: String)
}
public protocol BonjourProtocol {
var observer: BonjourObserver? { get set }
func start()
func stop()
}
public class Bonjour: NSObject, NetServiceBrowserDelegate, NetServiceDelegate, BonjourProtocol {
public weak var observer: BonjourObserver?
private var browser: NetServiceBrowser
private var resolving = [NetService]()
private var resolvingDict = [String: NetService]()
private var browserIsRunning: Bool = false
override public init() {
self.browser = NetServiceBrowser()
super.init()
}
public func start() {
precondition(Thread.isMainThread)
guard !browserIsRunning else { return }
Current.Log.info()
browserIsRunning = true
browser.delegate = self
browser.searchForServices(ofType: "_home-assistant._tcp.", inDomain: "")
}
public func stop() {
precondition(Thread.isMainThread)
guard browserIsRunning else { return }
Current.Log.info()
browserIsRunning = false
browser.stop()
browser.delegate = nil
}
// Browser methods
public func netServiceBrowser(
_ netServiceBrowser: NetServiceBrowser,
didFind netService: NetService,
moreComing moreServicesComing: Bool
) {
Current.Log.verbose()
netService.delegate = self
resolvingDict[netService.name] = netService
netService.resolve(withTimeout: 0.0)
}
public func netServiceDidResolveAddress(_ sender: NetService) {
Current.Log.verbose()
guard let txtRecord = sender.txtRecordData() else { return }
let potentialServiceDict = NetService.dictionary(fromTXTRecord: txtRecord) as NSDictionary
// This fixes a crash in 0.110, the root cause is the dictionary returned
// above contains NSNull instead of NSData, which Swift will crash trying
// to cast to the Swift dictionary. So we do it the hard way.
let serviceDict = (potentialServiceDict as? [String: Any])?
.compactMapValues { $0 as? Data } ?? [:]
do {
let discovered = try discoveredHomeAssistant(
bonjourName: sender.name,
netServiceDictionary: serviceDict
)
observer?.bonjour(self, didAdd: discovered)
} catch {
Current.Log.error(error)
}
}
public func netServiceBrowser(
_ netServiceBrowser: NetServiceBrowser,
didRemove netService: NetService,
moreComing moreServicesComing: Bool
) {
Current.Log.verbose(netService.name)
observer?.bonjour(self, didRemoveInstanceWithName: netService.name)
resolvingDict.removeValue(forKey: netService.name)
}
private func discoveredHomeAssistant(
bonjourName: String,
netServiceDictionary: [String: Data]
) throws -> DiscoveredHomeAssistant {
var outputDict: [String: Any] = [:]
for (key, value) in netServiceDictionary {
outputDict[key] = String(data: value, encoding: .utf8)
}
if outputDict["location_name"] == nil {
outputDict["location_name"] = bonjourName
}
var instance = try DiscoveredHomeAssistant(JSON: outputDict, context: nil)
instance.bonjourName = bonjourName
return instance
}
}