diff --git a/Taskfile.yml b/Taskfile.yml index 605041cd535..24ce844f7c6 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,6 +5,7 @@ tasks: desc: Compile protobuf definitions cmds: - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/commands/*.proto' + - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/monitor/*.proto' build: desc: Build the project diff --git a/appveyor.yml b/appveyor.yml index 966d3076697..db9dbd22ec8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ stack: go 1.12 install: # install the task executor - curl -o task.zip -LO https://github.com/go-task/task/releases/download/v2.6.0/task_windows_amd64.zip - - 7z e task.zip -o%GOPATH%\bin + - 7z x task.zip -o%GOPATH%\bin # golang dependencies needed at test time - go get github.com/golangci/govet - go get golang.org/x/lint/golint @@ -30,7 +30,7 @@ install: # because of this: https://github.com/protocolbuffers/protobuf/issues/3957 - go get github.com/golang/protobuf/protoc-gen-go - curl -o protoc.zip -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.4.0/protoc-3.4.0-win32.zip - - 7z e protoc.zip -o%PROTOC_PATH% + - 7z x protoc.zip -o%PROTOC_PATH% test_script: # Check if the Go code is properly formatted and run the linter diff --git a/arduino/monitors/serial.go b/arduino/monitors/serial.go new file mode 100644 index 00000000000..fcd1021bdd8 --- /dev/null +++ b/arduino/monitors/serial.go @@ -0,0 +1,62 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. + +package monitors + +import ( + "github.com/pkg/errors" + serial "go.bug.st/serial.v1" +) + +const ( + defaultBaudRate = 9600 +) + +// SerialMonitor is a monitor for serial ports +type SerialMonitor struct { + port serial.Port +} + +// OpenSerialMonitor creates a monitor instance for a serial port +func OpenSerialMonitor(portName string, baudRate int) (*SerialMonitor, error) { + // use default baud rate if not provided + if baudRate == 0 { + baudRate = defaultBaudRate + } + + port, err := serial.Open(portName, &serial.Mode{BaudRate: baudRate}) + if err != nil { + return nil, errors.Wrap(err, "error opening serial monitor") + } + + return &SerialMonitor{ + port: port, + }, nil +} + +// Close the connection +func (mon *SerialMonitor) Close() error { + return mon.port.Close() +} + +// Read bytes from the port +func (mon *SerialMonitor) Read(bytes []byte) (int, error) { + return mon.port.Read(bytes) +} + +// Write bytes to the port +func (mon *SerialMonitor) Write(bytes []byte) (int, error) { + return mon.port.Write(bytes) +} diff --git a/arduino/monitors/types.go b/arduino/monitors/types.go new file mode 100644 index 00000000000..1cba438a29b --- /dev/null +++ b/arduino/monitors/types.go @@ -0,0 +1,25 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. + +package monitors + +import ( + "io" +) + +// Monitor is the interface implemented by different device monitors +type Monitor interface { + io.ReadWriteCloser +} diff --git a/cli/daemon/daemon.go b/cli/daemon/daemon.go index afb69c9e7f1..211fc887b72 100644 --- a/cli/daemon/daemon.go +++ b/cli/daemon/daemon.go @@ -27,7 +27,8 @@ import ( "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/commands/daemon" - rpc "github.com/arduino/arduino-cli/rpc/commands" + srv_commands "github.com/arduino/arduino-cli/rpc/commands" + srv_monitor "github.com/arduino/arduino-cli/rpc/monitor" "github.com/spf13/cobra" "google.golang.org/grpc" ) @@ -59,14 +60,20 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { globals.VersionInfo.VersionString, runtime.GOARCH, runtime.GOOS, runtime.Version(), globals.VersionInfo.Commit) headers := http.Header{"User-Agent": []string{userAgentValue}} + // register the commands service coreServer := daemon.ArduinoCoreServerImpl{ DownloaderHeaders: headers, VersionString: globals.VersionInfo.VersionString, Config: globals.Config, } - rpc.RegisterArduinoCoreServer(s, &coreServer) + srv_commands.RegisterArduinoCoreServer(s, &coreServer) + + // register the monitors service + srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{}) + if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } + fmt.Println("Done serving") } diff --git a/commands/daemon/monitor.go b/commands/daemon/monitor.go new file mode 100644 index 00000000000..975d272a2ed --- /dev/null +++ b/commands/daemon/monitor.go @@ -0,0 +1,134 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package daemon + +import ( + "fmt" + "io" + + "github.com/arduino/arduino-cli/arduino/monitors" + rpc "github.com/arduino/arduino-cli/rpc/monitor" +) + +// MonitorService implements the `Monitor` service +type MonitorService struct{} + +// StreamingOpen returns a stream response that can be used to fetch data from the +// monitor target. The first message passed through the `StreamingOpenReq` must +// contain monitor configuration params, not data. +func (s *MonitorService) StreamingOpen(stream rpc.Monitor_StreamingOpenServer) error { + // grab the first message + msg, err := stream.Recv() + if err != nil { + return err + } + + // ensure it's a config message and not data + config := msg.GetMonitorConfig() + if config == nil { + return fmt.Errorf("first message must contain monitor configuration, not data") + } + + // select which type of monitor we need + var mon monitors.Monitor + switch config.GetType() { + case rpc.MonitorConfig_SERIAL: + // grab port speed from additional config data + var baudRate float64 + addCfg := config.GetAdditionalConfig() + for k, v := range addCfg.GetFields() { + if k == "BaudRate" { + baudRate = v.GetNumberValue() + break + } + } + + // get the Monitor instance + var err error + if mon, err = monitors.OpenSerialMonitor(config.GetTarget(), int(baudRate)); err != nil { + return err + } + } + + // we'll use these channels to communicate with the goroutines + // handling the stream and the target respectively + streamClosed := make(chan error) + targetClosed := make(chan error) + + // now we can read the other messages and re-route to the monitor... + go func() { + for { + msg, err := stream.Recv() + if err == io.EOF { + // stream was closed + streamClosed <- nil + break + } + + if err != nil { + // error reading from stream + streamClosed <- err + break + } + + if _, err := mon.Write(msg.GetData()); err != nil { + // error writing to target + targetClosed <- err + break + } + } + }() + + // ...and read from the monitor and forward to the output stream + go func() { + buf := make([]byte, 8) + for { + n, err := mon.Read(buf) + if err != nil { + // error reading from target + targetClosed <- err + break + } + + if n == 0 { + // target was closed + targetClosed <- nil + break + } + + if err = stream.Send(&rpc.StreamingOpenResp{ + Data: buf[:n], + }); err != nil { + // error sending to stream + streamClosed <- err + break + } + } + }() + + // let goroutines route messages from/to the monitor + // until either the client closes the stream or the + // monitor target is closed + for { + select { + case err := <-streamClosed: + mon.Close() + return err + case err := <-targetClosed: + return err + } + } +} diff --git a/commands/daemon/monitor_test.go b/commands/daemon/monitor_test.go new file mode 100644 index 00000000000..b369e82a48b --- /dev/null +++ b/commands/daemon/monitor_test.go @@ -0,0 +1,122 @@ +package daemon_test + +import ( + "context" + "io" + "reflect" + "testing" + + "bou.ke/monkey" + "github.com/arduino/arduino-cli/arduino/monitors" + "github.com/arduino/arduino-cli/commands/daemon" + "github.com/arduino/arduino-cli/rpc/monitor" + st "github.com/golang/protobuf/ptypes/struct" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/metadata" +) + +var ( + recvCounter int + resPortName string + resBaudRate int + resWrittenToSerial []byte + resReadFromSerial []byte +) + +type TestStreamingOpenServer struct{} + +func (s *TestStreamingOpenServer) Send(mon *monitor.StreamingOpenResp) error { + // if we're here, the Monitor read something from the target and + // is sending it back to the stream client + resReadFromSerial = mon.GetData() + return nil +} + +func (s *TestStreamingOpenServer) Recv() (*monitor.StreamingOpenReq, error) { + // if we're here, the monitor is reading the stream client + // we only send 3 messages, one for config, another with data and a final + // one with EOF so the monitor will gracefully exit + recvCounter++ + if recvCounter == 1 { + // send the first message containing the configuration + additionalFields := make(map[string]*st.Value, 1) + additionalFields["BaudRate"] = &st.Value{ + Kind: &st.Value_NumberValue{ + NumberValue: float64(42), + }, + } + return &monitor.StreamingOpenReq{ + Content: &monitor.StreamingOpenReq_MonitorConfig{ + MonitorConfig: &monitor.MonitorConfig{ + Target: "/dev/tty42", + Type: monitor.MonitorConfig_SERIAL, + AdditionalConfig: &st.Struct{ + Fields: additionalFields, + }, + }, + }, + }, nil + } else if recvCounter == 2 { + return &monitor.StreamingOpenReq{ + Content: &monitor.StreamingOpenReq_Data{ + Data: []byte("Hello Serial, this if for you!"), + }, + }, nil + } + + return nil, io.EOF +} + +func (s *TestStreamingOpenServer) SetHeader(metadata.MD) error { return nil } +func (s *TestStreamingOpenServer) SendHeader(metadata.MD) error { return nil } +func (s *TestStreamingOpenServer) SetTrailer(metadata.MD) {} +func (s *TestStreamingOpenServer) Context() context.Context { return context.Background() } +func (s *TestStreamingOpenServer) SendMsg(m interface{}) error { return nil } +func (s *TestStreamingOpenServer) RecvMsg(m interface{}) error { return nil } + +func mockOpenSerialMonitor(portName string, baudRate int) (*monitors.SerialMonitor, error) { + // this function will be called by the Monitor as soon as it receives the + // first message from the stream client + + // save parameters so the Test function can assert on the values passed to the monitor + // by the client + resPortName = portName + resBaudRate = baudRate + + mon := &monitors.SerialMonitor{} + monkey.PatchInstanceMethod(reflect.TypeOf(mon), "Close", func(_ *monitors.SerialMonitor) error { + return nil + }) + monkey.PatchInstanceMethod(reflect.TypeOf(mon), "Read", func(_ *monitors.SerialMonitor, bytes []byte) (int, error) { + copy(bytes, "I am Serial") + return len(bytes), nil + }) + monkey.PatchInstanceMethod(reflect.TypeOf(mon), "Write", func(_ *monitors.SerialMonitor, bytes []byte) (int, error) { + resWrittenToSerial = bytes + return len(bytes), nil + }) + + return mon, nil +} + +func TestFoo(t *testing.T) { + monkey.Patch(monitors.OpenSerialMonitor, mockOpenSerialMonitor) + + svc := daemon.MonitorService{} + stream := &TestStreamingOpenServer{} + + // let the monitor go, this will return when the monitor receives + // the EOF from the stream client + assert.Nil(t, svc.StreamingOpen(stream)) + + // ensure port setup was correct + assert.Equal(t, "/dev/tty42", resPortName) + assert.Equal(t, 42, resBaudRate) + + // ensure the serial received the message + assert.Equal(t, []byte("Hello Serial, this if for you!"), resWrittenToSerial) + + // ensure the monitor read from the serial, output is truncated because the test + // doesn't consume the whole buffer + assert.Equal(t, []byte("I am Ser"), resReadFromSerial) +} diff --git a/go.mod b/go.mod index cbbabed658a..c019a221cf5 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5 // indirect github.com/fsnotify/fsnotify v1.4.7 github.com/go-errors/errors v1.0.1 - github.com/golang/protobuf v1.3.1 + github.com/golang/protobuf v1.3.2 github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 github.com/h2non/filetype v1.0.8 // indirect github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect diff --git a/go.sum b/go.sum index b3bd9275a40..1a95b11c651 100644 --- a/go.sum +++ b/go.sum @@ -36,35 +36,27 @@ github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2 h1:C6sOwknxwWfLBE github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2/go.mod h1:c7sGIpDbBo0JZZ1tKyC1p5smWf8QcUjK4bFtZjHAecg= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5 h1:R8jFW6G/bjoXjWPFrEfw9G5YQDlYhwV4AC+Eonu6wmk= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5/go.mod h1:BEUDl7FG1cc76sM0J0x8dqr6RhiL4uqvk6oFkwuNyuM= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 h1:KFqmdzEPbU7Uck2tn50t+HQXZNVkxe8M9qRb/ZoSHaE= github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/h2non/filetype v1.0.8 h1:le8gpf+FQA0/DlDABbtisA1KiTS0Xi+YSC/E8yY3Y14= github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI= github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc h1:5xUWujf6ES9tEpFHFzI34vcHm8U07lGjxAuJML3qwqM= github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= @@ -75,7 +67,6 @@ github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/miekg/dns v1.0.5 h1:MQBGf2JEJDu0rg9WOpQZzeO+zW8UKwgkvP3R1dUU1Yw= github.com/miekg/dns v1.0.5/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228 h1:Cvfd2dOlXIPTeEkOT/h8PyK4phBngOM4at9/jlgy7d4= @@ -91,13 +82,10 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -175,9 +163,7 @@ google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRn google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go new file mode 100644 index 00000000000..641ef31de7d --- /dev/null +++ b/rpc/monitor/monitor.pb.go @@ -0,0 +1,379 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: monitor/monitor.proto + +package monitor + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + _struct "github.com/golang/protobuf/ptypes/struct" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type MonitorConfig_TargetType int32 + +const ( + MonitorConfig_SERIAL MonitorConfig_TargetType = 0 +) + +var MonitorConfig_TargetType_name = map[int32]string{ + 0: "SERIAL", +} + +var MonitorConfig_TargetType_value = map[string]int32{ + "SERIAL": 0, +} + +func (x MonitorConfig_TargetType) String() string { + return proto.EnumName(MonitorConfig_TargetType_name, int32(x)) +} + +func (MonitorConfig_TargetType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_94d5950496a7550d, []int{1, 0} +} + +// The top-level message sent by the client for the `StreamingOpen` method. +// Multiple `StreamingOpenReq` messages can be sent but the first message +// must contain a `monitor_config` message to initialize the monitor target. +// All subsequent messages must contain bytes to be sent to the target +// and must not contain a `monitor_config` message. +type StreamingOpenReq struct { + // Content must be either a monitor config or data to be sent. + // + // Types that are valid to be assigned to Content: + // *StreamingOpenReq_MonitorConfig + // *StreamingOpenReq_Data + Content isStreamingOpenReq_Content `protobuf_oneof:"content"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamingOpenReq) Reset() { *m = StreamingOpenReq{} } +func (m *StreamingOpenReq) String() string { return proto.CompactTextString(m) } +func (*StreamingOpenReq) ProtoMessage() {} +func (*StreamingOpenReq) Descriptor() ([]byte, []int) { + return fileDescriptor_94d5950496a7550d, []int{0} +} + +func (m *StreamingOpenReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamingOpenReq.Unmarshal(m, b) +} +func (m *StreamingOpenReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamingOpenReq.Marshal(b, m, deterministic) +} +func (m *StreamingOpenReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamingOpenReq.Merge(m, src) +} +func (m *StreamingOpenReq) XXX_Size() int { + return xxx_messageInfo_StreamingOpenReq.Size(m) +} +func (m *StreamingOpenReq) XXX_DiscardUnknown() { + xxx_messageInfo_StreamingOpenReq.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamingOpenReq proto.InternalMessageInfo + +type isStreamingOpenReq_Content interface { + isStreamingOpenReq_Content() +} + +type StreamingOpenReq_MonitorConfig struct { + MonitorConfig *MonitorConfig `protobuf:"bytes,1,opt,name=monitorConfig,proto3,oneof"` +} + +type StreamingOpenReq_Data struct { + Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"` +} + +func (*StreamingOpenReq_MonitorConfig) isStreamingOpenReq_Content() {} + +func (*StreamingOpenReq_Data) isStreamingOpenReq_Content() {} + +func (m *StreamingOpenReq) GetContent() isStreamingOpenReq_Content { + if m != nil { + return m.Content + } + return nil +} + +func (m *StreamingOpenReq) GetMonitorConfig() *MonitorConfig { + if x, ok := m.GetContent().(*StreamingOpenReq_MonitorConfig); ok { + return x.MonitorConfig + } + return nil +} + +func (m *StreamingOpenReq) GetData() []byte { + if x, ok := m.GetContent().(*StreamingOpenReq_Data); ok { + return x.Data + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*StreamingOpenReq) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*StreamingOpenReq_MonitorConfig)(nil), + (*StreamingOpenReq_Data)(nil), + } +} + +// Tells the monitor which target to open and provides additional parameters +// that might be needed to configure the target or the monitor itself. +type MonitorConfig struct { + Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"` + Type MonitorConfig_TargetType `protobuf:"varint,2,opt,name=type,proto3,enum=cc.arduino.cli.monitor.MonitorConfig_TargetType" json:"type,omitempty"` + AdditionalConfig *_struct.Struct `protobuf:"bytes,3,opt,name=additionalConfig,proto3" json:"additionalConfig,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MonitorConfig) Reset() { *m = MonitorConfig{} } +func (m *MonitorConfig) String() string { return proto.CompactTextString(m) } +func (*MonitorConfig) ProtoMessage() {} +func (*MonitorConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_94d5950496a7550d, []int{1} +} + +func (m *MonitorConfig) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MonitorConfig.Unmarshal(m, b) +} +func (m *MonitorConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MonitorConfig.Marshal(b, m, deterministic) +} +func (m *MonitorConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_MonitorConfig.Merge(m, src) +} +func (m *MonitorConfig) XXX_Size() int { + return xxx_messageInfo_MonitorConfig.Size(m) +} +func (m *MonitorConfig) XXX_DiscardUnknown() { + xxx_messageInfo_MonitorConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_MonitorConfig proto.InternalMessageInfo + +func (m *MonitorConfig) GetTarget() string { + if m != nil { + return m.Target + } + return "" +} + +func (m *MonitorConfig) GetType() MonitorConfig_TargetType { + if m != nil { + return m.Type + } + return MonitorConfig_SERIAL +} + +func (m *MonitorConfig) GetAdditionalConfig() *_struct.Struct { + if m != nil { + return m.AdditionalConfig + } + return nil +} + +// +type StreamingOpenResp struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamingOpenResp) Reset() { *m = StreamingOpenResp{} } +func (m *StreamingOpenResp) String() string { return proto.CompactTextString(m) } +func (*StreamingOpenResp) ProtoMessage() {} +func (*StreamingOpenResp) Descriptor() ([]byte, []int) { + return fileDescriptor_94d5950496a7550d, []int{2} +} + +func (m *StreamingOpenResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamingOpenResp.Unmarshal(m, b) +} +func (m *StreamingOpenResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamingOpenResp.Marshal(b, m, deterministic) +} +func (m *StreamingOpenResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamingOpenResp.Merge(m, src) +} +func (m *StreamingOpenResp) XXX_Size() int { + return xxx_messageInfo_StreamingOpenResp.Size(m) +} +func (m *StreamingOpenResp) XXX_DiscardUnknown() { + xxx_messageInfo_StreamingOpenResp.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamingOpenResp proto.InternalMessageInfo + +func (m *StreamingOpenResp) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func init() { + proto.RegisterEnum("cc.arduino.cli.monitor.MonitorConfig_TargetType", MonitorConfig_TargetType_name, MonitorConfig_TargetType_value) + proto.RegisterType((*StreamingOpenReq)(nil), "cc.arduino.cli.monitor.StreamingOpenReq") + proto.RegisterType((*MonitorConfig)(nil), "cc.arduino.cli.monitor.MonitorConfig") + proto.RegisterType((*StreamingOpenResp)(nil), "cc.arduino.cli.monitor.StreamingOpenResp") +} + +func init() { proto.RegisterFile("monitor/monitor.proto", fileDescriptor_94d5950496a7550d) } + +var fileDescriptor_94d5950496a7550d = []byte{ + // 339 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xd1, 0x4e, 0xf2, 0x30, + 0x14, 0xc7, 0xb7, 0xef, 0x23, 0x10, 0x8e, 0x60, 0xb0, 0x51, 0x24, 0xc4, 0x0b, 0xb2, 0xc4, 0x38, + 0x8d, 0x76, 0x04, 0x9f, 0x40, 0xd0, 0x04, 0x13, 0x89, 0x49, 0xe1, 0xca, 0xbb, 0xd2, 0x95, 0x59, + 0x33, 0xda, 0x5a, 0xba, 0x0b, 0x6e, 0x7d, 0x3e, 0x1f, 0xca, 0x58, 0x4a, 0x14, 0xd4, 0x84, 0xab, + 0xa6, 0xd9, 0xf9, 0x9d, 0x73, 0xfe, 0xbf, 0x15, 0x8e, 0xe6, 0x4a, 0x0a, 0xab, 0x4c, 0xe2, 0x4f, + 0xac, 0x8d, 0xb2, 0x0a, 0x35, 0x19, 0xc3, 0xd4, 0xa4, 0x85, 0x90, 0x0a, 0xb3, 0x5c, 0x60, 0xff, + 0xb5, 0x7d, 0x92, 0x29, 0x95, 0xe5, 0x3c, 0x71, 0x55, 0xd3, 0x62, 0x96, 0x2c, 0xac, 0x29, 0x98, + 0x5d, 0x51, 0xd1, 0x5b, 0x08, 0x8d, 0xb1, 0x35, 0x9c, 0xce, 0x85, 0xcc, 0x1e, 0x35, 0x97, 0x84, + 0xbf, 0xa2, 0x11, 0xd4, 0x3d, 0x3d, 0x50, 0x72, 0x26, 0xb2, 0x56, 0xd8, 0x09, 0xe3, 0xbd, 0xde, + 0x29, 0xfe, 0x7d, 0x04, 0x1e, 0x7d, 0x2f, 0x1e, 0x06, 0x64, 0x93, 0x46, 0x87, 0x50, 0x4a, 0xa9, + 0xa5, 0xad, 0x7f, 0x9d, 0x30, 0xae, 0x0d, 0x03, 0xe2, 0x6e, 0xfd, 0x2a, 0x54, 0x98, 0x92, 0x96, + 0x4b, 0x1b, 0xbd, 0x87, 0x50, 0xdf, 0xe8, 0x81, 0x9a, 0x50, 0xb6, 0xd4, 0x64, 0xdc, 0xba, 0xd1, + 0x55, 0xe2, 0x6f, 0xe8, 0x16, 0x4a, 0x76, 0xa9, 0xb9, 0x6b, 0xb5, 0xdf, 0xeb, 0xee, 0xb4, 0x10, + 0x9e, 0x38, 0x76, 0xb2, 0xd4, 0x9c, 0x38, 0x1a, 0x0d, 0xa0, 0x41, 0xd3, 0x54, 0x58, 0xa1, 0x24, + 0xcd, 0x7d, 0xc4, 0xff, 0x2e, 0xe2, 0x31, 0x5e, 0xd9, 0xc2, 0x6b, 0x5b, 0x78, 0xec, 0x6c, 0x91, + 0x1f, 0x40, 0xd4, 0x02, 0xf8, 0x6a, 0x8c, 0x00, 0xca, 0xe3, 0x3b, 0x72, 0x7f, 0xf3, 0xd0, 0x08, + 0xa2, 0x33, 0x38, 0xd8, 0x52, 0xba, 0xd0, 0x08, 0x79, 0x09, 0x9f, 0x79, 0x6a, 0x2b, 0x05, 0xbd, + 0x02, 0x2a, 0x7e, 0x53, 0xf4, 0x02, 0xf5, 0x0d, 0x06, 0xc5, 0x7f, 0x65, 0xdb, 0xfe, 0x5b, 0xed, + 0xf3, 0x1d, 0x2b, 0x17, 0x3a, 0x0a, 0xe2, 0xb0, 0x1b, 0xf6, 0x2f, 0x9f, 0x2e, 0x32, 0x61, 0x9f, + 0x8b, 0x29, 0x66, 0x6a, 0x9e, 0x78, 0x72, 0x7d, 0x5e, 0xb1, 0x5c, 0x24, 0x46, 0xb3, 0xf5, 0xeb, + 0x9a, 0x96, 0x9d, 0x8a, 0xeb, 0x8f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x6c, 0x5e, 0x00, 0x77, + 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MonitorClient is the client API for Monitor service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MonitorClient interface { + StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Monitor_StreamingOpenClient, error) +} + +type monitorClient struct { + cc *grpc.ClientConn +} + +func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { + return &monitorClient{cc} +} + +func (c *monitorClient) StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Monitor_StreamingOpenClient, error) { + stream, err := c.cc.NewStream(ctx, &_Monitor_serviceDesc.Streams[0], "/cc.arduino.cli.monitor.Monitor/StreamingOpen", opts...) + if err != nil { + return nil, err + } + x := &monitorStreamingOpenClient{stream} + return x, nil +} + +type Monitor_StreamingOpenClient interface { + Send(*StreamingOpenReq) error + Recv() (*StreamingOpenResp, error) + grpc.ClientStream +} + +type monitorStreamingOpenClient struct { + grpc.ClientStream +} + +func (x *monitorStreamingOpenClient) Send(m *StreamingOpenReq) error { + return x.ClientStream.SendMsg(m) +} + +func (x *monitorStreamingOpenClient) Recv() (*StreamingOpenResp, error) { + m := new(StreamingOpenResp) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// MonitorServer is the server API for Monitor service. +type MonitorServer interface { + StreamingOpen(Monitor_StreamingOpenServer) error +} + +// UnimplementedMonitorServer can be embedded to have forward compatible implementations. +type UnimplementedMonitorServer struct { +} + +func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { + return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") +} + +func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { + s.RegisterService(&_Monitor_serviceDesc, srv) +} + +func _Monitor_StreamingOpen_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(MonitorServer).StreamingOpen(&monitorStreamingOpenServer{stream}) +} + +type Monitor_StreamingOpenServer interface { + Send(*StreamingOpenResp) error + Recv() (*StreamingOpenReq, error) + grpc.ServerStream +} + +type monitorStreamingOpenServer struct { + grpc.ServerStream +} + +func (x *monitorStreamingOpenServer) Send(m *StreamingOpenResp) error { + return x.ServerStream.SendMsg(m) +} + +func (x *monitorStreamingOpenServer) Recv() (*StreamingOpenReq, error) { + m := new(StreamingOpenReq) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Monitor_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cc.arduino.cli.monitor.Monitor", + HandlerType: (*MonitorServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "StreamingOpen", + Handler: _Monitor_StreamingOpen_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "monitor/monitor.proto", +} diff --git a/rpc/monitor/monitor.proto b/rpc/monitor/monitor.proto new file mode 100644 index 00000000000..89a387e38a3 --- /dev/null +++ b/rpc/monitor/monitor.proto @@ -0,0 +1,61 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +syntax = "proto3"; + +package cc.arduino.cli.monitor; + +option go_package = "github.com/arduino/arduino-cli/rpc/monitor"; + +import "google/protobuf/struct.proto"; + +// Service that abstract a Monitor usage +service Monitor { + rpc StreamingOpen(stream StreamingOpenReq) + returns (stream StreamingOpenResp) {} +} + +// The top-level message sent by the client for the `StreamingOpen` method. +// Multiple `StreamingOpenReq` messages can be sent but the first message +// must contain a `monitor_config` message to initialize the monitor target. +// All subsequent messages must contain bytes to be sent to the target +// and must not contain a `monitor_config` message. +message StreamingOpenReq { + // Content must be either a monitor config or data to be sent. + oneof content { + // Provides information to the monitor that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `monitor_config` + // message. + MonitorConfig monitorConfig = 1; + + // The data to be sent to the target being monitored. + bytes data = 2; + } +} + +// Tells the monitor which target to open and provides additional parameters +// that might be needed to configure the target or the monitor itself. +message MonitorConfig { + enum TargetType { SERIAL = 0; } + + string target = 1; + TargetType type = 2; + google.protobuf.Struct additionalConfig = 3; +} + +// +message StreamingOpenResp { + bytes data = 1; +} \ No newline at end of file