Unverified Commit 0a6a83c4 authored by Cristian Maglie's avatar Cristian Maglie Committed by GitHub

[skip changelog] Some PluggableMonitor client improvements (#1475)

* Addde QUIT command in monitor-client

* Use rpc.Port in pluggable monitor Open method

* Slightly improved monitor client error messages

* Fixed resource leaking in PluggableMonitor client

* fixed i18n

* Fixed test... ooops
parent 4708cde8
...@@ -24,10 +24,10 @@ import ( ...@@ -24,10 +24,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/arduino/arduino-cli/arduino/discovery"
"github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/executils" "github.com/arduino/arduino-cli/executils"
"github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
...@@ -45,6 +45,7 @@ const ( ...@@ -45,6 +45,7 @@ const (
// PluggableMonitor is a tool that communicates with a board through a communication port. // PluggableMonitor is a tool that communicates with a board through a communication port.
type PluggableMonitor struct { type PluggableMonitor struct {
id string id string
processArgs []string
process *executils.Process process *executils.Process
outgoingCommandsPipe io.Writer outgoingCommandsPipe io.Writer
incomingMessagesChan <-chan *monitorMessage incomingMessagesChan <-chan *monitorMessage
...@@ -96,29 +97,12 @@ func (msg monitorMessage) String() string { ...@@ -96,29 +97,12 @@ func (msg monitorMessage) String() string {
var tr = i18n.Tr var tr = i18n.Tr
// New create and connect to the given pluggable monitor // New create and connect to the given pluggable monitor
func New(id string, args ...string) (*PluggableMonitor, error) { func New(id string, args ...string) *PluggableMonitor {
proc, err := executils.NewProcess(args...) return &PluggableMonitor{
if err != nil { id: id,
return nil, err processArgs: args,
} state: Dead,
stdout, err := proc.StdoutPipe()
if err != nil {
return nil, err
}
stdin, err := proc.StdinPipe()
if err != nil {
return nil, err
} }
messageChan := make(chan *monitorMessage)
disc := &PluggableMonitor{
id: id,
process: proc,
incomingMessagesChan: messageChan,
outgoingCommandsPipe: stdin,
state: Dead,
}
go disc.jsonDecodeLoop(stdout, messageChan)
return disc, nil
} }
// GetID returns the identifier for this monitor // GetID returns the identifier for this monitor
...@@ -195,6 +179,25 @@ func (mon *PluggableMonitor) sendCommand(command string) error { ...@@ -195,6 +179,25 @@ func (mon *PluggableMonitor) sendCommand(command string) error {
func (mon *PluggableMonitor) runProcess() error { func (mon *PluggableMonitor) runProcess() error {
logrus.Infof("starting monitor %s process", mon.id) logrus.Infof("starting monitor %s process", mon.id)
proc, err := executils.NewProcess(mon.processArgs...)
if err != nil {
return err
}
stdout, err := proc.StdoutPipe()
if err != nil {
return err
}
stdin, err := proc.StdinPipe()
if err != nil {
return err
}
mon.outgoingCommandsPipe = stdin
mon.process = proc
messageChan := make(chan *monitorMessage)
mon.incomingMessagesChan = messageChan
go mon.jsonDecodeLoop(stdout, messageChan)
if err := mon.process.Start(); err != nil { if err := mon.process.Start(); err != nil {
return err return err
} }
...@@ -210,6 +213,9 @@ func (mon *PluggableMonitor) killProcess() error { ...@@ -210,6 +213,9 @@ func (mon *PluggableMonitor) killProcess() error {
if err := mon.process.Kill(); err != nil { if err := mon.process.Kill(); err != nil {
return err return err
} }
if err := mon.process.Wait(); err != nil {
return err
}
mon.statusMutex.Lock() mon.statusMutex.Lock()
defer mon.statusMutex.Unlock() defer mon.statusMutex.Unlock()
mon.state = Dead mon.state = Dead
...@@ -284,14 +290,14 @@ func (mon *PluggableMonitor) Configure(param, value string) error { ...@@ -284,14 +290,14 @@ func (mon *PluggableMonitor) Configure(param, value string) error {
} else if msg.EventType != "configure" { } else if msg.EventType != "configure" {
return errors.Errorf(tr("communication out of sync, expected 'configure', received '%s'"), msg.EventType) return errors.Errorf(tr("communication out of sync, expected 'configure', received '%s'"), msg.EventType)
} else if msg.Message != "OK" || msg.Error { } else if msg.Message != "OK" || msg.Error {
return errors.Errorf(tr("command failed: %s"), msg.Message) return errors.Errorf(tr("configure failed: %s"), msg.Message)
} else { } else {
return nil return nil
} }
} }
// Open connects to the given Port. A communication channel is opened // Open connects to the given Port. A communication channel is opened
func (mon *PluggableMonitor) Open(port *discovery.Port) (io.ReadWriter, error) { func (mon *PluggableMonitor) Open(port *rpc.Port) (io.ReadWriter, error) {
mon.statusMutex.Lock() mon.statusMutex.Lock()
defer mon.statusMutex.Unlock() defer mon.statusMutex.Unlock()
...@@ -320,7 +326,7 @@ func (mon *PluggableMonitor) Open(port *discovery.Port) (io.ReadWriter, error) { ...@@ -320,7 +326,7 @@ func (mon *PluggableMonitor) Open(port *discovery.Port) (io.ReadWriter, error) {
} else if msg.EventType != "open" { } else if msg.EventType != "open" {
return nil, errors.Errorf(tr("communication out of sync, expected 'open', received '%s'"), msg.EventType) return nil, errors.Errorf(tr("communication out of sync, expected 'open', received '%s'"), msg.EventType)
} else if msg.Message != "OK" || msg.Error { } else if msg.Message != "OK" || msg.Error {
return nil, errors.Errorf(tr("command failed: %s"), msg.Message) return nil, errors.Errorf(tr("open failed: %s"), msg.Message)
} }
conn, err := tcpListener.Accept() conn, err := tcpListener.Accept()
...@@ -354,3 +360,19 @@ func (mon *PluggableMonitor) Close() error { ...@@ -354,3 +360,19 @@ func (mon *PluggableMonitor) Close() error {
return nil return nil
} }
} }
// Quit terminates the monitor. No more commands can be accepted by the monitor.
func (mon *PluggableMonitor) Quit() error {
if err := mon.sendCommand("QUIT\n"); err != nil {
return err
}
if msg, err := mon.waitMessage(time.Second * 10); err != nil {
return fmt.Errorf(tr("calling %[1]s: %[2]w"), "QUIT", err)
} else if msg.EventType != "quit" {
return errors.Errorf(tr("communication out of sync, expected 'quit', received '%s'"), msg.EventType)
} else if msg.Message != "OK" || msg.Error {
return errors.Errorf(tr("command failed: %s"), msg.Message)
}
mon.killProcess()
return nil
}
...@@ -44,8 +44,7 @@ func TestDummyMonitor(t *testing.T) { ...@@ -44,8 +44,7 @@ func TestDummyMonitor(t *testing.T) {
require.NoError(t, builder.Run()) require.NoError(t, builder.Run())
// Run dummy-monitor and test if everything is working as expected // Run dummy-monitor and test if everything is working as expected
mon, err := New("dummy", "testdata/dummy-monitor") mon := New("dummy", "testdata/dummy-monitor")
require.NoError(t, err)
err = mon.Run() err = mon.Run()
require.NoError(t, err) require.NoError(t, err)
...@@ -60,11 +59,12 @@ func TestDummyMonitor(t *testing.T) { ...@@ -60,11 +59,12 @@ func TestDummyMonitor(t *testing.T) {
err = mon.Configure("speed", "38400") err = mon.Configure("speed", "38400")
require.NoError(t, err) require.NoError(t, err)
rw, err := mon.Open(&discovery.Port{Address: "/dev/ttyACM0", Protocol: "test"}) port := &discovery.Port{Address: "/dev/ttyACM0", Protocol: "test"}
rw, err := mon.Open(port.ToRPC())
require.NoError(t, err) require.NoError(t, err)
// Double open -> error: port already opened // Double open -> error: port already opened
_, err = mon.Open(&discovery.Port{Address: "/dev/ttyACM0", Protocol: "test"}) _, err = mon.Open(port.ToRPC())
require.Error(t, err) require.Error(t, err)
// Write "TEST" // Write "TEST"
...@@ -93,7 +93,7 @@ func TestDummyMonitor(t *testing.T) { ...@@ -93,7 +93,7 @@ func TestDummyMonitor(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
require.Equal(t, int32(1), atomic.LoadInt32(&completed)) require.Equal(t, int32(1), atomic.LoadInt32(&completed))
rw, err = mon.Open(&discovery.Port{Address: "/dev/ttyACM0", Protocol: "test"}) rw, err = mon.Open(port.ToRPC())
require.NoError(t, err) require.NoError(t, err)
n, err = rw.Write([]byte("TEST")) n, err = rw.Write([]byte("TEST"))
require.NoError(t, err) require.NoError(t, err)
......
...@@ -2394,7 +2394,8 @@ msgstr "boardname" ...@@ -2394,7 +2394,8 @@ msgstr "boardname"
#: arduino/discovery/discovery.go:375 #: arduino/discovery/discovery.go:375
#: arduino/discovery/discovery.go:392 #: arduino/discovery/discovery.go:392
#: arduino/discovery/discovery.go:415 #: arduino/discovery/discovery.go:415
#: arduino/monitor/monitor.go:246 #: arduino/monitor/monitor.go:252
#: arduino/monitor/monitor.go:370
msgid "calling %[1]s: %[2]w" msgid "calling %[1]s: %[2]w"
msgstr "calling %[1]s: %[2]w" msgstr "calling %[1]s: %[2]w"
...@@ -2447,28 +2448,27 @@ msgstr "command" ...@@ -2447,28 +2448,27 @@ msgstr "command"
#: arduino/discovery/discovery.go:379 #: arduino/discovery/discovery.go:379
#: arduino/discovery/discovery.go:396 #: arduino/discovery/discovery.go:396
#: arduino/discovery/discovery.go:419 #: arduino/discovery/discovery.go:419
#: arduino/monitor/monitor.go:250 #: arduino/monitor/monitor.go:256
#: arduino/monitor/monitor.go:270 #: arduino/monitor/monitor.go:276
#: arduino/monitor/monitor.go:287 #: arduino/monitor/monitor.go:357
#: arduino/monitor/monitor.go:323 #: arduino/monitor/monitor.go:374
#: arduino/monitor/monitor.go:351
msgid "command failed: %s" msgid "command failed: %s"
msgstr "command failed: %s" msgstr "command failed: %s"
#: arduino/monitor/monitor.go:349 #: arduino/monitor/monitor.go:355
msgid "communication out of sync, expected 'close', received '%s'" msgid "communication out of sync, expected 'close', received '%s'"
msgstr "communication out of sync, expected 'close', received '%s'" msgstr "communication out of sync, expected 'close', received '%s'"
#: arduino/monitor/monitor.go:285 #: arduino/monitor/monitor.go:291
msgid "communication out of sync, expected 'configure', received '%s'" msgid "communication out of sync, expected 'configure', received '%s'"
msgstr "communication out of sync, expected 'configure', received '%s'" msgstr "communication out of sync, expected 'configure', received '%s'"
#: arduino/monitor/monitor.go:268 #: arduino/monitor/monitor.go:274
msgid "communication out of sync, expected 'describe', received '%s'" msgid "communication out of sync, expected 'describe', received '%s'"
msgstr "communication out of sync, expected 'describe', received '%s'" msgstr "communication out of sync, expected 'describe', received '%s'"
#: arduino/discovery/discovery.go:313 #: arduino/discovery/discovery.go:313
#: arduino/monitor/monitor.go:248 #: arduino/monitor/monitor.go:254
msgid "communication out of sync, expected 'hello', received '%s'" msgid "communication out of sync, expected 'hello', received '%s'"
msgstr "communication out of sync, expected 'hello', received '%s'" msgstr "communication out of sync, expected 'hello', received '%s'"
...@@ -2476,11 +2476,12 @@ msgstr "communication out of sync, expected 'hello', received '%s'" ...@@ -2476,11 +2476,12 @@ msgstr "communication out of sync, expected 'hello', received '%s'"
msgid "communication out of sync, expected 'list', received '%s'" msgid "communication out of sync, expected 'list', received '%s'"
msgstr "communication out of sync, expected 'list', received '%s'" msgstr "communication out of sync, expected 'list', received '%s'"
#: arduino/monitor/monitor.go:321 #: arduino/monitor/monitor.go:327
msgid "communication out of sync, expected 'open', received '%s'" msgid "communication out of sync, expected 'open', received '%s'"
msgstr "communication out of sync, expected 'open', received '%s'" msgstr "communication out of sync, expected 'open', received '%s'"
#: arduino/discovery/discovery.go:377 #: arduino/discovery/discovery.go:377
#: arduino/monitor/monitor.go:372
msgid "communication out of sync, expected 'quit', received '%s'" msgid "communication out of sync, expected 'quit', received '%s'"
msgstr "communication out of sync, expected 'quit', received '%s'" msgstr "communication out of sync, expected 'quit', received '%s'"
...@@ -2500,6 +2501,10 @@ msgstr "communication out of sync, expected 'stop', received '%s'" ...@@ -2500,6 +2501,10 @@ msgstr "communication out of sync, expected 'stop', received '%s'"
msgid "computing hash: %s" msgid "computing hash: %s"
msgstr "computing hash: %s" msgstr "computing hash: %s"
#: arduino/monitor/monitor.go:293
msgid "configure failed: %s"
msgstr "configure failed: %s"
#: commands/upload/upload.go:611 #: commands/upload/upload.go:611
msgid "could not find a valid build artifact" msgid "could not find a valid build artifact"
msgstr "could not find a valid build artifact" msgstr "could not find a valid build artifact"
...@@ -2962,6 +2967,10 @@ msgstr "no valid sketch found in %[1]s: missing %[2]s" ...@@ -2962,6 +2967,10 @@ msgstr "no valid sketch found in %[1]s: missing %[2]s"
msgid "no versions available for the current OS" msgid "no versions available for the current OS"
msgstr "no versions available for the current OS" msgstr "no versions available for the current OS"
#: arduino/monitor/monitor.go:329
msgid "open failed: %s"
msgstr "open failed: %s"
#: arduino/resources/checksums.go:72 #: arduino/resources/checksums.go:72
#: arduino/resources/install.go:59 #: arduino/resources/install.go:59
msgid "opening archive file: %s" msgid "opening archive file: %s"
...@@ -3051,7 +3060,7 @@ msgid "port not found: %[1]s %[2]s" ...@@ -3051,7 +3060,7 @@ msgid "port not found: %[1]s %[2]s"
msgstr "port not found: %[1]s %[2]s" msgstr "port not found: %[1]s %[2]s"
#: arduino/discovery/discovery.go:317 #: arduino/discovery/discovery.go:317
#: arduino/monitor/monitor.go:252 #: arduino/monitor/monitor.go:258
msgid "protocol version not supported: requested 1, got %d" msgid "protocol version not supported: requested 1, got %d"
msgstr "protocol version not supported: requested 1, got %d" msgstr "protocol version not supported: requested 1, got %d"
...@@ -3241,7 +3250,7 @@ msgstr "the server responded with status %s" ...@@ -3241,7 +3250,7 @@ msgstr "the server responded with status %s"
msgid "timeout waiting for message from %s" msgid "timeout waiting for message from %s"
msgstr "timeout waiting for message from %s" msgstr "timeout waiting for message from %s"
#: arduino/monitor/monitor.go:177 #: arduino/monitor/monitor.go:161
msgid "timeout waiting for message from monitor %s" msgid "timeout waiting for message from monitor %s"
msgstr "timeout waiting for message from monitor %s" msgstr "timeout waiting for message from monitor %s"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
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