package discovery import ( "context" "log" "net" "github.com/grandcat/zeroconf" "github.com/pkg/errors" "github.com/wlynxg/anet" ) // Service is a ReachRS service discovered via MDNS-SD type Service struct { Name string AddrV4 *net.IP Port int } // Discover tries to discover ReachRS services on the local network via mDNS-SD func Discover(ctx context.Context) ([]Service, error) { services := make([]Service, 0) watch, err := Watch(ctx) if err != nil { return nil, errors.WithStack(err) } for srv := range watch { services = append(services, srv) } return services, nil } // Watch watches ReachRS services on the local network via mDNS-SD func Watch(ctx context.Context) (chan Service, error) { ifaces, err := anet.Interfaces() if err != nil { return nil, errors.WithStack(err) } log.Printf("%v", ifaces) out := make(chan Service, 0) resolver, err := zeroconf.NewResolver( zeroconf.SelectIfaces(ifaces), zeroconf.SelectIPTraffic(zeroconf.IPv4), ) if err != nil { return nil, errors.WithStack(err) } entries := make(chan *zeroconf.ServiceEntry) go func() { defer close(out) for e := range entries { var addr *net.IP if len(e.AddrIPv4) > 0 { addr = &e.AddrIPv4[0] } srv := Service{ Name: e.Instance, AddrV4: addr, Port: e.Port, } out <- srv } }() if err = resolver.Browse(ctx, "_reach._tcp", ".local", entries); err != nil { return nil, err } return out, nil }