diff --git a/cmd/client/main.go b/cmd/client/main.go index 139e92a..50b46cb 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -6,18 +6,18 @@ import ( "net/http" "github.com/bufbuild/connect-go" - featuresheetv1 "github.com/stillmatic/featuresheet/gen/featuresheet/v1" - "github.com/stillmatic/featuresheet/gen/featuresheet/v1/featuresheetv1connect" + flagsheetv1 "github.com/stillmatic/flagsheet/gen/flagsheet/v1" + "github.com/stillmatic/flagsheet/gen/flagsheet/v1/flagsheetv1connect" ) func main() { - client := featuresheetv1connect.NewFeatureSheetServiceClient( + client := flagsheetv1connect.NewFlagSheetServiceClient( http.DefaultClient, "http://localhost:8080", ) res, err := client.Evaluate( context.Background(), - connect.NewRequest(&featuresheetv1.EvaluateRequest{ + connect.NewRequest(&flagsheetv1.EvaluateRequest{ Feature: "my_key", EntityId: "my_id", }), diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index f14136a..be046dd 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -10,8 +10,8 @@ import ( "github.com/bufbuild/connect-go" - fsv1 "github.com/stillmatic/featuresheet/gen/featuresheet/v1" - "github.com/stillmatic/featuresheet/gen/featuresheet/v1/featuresheetv1connect" + fsv1 "github.com/stillmatic/flagsheet/gen/flagsheet/v1" + "github.com/stillmatic/flagsheet/gen/flagsheet/v1/flagsheetv1connect" ) var ( @@ -20,7 +20,7 @@ var ( ) func main() { - client := featuresheetv1connect.NewFeatureSheetServiceClient( + client := flagsheetv1connect.NewFlagSheetServiceClient( http.DefaultClient, "http://localhost:8080", ) diff --git a/cmd/server/main.go b/cmd/server/main.go index 0089d3e..826e1ab 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -14,21 +14,21 @@ import ( "gopkg.in/Iwark/spreadsheet.v2" grpchealth "github.com/bufbuild/connect-grpchealth-go" - "github.com/stillmatic/featuresheet" - fsv1 "github.com/stillmatic/featuresheet/gen/featuresheet/v1" - "github.com/stillmatic/featuresheet/gen/featuresheet/v1/featuresheetv1connect" + "github.com/stillmatic/flagsheet" + fsv1 "github.com/stillmatic/flagsheet/gen/flagsheet/v1" + "github.com/stillmatic/flagsheet/gen/flagsheet/v1/flagsheetv1connect" ) const ( - featureSheetVersionKey = "FeatureSheet-Version" - featureSheetVersionValue = "v1" + flagSheetVersionKey = "FlagSheet-Version" + flagSheetVersionValue = "v1" ) -type FeatureSheetServer struct { - fs *featuresheet.FeatureSheet +type FlagSheetServer struct { + fs *flagsheet.FlagSheet } -func (s *FeatureSheetServer) Evaluate( +func (s *FlagSheetServer) Evaluate( ctx context.Context, req *connect.Request[fsv1.EvaluateRequest], ) (*connect.Response[fsv1.EvaluateResponse], error) { @@ -42,7 +42,7 @@ func (s *FeatureSheetServer) Evaluate( res := connect.NewResponse(&fsv1.EvaluateResponse{ Variant: string(fv), }) - res.Header().Set(featureSheetVersionKey, featureSheetVersionValue) + res.Header().Set(flagSheetVersionKey, flagSheetVersionValue) return res, nil } @@ -80,20 +80,20 @@ func main() { client := conf.Client(context.Background()) service := spreadsheet.NewServiceWithClient(client) - fs, err := featuresheet.NewFeatureSheet(service, spreadsheetID, 10*time.Second) + fs, err := flagsheet.NewFlagSheet(service, spreadsheetID, 10*time.Second) if err != nil { panic(err) } // serving - s := &FeatureSheetServer{ + s := &FlagSheetServer{ fs: fs, } mux := http.NewServeMux() - path, handler := featuresheetv1connect.NewFeatureSheetServiceHandler(s) + path, handler := flagsheetv1connect.NewFlagSheetServiceHandler(s) mux.Handle(path, handler) checker := grpchealth.NewStaticChecker( - "featuresheet.v1.FeatureSheetService", + "flagsheet.v1.FlagSheetService", ) mux.Handle(grpchealth.NewHandler(checker)) mux.Handle("/health", http.HandlerFunc(ok)) diff --git a/featuresheet.go b/featuresheet.go index 7cdc47f..2275ff6 100644 --- a/featuresheet.go +++ b/featuresheet.go @@ -1,4 +1,4 @@ -package featuresheet +package flagsheet import ( "bytes" @@ -49,8 +49,8 @@ type Layer struct { cnt int } -// featureSheet is an internal representation for goroutine purposes. -type featureSheet struct { +// flagSheet is an internal representation for goroutine purposes. +type flagSheet struct { sheetID string service *spreadsheet.Service expiration time.Duration @@ -61,13 +61,13 @@ type featureSheet struct { fmap map[string]Feature } -type FeatureSheet struct { - *featureSheet +type FlagSheet struct { + *flagSheet } // Evaluate returns the feature variant for a given flagName and id // if the feature does not exist, it returns an empty string and false -func (f *featureSheet) Evaluate(key string, id *string) (FeatureValue, error) { +func (f *flagSheet) Evaluate(key string, id *string) (FeatureValue, error) { feature, ok := f.fmap[key] if !ok { return "", fmt.Errorf("feature %s not found", key) @@ -100,7 +100,7 @@ func (f *featureSheet) Evaluate(key string, id *string) (FeatureValue, error) { return fv, nil } -func (f *featureSheet) Refresh() error { +func (f *flagSheet) Refresh() error { // get spreadsheet spreadsheet, err := f.service.FetchSpreadsheet(f.sheetID) if err != nil { @@ -188,7 +188,7 @@ type janitor struct { stop chan bool } -func (j *janitor) Run(c *featureSheet) { +func (j *janitor) Run(c *flagSheet) { ticker := time.NewTicker(j.Interval) for { select { @@ -204,11 +204,11 @@ func (j *janitor) Run(c *featureSheet) { } } -func stopJanitor(c *FeatureSheet) { +func stopJanitor(c *FlagSheet) { c.janitor.stop <- true } -func runJanitor(c *featureSheet, ci time.Duration) { +func runJanitor(c *flagSheet, ci time.Duration) { j := &janitor{ Interval: ci, stop: make(chan bool), @@ -217,8 +217,8 @@ func runJanitor(c *featureSheet, ci time.Duration) { go j.Run(c) } -func NewFeatureSheet(service *spreadsheet.Service, sheetID string, duration time.Duration) (*FeatureSheet, error) { - fs := &featureSheet{ +func NewFlagSheet(service *spreadsheet.Service, sheetID string, duration time.Duration) (*FlagSheet, error) { + fs := &flagSheet{ sheetID: sheetID, service: service, expiration: duration, @@ -226,7 +226,7 @@ func NewFeatureSheet(service *spreadsheet.Service, sheetID string, duration time if err := fs.Refresh(); err != nil { return nil, err } - FS := &FeatureSheet{fs} + FS := &FlagSheet{fs} if duration > 0 { runJanitor(fs, duration) runtime.SetFinalizer(FS, stopJanitor) diff --git a/featuresheet_test.go b/featuresheet_test.go index 4857254..5a0535f 100644 --- a/featuresheet_test.go +++ b/featuresheet_test.go @@ -1,4 +1,4 @@ -package featuresheet_test +package flagsheet_test import ( "context" @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/stillmatic/featuresheet" + "github.com/stillmatic/flagsheet" "github.com/stretchr/testify/assert" "golang.org/x/oauth2/google" "gopkg.in/Iwark/spreadsheet.v2" @@ -27,7 +27,7 @@ func TestSheet(t *testing.T) { client := conf.Client(context.TODO()) service := spreadsheet.NewServiceWithClient(client) - spreadsheet, err := featuresheet.NewFeatureSheet(service, testSpreadsheetID, 1*time.Second) + spreadsheet, err := flagsheet.NewFlagSheet(service, testSpreadsheetID, 1*time.Second) assert.NoError(t, err) assert.NotNil(t, spreadsheet) fv, err := spreadsheet.Evaluate("my_key", stringPtr("my_id")) @@ -45,7 +45,7 @@ func BenchmarkEvaluate(b *testing.B) { client := conf.Client(context.TODO()) service := spreadsheet.NewServiceWithClient(client) - spreadsheet, err := featuresheet.NewFeatureSheet(service, testSpreadsheetID, 1*time.Second) + spreadsheet, err := flagsheet.NewFlagSheet(service, testSpreadsheetID, 1*time.Second) assert.NoError(b, err) assert.NotNil(b, spreadsheet) b.ResetTimer() diff --git a/featuresheet/v1/featuresheet.proto b/flagsheet/v1/flagsheet.proto similarity index 59% rename from featuresheet/v1/featuresheet.proto rename to flagsheet/v1/flagsheet.proto index a030e49..db9c7de 100644 --- a/featuresheet/v1/featuresheet.proto +++ b/flagsheet/v1/flagsheet.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package featuresheet.v1; +package flagsheet.v1; -option go_package = "github.com/stillmatic/featuresheet/gen/featuresheet/v1;featuresheetv1"; +option go_package = "github.com/stillmatic/flagsheet/gen/flagsheet/v1;flagsheetv1"; message EvaluateRequest { string feature = 1; @@ -13,6 +13,6 @@ message EvaluateResponse { string variant = 1; } -service FeatureSheetService { +service FlagSheetService { rpc Evaluate(EvaluateRequest) returns (EvaluateResponse); } diff --git a/gen/featuresheet/v1/featuresheet.pb.go b/gen/featuresheet/v1/featuresheet.pb.go deleted file mode 100644 index 133d0cf..0000000 --- a/gen/featuresheet/v1/featuresheet.pb.go +++ /dev/null @@ -1,229 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: featuresheet/v1/featuresheet.proto - -package featuresheetv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type EvaluateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Feature string `protobuf:"bytes,1,opt,name=feature,proto3" json:"feature,omitempty"` - EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` -} - -func (x *EvaluateRequest) Reset() { - *x = EvaluateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_featuresheet_v1_featuresheet_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EvaluateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EvaluateRequest) ProtoMessage() {} - -func (x *EvaluateRequest) ProtoReflect() protoreflect.Message { - mi := &file_featuresheet_v1_featuresheet_proto_msgTypes[0] - 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 EvaluateRequest.ProtoReflect.Descriptor instead. -func (*EvaluateRequest) Descriptor() ([]byte, []int) { - return file_featuresheet_v1_featuresheet_proto_rawDescGZIP(), []int{0} -} - -func (x *EvaluateRequest) GetFeature() string { - if x != nil { - return x.Feature - } - return "" -} - -func (x *EvaluateRequest) GetEntityId() string { - if x != nil { - return x.EntityId - } - return "" -} - -type EvaluateResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Variant string `protobuf:"bytes,1,opt,name=variant,proto3" json:"variant,omitempty"` -} - -func (x *EvaluateResponse) Reset() { - *x = EvaluateResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_featuresheet_v1_featuresheet_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EvaluateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EvaluateResponse) ProtoMessage() {} - -func (x *EvaluateResponse) ProtoReflect() protoreflect.Message { - mi := &file_featuresheet_v1_featuresheet_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 EvaluateResponse.ProtoReflect.Descriptor instead. -func (*EvaluateResponse) Descriptor() ([]byte, []int) { - return file_featuresheet_v1_featuresheet_proto_rawDescGZIP(), []int{1} -} - -func (x *EvaluateResponse) GetVariant() string { - if x != nil { - return x.Variant - } - return "" -} - -var File_featuresheet_v1_featuresheet_proto protoreflect.FileDescriptor - -var file_featuresheet_v1_featuresheet_proto_rawDesc = []byte{ - 0x0a, 0x22, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2f, 0x76, - 0x31, 0x2f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x48, 0x0a, 0x0f, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x22, - 0x2c, 0x0a, 0x10, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x32, 0x66, 0x0a, - 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x68, 0x65, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x08, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, - 0x12, 0x20, 0x2e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x2f, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, - 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_featuresheet_v1_featuresheet_proto_rawDescOnce sync.Once - file_featuresheet_v1_featuresheet_proto_rawDescData = file_featuresheet_v1_featuresheet_proto_rawDesc -) - -func file_featuresheet_v1_featuresheet_proto_rawDescGZIP() []byte { - file_featuresheet_v1_featuresheet_proto_rawDescOnce.Do(func() { - file_featuresheet_v1_featuresheet_proto_rawDescData = protoimpl.X.CompressGZIP(file_featuresheet_v1_featuresheet_proto_rawDescData) - }) - return file_featuresheet_v1_featuresheet_proto_rawDescData -} - -var file_featuresheet_v1_featuresheet_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_featuresheet_v1_featuresheet_proto_goTypes = []interface{}{ - (*EvaluateRequest)(nil), // 0: featuresheet.v1.EvaluateRequest - (*EvaluateResponse)(nil), // 1: featuresheet.v1.EvaluateResponse -} -var file_featuresheet_v1_featuresheet_proto_depIdxs = []int32{ - 0, // 0: featuresheet.v1.FeatureSheetService.Evaluate:input_type -> featuresheet.v1.EvaluateRequest - 1, // 1: featuresheet.v1.FeatureSheetService.Evaluate:output_type -> featuresheet.v1.EvaluateResponse - 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 -} - -func init() { file_featuresheet_v1_featuresheet_proto_init() } -func file_featuresheet_v1_featuresheet_proto_init() { - if File_featuresheet_v1_featuresheet_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_featuresheet_v1_featuresheet_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EvaluateRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_featuresheet_v1_featuresheet_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EvaluateResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_featuresheet_v1_featuresheet_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_featuresheet_v1_featuresheet_proto_goTypes, - DependencyIndexes: file_featuresheet_v1_featuresheet_proto_depIdxs, - MessageInfos: file_featuresheet_v1_featuresheet_proto_msgTypes, - }.Build() - File_featuresheet_v1_featuresheet_proto = out.File - file_featuresheet_v1_featuresheet_proto_rawDesc = nil - file_featuresheet_v1_featuresheet_proto_goTypes = nil - file_featuresheet_v1_featuresheet_proto_depIdxs = nil -} diff --git a/gen/featuresheet/v1/featuresheetv1connect/featuresheet.connect.go b/gen/featuresheet/v1/featuresheetv1connect/featuresheet.connect.go deleted file mode 100644 index 77225a1..0000000 --- a/gen/featuresheet/v1/featuresheetv1connect/featuresheet.connect.go +++ /dev/null @@ -1,100 +0,0 @@ -// Code generated by protoc-gen-connect-go. DO NOT EDIT. -// -// Source: featuresheet/v1/featuresheet.proto - -package featuresheetv1connect - -import ( - context "context" - errors "errors" - connect_go "github.com/bufbuild/connect-go" - v1 "github.com/stillmatic/featuresheet/gen/featuresheet/v1" - http "net/http" - strings "strings" -) - -// This is a compile-time assertion to ensure that this generated file and the connect package are -// compatible. If you get a compiler error that this constant is not defined, this code was -// generated with a version of connect newer than the one compiled into your binary. You can fix the -// problem by either regenerating this code with an older version of connect or updating the connect -// version compiled into your binary. -const _ = connect_go.IsAtLeastVersion0_1_0 - -const ( - // FeatureSheetServiceName is the fully-qualified name of the FeatureSheetService service. - FeatureSheetServiceName = "featuresheet.v1.FeatureSheetService" -) - -// These constants are the fully-qualified names of the RPCs defined in this package. They're -// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. -// -// Note that these are different from the fully-qualified method names used by -// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to -// reflection-formatted method names, remove the leading slash and convert the remaining slash to a -// period. -const ( - // FeatureSheetServiceEvaluateProcedure is the fully-qualified name of the FeatureSheetService's - // Evaluate RPC. - FeatureSheetServiceEvaluateProcedure = "/featuresheet.v1.FeatureSheetService/Evaluate" -) - -// FeatureSheetServiceClient is a client for the featuresheet.v1.FeatureSheetService service. -type FeatureSheetServiceClient interface { - Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) -} - -// NewFeatureSheetServiceClient constructs a client for the featuresheet.v1.FeatureSheetService -// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for -// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply -// the connect.WithGRPC() or connect.WithGRPCWeb() options. -// -// The URL supplied here should be the base URL for the Connect or gRPC server (for example, -// http://api.acme.com or https://acme.com/grpc). -func NewFeatureSheetServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) FeatureSheetServiceClient { - baseURL = strings.TrimRight(baseURL, "/") - return &featureSheetServiceClient{ - evaluate: connect_go.NewClient[v1.EvaluateRequest, v1.EvaluateResponse]( - httpClient, - baseURL+FeatureSheetServiceEvaluateProcedure, - opts..., - ), - } -} - -// featureSheetServiceClient implements FeatureSheetServiceClient. -type featureSheetServiceClient struct { - evaluate *connect_go.Client[v1.EvaluateRequest, v1.EvaluateResponse] -} - -// Evaluate calls featuresheet.v1.FeatureSheetService.Evaluate. -func (c *featureSheetServiceClient) Evaluate(ctx context.Context, req *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) { - return c.evaluate.CallUnary(ctx, req) -} - -// FeatureSheetServiceHandler is an implementation of the featuresheet.v1.FeatureSheetService -// service. -type FeatureSheetServiceHandler interface { - Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) -} - -// NewFeatureSheetServiceHandler builds an HTTP handler from the service implementation. It returns -// the path on which to mount the handler and the handler itself. -// -// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf -// and JSON codecs. They also support gzip compression. -func NewFeatureSheetServiceHandler(svc FeatureSheetServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { - mux := http.NewServeMux() - mux.Handle(FeatureSheetServiceEvaluateProcedure, connect_go.NewUnaryHandler( - FeatureSheetServiceEvaluateProcedure, - svc.Evaluate, - opts..., - )) - return "/featuresheet.v1.FeatureSheetService/", mux -} - -// UnimplementedFeatureSheetServiceHandler returns CodeUnimplemented from all methods. -type UnimplementedFeatureSheetServiceHandler struct{} - -func (UnimplementedFeatureSheetServiceHandler) Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("featuresheet.v1.FeatureSheetService.Evaluate is not implemented")) -} diff --git a/gen/flagsheet/v1/flagsheet.pb.go b/gen/flagsheet/v1/flagsheet.pb.go new file mode 100644 index 0000000..7fb2fbe --- /dev/null +++ b/gen/flagsheet/v1/flagsheet.pb.go @@ -0,0 +1,227 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: flagsheet/v1/flagsheet.proto + +package flagsheetv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type EvaluateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Feature string `protobuf:"bytes,1,opt,name=feature,proto3" json:"feature,omitempty"` + EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` +} + +func (x *EvaluateRequest) Reset() { + *x = EvaluateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_flagsheet_v1_flagsheet_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EvaluateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvaluateRequest) ProtoMessage() {} + +func (x *EvaluateRequest) ProtoReflect() protoreflect.Message { + mi := &file_flagsheet_v1_flagsheet_proto_msgTypes[0] + 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 EvaluateRequest.ProtoReflect.Descriptor instead. +func (*EvaluateRequest) Descriptor() ([]byte, []int) { + return file_flagsheet_v1_flagsheet_proto_rawDescGZIP(), []int{0} +} + +func (x *EvaluateRequest) GetFeature() string { + if x != nil { + return x.Feature + } + return "" +} + +func (x *EvaluateRequest) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +type EvaluateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Variant string `protobuf:"bytes,1,opt,name=variant,proto3" json:"variant,omitempty"` +} + +func (x *EvaluateResponse) Reset() { + *x = EvaluateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_flagsheet_v1_flagsheet_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EvaluateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvaluateResponse) ProtoMessage() {} + +func (x *EvaluateResponse) ProtoReflect() protoreflect.Message { + mi := &file_flagsheet_v1_flagsheet_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 EvaluateResponse.ProtoReflect.Descriptor instead. +func (*EvaluateResponse) Descriptor() ([]byte, []int) { + return file_flagsheet_v1_flagsheet_proto_rawDescGZIP(), []int{1} +} + +func (x *EvaluateResponse) GetVariant() string { + if x != nil { + return x.Variant + } + return "" +} + +var File_flagsheet_v1_flagsheet_proto protoreflect.FileDescriptor + +var file_flagsheet_v1_flagsheet_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, + 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x48, 0x0a, 0x0f, + 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x22, 0x2c, 0x0a, 0x10, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x61, 0x72, + 0x69, 0x61, 0x6e, 0x74, 0x32, 0x5d, 0x0a, 0x10, 0x46, 0x6c, 0x61, 0x67, 0x53, 0x68, 0x65, 0x65, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x45, 0x76, 0x61, 0x6c, + 0x75, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x2f, 0x66, 0x6c, 0x61, + 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x65, 0x65, + 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_flagsheet_v1_flagsheet_proto_rawDescOnce sync.Once + file_flagsheet_v1_flagsheet_proto_rawDescData = file_flagsheet_v1_flagsheet_proto_rawDesc +) + +func file_flagsheet_v1_flagsheet_proto_rawDescGZIP() []byte { + file_flagsheet_v1_flagsheet_proto_rawDescOnce.Do(func() { + file_flagsheet_v1_flagsheet_proto_rawDescData = protoimpl.X.CompressGZIP(file_flagsheet_v1_flagsheet_proto_rawDescData) + }) + return file_flagsheet_v1_flagsheet_proto_rawDescData +} + +var file_flagsheet_v1_flagsheet_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_flagsheet_v1_flagsheet_proto_goTypes = []interface{}{ + (*EvaluateRequest)(nil), // 0: flagsheet.v1.EvaluateRequest + (*EvaluateResponse)(nil), // 1: flagsheet.v1.EvaluateResponse +} +var file_flagsheet_v1_flagsheet_proto_depIdxs = []int32{ + 0, // 0: flagsheet.v1.FlagSheetService.Evaluate:input_type -> flagsheet.v1.EvaluateRequest + 1, // 1: flagsheet.v1.FlagSheetService.Evaluate:output_type -> flagsheet.v1.EvaluateResponse + 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 +} + +func init() { file_flagsheet_v1_flagsheet_proto_init() } +func file_flagsheet_v1_flagsheet_proto_init() { + if File_flagsheet_v1_flagsheet_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_flagsheet_v1_flagsheet_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EvaluateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_flagsheet_v1_flagsheet_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EvaluateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_flagsheet_v1_flagsheet_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_flagsheet_v1_flagsheet_proto_goTypes, + DependencyIndexes: file_flagsheet_v1_flagsheet_proto_depIdxs, + MessageInfos: file_flagsheet_v1_flagsheet_proto_msgTypes, + }.Build() + File_flagsheet_v1_flagsheet_proto = out.File + file_flagsheet_v1_flagsheet_proto_rawDesc = nil + file_flagsheet_v1_flagsheet_proto_goTypes = nil + file_flagsheet_v1_flagsheet_proto_depIdxs = nil +} diff --git a/gen/flagsheet/v1/flagsheetv1connect/flagsheet.connect.go b/gen/flagsheet/v1/flagsheetv1connect/flagsheet.connect.go new file mode 100644 index 0000000..0ea2e3f --- /dev/null +++ b/gen/flagsheet/v1/flagsheetv1connect/flagsheet.connect.go @@ -0,0 +1,99 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: flagsheet/v1/flagsheet.proto + +package flagsheetv1connect + +import ( + context "context" + errors "errors" + connect_go "github.com/bufbuild/connect-go" + v1 "github.com/stillmatic/flagsheet/gen/flagsheet/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect_go.IsAtLeastVersion0_1_0 + +const ( + // FlagSheetServiceName is the fully-qualified name of the FlagSheetService service. + FlagSheetServiceName = "flagsheet.v1.FlagSheetService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // FlagSheetServiceEvaluateProcedure is the fully-qualified name of the FlagSheetService's Evaluate + // RPC. + FlagSheetServiceEvaluateProcedure = "/flagsheet.v1.FlagSheetService/Evaluate" +) + +// FlagSheetServiceClient is a client for the flagsheet.v1.FlagSheetService service. +type FlagSheetServiceClient interface { + Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) +} + +// NewFlagSheetServiceClient constructs a client for the flagsheet.v1.FlagSheetService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewFlagSheetServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) FlagSheetServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + return &flagSheetServiceClient{ + evaluate: connect_go.NewClient[v1.EvaluateRequest, v1.EvaluateResponse]( + httpClient, + baseURL+FlagSheetServiceEvaluateProcedure, + opts..., + ), + } +} + +// flagSheetServiceClient implements FlagSheetServiceClient. +type flagSheetServiceClient struct { + evaluate *connect_go.Client[v1.EvaluateRequest, v1.EvaluateResponse] +} + +// Evaluate calls flagsheet.v1.FlagSheetService.Evaluate. +func (c *flagSheetServiceClient) Evaluate(ctx context.Context, req *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) { + return c.evaluate.CallUnary(ctx, req) +} + +// FlagSheetServiceHandler is an implementation of the flagsheet.v1.FlagSheetService service. +type FlagSheetServiceHandler interface { + Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) +} + +// NewFlagSheetServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewFlagSheetServiceHandler(svc FlagSheetServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { + mux := http.NewServeMux() + mux.Handle(FlagSheetServiceEvaluateProcedure, connect_go.NewUnaryHandler( + FlagSheetServiceEvaluateProcedure, + svc.Evaluate, + opts..., + )) + return "/flagsheet.v1.FlagSheetService/", mux +} + +// UnimplementedFlagSheetServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedFlagSheetServiceHandler struct{} + +func (UnimplementedFlagSheetServiceHandler) Evaluate(context.Context, *connect_go.Request[v1.EvaluateRequest]) (*connect_go.Response[v1.EvaluateResponse], error) { + return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("flagsheet.v1.FlagSheetService.Evaluate is not implemented")) +} diff --git a/go.mod b/go.mod index bb5231d..400983b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/stillmatic/featuresheet +module github.com/stillmatic/flagsheet go 1.20 diff --git a/readme.md b/readme.md index a671e18..a5c089f 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# FeatureSheet +# FlagSheet The easiest way to do feature flagging - just use Google sheets! @@ -78,11 +78,11 @@ client := conf.Client(context.TODO()) service := spreadsheet.NewServiceWithClient(client) ``` -Instantiate a FeatureSheet client: +Instantiate a FlagSheet client: ```go spreadsheetID := "15_oV5NcvYK7wK3VVD5ol6KVkWHzPLFl22c1QyLYplpU" -fs, err := featuresheet.NewFeatureSheet(service, spreadsheetID, 1*time.Second) +fs, err := flagsheet.NewFlagSheet(service, spreadsheetID, 1*time.Second) assert.NoError(t, err) assert.NotNil(t, spreadsheet) fv, ok := fs.Get("custom_backend")