@@ -20,12 +20,16 @@ package main
2020import (
2121 "context"
2222 "fmt"
23+ "io/ioutil"
24+ "log"
2325 "os"
2426 "strconv"
27+ "strings"
28+ "time"
2529
2630 properties "github.com/arduino/go-properties-orderedmap"
2731 discovery "github.com/arduino/pluggable-discovery-protocol-handler"
28- "github.com/brutella/dnssd "
32+ "github.com/hashicorp/mdns "
2933)
3034
3135func main () {
@@ -39,15 +43,18 @@ func main() {
3943
4044}
4145
42- const mdnsServiceName = "_arduino._tcp.local. "
46+ const mdnsServiceName = "_arduino._tcp"
4347
4448// MDNSDiscovery is the implementation of the network pluggable-discovery
4549type MDNSDiscovery struct {
46- cancelFunc func ()
50+ cancelFunc func ()
51+ entriesChan chan * mdns.ServiceEntry
4752}
4853
4954// Hello handles the pluggable-discovery HELLO command
5055func (d * MDNSDiscovery ) Hello (userAgent string , protocolVersion int ) error {
56+ // The mdns library used has some logs statement that we must disable
57+ log .SetOutput (ioutil .Discard )
5158 return nil
5259}
5360
@@ -57,52 +64,87 @@ func (d *MDNSDiscovery) Stop() error {
5764 d .cancelFunc ()
5865 d .cancelFunc = nil
5966 }
67+ if d .entriesChan != nil {
68+ close (d .entriesChan )
69+ d .entriesChan = nil
70+ }
6071 return nil
6172}
6273
6374// Quit handles the pluggable-discovery QUIT command
6475func (d * MDNSDiscovery ) Quit () {
76+ close (d .entriesChan )
6577}
6678
6779// StartSync handles the pluggable-discovery START_SYNC command
6880func (d * MDNSDiscovery ) StartSync (eventCB discovery.EventCallback , errorCB discovery.ErrorCallback ) error {
69- addFn := func ( srv dnssd. Service ) {
70- eventCB ( "add" , newBoardPortJSON ( & srv ) )
81+ if d . entriesChan != nil {
82+ return fmt . Errorf ( "already syncing" )
7183 }
72- remFn := func (srv dnssd.Service ) {
73- eventCB ("remove" , newBoardPortJSON (& srv ))
84+
85+ d .entriesChan = make (chan * mdns.ServiceEntry , 4 )
86+ var receiver <- chan * mdns.ServiceEntry = d .entriesChan
87+ var sender chan <- * mdns.ServiceEntry = d .entriesChan
88+
89+ go func () {
90+ for entry := range receiver {
91+ eventCB ("add" , toDiscoveryPort (entry ))
92+ }
93+ }()
94+
95+ params := & mdns.QueryParam {
96+ Service : mdnsServiceName ,
97+ Domain : "local" ,
98+ Timeout : time .Second * 15 ,
99+ Entries : sender ,
100+ WantUnicastResponse : false ,
74101 }
75- ctx , cancel := context .WithCancel (context .Background ())
76102
103+ ctx , cancel := context .WithCancel (context .Background ())
77104 go func () {
78- if err := dnssd .LookupType (ctx , mdnsServiceName , addFn , remFn ); err != nil {
79- errorCB ("mdns lookup error: " + err .Error ())
105+ for {
106+ if err := mdns .Query (params ); err != nil {
107+ errorCB ("mdns lookup error: " + err .Error ())
108+ }
109+ select {
110+ default :
111+ case <- ctx .Done ():
112+ return
113+ }
80114 }
81115 }()
82116 d .cancelFunc = cancel
83117 return nil
84118}
85119
86- func newBoardPortJSON (port * dnssd.Service ) * discovery.Port {
87- ip := "127.0.0.1"
88- if len (port .IPs ) > 0 {
89- ip = port .IPs [0 ].String ()
120+ func toDiscoveryPort (entry * mdns.ServiceEntry ) * discovery.Port {
121+ ip := ""
122+ if len (entry .AddrV4 ) > 0 {
123+ ip = entry .AddrV4 .String ()
124+ } else if len (entry .AddrV6 ) > 0 {
125+ ip = entry .AddrV6 .String ()
90126 }
91127
92128 props := properties .NewMap ()
93- props .Set ("ttl" , strconv .Itoa (int (port .TTL .Seconds ())))
94- props .Set ("hostname" , port .Hostname ())
95- props .Set ("port" , strconv .Itoa (port .Port ))
96- for key , value := range port .Text {
129+ props .Set ("hostname" , entry .Host )
130+ props .Set ("port" , strconv .Itoa (entry .Port ))
131+
132+ for _ , field := range entry .InfoFields {
133+ split := strings .Split (field , "=" )
134+ if len (split ) != 2 {
135+ continue
136+ }
137+ key , value := split [0 ], split [1 ]
97138 props .Set (key , value )
98139 if key == "board" {
99140 // duplicate for backwards compatibility
100141 props .Set ("." , value )
101142 }
102143 }
144+
103145 return & discovery.Port {
104146 Address : ip ,
105- AddressLabel : port . Name + " at " + ip ,
147+ AddressLabel : fmt . Sprintf ( "%s at %s" , entry . Name , ip ) ,
106148 Protocol : "network" ,
107149 ProtocolLabel : "Network Port" ,
108150 Properties : props ,
0 commit comments