From bf067ea2cf54fded919298c7b0b54d43486ab054 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 21 Aug 2023 13:55:06 +0200 Subject: [PATCH 1/9] Refactored gRPC Monitor API --- commands/daemon/daemon.go | 8 +- commands/daemon/term_example/main.go | 10 +- commands/monitor/monitor.go | 2 +- internal/cli/monitor/monitor.go | 2 +- rpc/cc/arduino/cli/commands/v1/monitor.pb.go | 403 ++++++++++++------- rpc/cc/arduino/cli/commands/v1/monitor.proto | 15 +- 6 files changed, 289 insertions(+), 151 deletions(-) diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 88b0420ff27..e4747e768ae 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -477,7 +477,11 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer return err } - portProxy, _, err := monitor.Monitor(stream.Context(), req) + openReq := req.GetOpenRequest() + if openReq == nil { + return &cmderrors.InvalidInstanceError{} + } + portProxy, _, err := monitor.Monitor(stream.Context(), openReq) if err != nil { return err } @@ -497,7 +501,7 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer syncSend.Send(&rpc.MonitorResponse{Error: err.Error()}) return } - if conf := msg.GetPortConfiguration(); conf != nil { + if conf := msg.GetUpdatedConfiguration(); conf != nil { for _, c := range conf.GetSettings() { if err := portProxy.Config(c.GetSettingId(), c.GetValue()); err != nil { syncSend.Send(&rpc.MonitorResponse{Error: err.Error()}) diff --git a/commands/daemon/term_example/main.go b/commands/daemon/term_example/main.go index faa86198a5f..4d202ec5bd7 100644 --- a/commands/daemon/term_example/main.go +++ b/commands/daemon/term_example/main.go @@ -89,8 +89,10 @@ func connectToPort(cli commands.ArduinoCoreServiceClient, instance *commands.Ins log.Fatal("Error opening Monitor:", err) } if err := monitorClient.Send(&commands.MonitorRequest{ - Instance: instance, - Port: port, + Message: &commands.MonitorRequest_OpenRequest{OpenRequest: &commands.MonitorPortOpenRequest{ + Instance: instance, + Port: port, + }}, }); err != nil { log.Fatal("Error sending Monitor config:", err) } @@ -106,9 +108,9 @@ func connectToPort(cli commands.ArduinoCoreServiceClient, instance *commands.Ins } }() - hello := &commands.MonitorRequest{ + hello := &commands.MonitorRequest{Message: &commands.MonitorRequest_TxData{ TxData: []byte("HELLO!"), - } + }} fmt.Println("Send:", hello) if err := monitorClient.Send(hello); err != nil { log.Fatal("Monitor send HELLO:", err) diff --git a/commands/monitor/monitor.go b/commands/monitor/monitor.go index 4f136181697..357a885be31 100644 --- a/commands/monitor/monitor.go +++ b/commands/monitor/monitor.go @@ -60,7 +60,7 @@ func (p *PortProxy) Close() error { // Monitor opens a communication port. It returns a PortProxy to communicate with the port and a PortDescriptor // that describes the available configuration settings. -func Monitor(ctx context.Context, req *rpc.MonitorRequest) (*PortProxy, *pluggableMonitor.PortDescriptor, error) { +func Monitor(ctx context.Context, req *rpc.MonitorPortOpenRequest) (*PortProxy, *pluggableMonitor.PortDescriptor, error) { pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance()) if err != nil { return nil, nil, err diff --git a/internal/cli/monitor/monitor.go b/internal/cli/monitor/monitor.go index ea6018fa2df..25e8b757483 100644 --- a/internal/cli/monitor/monitor.go +++ b/internal/cli/monitor/monitor.go @@ -203,7 +203,7 @@ func runMonitorCmd( } } } - portProxy, _, err := monitor.Monitor(context.Background(), &rpc.MonitorRequest{ + portProxy, _, err := monitor.Monitor(context.Background(), &rpc.MonitorPortOpenRequest{ Instance: inst, Port: &rpc.Port{Address: portAddress, Protocol: portProtocol}, Fqbn: fqbn, diff --git a/rpc/cc/arduino/cli/commands/v1/monitor.pb.go b/rpc/cc/arduino/cli/commands/v1/monitor.pb.go index 39ce46f4784..ee9b29fd25f 100644 --- a/rpc/cc/arduino/cli/commands/v1/monitor.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/monitor.pb.go @@ -40,18 +40,12 @@ type MonitorRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Arduino Core Service instance from the `Init` response. - Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` - // Port to open, must be filled only on the first request - Port *Port `protobuf:"bytes,2,opt,name=port,proto3" json:"port,omitempty"` - // The board FQBN we are trying to connect to. This is optional, and it's - // needed to disambiguate if more than one platform provides the pluggable - // monitor for a given port protocol. - Fqbn string `protobuf:"bytes,3,opt,name=fqbn,proto3" json:"fqbn,omitempty"` - // Data to send to the port - TxData []byte `protobuf:"bytes,4,opt,name=tx_data,json=txData,proto3" json:"tx_data,omitempty"` - // Port configuration, optional, contains settings of the port to be applied - PortConfiguration *MonitorPortConfiguration `protobuf:"bytes,5,opt,name=port_configuration,json=portConfiguration,proto3" json:"port_configuration,omitempty"` + // Types that are assignable to Message: + // + // *MonitorRequest_OpenRequest + // *MonitorRequest_TxData + // *MonitorRequest_UpdatedConfiguration + Message isMonitorRequest_Message `protobuf_oneof:"message"` } func (x *MonitorRequest) Reset() { @@ -86,35 +80,130 @@ func (*MonitorRequest) Descriptor() ([]byte, []int) { return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{0} } -func (x *MonitorRequest) GetInstance() *Instance { +func (m *MonitorRequest) GetMessage() isMonitorRequest_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *MonitorRequest) GetOpenRequest() *MonitorPortOpenRequest { + if x, ok := x.GetMessage().(*MonitorRequest_OpenRequest); ok { + return x.OpenRequest + } + return nil +} + +func (x *MonitorRequest) GetTxData() []byte { + if x, ok := x.GetMessage().(*MonitorRequest_TxData); ok { + return x.TxData + } + return nil +} + +func (x *MonitorRequest) GetUpdatedConfiguration() *MonitorPortConfiguration { + if x, ok := x.GetMessage().(*MonitorRequest_UpdatedConfiguration); ok { + return x.UpdatedConfiguration + } + return nil +} + +type isMonitorRequest_Message interface { + isMonitorRequest_Message() +} + +type MonitorRequest_OpenRequest struct { + // Open request, it must be the first incoming message + OpenRequest *MonitorPortOpenRequest `protobuf:"bytes,1,opt,name=open_request,json=openRequest,proto3,oneof"` +} + +type MonitorRequest_TxData struct { + // Data to send to the port + TxData []byte `protobuf:"bytes,2,opt,name=tx_data,json=txData,proto3,oneof"` +} + +type MonitorRequest_UpdatedConfiguration struct { + // Port configuration, contains settings of the port to be changed + UpdatedConfiguration *MonitorPortConfiguration `protobuf:"bytes,3,opt,name=updated_configuration,json=updatedConfiguration,proto3,oneof"` +} + +func (*MonitorRequest_OpenRequest) isMonitorRequest_Message() {} + +func (*MonitorRequest_TxData) isMonitorRequest_Message() {} + +func (*MonitorRequest_UpdatedConfiguration) isMonitorRequest_Message() {} + +type MonitorPortOpenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Arduino Core Service instance from the `Init` response. + Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` + // Port to open, must be filled only on the first request + Port *Port `protobuf:"bytes,2,opt,name=port,proto3" json:"port,omitempty"` + // The board FQBN we are trying to connect to. This is optional, and it's + // needed to disambiguate if more than one platform provides the pluggable + // monitor for a given port protocol. + Fqbn string `protobuf:"bytes,3,opt,name=fqbn,proto3" json:"fqbn,omitempty"` + // Port configuration, optional, contains settings of the port to be applied + PortConfiguration *MonitorPortConfiguration `protobuf:"bytes,4,opt,name=port_configuration,json=portConfiguration,proto3" json:"port_configuration,omitempty"` +} + +func (x *MonitorPortOpenRequest) Reset() { + *x = MonitorPortOpenRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MonitorPortOpenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MonitorPortOpenRequest) ProtoMessage() {} + +func (x *MonitorPortOpenRequest) ProtoReflect() protoreflect.Message { + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MonitorPortOpenRequest.ProtoReflect.Descriptor instead. +func (*MonitorPortOpenRequest) Descriptor() ([]byte, []int) { + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{1} +} + +func (x *MonitorPortOpenRequest) GetInstance() *Instance { if x != nil { return x.Instance } return nil } -func (x *MonitorRequest) GetPort() *Port { +func (x *MonitorPortOpenRequest) GetPort() *Port { if x != nil { return x.Port } return nil } -func (x *MonitorRequest) GetFqbn() string { +func (x *MonitorPortOpenRequest) GetFqbn() string { if x != nil { return x.Fqbn } return "" } -func (x *MonitorRequest) GetTxData() []byte { - if x != nil { - return x.TxData - } - return nil -} - -func (x *MonitorRequest) GetPortConfiguration() *MonitorPortConfiguration { +func (x *MonitorPortOpenRequest) GetPortConfiguration() *MonitorPortConfiguration { if x != nil { return x.PortConfiguration } @@ -133,7 +222,7 @@ type MonitorPortConfiguration struct { func (x *MonitorPortConfiguration) Reset() { *x = MonitorPortConfiguration{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[1] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -146,7 +235,7 @@ func (x *MonitorPortConfiguration) String() string { func (*MonitorPortConfiguration) ProtoMessage() {} func (x *MonitorPortConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[1] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -159,7 +248,7 @@ func (x *MonitorPortConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorPortConfiguration.ProtoReflect.Descriptor instead. func (*MonitorPortConfiguration) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{1} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{2} } func (x *MonitorPortConfiguration) GetSettings() []*MonitorPortSetting { @@ -190,7 +279,7 @@ type MonitorResponse struct { func (x *MonitorResponse) Reset() { *x = MonitorResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[2] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -203,7 +292,7 @@ func (x *MonitorResponse) String() string { func (*MonitorResponse) ProtoMessage() {} func (x *MonitorResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[2] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -216,7 +305,7 @@ func (x *MonitorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorResponse.ProtoReflect.Descriptor instead. func (*MonitorResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{2} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{3} } func (x *MonitorResponse) GetError() string { @@ -259,7 +348,7 @@ type MonitorPortSetting struct { func (x *MonitorPortSetting) Reset() { *x = MonitorPortSetting{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[3] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -272,7 +361,7 @@ func (x *MonitorPortSetting) String() string { func (*MonitorPortSetting) ProtoMessage() {} func (x *MonitorPortSetting) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[3] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -285,7 +374,7 @@ func (x *MonitorPortSetting) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorPortSetting.ProtoReflect.Descriptor instead. func (*MonitorPortSetting) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{3} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{4} } func (x *MonitorPortSetting) GetSettingId() string { @@ -320,7 +409,7 @@ type EnumerateMonitorPortSettingsRequest struct { func (x *EnumerateMonitorPortSettingsRequest) Reset() { *x = EnumerateMonitorPortSettingsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[4] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -333,7 +422,7 @@ func (x *EnumerateMonitorPortSettingsRequest) String() string { func (*EnumerateMonitorPortSettingsRequest) ProtoMessage() {} func (x *EnumerateMonitorPortSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[4] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -346,7 +435,7 @@ func (x *EnumerateMonitorPortSettingsRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use EnumerateMonitorPortSettingsRequest.ProtoReflect.Descriptor instead. func (*EnumerateMonitorPortSettingsRequest) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{4} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{5} } func (x *EnumerateMonitorPortSettingsRequest) GetInstance() *Instance { @@ -383,7 +472,7 @@ type EnumerateMonitorPortSettingsResponse struct { func (x *EnumerateMonitorPortSettingsResponse) Reset() { *x = EnumerateMonitorPortSettingsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[5] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -396,7 +485,7 @@ func (x *EnumerateMonitorPortSettingsResponse) String() string { func (*EnumerateMonitorPortSettingsResponse) ProtoMessage() {} func (x *EnumerateMonitorPortSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[5] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -409,7 +498,7 @@ func (x *EnumerateMonitorPortSettingsResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use EnumerateMonitorPortSettingsResponse.ProtoReflect.Descriptor instead. func (*EnumerateMonitorPortSettingsResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{5} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{6} } func (x *EnumerateMonitorPortSettingsResponse) GetSettings() []*MonitorPortSettingDescriptor { @@ -439,7 +528,7 @@ type MonitorPortSettingDescriptor struct { func (x *MonitorPortSettingDescriptor) Reset() { *x = MonitorPortSettingDescriptor{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[6] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -452,7 +541,7 @@ func (x *MonitorPortSettingDescriptor) String() string { func (*MonitorPortSettingDescriptor) ProtoMessage() {} func (x *MonitorPortSettingDescriptor) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[6] + mi := &file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -465,7 +554,7 @@ func (x *MonitorPortSettingDescriptor) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorPortSettingDescriptor.ProtoReflect.Descriptor instead. func (*MonitorPortSettingDescriptor) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{6} + return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP(), []int{7} } func (x *MonitorPortSettingDescriptor) GetSettingId() string { @@ -515,81 +604,95 @@ var file_cc_arduino_cli_commands_v1_monitor_proto_rawDesc = []byte{ 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x25, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, - 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x63, - 0x0a, 0x12, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x63, 0x2e, - 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, - 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x11, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, - 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x4a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, - 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x0f, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x59, - 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfc, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x0c, 0x6f, 0x70, 0x65, + 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x32, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x19, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x74, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x6b, 0x0a, + 0x15, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, + 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x89, 0x02, 0x0a, 0x16, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, + 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, + 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, + 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x63, 0x0a, 0x12, + 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, - 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, - 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa0, - 0x01, 0x0a, 0x23, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, + 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, + 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, + 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x59, 0x0a, 0x10, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, + 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa0, 0x01, 0x0a, + 0x23, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, + 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, + 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, + 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, + 0x7c, 0x0a, 0x24, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, - 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6f, 0x72, 0x74, - 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, - 0x6e, 0x22, 0x7c, 0x0a, 0x24, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, - 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x08, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x63, - 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, - 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, - 0x9e, 0x01, 0x0a, 0x1c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x75, - 0x6d, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, - 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, - 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, - 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x63, 0x2e, 0x61, + 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, + 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x9e, 0x01, + 0x0a, 0x1c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x75, 0x6d, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, + 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x48, + 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, + 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, + 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -604,31 +707,34 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_rawDescGZIP() []byte { return file_cc_arduino_cli_commands_v1_monitor_proto_rawDescData } -var file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_cc_arduino_cli_commands_v1_monitor_proto_goTypes = []interface{}{ (*MonitorRequest)(nil), // 0: cc.arduino.cli.commands.v1.MonitorRequest - (*MonitorPortConfiguration)(nil), // 1: cc.arduino.cli.commands.v1.MonitorPortConfiguration - (*MonitorResponse)(nil), // 2: cc.arduino.cli.commands.v1.MonitorResponse - (*MonitorPortSetting)(nil), // 3: cc.arduino.cli.commands.v1.MonitorPortSetting - (*EnumerateMonitorPortSettingsRequest)(nil), // 4: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsRequest - (*EnumerateMonitorPortSettingsResponse)(nil), // 5: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsResponse - (*MonitorPortSettingDescriptor)(nil), // 6: cc.arduino.cli.commands.v1.MonitorPortSettingDescriptor - (*Instance)(nil), // 7: cc.arduino.cli.commands.v1.Instance - (*Port)(nil), // 8: cc.arduino.cli.commands.v1.Port + (*MonitorPortOpenRequest)(nil), // 1: cc.arduino.cli.commands.v1.MonitorPortOpenRequest + (*MonitorPortConfiguration)(nil), // 2: cc.arduino.cli.commands.v1.MonitorPortConfiguration + (*MonitorResponse)(nil), // 3: cc.arduino.cli.commands.v1.MonitorResponse + (*MonitorPortSetting)(nil), // 4: cc.arduino.cli.commands.v1.MonitorPortSetting + (*EnumerateMonitorPortSettingsRequest)(nil), // 5: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsRequest + (*EnumerateMonitorPortSettingsResponse)(nil), // 6: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsResponse + (*MonitorPortSettingDescriptor)(nil), // 7: cc.arduino.cli.commands.v1.MonitorPortSettingDescriptor + (*Instance)(nil), // 8: cc.arduino.cli.commands.v1.Instance + (*Port)(nil), // 9: cc.arduino.cli.commands.v1.Port } var file_cc_arduino_cli_commands_v1_monitor_proto_depIdxs = []int32{ - 7, // 0: cc.arduino.cli.commands.v1.MonitorRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 8, // 1: cc.arduino.cli.commands.v1.MonitorRequest.port:type_name -> cc.arduino.cli.commands.v1.Port - 1, // 2: cc.arduino.cli.commands.v1.MonitorRequest.port_configuration:type_name -> cc.arduino.cli.commands.v1.MonitorPortConfiguration - 3, // 3: cc.arduino.cli.commands.v1.MonitorPortConfiguration.settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSetting - 3, // 4: cc.arduino.cli.commands.v1.MonitorResponse.applied_settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSetting - 7, // 5: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 6, // 6: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsResponse.settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSettingDescriptor - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 1, // 0: cc.arduino.cli.commands.v1.MonitorRequest.open_request:type_name -> cc.arduino.cli.commands.v1.MonitorPortOpenRequest + 2, // 1: cc.arduino.cli.commands.v1.MonitorRequest.updated_configuration:type_name -> cc.arduino.cli.commands.v1.MonitorPortConfiguration + 8, // 2: cc.arduino.cli.commands.v1.MonitorPortOpenRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 9, // 3: cc.arduino.cli.commands.v1.MonitorPortOpenRequest.port:type_name -> cc.arduino.cli.commands.v1.Port + 2, // 4: cc.arduino.cli.commands.v1.MonitorPortOpenRequest.port_configuration:type_name -> cc.arduino.cli.commands.v1.MonitorPortConfiguration + 4, // 5: cc.arduino.cli.commands.v1.MonitorPortConfiguration.settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSetting + 4, // 6: cc.arduino.cli.commands.v1.MonitorResponse.applied_settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSetting + 8, // 7: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 7, // 8: cc.arduino.cli.commands.v1.EnumerateMonitorPortSettingsResponse.settings:type_name -> cc.arduino.cli.commands.v1.MonitorPortSettingDescriptor + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_cc_arduino_cli_commands_v1_monitor_proto_init() } @@ -652,7 +758,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MonitorPortConfiguration); i { + switch v := v.(*MonitorPortOpenRequest); i { case 0: return &v.state case 1: @@ -664,7 +770,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MonitorResponse); i { + switch v := v.(*MonitorPortConfiguration); i { case 0: return &v.state case 1: @@ -676,7 +782,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MonitorPortSetting); i { + switch v := v.(*MonitorResponse); i { case 0: return &v.state case 1: @@ -688,7 +794,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EnumerateMonitorPortSettingsRequest); i { + switch v := v.(*MonitorPortSetting); i { case 0: return &v.state case 1: @@ -700,7 +806,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EnumerateMonitorPortSettingsResponse); i { + switch v := v.(*EnumerateMonitorPortSettingsRequest); i { case 0: return &v.state case 1: @@ -712,6 +818,18 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EnumerateMonitorPortSettingsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MonitorPortSettingDescriptor); i { case 0: return &v.state @@ -724,13 +842,18 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { } } } + file_cc_arduino_cli_commands_v1_monitor_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*MonitorRequest_OpenRequest)(nil), + (*MonitorRequest_TxData)(nil), + (*MonitorRequest_UpdatedConfiguration)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cc_arduino_cli_commands_v1_monitor_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 0, }, diff --git a/rpc/cc/arduino/cli/commands/v1/monitor.proto b/rpc/cc/arduino/cli/commands/v1/monitor.proto index 68d52fa02ae..be178f92be4 100644 --- a/rpc/cc/arduino/cli/commands/v1/monitor.proto +++ b/rpc/cc/arduino/cli/commands/v1/monitor.proto @@ -23,6 +23,17 @@ import "cc/arduino/cli/commands/v1/common.proto"; import "cc/arduino/cli/commands/v1/port.proto"; message MonitorRequest { + oneof message { + // Open request, it must be the first incoming message + MonitorPortOpenRequest open_request = 1; + // Data to send to the port + bytes tx_data = 2; + // Port configuration, contains settings of the port to be changed + MonitorPortConfiguration updated_configuration = 3; + } +} + +message MonitorPortOpenRequest { // Arduino Core Service instance from the `Init` response. Instance instance = 1; // Port to open, must be filled only on the first request @@ -31,10 +42,8 @@ message MonitorRequest { // needed to disambiguate if more than one platform provides the pluggable // monitor for a given port protocol. string fqbn = 3; - // Data to send to the port - bytes tx_data = 4; // Port configuration, optional, contains settings of the port to be applied - MonitorPortConfiguration port_configuration = 5; + MonitorPortConfiguration port_configuration = 4; } message MonitorPortConfiguration { From 9c59c34ab8d3e846151f7ec12301f9af41a773ec Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 21 Aug 2023 13:55:45 +0200 Subject: [PATCH 2/9] Added Close request to gRPC Monitor API --- commands/daemon/daemon.go | 5 + rpc/cc/arduino/cli/commands/v1/monitor.pb.go | 168 +++++++++++-------- rpc/cc/arduino/cli/commands/v1/monitor.proto | 4 + 3 files changed, 103 insertions(+), 74 deletions(-) diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index e4747e768ae..297bb008e34 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -508,6 +508,11 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer } } } + if close := msg.GetClose(); close { + if err := portProxy.Close(); err != nil { + logrus.WithError(err).Debug("Error closing monitor port") + } + } tx := msg.GetTxData() for len(tx) > 0 { n, err := portProxy.Write(tx) diff --git a/rpc/cc/arduino/cli/commands/v1/monitor.pb.go b/rpc/cc/arduino/cli/commands/v1/monitor.pb.go index ee9b29fd25f..e0341c1a20b 100644 --- a/rpc/cc/arduino/cli/commands/v1/monitor.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/monitor.pb.go @@ -45,6 +45,7 @@ type MonitorRequest struct { // *MonitorRequest_OpenRequest // *MonitorRequest_TxData // *MonitorRequest_UpdatedConfiguration + // *MonitorRequest_Close Message isMonitorRequest_Message `protobuf_oneof:"message"` } @@ -108,6 +109,13 @@ func (x *MonitorRequest) GetUpdatedConfiguration() *MonitorPortConfiguration { return nil } +func (x *MonitorRequest) GetClose() bool { + if x, ok := x.GetMessage().(*MonitorRequest_Close); ok { + return x.Close + } + return false +} + type isMonitorRequest_Message interface { isMonitorRequest_Message() } @@ -127,12 +135,21 @@ type MonitorRequest_UpdatedConfiguration struct { UpdatedConfiguration *MonitorPortConfiguration `protobuf:"bytes,3,opt,name=updated_configuration,json=updatedConfiguration,proto3,oneof"` } +type MonitorRequest_Close struct { + // Close message, set to true to gracefully close a port (this ensure + // that the gRPC streaming call is closed by the daemon AFTER the port + // has been successfully closed) + Close bool `protobuf:"varint,4,opt,name=close,proto3,oneof"` +} + func (*MonitorRequest_OpenRequest) isMonitorRequest_Message() {} func (*MonitorRequest_TxData) isMonitorRequest_Message() {} func (*MonitorRequest_UpdatedConfiguration) isMonitorRequest_Message() {} +func (*MonitorRequest_Close) isMonitorRequest_Message() {} + type MonitorPortOpenRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -604,7 +621,7 @@ var file_cc_arduino_cli_commands_v1_monitor_proto_rawDesc = []byte{ 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x25, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfc, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x02, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, @@ -619,80 +636,82 @@ var file_cc_arduino_cli_commands_v1_monitor_proto_rawDesc = []byte{ 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x89, 0x02, 0x0a, 0x16, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, - 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, - 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, - 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x63, 0x0a, 0x12, - 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x6c, + 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x89, 0x02, + 0x0a, 0x16, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, + 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, - 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, - 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, - 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x6f, - 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x59, 0x0a, 0x10, - 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, - 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa0, 0x01, 0x0a, - 0x23, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, - 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, - 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, - 0x7c, 0x0a, 0x24, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, - 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x63, 0x2e, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, - 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x9e, 0x01, - 0x0a, 0x1c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x75, 0x6d, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, - 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x48, - 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, - 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, - 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, - 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, - 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x66, 0x71, 0x62, 0x6e, 0x12, 0x63, 0x0a, 0x12, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x34, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, + 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x72, + 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x78, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x59, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, + 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0f, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x23, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x7c, 0x0a, 0x24, 0x45, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, + 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x1c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, + 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -846,6 +865,7 @@ func file_cc_arduino_cli_commands_v1_monitor_proto_init() { (*MonitorRequest_OpenRequest)(nil), (*MonitorRequest_TxData)(nil), (*MonitorRequest_UpdatedConfiguration)(nil), + (*MonitorRequest_Close)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/rpc/cc/arduino/cli/commands/v1/monitor.proto b/rpc/cc/arduino/cli/commands/v1/monitor.proto index be178f92be4..5c122789d9c 100644 --- a/rpc/cc/arduino/cli/commands/v1/monitor.proto +++ b/rpc/cc/arduino/cli/commands/v1/monitor.proto @@ -30,6 +30,10 @@ message MonitorRequest { bytes tx_data = 2; // Port configuration, contains settings of the port to be changed MonitorPortConfiguration updated_configuration = 3; + // Close message, set to true to gracefully close a port (this ensure + // that the gRPC streaming call is closed by the daemon AFTER the port + // has been successfully closed) + bool close = 4; } } From 86cb04faa1392bb0aa17691e5a0d28dde61de892 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Aug 2023 19:19:00 +0200 Subject: [PATCH 3/9] Updated docs --- docs/UPGRADING.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index fd54320c1a5..24923d924e2 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -8,6 +8,65 @@ Here you can find a list of migration guides to handle breaking changes between We're dropping the `builtin.tools` support. It was the equivalent of Arduino IDE 1.x bundled tools directory. +### The gRPC `cc.arduino.cli.commands.v1.MonitorRequest` message has been changed. + +Previously the `MonitorRequest` was a single message used to open the monitor, to stream data, and to change the port +configuration: + +```proto +message MonitorRequest { + // Arduino Core Service instance from the `Init` response. + Instance instance = 1; + // Port to open, must be filled only on the first request + Port port = 2; + // The board FQBN we are trying to connect to. This is optional, and it's + // needed to disambiguate if more than one platform provides the pluggable + // monitor for a given port protocol. + string fqbn = 3; + // Data to send to the port + bytes tx_data = 4; + // Port configuration, optional, contains settings of the port to be applied + MonitorPortConfiguration port_configuration = 5; +} +``` + +Now the meaning of the fields has been clarified with the `oneof` clause, making it more explicit: + +```proto +message MonitorRequest { + oneof message { + // Open request, it must be the first incoming message + MonitorPortOpenRequest open_request = 1; + // Data to send to the port + bytes tx_data = 2; + // Port configuration, contains settings of the port to be changed + MonitorPortConfiguration updated_configuration = 3; + // Close message, set to true to gracefully close a port (this ensure + // that the gRPC streaming call is closed by the daemon AFTER the port + // has been successfully closed) + bool close = 4; + } +} + +message MonitorPortOpenRequest { + // Arduino Core Service instance from the `Init` response. + Instance instance = 1; + // Port to open, must be filled only on the first request + Port port = 2; + // The board FQBN we are trying to connect to. This is optional, and it's + // needed to disambiguate if more than one platform provides the pluggable + // monitor for a given port protocol. + string fqbn = 3; + // Port configuration, optional, contains settings of the port to be applied + MonitorPortConfiguration port_configuration = 4; +} +``` + +Now the message field `MonitorPortOpenRequest.open_request` must be sent in the first message after opening the +streaming gRPC call. + +The identification number of the fields has been changed, this change is not binary compatible with old clients. + ### Some golang modules from `github.com/arduino/arduino-cli/*` have been made private. The following golang modules are no longer available as public API: From 5a39d1cc265090c91a179b76163101368e540453 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 25 Oct 2023 11:26:34 +0200 Subject: [PATCH 4/9] Made CreateEnvForDaeamon available in all integration tests --- internal/integrationtest/arduino-cli.go | 15 ++++++++ .../daemon/daemon_concurrency_test.go | 3 +- .../integrationtest/daemon/daemon_test.go | 37 ++++++------------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/internal/integrationtest/arduino-cli.go b/internal/integrationtest/arduino-cli.go index af77725d820..796fb8f0c98 100644 --- a/internal/integrationtest/arduino-cli.go +++ b/internal/integrationtest/arduino-cli.go @@ -119,6 +119,21 @@ func NewArduinoCliWithinEnvironment(env *Environment, config *ArduinoCLIConfig) return cli } +// CreateEnvForDaemon performs the minimum required operations to start the arduino-cli daemon. +// It returns a testsuite.Environment and an ArduinoCLI client to perform the integration tests. +// The Environment must be disposed by calling the CleanUp method via defer. +func CreateEnvForDaemon(t *testing.T) (*Environment, *ArduinoCLI) { + env := NewEnvironment(t) + + cli := NewArduinoCliWithinEnvironment(env, &ArduinoCLIConfig{ + ArduinoCLIPath: FindRepositoryRootPath(t).Join("arduino-cli"), + UseSharedStagingFolder: true, + }) + + _ = cli.StartDaemon(false) + return env, cli +} + // CleanUp closes the Arduino CLI client. func (cli *ArduinoCLI) CleanUp() { if cli.proc != nil { diff --git a/internal/integrationtest/daemon/daemon_concurrency_test.go b/internal/integrationtest/daemon/daemon_concurrency_test.go index 02e9f2501b6..733fe54504a 100644 --- a/internal/integrationtest/daemon/daemon_concurrency_test.go +++ b/internal/integrationtest/daemon/daemon_concurrency_test.go @@ -23,6 +23,7 @@ import ( "testing" "time" + "github.com/arduino/arduino-cli/internal/integrationtest" "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" @@ -31,7 +32,7 @@ import ( func TestArduinoCliDaemonCompileWithLotOfOutput(t *testing.T) { // See: https://github.com/arduino/arduino-cli/issues/2169 - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() _, _, err := cli.Run("core", "install", "arduino:avr") diff --git a/internal/integrationtest/daemon/daemon_test.go b/internal/integrationtest/daemon/daemon_test.go index f7e59a02896..3bae601a01d 100644 --- a/internal/integrationtest/daemon/daemon_test.go +++ b/internal/integrationtest/daemon/daemon_test.go @@ -37,7 +37,7 @@ import ( func TestArduinoCliDaemon(t *testing.T) { // See: https://github.com/arduino/arduino-cli/pull/1804 - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -96,7 +96,7 @@ func TestArduinoCliDaemon(t *testing.T) { func TestDaemonAutoUpdateIndexOnFirstInit(t *testing.T) { // https://github.com/arduino/arduino-cli/issues/1529 - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -110,26 +110,11 @@ func TestDaemonAutoUpdateIndexOnFirstInit(t *testing.T) { require.FileExists(t, cli.DataDir().Join("package_index.json").String()) } -// createEnvForDaemon performs the minimum required operations to start the arduino-cli daemon. -// It returns a testsuite.Environment and an ArduinoCLI client to perform the integration tests. -// The Environment must be disposed by calling the CleanUp method via defer. -func createEnvForDaemon(t *testing.T) (*integrationtest.Environment, *integrationtest.ArduinoCLI) { - env := integrationtest.NewEnvironment(t) - - cli := integrationtest.NewArduinoCliWithinEnvironment(env, &integrationtest.ArduinoCLIConfig{ - ArduinoCLIPath: integrationtest.FindRepositoryRootPath(t).Join("arduino-cli"), - UseSharedStagingFolder: true, - }) - - _ = cli.StartDaemon(false) - return env, cli -} - func TestDaemonCompileOptions(t *testing.T) { // See: https://github.com/arduino/arduino-cli/issues/1614 // See: https://github.com/arduino/arduino-cli/pull/1820 - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -203,7 +188,7 @@ func TestDaemonCompileOptions(t *testing.T) { func TestDaemonCompileAfterFailedLibInstall(t *testing.T) { // See: https://github.com/arduino/arduino-cli/issues/1812 - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -233,7 +218,7 @@ func TestDaemonCompileAfterFailedLibInstall(t *testing.T) { } func TestDaemonCoreUpdateIndex(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -269,7 +254,7 @@ func TestDaemonCoreUpdateIndex(t *testing.T) { } func TestDaemonBundleLibInstall(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -409,7 +394,7 @@ func TestDaemonLibrariesRescanOnInstall(t *testing.T) { with the gprc instance The last attempt is expected to not raise an error */ - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -465,7 +450,7 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) { t.Run("upgraded successfully with additional urls", func(t *testing.T) { t.Run("and install.json is present", func(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -481,7 +466,7 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) { require.False(t, platform.GetRelease().GetMissingMetadata()) // install.json is present }) t.Run("and install.json is missing", func(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -504,7 +489,7 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) { t.Run("upgrade failed", func(t *testing.T) { t.Run("without additional URLs", func(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() @@ -524,7 +509,7 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) { require.False(t, platform.GetRelease().GetMissingMetadata()) // install.json is present }) t.Run("missing both additional URLs and install.json", func(t *testing.T) { - env, cli := createEnvForDaemon(t) + env, cli := integrationtest.CreateEnvForDaemon(t) defer env.CleanUp() grpcInst := cli.Create() From 62f3f1b8ee3e93f644b0f95acd00ae0c3db735d2 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 25 Oct 2023 14:46:47 +0200 Subject: [PATCH 5/9] Added integration test --- internal/integrationtest/arduino-cli.go | 19 +++ .../monitor/monitor_grpc_test.go | 116 ++++++++++++++++++ internal/mock_serial_monitor/main.go | 15 +++ 3 files changed, 150 insertions(+) create mode 100644 internal/integrationtest/monitor/monitor_grpc_test.go diff --git a/internal/integrationtest/arduino-cli.go b/internal/integrationtest/arduino-cli.go index 796fb8f0c98..f3266a7e153 100644 --- a/internal/integrationtest/arduino-cli.go +++ b/internal/integrationtest/arduino-cli.go @@ -611,3 +611,22 @@ func (inst *ArduinoCLIInstance) PlatformSearch(ctx context.Context, args string, resp, err := inst.cli.daemonClient.PlatformSearch(ctx, req) return resp, err } + +// Monitor calls the "Monitor" gRPC method and sends the OpenRequest message. +func (inst *ArduinoCLIInstance) Monitor(ctx context.Context, port *commands.Port) (commands.ArduinoCoreService_MonitorClient, error) { + req := &commands.MonitorRequest{} + logCallf(">>> Monitor(%+v)\n", req) + monitorClient, err := inst.cli.daemonClient.Monitor(ctx) + if err != nil { + return nil, err + } + err = monitorClient.Send(&commands.MonitorRequest{ + Message: &commands.MonitorRequest_OpenRequest{ + OpenRequest: &commands.MonitorPortOpenRequest{ + Instance: inst.instance, + Port: port, + }, + }, + }) + return monitorClient, err +} diff --git a/internal/integrationtest/monitor/monitor_grpc_test.go b/internal/integrationtest/monitor/monitor_grpc_test.go new file mode 100644 index 00000000000..fe144e26195 --- /dev/null +++ b/internal/integrationtest/monitor/monitor_grpc_test.go @@ -0,0 +1,116 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 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 monitor_test + +import ( + "context" + "fmt" + "io" + "regexp" + "testing" + "time" + + "github.com/arduino/arduino-cli/internal/integrationtest" + "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/arduino/go-paths-helper" + "github.com/stretchr/testify/require" +) + +func TestMonitorGRPCClose(t *testing.T) { + // See: https://github.com/arduino/arduino-cli/issues/2271 + + env, cli := integrationtest.CreateEnvForDaemon(t) + defer env.CleanUp() + + _, _, err := cli.Run("core", "install", "arduino:avr@1.8.6") + require.NoError(t, err) + + cli.InstallMockedSerialDiscovery(t) + cli.InstallMockedSerialMonitor(t) + + grpcInst := cli.Create() + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Run a one-shot board list + boardListResp, err := grpcInst.BoardList(time.Second) + require.NoError(t, err) + ports := boardListResp.GetPorts() + require.NotEmpty(t, ports) + fmt.Printf("Got boardlist response with %d ports\n", len(ports)) + + // Open mocked serial-monitor and close it client-side + tmpFileMatcher := regexp.MustCompile("Tmpfile: (.*)\n") + { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + mon, err := grpcInst.Monitor(ctx, ports[0].Port) + var tmpFile *paths.Path + for { + monResp, err := mon.Recv() + if err != nil { + fmt.Println("MON>", err) + break + } + fmt.Printf("MON> %v\n", monResp) + if rx := monResp.GetRxData(); rx != nil { + if matches := tmpFileMatcher.FindAllStringSubmatch(string(rx), -1); len(matches) > 0 { + fmt.Println("Found tmpFile", matches[0][1]) + tmpFile = paths.New(matches[0][1]) + } + } + } + require.NotNil(t, tmpFile) + // The port is close client-side, it may be still open server-side + require.True(t, tmpFile.Exist()) + cancel() + require.NoError(t, err) + } + + // Now close the monitor using MonitorRequest_Close + for tries := 0; tries < 5; tries++ { // Try the test 5 times to avoid flukes + // Keep a timeout to allow the test to exit in any case + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + mon, err := grpcInst.Monitor(ctx, ports[0].Port) + var tmpFile *paths.Path + for { + monResp, err := mon.Recv() + if err == io.EOF { + fmt.Println("MON>", err) + break + } + + require.NoError(t, err) + fmt.Printf("MON> %v\n", monResp) + if rx := monResp.GetRxData(); rx != nil { + if matches := tmpFileMatcher.FindAllStringSubmatch(string(rx), -1); len(matches) > 0 { + fmt.Println("Found tmpFile", matches[0][1]) + tmpFile = paths.New(matches[0][1]) + go func() { + time.Sleep(time.Second) + fmt.Println(" Date: Wed, 25 Oct 2023 16:08:49 +0200 Subject: [PATCH 6/9] lint: avoid redefinition of the built-in function close --- commands/daemon/daemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 297bb008e34..66efc357d22 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -508,7 +508,7 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer } } } - if close := msg.GetClose(); close { + if closeMsg := msg.GetClose(); closeMsg { if err := portProxy.Close(); err != nil { logrus.WithError(err).Debug("Error closing monitor port") } From 3fd0bad53ba80e0c70f47054e706519a3e68439a Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 25 Oct 2023 16:12:21 +0200 Subject: [PATCH 7/9] lint: comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error --- internal/integrationtest/monitor/monitor_grpc_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/integrationtest/monitor/monitor_grpc_test.go b/internal/integrationtest/monitor/monitor_grpc_test.go index fe144e26195..a7a681ce28a 100644 --- a/internal/integrationtest/monitor/monitor_grpc_test.go +++ b/internal/integrationtest/monitor/monitor_grpc_test.go @@ -17,6 +17,7 @@ package monitor_test import ( "context" + "errors" "fmt" "io" "regexp" @@ -88,7 +89,7 @@ func TestMonitorGRPCClose(t *testing.T) { var tmpFile *paths.Path for { monResp, err := mon.Recv() - if err == io.EOF { + if errors.Is(err, io.EOF) { fmt.Println("MON>", err) break } From f2a023ad0c7a5125572c35d0218ecddb662af6ba Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 26 Oct 2023 16:24:59 +0200 Subject: [PATCH 8/9] Allow up to 5 seconds for a pluggable monitor to gracefully close --- internal/arduino/monitor/monitor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/arduino/monitor/monitor.go b/internal/arduino/monitor/monitor.go index c2dc81669fa..cf993e5029d 100644 --- a/internal/arduino/monitor/monitor.go +++ b/internal/arduino/monitor/monitor.go @@ -292,7 +292,7 @@ func (mon *PluggableMonitor) Close() error { if err := mon.sendCommand("CLOSE\n"); err != nil { return err } - _, err := mon.waitMessage(time.Millisecond*250, "close") + _, err := mon.waitMessage(time.Millisecond*5000, "close") return err } From 094e3a5eab05aff06ab84bb417a25c552a475c06 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 26 Oct 2023 17:05:43 +0200 Subject: [PATCH 9/9] Made the gRPC daemon actually wait for port close completion --- commands/daemon/daemon.go | 17 +++++++++++++++-- .../monitor/monitor_grpc_test.go | 2 +- internal/mock_serial_monitor/main.go | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 66efc357d22..f9f6215973c 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "io" + "sync/atomic" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/board" @@ -490,6 +491,10 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer _ = syncSend.Send(&rpc.MonitorResponse{Success: true}) cancelCtx, cancel := context.WithCancel(stream.Context()) + gracefulCloseInitiated := &atomic.Bool{} + gracefuleCloseCtx, gracefulCloseCancel := context.WithCancel(context.Background()) + + // gRPC stream receiver (gRPC data -> monitor, config, close) go func() { defer cancel() for { @@ -509,9 +514,11 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer } } if closeMsg := msg.GetClose(); closeMsg { + gracefulCloseInitiated.Store(true) if err := portProxy.Close(); err != nil { logrus.WithError(err).Debug("Error closing monitor port") } + gracefulCloseCancel() } tx := msg.GetTxData() for len(tx) > 0 { @@ -528,8 +535,9 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer } }() + // gRPC stream sender (monitor -> gRPC) go func() { - defer cancel() + defer cancel() // unlock the receiver buff := make([]byte, 4096) for { n, err := portProxy.Read(buff) @@ -547,6 +555,11 @@ func (s *ArduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer }() <-cancelCtx.Done() - portProxy.Close() + if gracefulCloseInitiated.Load() { + // Port closing has been initiated in the receiver + <-gracefuleCloseCtx.Done() + } else { + portProxy.Close() + } return nil } diff --git a/internal/integrationtest/monitor/monitor_grpc_test.go b/internal/integrationtest/monitor/monitor_grpc_test.go index a7a681ce28a..c96dc36d304 100644 --- a/internal/integrationtest/monitor/monitor_grpc_test.go +++ b/internal/integrationtest/monitor/monitor_grpc_test.go @@ -82,7 +82,7 @@ func TestMonitorGRPCClose(t *testing.T) { } // Now close the monitor using MonitorRequest_Close - for tries := 0; tries < 5; tries++ { // Try the test 5 times to avoid flukes + { // Keep a timeout to allow the test to exit in any case ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) mon, err := grpcInst.Monitor(ctx, ports[0].Port) diff --git a/internal/mock_serial_monitor/main.go b/internal/mock_serial_monitor/main.go index c7779ca0e00..f13745e1458 100644 --- a/internal/mock_serial_monitor/main.go +++ b/internal/mock_serial_monitor/main.go @@ -197,7 +197,7 @@ func (d *SerialMonitor) Close() error { d.mockedSerialPort.Close() d.openedPort = false if d.muxFile != nil { - time.Sleep(500 * time.Millisecond) // Emulate a small delay closing the port to check gRPC synchronization + time.Sleep(2000 * time.Millisecond) // Emulate a small delay closing the port to check gRPC synchronization d.muxFile.Remove() d.muxFile = nil }