Add HTTP prober, optimize mDNS timeout, add Trassir/ZOSI to OUI
- Add HTTPProber: parallel HEAD+GET on ports 80/8080, extracts Server header - Reduce mDNS timeout from 1s to 100ms using context wrapper around mdns.Query (HomeKit devices respond in 2-10ms, no need to wait 1s) - Add Trassir (F0:23:B9) and ZOSI (00:05:FE) to camera OUI database - Probe response time improved from ~1s to ~110ms for reachable devices
This commit is contained in:
@@ -2,15 +2,27 @@ package discovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap"
|
||||
"github.com/AlexxIT/go2rtc/pkg/mdns"
|
||||
"github.com/eduard256/Strix/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
// mdnsTimeout is the maximum time to wait for mDNS response.
|
||||
// HomeKit devices respond in 2-10ms. If no response in 100ms,
|
||||
// the device is definitely not a HomeKit camera.
|
||||
// The underlying mdns.Query has a 1s internal timeout, but we
|
||||
// cut it short with this context-based wrapper.
|
||||
mdnsTimeout = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
// MDNSProber performs mDNS unicast query to detect HomeKit devices.
|
||||
// It sends a DNS query to ip:5353 for the _hap._tcp.local. service
|
||||
// and parses TXT records to extract device information.
|
||||
// Uses a 100ms timeout wrapper around go2rtc's mdns.Query to avoid
|
||||
// waiting the full 1s on non-HomeKit devices.
|
||||
type MDNSProber struct{}
|
||||
|
||||
func (p *MDNSProber) Name() string { return "mdns" }
|
||||
@@ -18,11 +30,37 @@ func (p *MDNSProber) Name() string { return "mdns" }
|
||||
// Probe queries the device for HomeKit (HAP) mDNS service.
|
||||
// Returns nil if the device does not advertise HomeKit or is not a camera/doorbell.
|
||||
func (p *MDNSProber) Probe(ctx context.Context, ip string) (any, error) {
|
||||
// Unicast mDNS query directly to the device IP.
|
||||
// mdns.Query has internal timeouts (~1s), which fits within our 3s budget.
|
||||
entry, err := mdns.Query(ip, mdns.ServiceHAP)
|
||||
if err != nil || entry == nil {
|
||||
return nil, nil // Not a HomeKit device is not an error
|
||||
// Run mdns.Query in a goroutine with 100ms timeout.
|
||||
// mdns.Query has an internal 1s timeout and doesn't accept context,
|
||||
// so we wrap it. The background goroutine will clean up on its own
|
||||
// after the internal timeout expires (~1s, negligible resource cost).
|
||||
type queryResult struct {
|
||||
entry *mdns.ServiceEntry
|
||||
err error
|
||||
}
|
||||
|
||||
ch := make(chan queryResult, 1)
|
||||
go func() {
|
||||
entry, err := mdns.Query(ip, mdns.ServiceHAP)
|
||||
ch <- queryResult{entry, err}
|
||||
}()
|
||||
|
||||
// Wait for result or timeout
|
||||
timer := time.NewTimer(mdnsTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
var entry *mdns.ServiceEntry
|
||||
|
||||
select {
|
||||
case r := <-ch:
|
||||
if r.err != nil || r.entry == nil {
|
||||
return nil, nil
|
||||
}
|
||||
entry = r.entry
|
||||
case <-timer.C:
|
||||
return nil, nil // No response within 100ms -- not a HomeKit device
|
||||
case <-ctx.Done():
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Check if it's complete (has IP, port, and TXT records)
|
||||
|
||||
Reference in New Issue
Block a user