From d0a25e3ab2db53ba9a5cf21915a1fbc586a5800e Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 22 Sep 2023 08:15:18 +0800 Subject: [PATCH] chore: add feature matrix --- api/v2/v2.go | 2 +- api/v2/workspace_service.go | 17 ++++++++++++----- server/server.go | 6 +++++- server/service/license/feature_matrix.go | 21 +++++++++++++++++++++ server/service/license/license.go | 19 ++++++++++++++----- 5 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 server/service/license/feature_matrix.go diff --git a/api/v2/v2.go b/api/v2/v2.go index b0b2b3c..5c8ae77 100644 --- a/api/v2/v2.go +++ b/api/v2/v2.go @@ -34,7 +34,7 @@ func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store ), ) apiv2pb.RegisterSubscriptionServiceServer(grpcServer, NewSubscriptionService(profile, store, licenseService)) - apiv2pb.RegisterWorkspaceServiceServer(grpcServer, NewWorkspaceService(profile, store)) + apiv2pb.RegisterWorkspaceServiceServer(grpcServer, NewWorkspaceService(profile, store, licenseService)) apiv2pb.RegisterUserServiceServer(grpcServer, NewUserService(secret, store)) apiv2pb.RegisterUserSettingServiceServer(grpcServer, NewUserSettingService(store)) apiv2pb.RegisterShortcutServiceServer(grpcServer, NewShortcutService(secret, store)) diff --git a/api/v2/workspace_service.go b/api/v2/workspace_service.go index 2f4c9b2..4e60e41 100644 --- a/api/v2/workspace_service.go +++ b/api/v2/workspace_service.go @@ -6,6 +6,7 @@ import ( apiv2pb "github.com/boojack/slash/proto/gen/api/v2" storepb "github.com/boojack/slash/proto/gen/store" "github.com/boojack/slash/server/profile" + "github.com/boojack/slash/server/service/license" "github.com/boojack/slash/store" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -14,15 +15,17 @@ import ( type WorkspaceService struct { apiv2pb.UnimplementedWorkspaceServiceServer - Profile *profile.Profile - Store *store.Store + Profile *profile.Profile + Store *store.Store + LicenseService *license.LicenseService } // NewWorkspaceService creates a new WorkspaceService. -func NewWorkspaceService(profile *profile.Profile, store *store.Store) *WorkspaceService { +func NewWorkspaceService(profile *profile.Profile, store *store.Store, licenseService *license.LicenseService) *WorkspaceService { return &WorkspaceService{ - Profile: profile, - Store: store, + Profile: profile, + Store: store, + LicenseService: licenseService, } } @@ -117,6 +120,10 @@ func (s *WorkspaceService) UpdateWorkspaceSetting(ctx context.Context, request * return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err) } } else if path == "custom_style" { + if !s.LicenseService.IsFeatureEnabled(license.FeatureTypeCustomeStyle) { + return nil, status.Errorf(codes.PermissionDenied, "feature custom style is not available") + } + if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{ Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE, Value: &storepb.WorkspaceSetting_CustomStyle{ diff --git a/server/server.go b/server/server.go index be246fd..1215fbf 100644 --- a/server/server.go +++ b/server/server.go @@ -112,7 +112,11 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store return s, nil } -func (s *Server) Start(_ context.Context) error { +func (s *Server) Start(ctx context.Context) error { + // Load subscription. + if _, err := s.licenseService.LoadSubscription(ctx); err != nil { + println("failed to load subscription", err) + } // Start gRPC server. listen, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Profile.Port+1)) if err != nil { diff --git a/server/service/license/feature_matrix.go b/server/service/license/feature_matrix.go new file mode 100644 index 0000000..ab01d1e --- /dev/null +++ b/server/service/license/feature_matrix.go @@ -0,0 +1,21 @@ +package license + +type FeatureType string + +const ( + // Accounts. + + // FeatureTypeUnlimitedAccounts allows the user to create unlimited accounts. + FeatureTypeUnlimitedAccounts FeatureType = "unlimited_accounts" + + // Customization. + + // FeatureTypeCustomStyle allows the user to customize the style. + FeatureTypeCustomeStyle FeatureType = "custom_style" +) + +// FeatureMatrix is a matrix of features in [Free, Pro]. +var FeatureMatrix = map[FeatureType][2]bool{ + FeatureTypeUnlimitedAccounts: {false, true}, + FeatureTypeCustomeStyle: {false, true}, +} diff --git a/server/service/license/license.go b/server/service/license/license.go index 7d82881..ba78577 100644 --- a/server/service/license/license.go +++ b/server/service/license/license.go @@ -13,9 +13,10 @@ import ( ) type LicenseService struct { - Profile *profile.Profile - Store *store.Store - CachedSubscription *apiv2pb.Subscription + Profile *profile.Profile + Store *store.Store + + cachedSubscription *apiv2pb.Subscription } // NewLicenseService creates a new LicenseService. @@ -23,7 +24,7 @@ func NewLicenseService(profile *profile.Profile, store *store.Store) *LicenseSer return &LicenseService{ Profile: profile, Store: store, - CachedSubscription: &apiv2pb.Subscription{ + cachedSubscription: &apiv2pb.Subscription{ Plan: apiv2pb.PlanType_FREE, }, } @@ -66,7 +67,7 @@ func (s *LicenseService) LoadSubscription(ctx context.Context) (*apiv2pb.Subscri } subscription.StartedTime = timestamppb.New(startedTime) } - s.CachedSubscription = subscription + s.cachedSubscription = subscription return subscription, nil } @@ -92,3 +93,11 @@ func (s *LicenseService) UpdateSubscription(ctx context.Context, licenseKey stri } return s.LoadSubscription(ctx) } + +func (s *LicenseService) IsFeatureEnabled(feature FeatureType) bool { + matrix, ok := FeatureMatrix[feature] + if !ok { + return false + } + return matrix[s.cachedSubscription.Plan-1] +}