diff --git a/internal/notification/feature.go b/internal/notification/feature.go index 36520b0..cadcb9e 100644 --- a/internal/notification/feature.go +++ b/internal/notification/feature.go @@ -11,28 +11,37 @@ import ( type FeatureStore interface { GetAll(ctx context.Context) ([]sqlc.Feature, error) + Upsert(ctx context.Context, feature sqlc.Feature) error } type FeatureNotifier struct { proto.UnimplementedFeatureStateServiceServer - store FeatureStore - streams map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{} - mu *sync.Mutex + store FeatureStore + streams map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{} + subscriptions map[string]map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{} + mu *sync.Mutex } func NewFeatureNotifier(grpcServer grpc.ServiceRegistrar, store FeatureStore) *FeatureNotifier { notifier := FeatureNotifier{ - streams: make(map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{}), - store: store, - mu: &sync.Mutex{}, + streams: make(map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{}), + subscriptions: make(map[string]map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{}), + store: store, + mu: &sync.Mutex{}, } proto.RegisterFeatureStateServiceServer(grpcServer, ¬ifier) return ¬ifier } -func (n *FeatureNotifier) SubscribeFeatureChanges(_ *proto.FeatureSubscription, stream proto.FeatureStateService_SubscribeFeatureChangesServer) error { +func (n *FeatureNotifier) SubscribeFeatureChanges(subscription *proto.FeatureSubscription, stream proto.FeatureStateService_SubscribeFeatureChangesServer) error { n.mu.Lock() - n.streams[stream] = struct{}{} + for _, f := range subscription.FeatureToggles { + if _, ok := n.subscriptions[f.FeatureId]; !ok { + n.subscriptions[f.FeatureId] = make(map[proto.FeatureStateService_SubscribeFeatureChangesServer]struct{}) + } + + n.subscriptions[f.FeatureId][stream] = struct{}{} + } n.mu.Unlock() features, err := n.store.GetAll(stream.Context()) @@ -40,6 +49,26 @@ func (n *FeatureNotifier) SubscribeFeatureChanges(_ *proto.FeatureSubscription, return err } + featureLookup := make(map[string]sqlc.Feature) + for _, f := range features { + featureLookup[f.FeatureID] = f + } + + var featuresToAdd []sqlc.Feature + for _, f := range subscription.FeatureToggles { + if _, ok := featureLookup[f.FeatureId]; !ok { + featuresToAdd = append(featuresToAdd, sqlc.Feature{ + FeatureID: f.FeatureId, + Description: f.Description, + Enabled: false, + }) + } + } + + for _, f := range featuresToAdd { + n.store.Upsert(stream.Context(), f) + } + for _, feature := range features { n.Notify(feature) } @@ -47,7 +76,9 @@ func (n *FeatureNotifier) SubscribeFeatureChanges(_ *proto.FeatureSubscription, <-stream.Context().Done() n.mu.Lock() - delete(n.streams, stream) + for _, f := range subscription.FeatureToggles { + delete(n.subscriptions[f.FeatureId], stream) + } n.mu.Unlock() return nil @@ -57,8 +88,8 @@ func (n *FeatureNotifier) Notify(feature sqlc.Feature) error { n.mu.Lock() defer n.mu.Unlock() - for stream := range n.streams { - err := stream.Send(&proto.Feature{ + for stream := range n.subscriptions[feature.FeatureID] { + err := stream.Send(&proto.FeatureToggleChange{ FeatureId: feature.FeatureID, Enabled: feature.Enabled, }) diff --git a/internal/notification/feature_test.go b/internal/notification/feature_test.go index 0393846..211c74a 100644 --- a/internal/notification/feature_test.go +++ b/internal/notification/feature_test.go @@ -41,15 +41,34 @@ func TestFeatureNotifier(t *testing.T) { Return([]sqlc.Feature{}, nil). Times(2) + store.EXPECT(). + Upsert(gomock.Any(), sqlc.Feature{ + FeatureID: "SOME_FEATURE_ID", + }). + Return(nil). + Times(2) + ctx := context.Background() client1 := createClient(t, ctx, bufDialer(lis)) - stream1, err := client1.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{}) + stream1, err := client1.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{ + FeatureToggles: []*proto.FeatureToggle{ + { + FeatureId: "SOME_FEATURE_ID", + }, + }, + }) if err != nil { t.Fatal(err) } client2 := createClient(t, ctx, bufDialer(lis)) - stream2, err := client2.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{}) + stream2, err := client2.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{ + FeatureToggles: []*proto.FeatureToggle{ + { + FeatureId: "SOME_FEATURE_ID", + }, + }, + }) if err != nil { t.Fatal(err) } diff --git a/pkg/dasher/dasher.go b/pkg/dasher/dasher.go index 8a29449..b209d78 100644 --- a/pkg/dasher/dasher.go +++ b/pkg/dasher/dasher.go @@ -40,8 +40,18 @@ func Connect(ctx context.Context, addr string) { errors.Wrap(err, "create new grpc client") } + featureToggles := make([]*proto.FeatureToggle, 0, len(registeredFeatures)) + for featureID, feature := range registeredFeatures { + featureToggles = append(featureToggles, &proto.FeatureToggle{ + FeatureId: featureID, + Description: feature.Description, + }) + } + client := proto.NewFeatureStateServiceClient(conn) - stream, err := client.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{}) + stream, err := client.SubscribeFeatureChanges(ctx, &proto.FeatureSubscription{ + FeatureToggles: featureToggles, + }) if err != nil { log.Fatal(errors.Wrap(err, "subscribe to feature changes")) } diff --git a/pkg/proto/feature.pb.go b/pkg/proto/feature.pb.go index d3f3784..75ef24d 100644 --- a/pkg/proto/feature.pb.go +++ b/pkg/proto/feature.pb.go @@ -20,18 +20,17 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// Main message for feature toggle states -type Feature struct { +type FeatureToggle struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FeatureId string `protobuf:"bytes,1,opt,name=feature_id,json=featureId,proto3" json:"feature_id,omitempty"` - Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` + FeatureId string `protobuf:"bytes,1,opt,name=feature_id,json=featureId,proto3" json:"feature_id,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` } -func (x *Feature) Reset() { - *x = Feature{} +func (x *FeatureToggle) Reset() { + *x = FeatureToggle{} if protoimpl.UnsafeEnabled { mi := &file_pkg_proto_feature_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -39,13 +38,13 @@ func (x *Feature) Reset() { } } -func (x *Feature) String() string { +func (x *FeatureToggle) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Feature) ProtoMessage() {} +func (*FeatureToggle) ProtoMessage() {} -func (x *Feature) ProtoReflect() protoreflect.Message { +func (x *FeatureToggle) ProtoReflect() protoreflect.Message { mi := &file_pkg_proto_feature_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -57,19 +56,75 @@ func (x *Feature) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Feature.ProtoReflect.Descriptor instead. -func (*Feature) Descriptor() ([]byte, []int) { +// Deprecated: Use FeatureToggle.ProtoReflect.Descriptor instead. +func (*FeatureToggle) Descriptor() ([]byte, []int) { return file_pkg_proto_feature_proto_rawDescGZIP(), []int{0} } -func (x *Feature) GetFeatureId() string { +func (x *FeatureToggle) GetFeatureId() string { + if x != nil { + return x.FeatureId + } + return "" +} + +func (x *FeatureToggle) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// Main message for feature toggle states +type FeatureToggleChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FeatureId string `protobuf:"bytes,1,opt,name=feature_id,json=featureId,proto3" json:"feature_id,omitempty"` + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` +} + +func (x *FeatureToggleChange) Reset() { + *x = FeatureToggleChange{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_proto_feature_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FeatureToggleChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FeatureToggleChange) ProtoMessage() {} + +func (x *FeatureToggleChange) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_feature_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 FeatureToggleChange.ProtoReflect.Descriptor instead. +func (*FeatureToggleChange) Descriptor() ([]byte, []int) { + return file_pkg_proto_feature_proto_rawDescGZIP(), []int{1} +} + +func (x *FeatureToggleChange) GetFeatureId() string { if x != nil { return x.FeatureId } return "" } -func (x *Feature) GetEnabled() bool { +func (x *FeatureToggleChange) GetEnabled() bool { if x != nil { return x.Enabled } @@ -81,12 +136,14 @@ type FeatureSubscription struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + FeatureToggles []*FeatureToggle `protobuf:"bytes,1,rep,name=featureToggles,proto3" json:"featureToggles,omitempty"` } func (x *FeatureSubscription) Reset() { *x = FeatureSubscription{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_proto_feature_proto_msgTypes[1] + mi := &file_pkg_proto_feature_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -99,7 +156,7 @@ func (x *FeatureSubscription) String() string { func (*FeatureSubscription) ProtoMessage() {} func (x *FeatureSubscription) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_feature_proto_msgTypes[1] + mi := &file_pkg_proto_feature_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -112,7 +169,14 @@ func (x *FeatureSubscription) ProtoReflect() protoreflect.Message { // Deprecated: Use FeatureSubscription.ProtoReflect.Descriptor instead. func (*FeatureSubscription) Descriptor() ([]byte, []int) { - return file_pkg_proto_feature_proto_rawDescGZIP(), []int{1} + return file_pkg_proto_feature_proto_rawDescGZIP(), []int{2} +} + +func (x *FeatureSubscription) GetFeatureToggles() []*FeatureToggle { + if x != nil { + return x.FeatureToggles + } + return nil } var File_pkg_proto_feature_proto protoreflect.FileDescriptor @@ -120,22 +184,32 @@ var File_pkg_proto_feature_proto protoreflect.FileDescriptor var file_pkg_proto_feature_proto_rawDesc = []byte{ 0x0a, 0x17, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x66, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x42, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x62, 0x0a, - 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, - 0x1c, 0x2e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, - 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x30, - 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x66, 0x6c, 0x6f, 0x68, 0x61, 0x6e, 0x73, 0x65, 0x6e, 0x2f, 0x64, 0x61, 0x73, 0x68, 0x65, 0x72, - 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x72, 0x65, 0x22, 0x50, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x6f, 0x67, + 0x67, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4e, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, + 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x22, 0x55, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0e, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x52, 0x0e, 0x66, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x73, 0x32, 0x6e, 0x0a, 0x13, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x57, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x2e, + 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x2e, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x6f, 0x67, + 0x67, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x30, 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x6f, 0x68, 0x61, 0x6e, + 0x73, 0x65, 0x6e, 0x2f, 0x64, 0x61, 0x73, 0x68, 0x65, 0x72, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -150,19 +224,21 @@ func file_pkg_proto_feature_proto_rawDescGZIP() []byte { return file_pkg_proto_feature_proto_rawDescData } -var file_pkg_proto_feature_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_pkg_proto_feature_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_pkg_proto_feature_proto_goTypes = []interface{}{ - (*Feature)(nil), // 0: feature.Feature - (*FeatureSubscription)(nil), // 1: feature.FeatureSubscription + (*FeatureToggle)(nil), // 0: feature.FeatureToggle + (*FeatureToggleChange)(nil), // 1: feature.FeatureToggleChange + (*FeatureSubscription)(nil), // 2: feature.FeatureSubscription } var file_pkg_proto_feature_proto_depIdxs = []int32{ - 1, // 0: feature.FeatureStateService.SubscribeFeatureChanges:input_type -> feature.FeatureSubscription - 0, // 1: feature.FeatureStateService.SubscribeFeatureChanges:output_type -> feature.Feature - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: feature.FeatureSubscription.featureToggles:type_name -> feature.FeatureToggle + 2, // 1: feature.FeatureStateService.SubscribeFeatureChanges:input_type -> feature.FeatureSubscription + 1, // 2: feature.FeatureStateService.SubscribeFeatureChanges:output_type -> feature.FeatureToggleChange + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_pkg_proto_feature_proto_init() } @@ -172,7 +248,7 @@ func file_pkg_proto_feature_proto_init() { } if !protoimpl.UnsafeEnabled { file_pkg_proto_feature_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Feature); i { + switch v := v.(*FeatureToggle); i { case 0: return &v.state case 1: @@ -184,6 +260,18 @@ func file_pkg_proto_feature_proto_init() { } } file_pkg_proto_feature_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FeatureToggleChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_proto_feature_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FeatureSubscription); i { case 0: return &v.state @@ -202,7 +290,7 @@ func file_pkg_proto_feature_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_proto_feature_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 3, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/proto/feature.proto b/pkg/proto/feature.proto index 362b961..0a68f57 100644 --- a/pkg/proto/feature.proto +++ b/pkg/proto/feature.proto @@ -6,14 +6,21 @@ package feature; // Service for subscribing to toggle changes service FeatureStateService { - rpc SubscribeFeatureChanges(FeatureSubscription) returns (stream Feature); + rpc SubscribeFeatureChanges(FeatureSubscription) returns (stream FeatureToggleChange); +} + +message FeatureToggle { + string feature_id = 1; + string description = 2; } // Main message for feature toggle states -message Feature { +message FeatureToggleChange { string feature_id = 1; bool enabled = 2; } // Empty message for subscription request -message FeatureSubscription {} \ No newline at end of file +message FeatureSubscription { + repeated FeatureToggle featureToggles = 1; +} \ No newline at end of file diff --git a/pkg/proto/feature_grpc.pb.go b/pkg/proto/feature_grpc.pb.go index 072d512..d58c877 100644 --- a/pkg/proto/feature_grpc.pb.go +++ b/pkg/proto/feature_grpc.pb.go @@ -49,7 +49,7 @@ func (c *featureStateServiceClient) SubscribeFeatureChanges(ctx context.Context, } type FeatureStateService_SubscribeFeatureChangesClient interface { - Recv() (*Feature, error) + Recv() (*FeatureToggleChange, error) grpc.ClientStream } @@ -57,8 +57,8 @@ type featureStateServiceSubscribeFeatureChangesClient struct { grpc.ClientStream } -func (x *featureStateServiceSubscribeFeatureChangesClient) Recv() (*Feature, error) { - m := new(Feature) +func (x *featureStateServiceSubscribeFeatureChangesClient) Recv() (*FeatureToggleChange, error) { + m := new(FeatureToggleChange) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -102,7 +102,7 @@ func _FeatureStateService_SubscribeFeatureChanges_Handler(srv interface{}, strea } type FeatureStateService_SubscribeFeatureChangesServer interface { - Send(*Feature) error + Send(*FeatureToggleChange) error grpc.ServerStream } @@ -110,7 +110,7 @@ type featureStateServiceSubscribeFeatureChangesServer struct { grpc.ServerStream } -func (x *featureStateServiceSubscribeFeatureChangesServer) Send(m *Feature) error { +func (x *featureStateServiceSubscribeFeatureChangesServer) Send(m *FeatureToggleChange) error { return x.ServerStream.SendMsg(m) }