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 ( ...@@ -25,7 +25,6 @@ import (
"github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/board" "github.com/arduino/arduino-cli/commands/board"
rpc "github.com/arduino/arduino-cli/rpc/commands" rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/arduino/arduino-cli/table" "github.com/arduino/arduino-cli/table"
...@@ -90,8 +89,7 @@ func runListCommand(cmd *cobra.Command, args []string) { ...@@ -90,8 +89,7 @@ func runListCommand(cmd *cobra.Command, args []string) {
} }
func watchList(cmd *cobra.Command, inst *rpc.Instance) { func watchList(cmd *cobra.Command, inst *rpc.Instance) {
pm := commands.GetPackageManager(inst.Id) eventsChan, err := board.Watch(inst.Id, nil)
eventsChan, err := commands.WatchListBoards(pm)
if err != nil { if err != nil {
feedback.Errorf("Error detecting boards: %v", err) feedback.Errorf("Error detecting boards: %v", err)
os.Exit(errorcodes.ErrNetwork) os.Exit(errorcodes.ErrNetwork)
...@@ -105,28 +103,13 @@ func watchList(cmd *cobra.Command, inst *rpc.Instance) { ...@@ -105,28 +103,13 @@ func watchList(cmd *cobra.Command, inst *rpc.Instance) {
} }
for event := range eventsChan { 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{ feedback.PrintResult(watchEvent{
Type: event.Type, Type: event.EventType,
Address: event.Port.Address, Address: event.Port.Address,
Protocol: event.Port.Protocol, Protocol: event.Port.Protocol,
ProtocolLabel: event.Port.ProtocolLabel, ProtocolLabel: event.Port.ProtocolLabel,
Boards: boards, Boards: event.Port.Boards,
Error: event.Error,
}) })
} }
} }
...@@ -198,6 +181,7 @@ type watchEvent struct { ...@@ -198,6 +181,7 @@ type watchEvent struct {
Protocol string `json:"protocol,omitempty"` Protocol string `json:"protocol,omitempty"`
ProtocolLabel string `json:"protocol_label,omitempty"` ProtocolLabel string `json:"protocol_label,omitempty"`
Boards []*rpc.BoardListItem `json:"boards,omitempty"` Boards []*rpc.BoardListItem `json:"boards,omitempty"`
Error string `json:"error,omitempty"`
} }
func (dr watchEvent) Data() interface{} { func (dr watchEvent) Data() interface{} {
......
This diff is collapsed.
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
rpc "github.com/arduino/arduino-cli/rpc/commands" rpc "github.com/arduino/arduino-cli/rpc/commands"
dbg "github.com/arduino/arduino-cli/rpc/debug" dbg "github.com/arduino/arduino-cli/rpc/debug"
...@@ -154,6 +155,10 @@ func main() { ...@@ -154,6 +155,10 @@ func main() {
log.Println("calling BoardList()") log.Println("calling BoardList()")
callBoardList(client, instance) callBoardList(client, instance)
// Watch for boards connection and disconnection
log.Println("calling BoardListWatch()")
callBoardListWatch(client, instance)
// Uninstall a platform // Uninstall a platform
log.Println("calling PlatformUninstall(arduino:samd)") log.Println("calling PlatformUninstall(arduino:samd)")
callPlatformUnInstall(client, instance) callPlatformUnInstall(client, instance)
...@@ -592,6 +597,41 @@ func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.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) { func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) {
uninstallRespStream, err := client.PlatformUninstall(context.Background(), uninstallRespStream, err := client.PlatformUninstall(context.Background(),
&rpc.PlatformUninstallReq{ &rpc.PlatformUninstallReq{
......
...@@ -108,8 +108,8 @@ func identifyViaCloudAPI(port *commands.BoardPort) ([]*rpc.BoardListItem, error) ...@@ -108,8 +108,8 @@ func identifyViaCloudAPI(port *commands.BoardPort) ([]*rpc.BoardListItem, error)
return apiByVidPid(id.Get("vid"), id.Get("pid")) return apiByVidPid(id.Get("vid"), id.Get("pid"))
} }
// Identify returns a list of boards checking first the installed platforms or the Cloud API // 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) { func identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*rpc.BoardListItem, error) {
boards := []*rpc.BoardListItem{} boards := []*rpc.BoardListItem{}
// first query installed cores through the Package Manager // first query installed cores through the Package Manager
...@@ -169,7 +169,7 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) { ...@@ -169,7 +169,7 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
retVal := []*rpc.DetectedPort{} retVal := []*rpc.DetectedPort{}
for _, port := range ports { for _, port := range ports {
boards, err := Identify(pm, port) boards, err := identify(pm, port)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -187,3 +187,52 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) { ...@@ -187,3 +187,52 @@ func List(instanceID int32) (r []*rpc.DetectedPort, e error) {
return retVal, nil 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 ...@@ -19,6 +19,7 @@ package daemon
import ( import (
"context" "context"
"io"
"github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands"
...@@ -58,6 +59,39 @@ func (s *ArduinoCoreServerImpl) BoardListAll(ctx context.Context, req *rpc.Board ...@@ -58,6 +59,39 @@ func (s *ArduinoCoreServerImpl) BoardListAll(ctx context.Context, req *rpc.Board
return board.ListAll(ctx, req) 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 // BoardAttach FIXMEDOC
func (s *ArduinoCoreServerImpl) BoardAttach(req *rpc.BoardAttachReq, stream rpc.ArduinoCore_BoardAttachServer) error { func (s *ArduinoCoreServerImpl) BoardAttach(req *rpc.BoardAttachReq, stream rpc.ArduinoCore_BoardAttachServer) error {
......
This diff is collapsed.
...@@ -206,6 +206,22 @@ message BoardListAllResp { ...@@ -206,6 +206,22 @@ message BoardListAllResp {
repeated BoardListItem boards = 1; 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 { message BoardListItem {
// The name for use when identifying the board to a human. // The name for use when identifying the board to a human.
string name = 1; string name = 1;
......
This diff is collapsed.
...@@ -80,6 +80,9 @@ service ArduinoCore { ...@@ -80,6 +80,9 @@ service ArduinoCore {
// List all the boards provided by installed platforms. // List all the boards provided by installed platforms.
rpc BoardListAll(BoardListAllReq) returns (BoardListAllResp); rpc BoardListAll(BoardListAllReq) returns (BoardListAllResp);
// List boards connection and disconnected events.
rpc BoardListWatch(stream BoardListWatchReq) returns (stream BoardListWatchResp);
// Compile an Arduino sketch. // Compile an Arduino sketch.
rpc Compile(CompileReq) returns (stream CompileResp); rpc Compile(CompileReq) returns (stream CompileResp);
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: commands/common.proto // source: commands/common.proto
package commands package commands
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: commands/compile.proto // source: commands/compile.proto
package commands package commands
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: commands/core.proto // source: commands/core.proto
package commands package commands
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: commands/lib.proto // source: commands/lib.proto
package commands package commands
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: commands/upload.proto // source: commands/upload.proto
package commands package commands
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: debug/debug.proto // source: debug/debug.proto
package debug package debug
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: monitor/monitor.proto // source: monitor/monitor.proto
package monitor package monitor
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.25.0 // protoc-gen-go v1.25.0
// protoc v3.13.0 // protoc v3.12.4
// source: settings/settings.proto // source: settings/settings.proto
package settings 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