Skip to content

Commit 09ce33b

Browse files
committed
Inlining methods in ArduinoCoreServiceImpl (part 4)
This commit feature a refactoring of the BoardListWatch command, now the gRPC stream is converted into a channel by leveraging the new stub boardListWatchServer that may be generic-ized to be reused for other streaming calls.
1 parent 276c7b1 commit 09ce33b

File tree

12 files changed

+85
-64
lines changed

12 files changed

+85
-64
lines changed

Diff for: commands/service.go

-32
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package commands
1818
import (
1919
"context"
2020
"errors"
21-
"fmt"
2221
"io"
2322
"sync/atomic"
2423

@@ -42,37 +41,6 @@ type arduinoCoreServerImpl struct {
4241
versionString string
4342
}
4443

45-
// BoardSearch exposes to the gRPC interface the board search command
46-
func (s *arduinoCoreServerImpl) BoardSearch(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchResponse, error) {
47-
return BoardSearch(ctx, req)
48-
}
49-
50-
// BoardListWatch FIXMEDOC
51-
func (s *arduinoCoreServerImpl) BoardListWatch(req *rpc.BoardListWatchRequest, stream rpc.ArduinoCoreService_BoardListWatchServer) error {
52-
syncSend := NewSynchronizedSend(stream.Send)
53-
if req.GetInstance() == nil {
54-
err := fmt.Errorf(tr("no instance specified"))
55-
syncSend.Send(&rpc.BoardListWatchResponse{
56-
EventType: "error",
57-
Error: err.Error(),
58-
})
59-
return err
60-
}
61-
62-
eventsChan, err := BoardListWatch(stream.Context(), req)
63-
if err != nil {
64-
return err
65-
}
66-
67-
for event := range eventsChan {
68-
if err := syncSend.Send(event); err != nil {
69-
logrus.Infof("sending board watch message: %v", err)
70-
}
71-
}
72-
73-
return nil
74-
}
75-
7644
// Destroy FIXMEDOC
7745
func (s *arduinoCoreServerImpl) Destroy(ctx context.Context, req *rpc.DestroyRequest) (*rpc.DestroyResponse, error) {
7846
return Destroy(ctx, req)

Diff for: commands/service_board_list.go

+55-10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"regexp"
2626
"sort"
2727
"strings"
28+
"sync"
2829
"time"
2930

3031
"github.com/arduino/arduino-cli/commands/cmderrors"
@@ -38,6 +39,7 @@ import (
3839
"github.com/arduino/go-properties-orderedmap"
3940
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
4041
"github.com/sirupsen/logrus"
42+
"google.golang.org/grpc/metadata"
4143
)
4244

4345
var (
@@ -262,29 +264,72 @@ func hasMatchingBoard(b *rpc.DetectedPort, fqbnFilter *cores.FQBN) bool {
262264
return false
263265
}
264266

265-
// BoardListWatch returns a channel that receives boards connection and disconnection events.
266-
func BoardListWatch(ctx context.Context, req *rpc.BoardListWatchRequest) (<-chan *rpc.BoardListWatchResponse, error) {
267+
type boardListWatchServer struct {
268+
ctx context.Context
269+
respChan chan<- *rpc.BoardListWatchResponse
270+
respLock sync.Mutex
271+
}
272+
273+
func NewBoardListWatchServerToChan(ctx context.Context, target chan<- *rpc.BoardListWatchResponse) rpc.ArduinoCoreService_BoardListWatchServer {
274+
w := &boardListWatchServer{ctx: ctx, respChan: target}
275+
go func() {
276+
<-ctx.Done()
277+
278+
w.respLock.Lock()
279+
close(w.respChan)
280+
w.respChan = nil
281+
w.respLock.Unlock()
282+
}()
283+
return w
284+
}
285+
286+
func (w *boardListWatchServer) Send(resp *rpc.BoardListWatchResponse) error {
287+
w.respLock.Lock()
288+
if w.respChan != nil {
289+
w.respChan <- resp
290+
}
291+
w.respLock.Unlock()
292+
return nil
293+
}
294+
295+
func (w *boardListWatchServer) Context() context.Context { return w.ctx }
296+
func (w *boardListWatchServer) RecvMsg(m any) error { return errors.New("not implemented") }
297+
func (w *boardListWatchServer) SendHeader(metadata.MD) error { return errors.New("not implemented") }
298+
func (w *boardListWatchServer) SendMsg(m any) error { return errors.New("not implemented") }
299+
func (w *boardListWatchServer) SetHeader(metadata.MD) error { return errors.New("not implemented") }
300+
func (w *boardListWatchServer) SetTrailer(metadata.MD) {}
301+
302+
// BoardListWatch FIXMEDOC
303+
func (s *arduinoCoreServerImpl) BoardListWatch(req *rpc.BoardListWatchRequest, stream rpc.ArduinoCoreService_BoardListWatchServer) error {
304+
syncSend := NewSynchronizedSend(stream.Send)
305+
if req.GetInstance() == nil {
306+
err := fmt.Errorf(tr("no instance specified"))
307+
syncSend.Send(&rpc.BoardListWatchResponse{
308+
EventType: "error",
309+
Error: err.Error(),
310+
})
311+
return err
312+
}
313+
267314
pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance())
268315
if err != nil {
269-
return nil, err
316+
return err
270317
}
271318
defer release()
272319
dm := pme.DiscoveryManager()
273320

274321
watcher, err := dm.Watch()
275322
if err != nil {
276-
return nil, err
323+
return err
277324
}
278325

279326
go func() {
280-
<-ctx.Done()
327+
<-stream.Context().Done()
281328
logrus.Trace("closed watch")
282329
watcher.Close()
283330
}()
284331

285-
outChan := make(chan *rpc.BoardListWatchResponse)
286332
go func() {
287-
defer close(outChan)
288333
for event := range watcher.Feed() {
289334
port := &rpc.DetectedPort{
290335
Port: rpc.DiscoveryPortToRPC(event.Port),
@@ -298,13 +343,13 @@ func BoardListWatch(ctx context.Context, req *rpc.BoardListWatchRequest) (<-chan
298343
}
299344
port.MatchingBoards = boards
300345
}
301-
outChan <- &rpc.BoardListWatchResponse{
346+
stream.Send(&rpc.BoardListWatchResponse{
302347
EventType: event.Type,
303348
Port: port,
304349
Error: boardsError,
305-
}
350+
})
306351
}
307352
}()
308353

309-
return outChan, nil
354+
return nil
310355
}

Diff for: commands/service_board_search.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
// Boards are searched in all platforms, including those in the index that are not yet
3030
// installed. Note that platforms that are not installed don't include boards' FQBNs.
3131
// If no search argument is used all boards are returned.
32-
func BoardSearch(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchResponse, error) {
32+
func (s *arduinoCoreServerImpl) BoardSearch(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchResponse, error) {
3333
pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance())
3434
if err != nil {
3535
return nil, err

Diff for: internal/cli/arguments/fqbn.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func CalculateFQBNAndPort(portArgs *Port, fqbnArg *Fqbn, instance *rpc.Instance,
8585
return fqbn, port
8686
}
8787

88-
port, err := portArgs.GetPort(instance, defaultAddress, defaultProtocol)
88+
port, err := portArgs.GetPort(instance, srv, defaultAddress, defaultProtocol)
8989
if err != nil {
9090
feedback.Fatal(tr("Error getting port metadata: %v", err), feedback.ErrGeneric)
9191
}

Diff for: internal/cli/arguments/port.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ func (p *Port) AddToCommand(cmd *cobra.Command, srv rpc.ArduinoCoreServiceServer
5656
// This method allows will bypass the discoveries if:
5757
// - a nil instance is passed: in this case the plain port and protocol arguments are returned (even if empty)
5858
// - a protocol is specified: in this case the discoveries are not needed to autodetect the protocol.
59-
func (p *Port) GetPortAddressAndProtocol(instance *rpc.Instance, defaultAddress, defaultProtocol string) (string, string, error) {
59+
func (p *Port) GetPortAddressAndProtocol(instance *rpc.Instance, srv rpc.ArduinoCoreServiceServer, defaultAddress, defaultProtocol string) (string, string, error) {
6060
if p.protocol != "" || instance == nil {
6161
return p.address, p.protocol, nil
6262
}
6363

64-
port, err := p.GetPort(instance, defaultAddress, defaultProtocol)
64+
port, err := p.GetPort(instance, srv, defaultAddress, defaultProtocol)
6565
if err != nil {
6666
return "", "", err
6767
}
@@ -70,8 +70,7 @@ func (p *Port) GetPortAddressAndProtocol(instance *rpc.Instance, defaultAddress,
7070

7171
// GetPort returns the Port obtained by parsing command line arguments.
7272
// The extra metadata for the ports is obtained using the pluggable discoveries.
73-
func (p *Port) GetPort(instance *rpc.Instance, defaultAddress, defaultProtocol string) (*rpc.Port, error) {
74-
73+
func (p *Port) GetPort(instance *rpc.Instance, srv rpc.ArduinoCoreServiceServer, defaultAddress, defaultProtocol string) (*rpc.Port, error) {
7574
address := p.address
7675
protocol := p.protocol
7776
if address == "" && (defaultAddress != "" || defaultProtocol != "") {
@@ -91,7 +90,12 @@ func (p *Port) GetPort(instance *rpc.Instance, defaultAddress, defaultProtocol s
9190

9291
ctx, cancel := context.WithCancel(context.Background())
9392
defer cancel()
94-
watcher, err := commands.BoardListWatch(ctx, &rpc.BoardListWatchRequest{Instance: instance})
93+
94+
watcher := make(chan *rpc.BoardListWatchResponse, 1)
95+
err := srv.BoardListWatch(
96+
&rpc.BoardListWatchRequest{Instance: instance},
97+
commands.NewBoardListWatchServerToChan(ctx, watcher))
98+
9599
if err != nil {
96100
return nil, err
97101
}

Diff for: internal/cli/board/attach.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func initAttachCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
4545
if len(args) > 0 {
4646
sketchPath = args[0]
4747
}
48-
runAttachCommand(sketchPath, &port, fqbn.String(), &programmer)
48+
runAttachCommand(srv, sketchPath, &port, fqbn.String(), &programmer)
4949
},
5050
}
5151
fqbn.AddToCommand(attachCommand, srv)
@@ -55,10 +55,10 @@ func initAttachCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
5555
return attachCommand
5656
}
5757

58-
func runAttachCommand(path string, port *arguments.Port, fqbn string, programmer *arguments.Programmer) {
58+
func runAttachCommand(srv rpc.ArduinoCoreServiceServer, path string, port *arguments.Port, fqbn string, programmer *arguments.Programmer) {
5959
sketchPath := arguments.InitSketchPath(path)
6060

61-
portAddress, portProtocol, _ := port.GetPortAddressAndProtocol(nil, "", "")
61+
portAddress, portProtocol, _ := port.GetPortAddressAndProtocol(nil, srv, "", "")
6262
newDefaults, err := commands.SetSketchDefaults(context.Background(), &rpc.SetSketchDefaultsRequest{
6363
SketchPath: sketchPath.String(),
6464
DefaultFqbn: fqbn,

Diff for: internal/cli/board/board.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
3939
boardCommand.AddCommand(initDetailsCommand(srv))
4040
boardCommand.AddCommand(initListCommand(srv))
4141
boardCommand.AddCommand(initListAllCommand(srv))
42-
boardCommand.AddCommand(initSearchCommand())
42+
boardCommand.AddCommand(initSearchCommand(srv))
4343

4444
return boardCommand
4545
}

Diff for: internal/cli/board/list.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func runListCommand(srv rpc.ArduinoCoreServiceServer, watch bool, timeout int64,
6363
logrus.Info("Executing `arduino-cli board list`")
6464

6565
if watch {
66-
watchList(inst)
66+
watchList(inst, srv)
6767
return
6868
}
6969

@@ -88,8 +88,11 @@ func runListCommand(srv rpc.ArduinoCoreServiceServer, watch bool, timeout int64,
8888
feedback.PrintResult(listResult{result.NewDetectedPorts(ports)})
8989
}
9090

91-
func watchList(inst *rpc.Instance) {
92-
eventsChan, err := commands.BoardListWatch(context.Background(), &rpc.BoardListWatchRequest{Instance: inst})
91+
func watchList(inst *rpc.Instance, srv rpc.ArduinoCoreServiceServer) {
92+
eventsChan := make(chan *rpc.BoardListWatchResponse, 1)
93+
err := srv.BoardListWatch(
94+
&rpc.BoardListWatchRequest{Instance: inst},
95+
commands.NewBoardListWatchServerToChan(context.Background(), eventsChan))
9396
if err != nil {
9497
feedback.Fatal(tr("Error detecting boards: %v", err), feedback.ErrNetwork)
9598
}

Diff for: internal/cli/board/search.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"sort"
2323
"strings"
2424

25-
"github.com/arduino/arduino-cli/commands"
2625
"github.com/arduino/arduino-cli/internal/cli/feedback"
2726
"github.com/arduino/arduino-cli/internal/cli/feedback/result"
2827
"github.com/arduino/arduino-cli/internal/cli/feedback/table"
@@ -32,7 +31,7 @@ import (
3231
"github.com/spf13/cobra"
3332
)
3433

35-
func initSearchCommand() *cobra.Command {
34+
func initSearchCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
3635
var searchCommand = &cobra.Command{
3736
Use: fmt.Sprintf("search [%s]", tr("boardname")),
3837
Short: tr("Search for a board in the Boards Manager."),
@@ -41,18 +40,20 @@ func initSearchCommand() *cobra.Command {
4140
" " + os.Args[0] + " board search\n" +
4241
" " + os.Args[0] + " board search zero",
4342
Args: cobra.ArbitraryArgs,
44-
Run: runSearchCommand,
43+
Run: func(cmd *cobra.Command, args []string) {
44+
runSearchCommand(srv, args)
45+
},
4546
}
4647
searchCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, tr("Show also boards marked as 'hidden' in the platform"))
4748
return searchCommand
4849
}
4950

50-
func runSearchCommand(cmd *cobra.Command, args []string) {
51+
func runSearchCommand(srv rpc.ArduinoCoreServiceServer, args []string) {
5152
inst := instance.CreateAndInit()
5253

5354
logrus.Info("Executing `arduino-cli board search`")
5455

55-
res, err := commands.BoardSearch(context.Background(), &rpc.BoardSearchRequest{
56+
res, err := srv.BoardSearch(context.Background(), &rpc.BoardSearchRequest{
5657
Instance: inst,
5758
SearchArgs: strings.Join(args, " "),
5859
IncludeHiddenBoards: showHiddenBoard,

Diff for: internal/cli/burnbootloader/burnbootloader.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func runBootloaderCommand(srv rpc.ArduinoCoreServiceServer) {
7171
logrus.Info("Executing `arduino-cli burn-bootloader`")
7272

7373
// We don't need a Sketch to upload a board's bootloader
74-
discoveryPort, err := port.GetPort(instance, "", "")
74+
discoveryPort, err := port.GetPort(instance, srv, "", "")
7575
if err != nil {
7676
feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric)
7777
}

Diff for: internal/cli/debug/debug_check.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func runDebugCheckCommand(srv rpc.ArduinoCoreServiceServer, portArgs *arguments.
5555
instance := instance.CreateAndInit()
5656
logrus.Info("Executing `arduino-cli debug`")
5757

58-
port, err := portArgs.GetPort(instance, "", "")
58+
port, err := portArgs.GetPort(instance, srv, "", "")
5959
if err != nil {
6060
feedback.FatalError(err, feedback.ErrBadArgument)
6161
}

Diff for: internal/cli/monitor/monitor.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func runMonitorCmd(
140140
fqbn, _ = portArgs.DetectFQBN(inst, srv)
141141
}
142142

143-
portAddress, portProtocol, err := portArgs.GetPortAddressAndProtocol(inst, defaultPort, defaultProtocol)
143+
portAddress, portProtocol, err := portArgs.GetPortAddressAndProtocol(inst, srv, defaultPort, defaultProtocol)
144144
if err != nil {
145145
feedback.FatalError(err, feedback.ErrGeneric)
146146
}

0 commit comments

Comments
 (0)