Skip to content

Commit 27381c5

Browse files
authored
Add gRPC interface for board list watcher (#1048)
1 parent ff3302f commit 27381c5

File tree

17 files changed

+707
-312
lines changed

17 files changed

+707
-312
lines changed

Diff for: cli/board/list.go

+5-21
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/arduino/arduino-cli/cli/errorcodes"
2626
"github.com/arduino/arduino-cli/cli/feedback"
2727
"github.com/arduino/arduino-cli/cli/instance"
28-
"github.com/arduino/arduino-cli/commands"
2928
"github.com/arduino/arduino-cli/commands/board"
3029
rpc "github.com/arduino/arduino-cli/rpc/commands"
3130
"github.com/arduino/arduino-cli/table"
@@ -90,8 +89,7 @@ func runListCommand(cmd *cobra.Command, args []string) {
9089
}
9190

9291
func watchList(cmd *cobra.Command, inst *rpc.Instance) {
93-
pm := commands.GetPackageManager(inst.Id)
94-
eventsChan, err := commands.WatchListBoards(pm)
92+
eventsChan, err := board.Watch(inst.Id, nil)
9593
if err != nil {
9694
feedback.Errorf("Error detecting boards: %v", err)
9795
os.Exit(errorcodes.ErrNetwork)
@@ -105,28 +103,13 @@ func watchList(cmd *cobra.Command, inst *rpc.Instance) {
105103
}
106104

107105
for event := range eventsChan {
108-
boards := []*rpc.BoardListItem{}
109-
if event.Type == "add" {
110-
boards, err = board.Identify(pm, &commands.BoardPort{
111-
Address: event.Port.Address,
112-
Label: event.Port.AddressLabel,
113-
Prefs: event.Port.Properties,
114-
IdentificationPrefs: event.Port.IdentificationProperties,
115-
Protocol: event.Port.Protocol,
116-
ProtocolLabel: event.Port.ProtocolLabel,
117-
})
118-
if err != nil {
119-
feedback.Errorf("Error identifying board: %v", err)
120-
os.Exit(errorcodes.ErrNetwork)
121-
}
122-
}
123-
124106
feedback.PrintResult(watchEvent{
125-
Type: event.Type,
107+
Type: event.EventType,
126108
Address: event.Port.Address,
127109
Protocol: event.Port.Protocol,
128110
ProtocolLabel: event.Port.ProtocolLabel,
129-
Boards: boards,
111+
Boards: event.Port.Boards,
112+
Error: event.Error,
130113
})
131114
}
132115
}
@@ -198,6 +181,7 @@ type watchEvent struct {
198181
Protocol string `json:"protocol,omitempty"`
199182
ProtocolLabel string `json:"protocol_label,omitempty"`
200183
Boards []*rpc.BoardListItem `json:"boards,omitempty"`
184+
Error string `json:"error,omitempty"`
201185
}
202186

203187
func (dr watchEvent) Data() interface{} {

Diff for: client_example/go.sum

+22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
1010
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c/go.mod h1:HK7SpkEax/3P+0w78iRQx1sz1vCDYYw9RXwHjQTB5i8=
1111
github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
1212
github.com/arduino/go-paths-helper v1.2.0/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
13+
github.com/arduino/go-paths-helper v1.3.2/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
1314
github.com/arduino/go-properties-orderedmap v0.0.0-20190828172252-05018b28ff6c/go.mod h1:kiSuHm7yz3chiy8rb2MphC7ECn3MlkQFAIe4SXmQg6o=
1415
github.com/arduino/go-properties-orderedmap v1.3.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
1516
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwGy5PpN4lqW97FiLnbcx+xx8jly5YuPMJWfVwwjJiQ=
@@ -20,10 +21,12 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
2021
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
2122
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
2223
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
24+
github.com/cmaglie/go.rice v1.0.3/go.mod h1:AF3bOWkvdOpp8/S3UL8qbQ4N7DiISIbJtj54GWFPAsc=
2325
github.com/cmaglie/pb v1.0.27 h1:ynGj8vBXR+dtj4B7Q/W/qGt31771Ux5iFfRQBnwdQiA=
2426
github.com/cmaglie/pb v1.0.27/go.mod h1:GilkKZMXYjBA4NxItWFfO+lwkp59PLHQ+IOW/b/kmZI=
2527
github.com/codeclysm/cc v1.2.2/go.mod h1:XtW4ArCNgQwFphcRGG9+sPX5WM1J6/u0gMy5ZdV3obA=
2628
github.com/codeclysm/extract v2.2.0+incompatible/go.mod h1:2nhFMPHiU9At61hz+12bfrlpXSUrOnK+wR+KlGO4Uks=
29+
github.com/codeclysm/extract/v3 v3.0.2/go.mod h1:NKsw+hqua9H+Rlwy/w/3Qgt9jDonYEgB6wJu+25eOKw=
2730
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
2831
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
2932
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
@@ -82,16 +85,24 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
8285
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
8386
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
8487
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
88+
github.com/h2non/filetype v1.0.6/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU=
8589
github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU=
8690
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
8791
github.com/imjasonmiller/godice v0.1.2/go.mod h1:8cTkdnVI+NglU2d6sv+ilYcNaJ5VSTBwvMbFULJd/QQ=
8892
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
8993
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
9094
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
9195
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
96+
github.com/juju/clock v0.0.0-20180524022203-d293bb356ca4/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
97+
github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
9298
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
99+
github.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
93100
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
101+
github.com/juju/retry v0.0.0-20160928201858-1998d01ba1c3/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
94102
github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
103+
github.com/juju/testing v0.0.0-20200510222523-6c8c298c77a0/go.mod h1:hpGvhGHPVbNBraRLZEhoQwFLMrjK8PSlO4D3nDjKYXo=
104+
github.com/juju/utils v0.0.0-20180808125547-9dfc6dbfb02b/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
105+
github.com/juju/version v0.0.0-20161031051906-1f41e27e54f2/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
95106
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
96107
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
97108
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -117,7 +128,9 @@ github.com/miekg/dns v1.0.5/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nr
117128
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
118129
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
119130
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
131+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
120132
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
133+
github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc=
121134
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
122135
github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228/go.mod h1:MGuVJ1+5TX1SCoO2Sx0eAnjpdRytYla2uC1YIZfkC9c=
123136
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -180,18 +193,21 @@ go.bug.st/downloader v1.1.0/go.mod h1:l+RPbNbrTB+MoAIp8nrZsP22nRPDy26XJZQqmm4gNT
180193
go.bug.st/downloader/v2 v2.0.1/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII=
181194
go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE=
182195
go.bug.st/serial v1.0.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q=
196+
go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY=
183197
go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw=
184198
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
185199
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
186200
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
187201
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
202+
golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
188203
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
189204
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
190205
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
191206
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
192207
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
193208
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
194209
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
210+
golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
195211
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
196212
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
197213
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -222,6 +238,8 @@ golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX
222238
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
223239
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
224240
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
241+
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
242+
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
225243
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
226244
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
227245
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -261,11 +279,15 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4
261279
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
262280
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
263281
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
282+
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
264283
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
265284
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
285+
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
266286
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
287+
gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
267288
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
268289
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
290+
gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
269291
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
270292
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
271293
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

Diff for: client_example/main.go

+40
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"path"
2727
"path/filepath"
2828
"strings"
29+
"time"
2930

3031
rpc "github.com/arduino/arduino-cli/rpc/commands"
3132
dbg "github.com/arduino/arduino-cli/rpc/debug"
@@ -154,6 +155,10 @@ func main() {
154155
log.Println("calling BoardList()")
155156
callBoardList(client, instance)
156157

158+
// Watch for boards connection and disconnection
159+
log.Println("calling BoardListWatch()")
160+
callBoardListWatch(client, instance)
161+
157162
// Uninstall a platform
158163
log.Println("calling PlatformUninstall(arduino:samd)")
159164
callPlatformUnInstall(client, instance)
@@ -592,6 +597,41 @@ func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
592597
}
593598
}
594599

600+
func callBoardListWatch(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
601+
watchClient, err := client.BoardListWatch(context.Background())
602+
if err != nil {
603+
log.Fatalf("Board list watch error: %s\n", err)
604+
}
605+
606+
// Start the watcher
607+
watchClient.Send(&rpc.BoardListWatchReq{
608+
Instance: instance,
609+
})
610+
611+
go func() {
612+
for {
613+
res, err := watchClient.Recv()
614+
if err != nil {
615+
log.Fatalf("Board list watch error: %s\n", err)
616+
}
617+
618+
log.Printf("event: %s, address: %s\n", res.EventType, res.Port.Address)
619+
if res.EventType == "add" {
620+
log.Printf("protocol: %s, ", res.Port.Protocol)
621+
log.Printf("protocolLabel: %s, ", res.Port.ProtocolLabel)
622+
log.Printf("boards: %s\n\n", res.Port.Boards)
623+
}
624+
}
625+
}()
626+
627+
// Watch for 10 seconds and then interrupts
628+
timer := time.NewTicker(time.Duration(10 * time.Second))
629+
<-timer.C
630+
watchClient.Send(&rpc.BoardListWatchReq{
631+
Interrupt: true,
632+
})
633+
}
634+
595635
func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
596636
uninstallRespStream, err := client.PlatformUninstall(context.Background(),
597637
&rpc.PlatformUninstallReq{

Diff for: commands/board/list.go

+52-3
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ func identifyViaCloudAPI(port *commands.BoardPort) ([]*rpc.BoardListItem, error)
108108
return apiByVidPid(id.Get("vid"), id.Get("pid"))
109109
}
110110

111-
// Identify returns a list of boards checking first the installed platforms or the Cloud API
112-
func Identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*rpc.BoardListItem, error) {
111+
// identify returns a list of boards checking first the installed platforms or the Cloud API
112+
func identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*rpc.BoardListItem, error) {
113113
boards := []*rpc.BoardListItem{}
114114

115115
// first query installed cores through the Package Manager
@@ -169,7 +169,7 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
169169

170170
retVal := []*rpc.DetectedPort{}
171171
for _, port := range ports {
172-
boards, err := Identify(pm, port)
172+
boards, err := identify(pm, port)
173173
if err != nil {
174174
return nil, err
175175
}
@@ -187,3 +187,52 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
187187

188188
return retVal, nil
189189
}
190+
191+
// Watch returns a channel that receives boards connection and disconnection events.
192+
// The discovery process can be interrupted by sending a message to the interrupt channel.
193+
func Watch(instanceID int32, interrupt <-chan bool) (<-chan *rpc.BoardListWatchResp, error) {
194+
pm := commands.GetPackageManager(instanceID)
195+
eventsChan, err := commands.WatchListBoards(pm)
196+
if err != nil {
197+
return nil, err
198+
}
199+
200+
outChan := make(chan *rpc.BoardListWatchResp)
201+
go func() {
202+
for {
203+
select {
204+
case event := <-eventsChan:
205+
boards := []*rpc.BoardListItem{}
206+
boardsError := ""
207+
if event.Type == "add" {
208+
boards, err = identify(pm, &commands.BoardPort{
209+
Address: event.Port.Address,
210+
Label: event.Port.AddressLabel,
211+
Prefs: event.Port.Properties,
212+
IdentificationPrefs: event.Port.IdentificationProperties,
213+
Protocol: event.Port.Protocol,
214+
ProtocolLabel: event.Port.ProtocolLabel,
215+
})
216+
if err != nil {
217+
boardsError = err.Error()
218+
}
219+
}
220+
221+
outChan <- &rpc.BoardListWatchResp{
222+
EventType: event.Type,
223+
Port: &rpc.DetectedPort{
224+
Address: event.Port.Address,
225+
Protocol: event.Port.Protocol,
226+
ProtocolLabel: event.Port.ProtocolLabel,
227+
Boards: boards,
228+
},
229+
Error: boardsError,
230+
}
231+
case <-interrupt:
232+
break
233+
}
234+
}
235+
}()
236+
237+
return outChan, nil
238+
}

Diff for: commands/daemon/daemon.go

+34
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package daemon
1919

2020
import (
2121
"context"
22+
"io"
2223

2324
"github.com/arduino/arduino-cli/arduino/utils"
2425
"github.com/arduino/arduino-cli/commands"
@@ -58,6 +59,39 @@ func (s *ArduinoCoreServerImpl) BoardListAll(ctx context.Context, req *rpc.Board
5859
return board.ListAll(ctx, req)
5960
}
6061

62+
// BoardListWatch FIXMEDOC
63+
func (s *ArduinoCoreServerImpl) BoardListWatch(stream rpc.ArduinoCore_BoardListWatchServer) error {
64+
msg, err := stream.Recv()
65+
if err == io.EOF {
66+
return nil
67+
}
68+
if err != nil {
69+
return err
70+
}
71+
72+
interrupt := make(chan bool)
73+
go func() {
74+
msg, err := stream.Recv()
75+
if err != nil {
76+
interrupt <- true
77+
}
78+
if msg != nil {
79+
interrupt <- msg.Interrupt
80+
}
81+
}()
82+
83+
eventsChan, err := board.Watch(msg.Instance.Id, interrupt)
84+
if err != nil {
85+
return err
86+
}
87+
88+
for event := range eventsChan {
89+
stream.Send(event)
90+
}
91+
92+
return nil
93+
}
94+
6195
// BoardAttach FIXMEDOC
6296
func (s *ArduinoCoreServerImpl) BoardAttach(req *rpc.BoardAttachReq, stream rpc.ArduinoCore_BoardAttachServer) error {
6397

0 commit comments

Comments
 (0)