From ac4e32697ca32bbb4fc3589a88e2b585993f4a57 Mon Sep 17 00:00:00 2001 From: Charles Hathaway Date: Sun, 1 Oct 2023 22:02:30 -0700 Subject: [PATCH] add: sensors --- cmd/watcher/watcher.go | 31 + gen/genconnect/signaler_service.connect.go | 62 ++ gen/signaler_service.pb.go | 720 +++++++++++++++------ internal/sensors/sensors.go | 144 +++++ internal/watcher/config/config.go | 6 +- pkg/signaler/signaler.go | 65 ++ proto/signaler_service.proto | 31 + rpi_camera.yaml | 32 + sample.yaml | 6 + ui/lib/gen/signaler_service.pb.dart | 212 ++++++ ui/lib/gen/signaler_service.pbenum.dart | 25 + ui/lib/gen/signaler_service.pbgrpc.dart | 40 ++ ui/lib/gen/signaler_service.pbjson.dart | 64 ++ 13 files changed, 1247 insertions(+), 191 deletions(-) create mode 100644 internal/sensors/sensors.go create mode 100644 rpi_camera.yaml diff --git a/cmd/watcher/watcher.go b/cmd/watcher/watcher.go index 77ed909..456d88e 100644 --- a/cmd/watcher/watcher.go +++ b/cmd/watcher/watcher.go @@ -14,6 +14,7 @@ import ( "connectrpc.com/connect" pb "github.com/chathaway-codes/home-sensors/v2/gen" servicepb "github.com/chathaway-codes/home-sensors/v2/gen/genconnect" + "github.com/chathaway-codes/home-sensors/v2/internal/sensors" "github.com/chathaway-codes/home-sensors/v2/internal/video" "github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3/pkg/media" @@ -37,6 +38,11 @@ func main() { if err != nil { log.Fatal().Err(err).Msg("failed to get default video") } + + sensors, err := sensors.Default.Get() + if err != nil { + log.Fatal().Err(err).Msg("failed to get default sensor") + } client := servicepb.NewSignalerServiceClient(http.DefaultClient, "http://192.168.0.65:8080/") authToken, err := client.CreateAuthToken(ctx, connect.NewRequest(&pb.CreateAuthTokenRequest{ Home: "home1234", @@ -54,6 +60,14 @@ func main() { go vid.Run() defer vid.Done() + go sensors.Run() + defer sensors.Done() + + sensorCh, sensorDone := sensors.Join() + defer sensorDone() + + go handleSensor(ctx, client, token, sensorCh) + // Create a new RTCPeerConnection log.Info().Msg("waiting for connections") @@ -67,6 +81,23 @@ func main() { } } +func handleSensor(ctx context.Context, client servicepb.SignalerServiceClient, token string, ch <-chan *pb.Sample) { + for { + var sample *pb.Sample + select { + case sample = <-ch: + // proceed + case <-ctx.Done(): + return + } + if _, err := client.CreateSample(ctx, withAuth(token, &pb.CreateSampleRequest{ + Sample: sample, + })); err != nil { + log.Error().Err(err).Msg("failed to create sample") + } + } +} + func handleSession(ctx context.Context, client servicepb.SignalerServiceClient, token string, session *connect.Response[pb.Session], vid *video.Video) { var err error log.Debug().Msg("new session") diff --git a/gen/genconnect/signaler_service.connect.go b/gen/genconnect/signaler_service.connect.go index 66f7485..89e9c76 100644 --- a/gen/genconnect/signaler_service.connect.go +++ b/gen/genconnect/signaler_service.connect.go @@ -51,6 +51,12 @@ const ( // SignalerServicePopIceMessageProcedure is the fully-qualified name of the SignalerService's // PopIceMessage RPC. SignalerServicePopIceMessageProcedure = "/signaler.SignalerService/PopIceMessage" + // SignalerServiceCreateSampleProcedure is the fully-qualified name of the SignalerService's + // CreateSample RPC. + SignalerServiceCreateSampleProcedure = "/signaler.SignalerService/CreateSample" + // SignalerServiceListSamplesProcedure is the fully-qualified name of the SignalerService's + // ListSamples RPC. + SignalerServiceListSamplesProcedure = "/signaler.SignalerService/ListSamples" ) // SignalerServiceClient is a client for the signaler.SignalerService service. @@ -72,6 +78,12 @@ type SignalerServiceClient interface { // // If there are no messages, this blocks until one becomes available. PopIceMessage(context.Context, *connect.Request[gen.PopIceMessageRequest]) (*connect.Response[gen.IceMessage], error) + // CreateSample creates a sample for the given camera. + // If called without an auth token indicating a camera, an error + // is returned. + // TODO: this should be moved to a seperate service + CreateSample(context.Context, *connect.Request[gen.CreateSampleRequest]) (*connect.Response[gen.Sample], error) + ListSamples(context.Context, *connect.Request[gen.ListSamplesRequest]) (*connect.Response[gen.ListSamplesResponse], error) } // NewSignalerServiceClient constructs a client for the signaler.SignalerService service. By @@ -114,6 +126,16 @@ func NewSignalerServiceClient(httpClient connect.HTTPClient, baseURL string, opt baseURL+SignalerServicePopIceMessageProcedure, opts..., ), + createSample: connect.NewClient[gen.CreateSampleRequest, gen.Sample]( + httpClient, + baseURL+SignalerServiceCreateSampleProcedure, + opts..., + ), + listSamples: connect.NewClient[gen.ListSamplesRequest, gen.ListSamplesResponse]( + httpClient, + baseURL+SignalerServiceListSamplesProcedure, + opts..., + ), } } @@ -125,6 +147,8 @@ type signalerServiceClient struct { popSession *connect.Client[gen.PopSessionRequest, gen.Session] createIceMessage *connect.Client[gen.CreateIceMessageRequest, gen.IceMessage] popIceMessage *connect.Client[gen.PopIceMessageRequest, gen.IceMessage] + createSample *connect.Client[gen.CreateSampleRequest, gen.Sample] + listSamples *connect.Client[gen.ListSamplesRequest, gen.ListSamplesResponse] } // CreateAuthToken calls signaler.SignalerService.CreateAuthToken. @@ -157,6 +181,16 @@ func (c *signalerServiceClient) PopIceMessage(ctx context.Context, req *connect. return c.popIceMessage.CallUnary(ctx, req) } +// CreateSample calls signaler.SignalerService.CreateSample. +func (c *signalerServiceClient) CreateSample(ctx context.Context, req *connect.Request[gen.CreateSampleRequest]) (*connect.Response[gen.Sample], error) { + return c.createSample.CallUnary(ctx, req) +} + +// ListSamples calls signaler.SignalerService.ListSamples. +func (c *signalerServiceClient) ListSamples(ctx context.Context, req *connect.Request[gen.ListSamplesRequest]) (*connect.Response[gen.ListSamplesResponse], error) { + return c.listSamples.CallUnary(ctx, req) +} + // SignalerServiceHandler is an implementation of the signaler.SignalerService service. type SignalerServiceHandler interface { CreateAuthToken(context.Context, *connect.Request[gen.CreateAuthTokenRequest]) (*connect.Response[gen.AuthToken], error) @@ -176,6 +210,12 @@ type SignalerServiceHandler interface { // // If there are no messages, this blocks until one becomes available. PopIceMessage(context.Context, *connect.Request[gen.PopIceMessageRequest]) (*connect.Response[gen.IceMessage], error) + // CreateSample creates a sample for the given camera. + // If called without an auth token indicating a camera, an error + // is returned. + // TODO: this should be moved to a seperate service + CreateSample(context.Context, *connect.Request[gen.CreateSampleRequest]) (*connect.Response[gen.Sample], error) + ListSamples(context.Context, *connect.Request[gen.ListSamplesRequest]) (*connect.Response[gen.ListSamplesResponse], error) } // NewSignalerServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -214,6 +254,16 @@ func NewSignalerServiceHandler(svc SignalerServiceHandler, opts ...connect.Handl svc.PopIceMessage, opts..., ) + signalerServiceCreateSampleHandler := connect.NewUnaryHandler( + SignalerServiceCreateSampleProcedure, + svc.CreateSample, + opts..., + ) + signalerServiceListSamplesHandler := connect.NewUnaryHandler( + SignalerServiceListSamplesProcedure, + svc.ListSamples, + opts..., + ) return "/signaler.SignalerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case SignalerServiceCreateAuthTokenProcedure: @@ -228,6 +278,10 @@ func NewSignalerServiceHandler(svc SignalerServiceHandler, opts ...connect.Handl signalerServiceCreateIceMessageHandler.ServeHTTP(w, r) case SignalerServicePopIceMessageProcedure: signalerServicePopIceMessageHandler.ServeHTTP(w, r) + case SignalerServiceCreateSampleProcedure: + signalerServiceCreateSampleHandler.ServeHTTP(w, r) + case SignalerServiceListSamplesProcedure: + signalerServiceListSamplesHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -260,3 +314,11 @@ func (UnimplementedSignalerServiceHandler) CreateIceMessage(context.Context, *co func (UnimplementedSignalerServiceHandler) PopIceMessage(context.Context, *connect.Request[gen.PopIceMessageRequest]) (*connect.Response[gen.IceMessage], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("signaler.SignalerService.PopIceMessage is not implemented")) } + +func (UnimplementedSignalerServiceHandler) CreateSample(context.Context, *connect.Request[gen.CreateSampleRequest]) (*connect.Response[gen.Sample], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("signaler.SignalerService.CreateSample is not implemented")) +} + +func (UnimplementedSignalerServiceHandler) ListSamples(context.Context, *connect.Request[gen.ListSamplesRequest]) (*connect.Response[gen.ListSamplesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("signaler.SignalerService.ListSamples is not implemented")) +} diff --git a/gen/signaler_service.pb.go b/gen/signaler_service.pb.go index d2f4453..1110e11 100644 --- a/gen/signaler_service.pb.go +++ b/gen/signaler_service.pb.go @@ -20,6 +20,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type Sample_Type int32 + +const ( + Sample_UNSPECIFIED Sample_Type = 0 + Sample_TEMPERATURE_C Sample_Type = 1 + Sample_HUMIDITY Sample_Type = 2 + Sample_PRESSURE Sample_Type = 3 +) + +// Enum value maps for Sample_Type. +var ( + Sample_Type_name = map[int32]string{ + 0: "UNSPECIFIED", + 1: "TEMPERATURE_C", + 2: "HUMIDITY", + 3: "PRESSURE", + } + Sample_Type_value = map[string]int32{ + "UNSPECIFIED": 0, + "TEMPERATURE_C": 1, + "HUMIDITY": 2, + "PRESSURE": 3, + } +) + +func (x Sample_Type) Enum() *Sample_Type { + p := new(Sample_Type) + *p = x + return p +} + +func (x Sample_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Sample_Type) Descriptor() protoreflect.EnumDescriptor { + return file_signaler_service_proto_enumTypes[0].Descriptor() +} + +func (Sample_Type) Type() protoreflect.EnumType { + return &file_signaler_service_proto_enumTypes[0] +} + +func (x Sample_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Sample_Type.Descriptor instead. +func (Sample_Type) EnumDescriptor() ([]byte, []int) { + return file_signaler_service_proto_rawDescGZIP(), []int{20, 0} +} + type CreateAuthTokenRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -545,6 +597,138 @@ func (x *PopIceMessageRequest) GetSessionIdentifier() *Session_Identifier { return nil } +type CreateSampleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sample *Sample `protobuf:"bytes,1,opt,name=sample,proto3" json:"sample,omitempty"` +} + +func (x *CreateSampleRequest) Reset() { + *x = CreateSampleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_signaler_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSampleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSampleRequest) ProtoMessage() {} + +func (x *CreateSampleRequest) ProtoReflect() protoreflect.Message { + mi := &file_signaler_service_proto_msgTypes[10] + 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 CreateSampleRequest.ProtoReflect.Descriptor instead. +func (*CreateSampleRequest) Descriptor() ([]byte, []int) { + return file_signaler_service_proto_rawDescGZIP(), []int{10} +} + +func (x *CreateSampleRequest) GetSample() *Sample { + if x != nil { + return x.Sample + } + return nil +} + +type ListSamplesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListSamplesRequest) Reset() { + *x = ListSamplesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_signaler_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListSamplesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSamplesRequest) ProtoMessage() {} + +func (x *ListSamplesRequest) ProtoReflect() protoreflect.Message { + mi := &file_signaler_service_proto_msgTypes[11] + 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 ListSamplesRequest.ProtoReflect.Descriptor instead. +func (*ListSamplesRequest) Descriptor() ([]byte, []int) { + return file_signaler_service_proto_rawDescGZIP(), []int{11} +} + +type ListSamplesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Samples []*Sample `protobuf:"bytes,1,rep,name=samples,proto3" json:"samples,omitempty"` +} + +func (x *ListSamplesResponse) Reset() { + *x = ListSamplesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_signaler_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListSamplesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSamplesResponse) ProtoMessage() {} + +func (x *ListSamplesResponse) ProtoReflect() protoreflect.Message { + mi := &file_signaler_service_proto_msgTypes[12] + 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 ListSamplesResponse.ProtoReflect.Descriptor instead. +func (*ListSamplesResponse) Descriptor() ([]byte, []int) { + return file_signaler_service_proto_rawDescGZIP(), []int{12} +} + +func (x *ListSamplesResponse) GetSamples() []*Sample { + if x != nil { + return x.Samples + } + return nil +} + type Camera struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -556,7 +740,7 @@ type Camera struct { func (x *Camera) Reset() { *x = Camera{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[10] + mi := &file_signaler_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -569,7 +753,7 @@ func (x *Camera) String() string { func (*Camera) ProtoMessage() {} func (x *Camera) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[10] + mi := &file_signaler_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -582,7 +766,7 @@ func (x *Camera) ProtoReflect() protoreflect.Message { // Deprecated: Use Camera.ProtoReflect.Descriptor instead. func (*Camera) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{10} + return file_signaler_service_proto_rawDescGZIP(), []int{13} } func (x *Camera) GetIdentifier() *Camera_Identifier { @@ -608,7 +792,7 @@ type IceMessage struct { func (x *IceMessage) Reset() { *x = IceMessage{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[11] + mi := &file_signaler_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -621,7 +805,7 @@ func (x *IceMessage) String() string { func (*IceMessage) ProtoMessage() {} func (x *IceMessage) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[11] + mi := &file_signaler_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -634,7 +818,7 @@ func (x *IceMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IceMessage.ProtoReflect.Descriptor instead. func (*IceMessage) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{11} + return file_signaler_service_proto_rawDescGZIP(), []int{14} } func (m *IceMessage) GetType() isIceMessage_Type { @@ -696,7 +880,7 @@ type NoMoreCandidates struct { func (x *NoMoreCandidates) Reset() { *x = NoMoreCandidates{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[12] + mi := &file_signaler_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -709,7 +893,7 @@ func (x *NoMoreCandidates) String() string { func (*NoMoreCandidates) ProtoMessage() {} func (x *NoMoreCandidates) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[12] + mi := &file_signaler_service_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -722,7 +906,7 @@ func (x *NoMoreCandidates) ProtoReflect() protoreflect.Message { // Deprecated: Use NoMoreCandidates.ProtoReflect.Descriptor instead. func (*NoMoreCandidates) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{12} + return file_signaler_service_proto_rawDescGZIP(), []int{15} } type IceCandidate struct { @@ -740,7 +924,7 @@ type IceCandidate struct { func (x *IceCandidate) Reset() { *x = IceCandidate{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[13] + mi := &file_signaler_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -753,7 +937,7 @@ func (x *IceCandidate) String() string { func (*IceCandidate) ProtoMessage() {} func (x *IceCandidate) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[13] + mi := &file_signaler_service_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -766,7 +950,7 @@ func (x *IceCandidate) ProtoReflect() protoreflect.Message { // Deprecated: Use IceCandidate.ProtoReflect.Descriptor instead. func (*IceCandidate) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{13} + return file_signaler_service_proto_rawDescGZIP(), []int{16} } func (x *IceCandidate) GetCandidate() string { @@ -810,7 +994,7 @@ type IceSessionDescription struct { func (x *IceSessionDescription) Reset() { *x = IceSessionDescription{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[14] + mi := &file_signaler_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -823,7 +1007,7 @@ func (x *IceSessionDescription) String() string { func (*IceSessionDescription) ProtoMessage() {} func (x *IceSessionDescription) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[14] + mi := &file_signaler_service_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -836,7 +1020,7 @@ func (x *IceSessionDescription) ProtoReflect() protoreflect.Message { // Deprecated: Use IceSessionDescription.ProtoReflect.Descriptor instead. func (*IceSessionDescription) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{14} + return file_signaler_service_proto_rawDescGZIP(), []int{17} } func (x *IceSessionDescription) GetSdpType() int64 { @@ -865,7 +1049,7 @@ type Session struct { func (x *Session) Reset() { *x = Session{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[15] + mi := &file_signaler_service_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -878,7 +1062,7 @@ func (x *Session) String() string { func (*Session) ProtoMessage() {} func (x *Session) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[15] + mi := &file_signaler_service_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -891,7 +1075,7 @@ func (x *Session) ProtoReflect() protoreflect.Message { // Deprecated: Use Session.ProtoReflect.Descriptor instead. func (*Session) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{15} + return file_signaler_service_proto_rawDescGZIP(), []int{18} } func (x *Session) GetId() *Session_Identifier { @@ -919,7 +1103,7 @@ type AuthToken struct { func (x *AuthToken) Reset() { *x = AuthToken{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[16] + mi := &file_signaler_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -932,7 +1116,7 @@ func (x *AuthToken) String() string { func (*AuthToken) ProtoMessage() {} func (x *AuthToken) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[16] + mi := &file_signaler_service_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -945,7 +1129,7 @@ func (x *AuthToken) ProtoReflect() protoreflect.Message { // Deprecated: Use AuthToken.ProtoReflect.Descriptor instead. func (*AuthToken) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{16} + return file_signaler_service_proto_rawDescGZIP(), []int{19} } func (x *AuthToken) GetToken() string { @@ -955,6 +1139,69 @@ func (x *AuthToken) GetToken() string { return "" } +type Sample struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type Sample_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signaler.Sample_Type" json:"type,omitempty"` + Reading float64 `protobuf:"fixed64,2,opt,name=reading,proto3" json:"reading,omitempty"` + CameraId *Camera_Identifier `protobuf:"bytes,3,opt,name=camera_id,json=cameraId,proto3" json:"camera_id,omitempty"` +} + +func (x *Sample) Reset() { + *x = Sample{} + if protoimpl.UnsafeEnabled { + mi := &file_signaler_service_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Sample) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Sample) ProtoMessage() {} + +func (x *Sample) ProtoReflect() protoreflect.Message { + mi := &file_signaler_service_proto_msgTypes[20] + 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 Sample.ProtoReflect.Descriptor instead. +func (*Sample) Descriptor() ([]byte, []int) { + return file_signaler_service_proto_rawDescGZIP(), []int{20} +} + +func (x *Sample) GetType() Sample_Type { + if x != nil { + return x.Type + } + return Sample_UNSPECIFIED +} + +func (x *Sample) GetReading() float64 { + if x != nil { + return x.Reading + } + return 0 +} + +func (x *Sample) GetCameraId() *Camera_Identifier { + if x != nil { + return x.CameraId + } + return nil +} + type CreateAuthTokenRequest_Camera struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -968,7 +1215,7 @@ type CreateAuthTokenRequest_Camera struct { func (x *CreateAuthTokenRequest_Camera) Reset() { *x = CreateAuthTokenRequest_Camera{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[17] + mi := &file_signaler_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -981,7 +1228,7 @@ func (x *CreateAuthTokenRequest_Camera) String() string { func (*CreateAuthTokenRequest_Camera) ProtoMessage() {} func (x *CreateAuthTokenRequest_Camera) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[17] + mi := &file_signaler_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1013,7 +1260,7 @@ type CreateAuthTokenRequest_Client struct { func (x *CreateAuthTokenRequest_Client) Reset() { *x = CreateAuthTokenRequest_Client{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[18] + mi := &file_signaler_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1026,7 +1273,7 @@ func (x *CreateAuthTokenRequest_Client) String() string { func (*CreateAuthTokenRequest_Client) ProtoMessage() {} func (x *CreateAuthTokenRequest_Client) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[18] + mi := &file_signaler_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1053,7 +1300,7 @@ type Camera_Identifier struct { func (x *Camera_Identifier) Reset() { *x = Camera_Identifier{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[19] + mi := &file_signaler_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1066,7 +1313,7 @@ func (x *Camera_Identifier) String() string { func (*Camera_Identifier) ProtoMessage() {} func (x *Camera_Identifier) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[19] + mi := &file_signaler_service_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1079,7 +1326,7 @@ func (x *Camera_Identifier) ProtoReflect() protoreflect.Message { // Deprecated: Use Camera_Identifier.ProtoReflect.Descriptor instead. func (*Camera_Identifier) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{10, 0} + return file_signaler_service_proto_rawDescGZIP(), []int{13, 0} } func (x *Camera_Identifier) GetId() string { @@ -1100,7 +1347,7 @@ type Session_Identifier struct { func (x *Session_Identifier) Reset() { *x = Session_Identifier{} if protoimpl.UnsafeEnabled { - mi := &file_signaler_service_proto_msgTypes[20] + mi := &file_signaler_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1113,7 +1360,7 @@ func (x *Session_Identifier) String() string { func (*Session_Identifier) ProtoMessage() {} func (x *Session_Identifier) ProtoReflect() protoreflect.Message { - mi := &file_signaler_service_proto_msgTypes[20] + mi := &file_signaler_service_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1126,7 +1373,7 @@ func (x *Session_Identifier) ProtoReflect() protoreflect.Message { // Deprecated: Use Session_Identifier.ProtoReflect.Descriptor instead. func (*Session_Identifier) Descriptor() ([]byte, []int) { - return file_signaler_service_proto_rawDescGZIP(), []int{15, 0} + return file_signaler_service_proto_rawDescGZIP(), []int{18, 0} } func (x *Session_Identifier) GetId() string { @@ -1200,95 +1447,127 @@ var file_signaler_service_proto_rawDesc = []byte{ 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x63, 0x0a, 0x06, 0x43, - 0x61, 0x6d, 0x65, 0x72, 0x61, 0x12, 0x3b, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x1a, 0x1c, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x22, 0xd5, 0x01, 0x0a, 0x0a, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x36, 0x0a, 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, - 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x09, 0x63, 0x61, - 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x12, 0x6e, 0x6f, 0x5f, 0x6d, 0x6f, 0x72, 0x65, 0x5f, - 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4e, 0x6f, 0x4d, 0x6f, - 0x72, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x48, 0x00, 0x52, 0x10, - 0x6e, 0x6f, 0x4d, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, - 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x4e, 0x6f, 0x4d, 0x6f, - 0x72, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xdc, 0x01, 0x0a, - 0x0c, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x73, - 0x64, 0x70, 0x5f, 0x6d, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, - 0x73, 0x64, 0x70, 0x4d, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x73, 0x64, 0x70, - 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x48, 0x01, 0x52, 0x0c, 0x73, 0x64, 0x70, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x02, 0x52, 0x10, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, - 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x64, 0x70, 0x5f, 0x6d, - 0x69, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x73, 0x64, 0x70, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, - 0x6d, 0x65, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x15, 0x49, - 0x63, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x64, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x64, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, - 0x70, 0x22, 0x8a, 0x01, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x02, 0x69, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x63, - 0x61, 0x6d, 0x65, 0x72, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x2e, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x06, 0x63, 0x61, 0x6d, 0x65, 0x72, 0x61, - 0x1a, 0x1c, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x21, - 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x32, 0xbd, 0x03, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, - 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x4a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x73, 0x12, 0x1c, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, - 0x6d, 0x65, 0x72, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6d, 0x65, - 0x72, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x3c, 0x0a, 0x0a, 0x50, 0x6f, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x70, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, - 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, - 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x50, 0x6f, - 0x70, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x70, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x42, 0x94, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x65, 0x72, 0x42, 0x14, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x68, 0x61, 0x77, 0x61, 0x79, - 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2d, 0x73, 0x65, 0x6e, 0x73, - 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x65, 0x6e, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, - 0xaa, 0x02, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0xca, 0x02, 0x08, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0xe2, 0x02, 0x14, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, - 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x08, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x3f, 0x0a, 0x13, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0x14, 0x0a, 0x12, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x41, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x22, 0x63, 0x0a, 0x06, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x12, + 0x3b, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, + 0x61, 0x6d, 0x65, 0x72, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x1c, 0x0a, 0x0a, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xd5, 0x01, 0x0a, 0x0a, 0x49, + 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x63, 0x61, 0x6e, + 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, + 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4a, + 0x0a, 0x12, 0x6e, 0x6f, 0x5f, 0x6d, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4e, 0x6f, 0x4d, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x6e, 0x64, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x48, 0x00, 0x52, 0x10, 0x6e, 0x6f, 0x4d, 0x6f, 0x72, 0x65, + 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x4e, 0x6f, 0x4d, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x6e, 0x64, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xdc, 0x01, 0x0a, 0x0c, 0x49, 0x63, 0x65, 0x43, 0x61, + 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x64, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x73, 0x64, 0x70, 0x5f, 0x6d, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73, 0x64, 0x70, 0x4d, 0x69, 0x64, + 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x73, 0x64, 0x70, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x0c, 0x73, + 0x64, 0x70, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x88, 0x01, 0x01, 0x12, 0x30, + 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x10, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x64, 0x70, 0x5f, 0x6d, 0x69, 0x64, 0x42, 0x11, 0x0a, 0x0f, + 0x5f, 0x73, 0x64, 0x70, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, + 0x14, 0x0a, 0x12, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x72, 0x61, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x15, 0x49, 0x63, 0x65, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x64, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x07, 0x73, 0x64, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0x8a, 0x01, 0x0a, 0x07, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x52, 0x02, 0x69, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x63, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, + 0x2e, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x52, 0x06, 0x63, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x1a, 0x1c, 0x0a, 0x0a, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x21, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xcf, 0x01, 0x0a, 0x06, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x07, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x63, + 0x61, 0x6d, 0x65, 0x72, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x08, 0x63, 0x61, 0x6d, + 0x65, 0x72, 0x61, 0x49, 0x64, 0x22, 0x46, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, + 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, + 0x0a, 0x0d, 0x54, 0x45, 0x4d, 0x50, 0x45, 0x52, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x10, + 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x48, 0x55, 0x4d, 0x49, 0x44, 0x49, 0x54, 0x59, 0x10, 0x02, 0x12, + 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x53, 0x53, 0x55, 0x52, 0x45, 0x10, 0x03, 0x32, 0xca, 0x04, + 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, + 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x0b, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x73, 0x12, 0x1c, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, 0x50, + 0x6f, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, + 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x10, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, + 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x49, 0x63, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x50, 0x6f, 0x70, 0x49, 0x63, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x70, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x65, 0x72, 0x2e, 0x49, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, + 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1d, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x4a, + 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x94, 0x01, 0x0a, 0x0c, 0x63, + 0x6f, 0x6d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x42, 0x14, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x68, 0x61, 0x74, 0x68, 0x61, 0x77, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2f, + 0x68, 0x6f, 0x6d, 0x65, 0x2d, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x32, 0x2f, + 0x67, 0x65, 0x6e, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x65, 0x72, 0xca, 0x02, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0xe2, + 0x02, 0x14, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, + 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1303,64 +1582,78 @@ func file_signaler_service_proto_rawDescGZIP() []byte { return file_signaler_service_proto_rawDescData } -var file_signaler_service_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_signaler_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_signaler_service_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_signaler_service_proto_goTypes = []interface{}{ - (*CreateAuthTokenRequest)(nil), // 0: signaler.CreateAuthTokenRequest - (*ListCamerasRequest)(nil), // 1: signaler.ListCamerasRequest - (*ListCamerasResponse)(nil), // 2: signaler.ListCamerasResponse - (*CreateSessionRequest)(nil), // 3: signaler.CreateSessionRequest - (*PopSessionRequest)(nil), // 4: signaler.PopSessionRequest - (*UpdateSessionRequest)(nil), // 5: signaler.UpdateSessionRequest - (*ListSessionsRequest)(nil), // 6: signaler.ListSessionsRequest - (*ListSessionsResponse)(nil), // 7: signaler.ListSessionsResponse - (*CreateIceMessageRequest)(nil), // 8: signaler.CreateIceMessageRequest - (*PopIceMessageRequest)(nil), // 9: signaler.PopIceMessageRequest - (*Camera)(nil), // 10: signaler.Camera - (*IceMessage)(nil), // 11: signaler.IceMessage - (*NoMoreCandidates)(nil), // 12: signaler.NoMoreCandidates - (*IceCandidate)(nil), // 13: signaler.IceCandidate - (*IceSessionDescription)(nil), // 14: signaler.IceSessionDescription - (*Session)(nil), // 15: signaler.Session - (*AuthToken)(nil), // 16: signaler.AuthToken - (*CreateAuthTokenRequest_Camera)(nil), // 17: signaler.CreateAuthTokenRequest.Camera - (*CreateAuthTokenRequest_Client)(nil), // 18: signaler.CreateAuthTokenRequest.Client - (*Camera_Identifier)(nil), // 19: signaler.Camera.Identifier - (*Session_Identifier)(nil), // 20: signaler.Session.Identifier + (Sample_Type)(0), // 0: signaler.Sample.Type + (*CreateAuthTokenRequest)(nil), // 1: signaler.CreateAuthTokenRequest + (*ListCamerasRequest)(nil), // 2: signaler.ListCamerasRequest + (*ListCamerasResponse)(nil), // 3: signaler.ListCamerasResponse + (*CreateSessionRequest)(nil), // 4: signaler.CreateSessionRequest + (*PopSessionRequest)(nil), // 5: signaler.PopSessionRequest + (*UpdateSessionRequest)(nil), // 6: signaler.UpdateSessionRequest + (*ListSessionsRequest)(nil), // 7: signaler.ListSessionsRequest + (*ListSessionsResponse)(nil), // 8: signaler.ListSessionsResponse + (*CreateIceMessageRequest)(nil), // 9: signaler.CreateIceMessageRequest + (*PopIceMessageRequest)(nil), // 10: signaler.PopIceMessageRequest + (*CreateSampleRequest)(nil), // 11: signaler.CreateSampleRequest + (*ListSamplesRequest)(nil), // 12: signaler.ListSamplesRequest + (*ListSamplesResponse)(nil), // 13: signaler.ListSamplesResponse + (*Camera)(nil), // 14: signaler.Camera + (*IceMessage)(nil), // 15: signaler.IceMessage + (*NoMoreCandidates)(nil), // 16: signaler.NoMoreCandidates + (*IceCandidate)(nil), // 17: signaler.IceCandidate + (*IceSessionDescription)(nil), // 18: signaler.IceSessionDescription + (*Session)(nil), // 19: signaler.Session + (*AuthToken)(nil), // 20: signaler.AuthToken + (*Sample)(nil), // 21: signaler.Sample + (*CreateAuthTokenRequest_Camera)(nil), // 22: signaler.CreateAuthTokenRequest.Camera + (*CreateAuthTokenRequest_Client)(nil), // 23: signaler.CreateAuthTokenRequest.Client + (*Camera_Identifier)(nil), // 24: signaler.Camera.Identifier + (*Session_Identifier)(nil), // 25: signaler.Session.Identifier } var file_signaler_service_proto_depIdxs = []int32{ - 17, // 0: signaler.CreateAuthTokenRequest.camera:type_name -> signaler.CreateAuthTokenRequest.Camera - 18, // 1: signaler.CreateAuthTokenRequest.client:type_name -> signaler.CreateAuthTokenRequest.Client - 10, // 2: signaler.ListCamerasResponse.cameras:type_name -> signaler.Camera - 15, // 3: signaler.CreateSessionRequest.session:type_name -> signaler.Session - 15, // 4: signaler.PopSessionRequest.session:type_name -> signaler.Session - 15, // 5: signaler.UpdateSessionRequest.session:type_name -> signaler.Session - 15, // 6: signaler.ListSessionsResponse.sessions:type_name -> signaler.Session - 20, // 7: signaler.CreateIceMessageRequest.session_identifier:type_name -> signaler.Session.Identifier - 11, // 8: signaler.CreateIceMessageRequest.ice_message:type_name -> signaler.IceMessage - 20, // 9: signaler.PopIceMessageRequest.session_identifier:type_name -> signaler.Session.Identifier - 19, // 10: signaler.Camera.identifier:type_name -> signaler.Camera.Identifier - 13, // 11: signaler.IceMessage.candidate:type_name -> signaler.IceCandidate - 14, // 12: signaler.IceMessage.session:type_name -> signaler.IceSessionDescription - 12, // 13: signaler.IceMessage.no_more_candidates:type_name -> signaler.NoMoreCandidates - 20, // 14: signaler.Session.id:type_name -> signaler.Session.Identifier - 19, // 15: signaler.Session.camera:type_name -> signaler.Camera.Identifier - 0, // 16: signaler.SignalerService.CreateAuthToken:input_type -> signaler.CreateAuthTokenRequest - 1, // 17: signaler.SignalerService.ListCameras:input_type -> signaler.ListCamerasRequest - 3, // 18: signaler.SignalerService.CreateSession:input_type -> signaler.CreateSessionRequest - 4, // 19: signaler.SignalerService.PopSession:input_type -> signaler.PopSessionRequest - 8, // 20: signaler.SignalerService.CreateIceMessage:input_type -> signaler.CreateIceMessageRequest - 9, // 21: signaler.SignalerService.PopIceMessage:input_type -> signaler.PopIceMessageRequest - 16, // 22: signaler.SignalerService.CreateAuthToken:output_type -> signaler.AuthToken - 2, // 23: signaler.SignalerService.ListCameras:output_type -> signaler.ListCamerasResponse - 15, // 24: signaler.SignalerService.CreateSession:output_type -> signaler.Session - 15, // 25: signaler.SignalerService.PopSession:output_type -> signaler.Session - 11, // 26: signaler.SignalerService.CreateIceMessage:output_type -> signaler.IceMessage - 11, // 27: signaler.SignalerService.PopIceMessage:output_type -> signaler.IceMessage - 22, // [22:28] is the sub-list for method output_type - 16, // [16:22] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 22, // 0: signaler.CreateAuthTokenRequest.camera:type_name -> signaler.CreateAuthTokenRequest.Camera + 23, // 1: signaler.CreateAuthTokenRequest.client:type_name -> signaler.CreateAuthTokenRequest.Client + 14, // 2: signaler.ListCamerasResponse.cameras:type_name -> signaler.Camera + 19, // 3: signaler.CreateSessionRequest.session:type_name -> signaler.Session + 19, // 4: signaler.PopSessionRequest.session:type_name -> signaler.Session + 19, // 5: signaler.UpdateSessionRequest.session:type_name -> signaler.Session + 19, // 6: signaler.ListSessionsResponse.sessions:type_name -> signaler.Session + 25, // 7: signaler.CreateIceMessageRequest.session_identifier:type_name -> signaler.Session.Identifier + 15, // 8: signaler.CreateIceMessageRequest.ice_message:type_name -> signaler.IceMessage + 25, // 9: signaler.PopIceMessageRequest.session_identifier:type_name -> signaler.Session.Identifier + 21, // 10: signaler.CreateSampleRequest.sample:type_name -> signaler.Sample + 21, // 11: signaler.ListSamplesResponse.samples:type_name -> signaler.Sample + 24, // 12: signaler.Camera.identifier:type_name -> signaler.Camera.Identifier + 17, // 13: signaler.IceMessage.candidate:type_name -> signaler.IceCandidate + 18, // 14: signaler.IceMessage.session:type_name -> signaler.IceSessionDescription + 16, // 15: signaler.IceMessage.no_more_candidates:type_name -> signaler.NoMoreCandidates + 25, // 16: signaler.Session.id:type_name -> signaler.Session.Identifier + 24, // 17: signaler.Session.camera:type_name -> signaler.Camera.Identifier + 0, // 18: signaler.Sample.type:type_name -> signaler.Sample.Type + 24, // 19: signaler.Sample.camera_id:type_name -> signaler.Camera.Identifier + 1, // 20: signaler.SignalerService.CreateAuthToken:input_type -> signaler.CreateAuthTokenRequest + 2, // 21: signaler.SignalerService.ListCameras:input_type -> signaler.ListCamerasRequest + 4, // 22: signaler.SignalerService.CreateSession:input_type -> signaler.CreateSessionRequest + 5, // 23: signaler.SignalerService.PopSession:input_type -> signaler.PopSessionRequest + 9, // 24: signaler.SignalerService.CreateIceMessage:input_type -> signaler.CreateIceMessageRequest + 10, // 25: signaler.SignalerService.PopIceMessage:input_type -> signaler.PopIceMessageRequest + 11, // 26: signaler.SignalerService.CreateSample:input_type -> signaler.CreateSampleRequest + 12, // 27: signaler.SignalerService.ListSamples:input_type -> signaler.ListSamplesRequest + 20, // 28: signaler.SignalerService.CreateAuthToken:output_type -> signaler.AuthToken + 3, // 29: signaler.SignalerService.ListCameras:output_type -> signaler.ListCamerasResponse + 19, // 30: signaler.SignalerService.CreateSession:output_type -> signaler.Session + 19, // 31: signaler.SignalerService.PopSession:output_type -> signaler.Session + 15, // 32: signaler.SignalerService.CreateIceMessage:output_type -> signaler.IceMessage + 15, // 33: signaler.SignalerService.PopIceMessage:output_type -> signaler.IceMessage + 21, // 34: signaler.SignalerService.CreateSample:output_type -> signaler.Sample + 13, // 35: signaler.SignalerService.ListSamples:output_type -> signaler.ListSamplesResponse + 28, // [28:36] is the sub-list for method output_type + 20, // [20:28] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_signaler_service_proto_init() } @@ -1490,7 +1783,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Camera); i { + switch v := v.(*CreateSampleRequest); i { case 0: return &v.state case 1: @@ -1502,7 +1795,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IceMessage); i { + switch v := v.(*ListSamplesRequest); i { case 0: return &v.state case 1: @@ -1514,7 +1807,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NoMoreCandidates); i { + switch v := v.(*ListSamplesResponse); i { case 0: return &v.state case 1: @@ -1526,7 +1819,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IceCandidate); i { + switch v := v.(*Camera); i { case 0: return &v.state case 1: @@ -1538,7 +1831,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IceSessionDescription); i { + switch v := v.(*IceMessage); i { case 0: return &v.state case 1: @@ -1550,7 +1843,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Session); i { + switch v := v.(*NoMoreCandidates); i { case 0: return &v.state case 1: @@ -1562,7 +1855,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AuthToken); i { + switch v := v.(*IceCandidate); i { case 0: return &v.state case 1: @@ -1574,7 +1867,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateAuthTokenRequest_Camera); i { + switch v := v.(*IceSessionDescription); i { case 0: return &v.state case 1: @@ -1586,7 +1879,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateAuthTokenRequest_Client); i { + switch v := v.(*Session); i { case 0: return &v.state case 1: @@ -1598,7 +1891,7 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Camera_Identifier); i { + switch v := v.(*AuthToken); i { case 0: return &v.state case 1: @@ -1610,6 +1903,54 @@ func file_signaler_service_proto_init() { } } file_signaler_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Sample); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signaler_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAuthTokenRequest_Camera); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signaler_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAuthTokenRequest_Client); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signaler_service_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Camera_Identifier); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signaler_service_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Session_Identifier); i { case 0: return &v.state @@ -1626,24 +1967,25 @@ func file_signaler_service_proto_init() { (*CreateAuthTokenRequest_Camera_)(nil), (*CreateAuthTokenRequest_Client_)(nil), } - file_signaler_service_proto_msgTypes[11].OneofWrappers = []interface{}{ + file_signaler_service_proto_msgTypes[14].OneofWrappers = []interface{}{ (*IceMessage_Candidate)(nil), (*IceMessage_Session)(nil), (*IceMessage_NoMoreCandidates)(nil), } - file_signaler_service_proto_msgTypes[13].OneofWrappers = []interface{}{} + file_signaler_service_proto_msgTypes[16].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_signaler_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 21, + NumEnums: 1, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, GoTypes: file_signaler_service_proto_goTypes, DependencyIndexes: file_signaler_service_proto_depIdxs, + EnumInfos: file_signaler_service_proto_enumTypes, MessageInfos: file_signaler_service_proto_msgTypes, }.Build() File_signaler_service_proto = out.File diff --git a/internal/sensors/sensors.go b/internal/sensors/sensors.go new file mode 100644 index 0000000..25f1433 --- /dev/null +++ b/internal/sensors/sensors.go @@ -0,0 +1,144 @@ +package sensors + +import ( + "bufio" + "context" + "os/exec" + "strconv" + "strings" + "sync" + "time" + + pb "github.com/chathaway-codes/home-sensors/v2/gen" + "github.com/chathaway-codes/home-sensors/v2/internal/pipespy" + "github.com/chathaway-codes/home-sensors/v2/internal/watcher/config" + "github.com/google/uuid" + "github.com/rs/zerolog/log" +) + +var Default = &Mod{} + +type Sensors struct { + mu sync.Mutex + ctx context.Context + readCmd *exec.Cmd + cancelFunc func() + ticker time.Ticker + + listeners map[string]chan<- *pb.Sample +} + +func New(cfg *config.Config) (*Sensors, error) { + ctx, cancelFunc := context.WithCancel(context.Background()) + readCmd := exec.CommandContext(ctx, cfg.SensorCmd.Binary, cfg.SensorCmd.Arguments...) + + ticker := time.NewTicker(time.Duration(cfg.SensorRateMS) * time.Millisecond) + return &Sensors{ + ctx: ctx, + cancelFunc: cancelFunc, + readCmd: readCmd, + ticker: *ticker, + // it would be better if sensors.Run handled sending to the server; to do that, + // it needs a connection and the auth token. I don't have a clean way of getting that + // right now. + listeners: make(map[string]chan<- *pb.Sample), + }, nil +} + +func (v *Sensors) Run() { + pipe := pipespy.New() + snoop := pipe.Add(pipespy.NewCmd(v.readCmd)).Snoop() + defer snoop.Close() + + cleanUp := pipe.Start() + defer func() { + errs := cleanUp() + for _, err := range errs { + log.Err(err).Send() + } + }() + + scanner := bufio.NewScanner(snoop) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Split(line, " ") + if len(parts) != 3 { + log.Error().Str("line", line).Msg("malformed line; expected 3 floats: humidity pressure temperature_c") + } + humidity, err := strconv.ParseFloat(parts[0], 64) + if err != nil { + log.Error().Err(err).Str("val", parts[0]).Msg("failed to parse humidity") + } + pressure, err := strconv.ParseFloat(parts[1], 64) + if err != nil { + log.Error().Err(err).Str("val", parts[1]).Msg("failed to parse pressure") + } + temperatureC, err := strconv.ParseFloat(parts[2], 64) + if err != nil { + log.Error().Err(err).Str("val", parts[2]).Msg("failed to parse temperature_c") + } + + select { + case <-v.ticker.C: + func() { + v.mu.Lock() + defer v.mu.Unlock() + + samples := []*pb.Sample{ + { + Type: pb.Sample_HUMIDITY, + Reading: humidity, + }, + { + Type: pb.Sample_PRESSURE, + Reading: pressure, + }, + { + Type: pb.Sample_TEMPERATURE_C, + Reading: temperatureC, + }, + } + + for _, listener := range v.listeners { + for _, sample := range samples { + listener <- sample + } + } + }() + default: + // do nothing + } + } +} + +// Join will connect to a running stream. +func (v *Sensors) Join() (<-chan *pb.Sample, func()) { + v.mu.Lock() + defer v.mu.Unlock() + + myID := uuid.New().String() + ch := make(chan *pb.Sample) + v.listeners[myID] = ch + + return ch, func() { + v.mu.Lock() + defer v.mu.Unlock() + + delete(v.listeners, myID) + } +} + +// Done stops the processing. +func (v *Sensors) Done() { + v.cancelFunc() +} + +type Mod struct{} + +func (m *Mod) Get() (*Sensors, error) { + cfg, err := config.Default.Get() + if err != nil { + return nil, err + } + return New(cfg) +} diff --git a/internal/watcher/config/config.go b/internal/watcher/config/config.go index 1c8e48d..d8d19b2 100644 --- a/internal/watcher/config/config.go +++ b/internal/watcher/config/config.go @@ -17,8 +17,10 @@ type Cmd struct { } type Config struct { - H264Cmd *Cmd `yaml:"h264"` - IVFCmd *Cmd `yaml:"ivf"` + H264Cmd *Cmd `yaml:"h264"` + IVFCmd *Cmd `yaml:"ivf"` + SensorCmd *Cmd `yaml:"sensor"` + SensorRateMS int64 `yaml:"sensor_rate_ms"` } func New(source []byte) (*Config, error) { diff --git a/pkg/signaler/signaler.go b/pkg/signaler/signaler.go index 9e32a6c..7c318f0 100644 --- a/pkg/signaler/signaler.go +++ b/pkg/signaler/signaler.go @@ -37,6 +37,9 @@ type Server struct { sessionsByCamera map[string]chan *session sessionsById map[string]*session + + // Most recent sample + samplesByCamera map[string]map[pb.Sample_Type]*pb.Sample } func New() *Server { @@ -44,6 +47,7 @@ func New() *Server { camerasByHome: make(map[string]map[string]*camera), sessionsByCamera: make(map[string]chan *session), sessionsById: make(map[string]*session), + samplesByCamera: make(map[string]map[pb.Sample_Type]*pb.Sample), } go s.cleanup() return s @@ -160,9 +164,11 @@ func (s *Server) PopSession(ctx context.Context, request *connect.Request[pb.Pop s.mu.Lock() if _, ok := s.camerasByHome[authToken.Home]; !ok { + s.mu.Unlock() return nil, status.Errorf(codes.NotFound, "home %q not found", authToken.Home) } if _, ok := s.camerasByHome[authToken.Home][authToken.Uid]; !ok { + s.mu.Unlock() return nil, status.Errorf(codes.Unauthenticated, "you are not a camera") } @@ -238,6 +244,65 @@ func (s *Server) PopIceMessage(ctx context.Context, request *connect.Request[pb. return connect.NewResponse(msg), nil } +func (s *Server) CreateSample(ctx context.Context, request *connect.Request[pb.CreateSampleRequest]) (*connect.Response[pb.Sample], error) { + authToken, err := getAuthToken(request) + if err != nil { + return nil, err + } + + s.mu.Lock() + defer s.mu.Unlock() + + if _, ok := s.camerasByHome[authToken.Home]; !ok { + return nil, status.Errorf(codes.NotFound, "home %q not found", authToken.Home) + } + cam, ok := s.camerasByHome[authToken.Home][authToken.Uid] + if !ok { + return nil, status.Errorf(codes.Unauthenticated, "you are not a camera") + } + + if _, ok := s.samplesByCamera[authToken.Uid]; !ok { + s.samplesByCamera[authToken.Uid] = make(map[pb.Sample_Type]*pb.Sample) + } + + sample := request.Msg.GetSample() + s.samplesByCamera[authToken.Uid][sample.Type] = &pb.Sample{ + Type: sample.Type, + Reading: sample.Reading, + + CameraId: &pb.Camera_Identifier{ + Id: cam.id, + }, + } + return connect.NewResponse(s.samplesByCamera[authToken.Uid][sample.Type]), nil +} + +func (s *Server) ListSamples(ctx context.Context, request *connect.Request[pb.ListSamplesRequest]) (*connect.Response[pb.ListSamplesResponse], error) { + authToken, err := getAuthToken(request) + if err != nil { + return nil, err + } + + s.mu.Lock() + defer s.mu.Unlock() + + if _, ok := s.camerasByHome[authToken.Home]; !ok { + return nil, status.Errorf(codes.NotFound, "home %q not found", authToken.Home) + } + + var samples []*pb.Sample + for camera := range s.camerasByHome[authToken.Home] { + if sample, ok := s.samplesByCamera[camera]; ok { + for _, sample := range sample { + samples = append(samples, sample) + } + } + } + return connect.NewResponse(&pb.ListSamplesResponse{ + Samples: samples, + }), nil +} + func (s *Server) cleanup() { ticker := time.NewTicker(time.Minute * 5) for t := range ticker.C { diff --git a/proto/signaler_service.proto b/proto/signaler_service.proto index 273c857..8f54baf 100644 --- a/proto/signaler_service.proto +++ b/proto/signaler_service.proto @@ -23,6 +23,12 @@ service SignalerService { // If there are no messages, this blocks until one becomes available. rpc PopIceMessage(PopIceMessageRequest) returns (IceMessage); + // CreateSample creates a sample for the given camera. + // If called without an auth token indicating a camera, an error + // is returned. + // TODO: this should be moved to a seperate service + rpc CreateSample(CreateSampleRequest) returns (Sample); + rpc ListSamples(ListSamplesRequest) returns (ListSamplesResponse); } message CreateAuthTokenRequest{ @@ -85,6 +91,17 @@ message PopIceMessageRequest { Session.Identifier session_identifier = 1; } +message CreateSampleRequest{ + Sample sample = 1; +} + +message ListSamplesRequest { +} + +message ListSamplesResponse { + repeated Sample samples = 1; +} + message Camera { message Identifier { string id = 1; @@ -126,4 +143,18 @@ message Session { message AuthToken { string token = 1; +} + +message Sample{ + enum Type { + UNSPECIFIED = 0; + TEMPERATURE_C = 1; + HUMIDITY = 2; + PRESSURE = 3; + } + Type type = 1; + double reading = 2; + + // Read-only; will be ignored in CreateSample. + Camera.Identifier camera_id = 3; } \ No newline at end of file diff --git a/rpi_camera.yaml b/rpi_camera.yaml new file mode 100644 index 0000000..c175d5d --- /dev/null +++ b/rpi_camera.yaml @@ -0,0 +1,32 @@ +h264: + binary: "/usr/bin/libcamera-vid" + arguments: + - "-n" + - "-t" + - "0" + - "--codec" + - "h264" + - "--mode" + - "1640:1232" + - "--denoise" + - "off" + - "--inline" + - "-o" + - "-" +ivf: + binary: "/usr/bin/ffmpeg" + arguments: + - "-i" + - "-" + - "-g" + - "30" + - "-b:v" + - "2M" + - "-f" + - "ivf" + - "-" +sensor: + binary: "/usr/bin/python3" + arguments: + - "/home/charles/temperature.py" +sensor_rate_ms: 10000 \ No newline at end of file diff --git a/sample.yaml b/sample.yaml index d5c8cc1..c075dc4 100644 --- a/sample.yaml +++ b/sample.yaml @@ -14,3 +14,9 @@ ivf: - "-f" - "ivf" - "-" + +sensor: + binary: "/usr/bin/yes" + arguments: + - "44.33889713096721 1015.1977693083448 23.60542243081727" +sensor_rate_ms: 10000 \ No newline at end of file diff --git a/ui/lib/gen/signaler_service.pb.dart b/ui/lib/gen/signaler_service.pb.dart index 8830cde..74a8d4b 100644 --- a/ui/lib/gen/signaler_service.pb.dart +++ b/ui/lib/gen/signaler_service.pb.dart @@ -14,6 +14,10 @@ import 'dart:core' as $core; import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; +import 'signaler_service.pbenum.dart'; + +export 'signaler_service.pbenum.dart'; + class CreateAuthTokenRequest_Camera extends $pb.GeneratedMessage { factory CreateAuthTokenRequest_Camera({ $core.String? id, @@ -658,6 +662,134 @@ class PopIceMessageRequest extends $pb.GeneratedMessage { Session_Identifier ensureSessionIdentifier() => $_ensure(0); } +class CreateSampleRequest extends $pb.GeneratedMessage { + factory CreateSampleRequest({ + Sample? sample, + }) { + final $result = create(); + if (sample != null) { + $result.sample = sample; + } + return $result; + } + CreateSampleRequest._() : super(); + factory CreateSampleRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateSampleRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateSampleRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'signaler'), createEmptyInstance: create) + ..aOM(1, _omitFieldNames ? '' : 'sample', subBuilder: Sample.create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CreateSampleRequest clone() => CreateSampleRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CreateSampleRequest copyWith(void Function(CreateSampleRequest) updates) => super.copyWith((message) => updates(message as CreateSampleRequest)) as CreateSampleRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CreateSampleRequest create() => CreateSampleRequest._(); + CreateSampleRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CreateSampleRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateSampleRequest? _defaultInstance; + + @$pb.TagNumber(1) + Sample get sample => $_getN(0); + @$pb.TagNumber(1) + set sample(Sample v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasSample() => $_has(0); + @$pb.TagNumber(1) + void clearSample() => clearField(1); + @$pb.TagNumber(1) + Sample ensureSample() => $_ensure(0); +} + +class ListSamplesRequest extends $pb.GeneratedMessage { + factory ListSamplesRequest() => create(); + ListSamplesRequest._() : super(); + factory ListSamplesRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ListSamplesRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListSamplesRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'signaler'), createEmptyInstance: create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + ListSamplesRequest clone() => ListSamplesRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ListSamplesRequest copyWith(void Function(ListSamplesRequest) updates) => super.copyWith((message) => updates(message as ListSamplesRequest)) as ListSamplesRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListSamplesRequest create() => ListSamplesRequest._(); + ListSamplesRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ListSamplesRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ListSamplesRequest? _defaultInstance; +} + +class ListSamplesResponse extends $pb.GeneratedMessage { + factory ListSamplesResponse({ + $core.Iterable? samples, + }) { + final $result = create(); + if (samples != null) { + $result.samples.addAll(samples); + } + return $result; + } + ListSamplesResponse._() : super(); + factory ListSamplesResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ListSamplesResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListSamplesResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'signaler'), createEmptyInstance: create) + ..pc(1, _omitFieldNames ? '' : 'samples', $pb.PbFieldType.PM, subBuilder: Sample.create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + ListSamplesResponse clone() => ListSamplesResponse()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ListSamplesResponse copyWith(void Function(ListSamplesResponse) updates) => super.copyWith((message) => updates(message as ListSamplesResponse)) as ListSamplesResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListSamplesResponse create() => ListSamplesResponse._(); + ListSamplesResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ListSamplesResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ListSamplesResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get samples => $_getList(0); +} + class Camera_Identifier extends $pb.GeneratedMessage { factory Camera_Identifier({ $core.String? id, @@ -1219,6 +1351,86 @@ class AuthToken extends $pb.GeneratedMessage { void clearToken() => clearField(1); } +class Sample extends $pb.GeneratedMessage { + factory Sample({ + Sample_Type? type, + $core.double? reading, + Camera_Identifier? cameraId, + }) { + final $result = create(); + if (type != null) { + $result.type = type; + } + if (reading != null) { + $result.reading = reading; + } + if (cameraId != null) { + $result.cameraId = cameraId; + } + return $result; + } + Sample._() : super(); + factory Sample.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Sample.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Sample', package: const $pb.PackageName(_omitMessageNames ? '' : 'signaler'), createEmptyInstance: create) + ..e(1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: Sample_Type.UNSPECIFIED, valueOf: Sample_Type.valueOf, enumValues: Sample_Type.values) + ..a<$core.double>(2, _omitFieldNames ? '' : 'reading', $pb.PbFieldType.OD) + ..aOM(3, _omitFieldNames ? '' : 'cameraId', subBuilder: Camera_Identifier.create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Sample clone() => Sample()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Sample copyWith(void Function(Sample) updates) => super.copyWith((message) => updates(message as Sample)) as Sample; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Sample create() => Sample._(); + Sample createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Sample getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Sample? _defaultInstance; + + @$pb.TagNumber(1) + Sample_Type get type => $_getN(0); + @$pb.TagNumber(1) + set type(Sample_Type v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasType() => $_has(0); + @$pb.TagNumber(1) + void clearType() => clearField(1); + + @$pb.TagNumber(2) + $core.double get reading => $_getN(1); + @$pb.TagNumber(2) + set reading($core.double v) { $_setDouble(1, v); } + @$pb.TagNumber(2) + $core.bool hasReading() => $_has(1); + @$pb.TagNumber(2) + void clearReading() => clearField(2); + + @$pb.TagNumber(3) + Camera_Identifier get cameraId => $_getN(2); + @$pb.TagNumber(3) + set cameraId(Camera_Identifier v) { setField(3, v); } + @$pb.TagNumber(3) + $core.bool hasCameraId() => $_has(2); + @$pb.TagNumber(3) + void clearCameraId() => clearField(3); + @$pb.TagNumber(3) + Camera_Identifier ensureCameraId() => $_ensure(2); +} + const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/ui/lib/gen/signaler_service.pbenum.dart b/ui/lib/gen/signaler_service.pbenum.dart index 65d3e63..98d3dc9 100644 --- a/ui/lib/gen/signaler_service.pbenum.dart +++ b/ui/lib/gen/signaler_service.pbenum.dart @@ -9,3 +9,28 @@ // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class Sample_Type extends $pb.ProtobufEnum { + static const Sample_Type UNSPECIFIED = Sample_Type._(0, _omitEnumNames ? '' : 'UNSPECIFIED'); + static const Sample_Type TEMPERATURE_C = Sample_Type._(1, _omitEnumNames ? '' : 'TEMPERATURE_C'); + static const Sample_Type HUMIDITY = Sample_Type._(2, _omitEnumNames ? '' : 'HUMIDITY'); + static const Sample_Type PRESSURE = Sample_Type._(3, _omitEnumNames ? '' : 'PRESSURE'); + + static const $core.List values = [ + UNSPECIFIED, + TEMPERATURE_C, + HUMIDITY, + PRESSURE, + ]; + + static final $core.Map<$core.int, Sample_Type> _byValue = $pb.ProtobufEnum.initByValue(values); + static Sample_Type? valueOf($core.int value) => _byValue[value]; + + const Sample_Type._($core.int v, $core.String n) : super(v, n); +} + + +const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/ui/lib/gen/signaler_service.pbgrpc.dart b/ui/lib/gen/signaler_service.pbgrpc.dart index afa4432..ad3a7dc 100644 --- a/ui/lib/gen/signaler_service.pbgrpc.dart +++ b/ui/lib/gen/signaler_service.pbgrpc.dart @@ -45,6 +45,14 @@ class SignalerServiceClient extends $grpc.Client { '/signaler.SignalerService/PopIceMessage', ($0.PopIceMessageRequest value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.IceMessage.fromBuffer(value)); + static final _$createSample = $grpc.ClientMethod<$0.CreateSampleRequest, $0.Sample>( + '/signaler.SignalerService/CreateSample', + ($0.CreateSampleRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.Sample.fromBuffer(value)); + static final _$listSamples = $grpc.ClientMethod<$0.ListSamplesRequest, $0.ListSamplesResponse>( + '/signaler.SignalerService/ListSamples', + ($0.ListSamplesRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.ListSamplesResponse.fromBuffer(value)); SignalerServiceClient($grpc.ClientChannel channel, {$grpc.CallOptions? options, @@ -75,6 +83,14 @@ class SignalerServiceClient extends $grpc.Client { $grpc.ResponseFuture<$0.IceMessage> popIceMessage($0.PopIceMessageRequest request, {$grpc.CallOptions? options}) { return $createUnaryCall(_$popIceMessage, request, options: options); } + + $grpc.ResponseFuture<$0.Sample> createSample($0.CreateSampleRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$createSample, request, options: options); + } + + $grpc.ResponseFuture<$0.ListSamplesResponse> listSamples($0.ListSamplesRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$listSamples, request, options: options); + } } @$pb.GrpcServiceName('signaler.SignalerService') @@ -124,6 +140,20 @@ abstract class SignalerServiceBase extends $grpc.Service { false, ($core.List<$core.int> value) => $0.PopIceMessageRequest.fromBuffer(value), ($0.IceMessage value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.CreateSampleRequest, $0.Sample>( + 'CreateSample', + createSample_Pre, + false, + false, + ($core.List<$core.int> value) => $0.CreateSampleRequest.fromBuffer(value), + ($0.Sample value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.ListSamplesRequest, $0.ListSamplesResponse>( + 'ListSamples', + listSamples_Pre, + false, + false, + ($core.List<$core.int> value) => $0.ListSamplesRequest.fromBuffer(value), + ($0.ListSamplesResponse value) => value.writeToBuffer())); } $async.Future<$0.AuthToken> createAuthToken_Pre($grpc.ServiceCall call, $async.Future<$0.CreateAuthTokenRequest> request) async { @@ -150,10 +180,20 @@ abstract class SignalerServiceBase extends $grpc.Service { return popIceMessage(call, await request); } + $async.Future<$0.Sample> createSample_Pre($grpc.ServiceCall call, $async.Future<$0.CreateSampleRequest> request) async { + return createSample(call, await request); + } + + $async.Future<$0.ListSamplesResponse> listSamples_Pre($grpc.ServiceCall call, $async.Future<$0.ListSamplesRequest> request) async { + return listSamples(call, await request); + } + $async.Future<$0.AuthToken> createAuthToken($grpc.ServiceCall call, $0.CreateAuthTokenRequest request); $async.Future<$0.ListCamerasResponse> listCameras($grpc.ServiceCall call, $0.ListCamerasRequest request); $async.Future<$0.Session> createSession($grpc.ServiceCall call, $0.CreateSessionRequest request); $async.Future<$0.Session> popSession($grpc.ServiceCall call, $0.PopSessionRequest request); $async.Future<$0.IceMessage> createIceMessage($grpc.ServiceCall call, $0.CreateIceMessageRequest request); $async.Future<$0.IceMessage> popIceMessage($grpc.ServiceCall call, $0.PopIceMessageRequest request); + $async.Future<$0.Sample> createSample($grpc.ServiceCall call, $0.CreateSampleRequest request); + $async.Future<$0.ListSamplesResponse> listSamples($grpc.ServiceCall call, $0.ListSamplesRequest request); } diff --git a/ui/lib/gen/signaler_service.pbjson.dart b/ui/lib/gen/signaler_service.pbjson.dart index e3ecfa5..c518bde 100644 --- a/ui/lib/gen/signaler_service.pbjson.dart +++ b/ui/lib/gen/signaler_service.pbjson.dart @@ -160,6 +160,41 @@ final $typed_data.Uint8List popIceMessageRequestDescriptor = $convert.base64Deco 'ChRQb3BJY2VNZXNzYWdlUmVxdWVzdBJLChJzZXNzaW9uX2lkZW50aWZpZXIYASABKAsyHC5zaW' 'duYWxlci5TZXNzaW9uLklkZW50aWZpZXJSEXNlc3Npb25JZGVudGlmaWVy'); +@$core.Deprecated('Use createSampleRequestDescriptor instead') +const CreateSampleRequest$json = { + '1': 'CreateSampleRequest', + '2': [ + {'1': 'sample', '3': 1, '4': 1, '5': 11, '6': '.signaler.Sample', '10': 'sample'}, + ], +}; + +/// Descriptor for `CreateSampleRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createSampleRequestDescriptor = $convert.base64Decode( + 'ChNDcmVhdGVTYW1wbGVSZXF1ZXN0EigKBnNhbXBsZRgBIAEoCzIQLnNpZ25hbGVyLlNhbXBsZV' + 'IGc2FtcGxl'); + +@$core.Deprecated('Use listSamplesRequestDescriptor instead') +const ListSamplesRequest$json = { + '1': 'ListSamplesRequest', +}; + +/// Descriptor for `ListSamplesRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listSamplesRequestDescriptor = $convert.base64Decode( + 'ChJMaXN0U2FtcGxlc1JlcXVlc3Q='); + +@$core.Deprecated('Use listSamplesResponseDescriptor instead') +const ListSamplesResponse$json = { + '1': 'ListSamplesResponse', + '2': [ + {'1': 'samples', '3': 1, '4': 3, '5': 11, '6': '.signaler.Sample', '10': 'samples'}, + ], +}; + +/// Descriptor for `ListSamplesResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listSamplesResponseDescriptor = $convert.base64Decode( + 'ChNMaXN0U2FtcGxlc1Jlc3BvbnNlEioKB3NhbXBsZXMYASADKAsyEC5zaWduYWxlci5TYW1wbG' + 'VSB3NhbXBsZXM='); + @$core.Deprecated('Use cameraDescriptor instead') const Camera$json = { '1': 'Camera', @@ -284,3 +319,32 @@ const AuthToken$json = { final $typed_data.Uint8List authTokenDescriptor = $convert.base64Decode( 'CglBdXRoVG9rZW4SFAoFdG9rZW4YASABKAlSBXRva2Vu'); +@$core.Deprecated('Use sampleDescriptor instead') +const Sample$json = { + '1': 'Sample', + '2': [ + {'1': 'type', '3': 1, '4': 1, '5': 14, '6': '.signaler.Sample.Type', '10': 'type'}, + {'1': 'reading', '3': 2, '4': 1, '5': 1, '10': 'reading'}, + {'1': 'camera_id', '3': 3, '4': 1, '5': 11, '6': '.signaler.Camera.Identifier', '10': 'cameraId'}, + ], + '4': [Sample_Type$json], +}; + +@$core.Deprecated('Use sampleDescriptor instead') +const Sample_Type$json = { + '1': 'Type', + '2': [ + {'1': 'UNSPECIFIED', '2': 0}, + {'1': 'TEMPERATURE_C', '2': 1}, + {'1': 'HUMIDITY', '2': 2}, + {'1': 'PRESSURE', '2': 3}, + ], +}; + +/// Descriptor for `Sample`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List sampleDescriptor = $convert.base64Decode( + 'CgZTYW1wbGUSKQoEdHlwZRgBIAEoDjIVLnNpZ25hbGVyLlNhbXBsZS5UeXBlUgR0eXBlEhgKB3' + 'JlYWRpbmcYAiABKAFSB3JlYWRpbmcSOAoJY2FtZXJhX2lkGAMgASgLMhsuc2lnbmFsZXIuQ2Ft' + 'ZXJhLklkZW50aWZpZXJSCGNhbWVyYUlkIkYKBFR5cGUSDwoLVU5TUEVDSUZJRUQQABIRCg1URU' + '1QRVJBVFVSRV9DEAESDAoISFVNSURJVFkQAhIMCghQUkVTU1VSRRAD'); +