Unverified Commit 27381c51 authored by Silvano Cerza's avatar Silvano Cerza Committed by GitHub

Add gRPC interface for board list watcher (#1048)

parent ff3302fc
......@@ -25,7 +25,6 @@ import (
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/board"
rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/arduino/arduino-cli/table"
......@@ -90,8 +89,7 @@ func runListCommand(cmd *cobra.Command, args []string) {
}
func watchList(cmd *cobra.Command, inst *rpc.Instance) {
pm := commands.GetPackageManager(inst.Id)
eventsChan, err := commands.WatchListBoards(pm)
eventsChan, err := board.Watch(inst.Id, nil)
if err != nil {
feedback.Errorf("Error detecting boards: %v", err)
os.Exit(errorcodes.ErrNetwork)
......@@ -105,28 +103,13 @@ func watchList(cmd *cobra.Command, inst *rpc.Instance) {
}
for event := range eventsChan {
boards := []*rpc.BoardListItem{}
if event.Type == "add" {
boards, err = board.Identify(pm, &commands.BoardPort{
Address: event.Port.Address,
Label: event.Port.AddressLabel,
Prefs: event.Port.Properties,
IdentificationPrefs: event.Port.IdentificationProperties,
Protocol: event.Port.Protocol,
ProtocolLabel: event.Port.ProtocolLabel,
})
if err != nil {
feedback.Errorf("Error identifying board: %v", err)
os.Exit(errorcodes.ErrNetwork)
}
}
feedback.PrintResult(watchEvent{
Type: event.Type,
Type: event.EventType,
Address: event.Port.Address,
Protocol: event.Port.Protocol,
ProtocolLabel: event.Port.ProtocolLabel,
Boards: boards,
Boards: event.Port.Boards,
Error: event.Error,
})
}
}
......@@ -198,6 +181,7 @@ type watchEvent struct {
Protocol string `json:"protocol,omitempty"`
ProtocolLabel string `json:"protocol_label,omitempty"`
Boards []*rpc.BoardListItem `json:"boards,omitempty"`
Error string `json:"error,omitempty"`
}
func (dr watchEvent) Data() interface{} {
......
This diff is collapsed.
......@@ -26,6 +26,7 @@ import (
"path"
"path/filepath"
"strings"
"time"
rpc "github.com/arduino/arduino-cli/rpc/commands"
dbg "github.com/arduino/arduino-cli/rpc/debug"
......@@ -154,6 +155,10 @@ func main() {
log.Println("calling BoardList()")
callBoardList(client, instance)
// Watch for boards connection and disconnection
log.Println("calling BoardListWatch()")
callBoardListWatch(client, instance)
// Uninstall a platform
log.Println("calling PlatformUninstall(arduino:samd)")
callPlatformUnInstall(client, instance)
......@@ -592,6 +597,41 @@ func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
}
}
func callBoardListWatch(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
watchClient, err := client.BoardListWatch(context.Background())
if err != nil {
log.Fatalf("Board list watch error: %s\n", err)
}
// Start the watcher
watchClient.Send(&rpc.BoardListWatchReq{
Instance: instance,
})
go func() {
for {
res, err := watchClient.Recv()
if err != nil {
log.Fatalf("Board list watch error: %s\n", err)
}
log.Printf("event: %s, address: %s\n", res.EventType, res.Port.Address)
if res.EventType == "add" {
log.Printf("protocol: %s, ", res.Port.Protocol)
log.Printf("protocolLabel: %s, ", res.Port.ProtocolLabel)
log.Printf("boards: %s\n\n", res.Port.Boards)
}
}
}()
// Watch for 10 seconds and then interrupts
timer := time.NewTicker(time.Duration(10 * time.Second))
<-timer.C
watchClient.Send(&rpc.BoardListWatchReq{
Interrupt: true,
})
}
func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
uninstallRespStream, err := client.PlatformUninstall(context.Background(),
&rpc.PlatformUninstallReq{
......
......@@ -108,8 +108,8 @@ func identifyViaCloudAPI(port *commands.BoardPort) ([]*rpc.BoardListItem, error)
return apiByVidPid(id.Get("vid"), id.Get("pid"))
}
// Identify returns a list of boards checking first the installed platforms or the Cloud API
func Identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*rpc.BoardListItem, error) {
// identify returns a list of boards checking first the installed platforms or the Cloud API
func identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*rpc.BoardListItem, error) {
boards := []*rpc.BoardListItem{}
// first query installed cores through the Package Manager
......@@ -169,7 +169,7 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
retVal := []*rpc.DetectedPort{}
for _, port := range ports {
boards, err := Identify(pm, port)
boards, err := identify(pm, port)
if err != nil {
return nil, err
}
......@@ -187,3 +187,52 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
return retVal, nil
}
// Watch returns a channel that receives boards connection and disconnection events.
// The discovery process can be interrupted by sending a message to the interrupt channel.
func Watch(instanceID int32, interrupt <-chan bool) (<-chan *rpc.BoardListWatchResp, error) {
pm := commands.GetPackageManager(instanceID)
eventsChan, err := commands.WatchListBoards(pm)
if err != nil {
return nil, err
}
outChan := make(chan *rpc.BoardListWatchResp)
go func() {
for {
select {
case event := <-eventsChan:
boards := []*rpc.BoardListItem{}
boardsError := ""
if event.Type == "add" {
boards, err = identify(pm, &commands.BoardPort{
Address: event.Port.Address,
Label: event.Port.AddressLabel,
Prefs: event.Port.Properties,
IdentificationPrefs: event.Port.IdentificationProperties,
Protocol: event.Port.Protocol,
ProtocolLabel: event.Port.ProtocolLabel,
})
if err != nil {
boardsError = err.Error()
}
}
outChan <- &rpc.BoardListWatchResp{
EventType: event.Type,
Port: &rpc.DetectedPort{
Address: event.Port.Address,
Protocol: event.Port.Protocol,
ProtocolLabel: event.Port.ProtocolLabel,
Boards: boards,
},
Error: boardsError,
}
case <-interrupt:
break
}
}
}()
return outChan, nil
}
......@@ -19,6 +19,7 @@ package daemon
import (
"context"
"io"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
......@@ -58,6 +59,39 @@ func (s *ArduinoCoreServerImpl) BoardListAll(ctx context.Context, req *rpc.Board
return board.ListAll(ctx, req)
}
// BoardListWatch FIXMEDOC
func (s *ArduinoCoreServerImpl) BoardListWatch(stream rpc.ArduinoCore_BoardListWatchServer) error {
msg, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
interrupt := make(chan bool)
go func() {
msg, err := stream.Recv()
if err != nil {
interrupt <- true
}
if msg != nil {
interrupt <- msg.Interrupt
}
}()
eventsChan, err := board.Watch(msg.Instance.Id, interrupt)
if err != nil {
return err
}
for event := range eventsChan {
stream.Send(event)
}
return nil
}
// BoardAttach FIXMEDOC
func (s *ArduinoCoreServerImpl) BoardAttach(req *rpc.BoardAttachReq, stream rpc.ArduinoCore_BoardAttachServer) error {
......
This diff is collapsed.
......@@ -206,6 +206,22 @@ message BoardListAllResp {
repeated BoardListItem boards = 1;
}
message BoardListWatchReq {
// Arduino Core Service instance from the `Init` response.
Instance instance = 1;
// Set this to true to stop the discovery process
bool interrupt = 2;
}
message BoardListWatchResp {
// Event type as received from the serial discovery tool
string event_type = 1;
// Information about the port
DetectedPort port = 2;
// Eventual errors when detecting connected boards
string error = 3;
}
message BoardListItem {
// The name for use when identifying the board to a human.
string name = 1;
......
This diff is collapsed.
......@@ -80,6 +80,9 @@ service ArduinoCore {
// List all the boards provided by installed platforms.
rpc BoardListAll(BoardListAllReq) returns (BoardListAllResp);
// List boards connection and disconnected events.
rpc BoardListWatch(stream BoardListWatchReq) returns (stream BoardListWatchResp);
// Compile an Arduino sketch.
rpc Compile(CompileReq) returns (stream CompileResp);
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: commands/common.proto
package commands
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: commands/compile.proto
package commands
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: commands/core.proto
package commands
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: commands/lib.proto
package commands
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: commands/upload.proto
package commands
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: debug/debug.proto
package debug
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: monitor/monitor.proto
package monitor
......
......@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// protoc v3.12.4
// source: settings/settings.proto
package settings
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment