Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TT-10623 Adds gRPC support for Tyk and MDCB to replace goRPC #6463

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

lonelycode
Copy link
Member

@lonelycode lonelycode commented Aug 15, 2024

User description

Description

See the internal PR for details on why this exists

Related Issue

This is PoC

Motivation and Context

See the other PR

How This Has Been Tested

Manual

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required
  • I would like a code coverage CI quality gate exception and have explained why

PR Type

Enhancement


Description

  • Added gRPC client and server implementation in dispatcher/handler_grpc.pb.go.
  • Implemented GPCStorageHandler for gRPC-based storage handling in gateway/grpc_storage_handler.go.
  • Added dynamic handler selection for RPC and gRPC in gateway/rpc_storage_handler.go.
  • Abstracted RPC client with dynamic handler selection in rpc/rpc_client.go.
  • Updated server setup to support gRPC as an RPC backend in gateway/server.go.
  • Implemented GRPCConnectionHandler in rpc/grpcHandler.go.
  • Updated analytics purger for dynamic RPC handler in rpc/rpc_analytics_purger.go.
  • Updated tests and test utilities for dynamic RPC handler in rpc/rpc_client_test.go and gateway/testutil.go.
  • Fixed syntax issues in various test cases and request handling.
  • Added configuration options for gRPC support in config/config.go.

Changes walkthrough 📝

Relevant files
Enhancement
10 files
handler_grpc.pb.go
Add gRPC client and server implementation                               

dispatcher/handler_grpc.pb.go

  • Added gRPC client and server code generated by protoc-gen-go-grpc.
  • Defined HandlerClient and HandlerServer interfaces.
  • Implemented gRPC methods for various operations like Login, GetKey,
    SetKey, etc.
  • +996/-0 
    grpc_storage_handler.go
    Implement gRPC-based storage handler                                         

    gateway/grpc_storage_handler.go

  • Introduced GPCStorageHandler for gRPC-based storage handling.
  • Implemented methods for connecting, login, and various key operations.
  • Added custom JSON codec for gRPC communication.
  • +862/-0 
    rpc_storage_handler.go
    Add dynamic handler selection for RPC and gRPC                     

    gateway/rpc_storage_handler.go

  • Added GetRPCBackendHandler to switch between gRPC and legacy RPC
    handlers.
  • Updated existing methods to use rpc.RPC() for dynamic handler
    selection.
  • +93/-51 
    rpc_client.go
    Abstract RPC client with dynamic handler selection             

    rpc/rpc_client.go

  • Introduced IRPCClient interface for RPC client abstraction.
  • Added gorpcClientManager and GRPCConnectionHandler implementations.
  • Updated methods to use rpc.RPC() for dynamic handler selection.
  • +95/-43 
    server.go
    Update server setup for gRPC support                                         

    gateway/server.go

  • Updated server setup to support gRPC as an RPC backend.
  • Modified initialization and connection logic to use
    GetRPCBackendHandler.
  • +69/-25 
    grpcHandler.go
    Implement gRPC connection handler                                               

    rpc/grpcHandler.go

  • Added a new file to implement GRPCConnectionHandler.
  • Defined methods for connecting, disconnecting, and handling
    gRPC-specific logic.
  • +42/-0   
    rpc_analytics_purger.go
    Update analytics purger for dynamic RPC handler                   

    rpc/rpc_analytics_purger.go

  • Updated analytics purger to use rpc.RPC() for dynamic handler
    selection.
  • +3/-3     
    api_loader.go
    Update API loader for dynamic RPC handler                               

    gateway/api_loader.go

  • Updated API loader to use GetRPCBackendHandler for dynamic handler
    selection.
  • +7/-1     
    health_check.go
    Update health checks for dynamic RPC handler                         

    gateway/health_check.go

  • Updated health checks to use rpc.RPC().Login() for dynamic handler
    selection.
  • +6/-3     
    graphql_request.go
    Fix syntax issues in GraphQL request handling                       

    internal/graphql/graphql_request.go

    • Fixed syntax issues in GraphQL request handling.
    +1/-1     
    Tests
    4 files
    rpc_client_test.go
    Update RPC client tests for dynamic handler                           

    rpc/rpc_client_test.go

  • Updated tests to use goRPCHandler for testing doLoginWithRetries.
  • +2/-2     
    testutil.go
    Update test utilities for dynamic RPC handler                       

    gateway/testutil.go

  • Updated test utilities to use rpc.RPC().Reset() for resetting the RPC
    client.
  • +2/-2     
    graphql_request_test.go
    Fix syntax issues in GraphQL request tests                             

    internal/graphql/graphql_request_test.go

    • Fixed syntax issues in test cases.
    +2/-2     
    linter_test.go
    Fix syntax issues in linter tests                                               

    apidef/oas/linter_test.go

    • Fixed syntax issues in linter test cases.
    +1/-1     
    Configuration changes
    1 files
    config.go
    Add configuration options for gRPC support                             

    config/config.go

  • Added new configuration options for gRPC support.
  • Introduced RPCType and GRPCForceJSON fields in SlaveOptionsConfig.
  • +3/-1     
    Additional files (token-limit)
    1 files
    handler.pb.go
    ...                                                                                                           

    dispatcher/handler.pb.go

    ...

    +2157/-0

    💡 PR-Agent usage:
    Comment /help on the PR to get a list of all available PR-Agent tools and their descriptions

    @lonelycode lonelycode requested a review from buger August 15, 2024 07:06
    Copy link
    Contributor

    API Changes

    --- prev.txt	2024-08-15 07:07:03.018620485 +0000
    +++ current.txt	2024-08-15 07:06:59.726568948 +0000
    @@ -5374,11 +5374,9 @@
     	// A policy can be defined in a file (Open Source installations) or from the same database as the Dashboard.
     	Policies PoliciesConfig `json:"policies"`
     
    -	// Defines the ports that will be available for the API services to bind to in the format
    -	// documented here https://tyk.io/docs/key-concepts/tcp-proxy/#allowing-specific-ports.
    -	// Ports can be configured per protocol, e.g. https, tls etc.
    -	// If configuring via environment variable `TYK_GW_PORTWHITELIST` then remember to escape
    -	// JSON strings.
    +	// Defines the ports that will be available for the API services to bind to in the following format: `"{“":“”}"`. Remember to escape JSON strings.
    +	// This is a map of protocol to PortWhiteList. This allows per protocol
    +	// configurations.
     	PortWhiteList PortsWhiteList `json:"ports_whitelist"`
     
     	// Disable port whilisting, essentially allowing you to use any port for your API.
    @@ -6196,7 +6194,9 @@
     
     type SlaveOptionsConfig struct {
     	// Set to `true` to connect a worker Gateway using RPC.
    -	UseRPC bool `json:"use_rpc"`
    +	UseRPC        bool   `json:"use_rpc"`
    +	RPCType       string `json:"rpc_type"`
    +	GRPCForceJSON bool   `json:"grpc_force_json"`
     
     	// Set this option to `true` to use an SSL RPC connection.
     	UseSSL bool `json:"use_ssl"`
    @@ -7209,6 +7209,835 @@
     	CacheOptions
     	OASDefinition
     )
    +# Package: ./dispatcher
    +
    +package dispatcher // import "github.com/TykTechnologies/tyk/dispatcher"
    +
    +
    +CONSTANTS
    +
    +const (
    +	Handler_Login_FullMethodName                        = "/handler.Handler/Login"
    +	Handler_LoginWithGroup_FullMethodName               = "/handler.Handler/LoginWithGroup"
    +	Handler_GetKey_FullMethodName                       = "/handler.Handler/GetKey"
    +	Handler_SetKey_FullMethodName                       = "/handler.Handler/SetKey"
    +	Handler_GetExp_FullMethodName                       = "/handler.Handler/GetExp"
    +	Handler_GetKeys_FullMethodName                      = "/handler.Handler/GetKeys"
    +	Handler_DeleteKey_FullMethodName                    = "/handler.Handler/DeleteKey"
    +	Handler_DeleteRawKey_FullMethodName                 = "/handler.Handler/DeleteRawKey"
    +	Handler_GetKeysAndValues_FullMethodName             = "/handler.Handler/GetKeysAndValues"
    +	Handler_GetKeysAndValuesWithFilter_FullMethodName   = "/handler.Handler/GetKeysAndValuesWithFilter"
    +	Handler_DeleteKeys_FullMethodName                   = "/handler.Handler/DeleteKeys"
    +	Handler_Decrement_FullMethodName                    = "/handler.Handler/Decrement"
    +	Handler_IncrementWithExpire_FullMethodName          = "/handler.Handler/IncrementWithExpire"
    +	Handler_AppendToSet_FullMethodName                  = "/handler.Handler/AppendToSet"
    +	Handler_SetRollingWindow_FullMethodName             = "/handler.Handler/SetRollingWindow"
    +	Handler_GetApiDefinitions_FullMethodName            = "/handler.Handler/GetApiDefinitions"
    +	Handler_GetPolicies_FullMethodName                  = "/handler.Handler/GetPolicies"
    +	Handler_PurgeAnalyticsData_FullMethodName           = "/handler.Handler/PurgeAnalyticsData"
    +	Handler_PurgeAnalyticsDataAggregated_FullMethodName = "/handler.Handler/PurgeAnalyticsDataAggregated"
    +	Handler_CheckReload_FullMethodName                  = "/handler.Handler/CheckReload"
    +	Handler_GetKeySpaceUpdate_FullMethodName            = "/handler.Handler/GetKeySpaceUpdate"
    +	Handler_GetGroupKeySpaceUpdate_FullMethodName       = "/handler.Handler/GetGroupKeySpaceUpdate"
    +	Handler_Ping_FullMethodName                         = "/handler.Handler/Ping"
    +	Handler_Disconnect_FullMethodName                   = "/handler.Handler/Disconnect"
    +)
    +
    +VARIABLES
    +
    +var File_handler_proto protoreflect.FileDescriptor
    +var Handler_ServiceDesc = grpc.ServiceDesc{
    +	ServiceName: "handler.Handler",
    +	HandlerType: (*HandlerServer)(nil),
    +	Methods: []grpc.MethodDesc{
    +		{
    +			MethodName: "Login",
    +			Handler:    _Handler_Login_Handler,
    +		},
    +		{
    +			MethodName: "LoginWithGroup",
    +			Handler:    _Handler_LoginWithGroup_Handler,
    +		},
    +		{
    +			MethodName: "GetKey",
    +			Handler:    _Handler_GetKey_Handler,
    +		},
    +		{
    +			MethodName: "SetKey",
    +			Handler:    _Handler_SetKey_Handler,
    +		},
    +		{
    +			MethodName: "GetExp",
    +			Handler:    _Handler_GetExp_Handler,
    +		},
    +		{
    +			MethodName: "GetKeys",
    +			Handler:    _Handler_GetKeys_Handler,
    +		},
    +		{
    +			MethodName: "DeleteKey",
    +			Handler:    _Handler_DeleteKey_Handler,
    +		},
    +		{
    +			MethodName: "DeleteRawKey",
    +			Handler:    _Handler_DeleteRawKey_Handler,
    +		},
    +		{
    +			MethodName: "GetKeysAndValues",
    +			Handler:    _Handler_GetKeysAndValues_Handler,
    +		},
    +		{
    +			MethodName: "GetKeysAndValuesWithFilter",
    +			Handler:    _Handler_GetKeysAndValuesWithFilter_Handler,
    +		},
    +		{
    +			MethodName: "DeleteKeys",
    +			Handler:    _Handler_DeleteKeys_Handler,
    +		},
    +		{
    +			MethodName: "Decrement",
    +			Handler:    _Handler_Decrement_Handler,
    +		},
    +		{
    +			MethodName: "IncrementWithExpire",
    +			Handler:    _Handler_IncrementWithExpire_Handler,
    +		},
    +		{
    +			MethodName: "AppendToSet",
    +			Handler:    _Handler_AppendToSet_Handler,
    +		},
    +		{
    +			MethodName: "SetRollingWindow",
    +			Handler:    _Handler_SetRollingWindow_Handler,
    +		},
    +		{
    +			MethodName: "GetApiDefinitions",
    +			Handler:    _Handler_GetApiDefinitions_Handler,
    +		},
    +		{
    +			MethodName: "GetPolicies",
    +			Handler:    _Handler_GetPolicies_Handler,
    +		},
    +		{
    +			MethodName: "PurgeAnalyticsData",
    +			Handler:    _Handler_PurgeAnalyticsData_Handler,
    +		},
    +		{
    +			MethodName: "PurgeAnalyticsDataAggregated",
    +			Handler:    _Handler_PurgeAnalyticsDataAggregated_Handler,
    +		},
    +		{
    +			MethodName: "CheckReload",
    +			Handler:    _Handler_CheckReload_Handler,
    +		},
    +		{
    +			MethodName: "GetKeySpaceUpdate",
    +			Handler:    _Handler_GetKeySpaceUpdate_Handler,
    +		},
    +		{
    +			MethodName: "GetGroupKeySpaceUpdate",
    +			Handler:    _Handler_GetGroupKeySpaceUpdate_Handler,
    +		},
    +		{
    +			MethodName: "Ping",
    +			Handler:    _Handler_Ping_Handler,
    +		},
    +		{
    +			MethodName: "Disconnect",
    +			Handler:    _Handler_Disconnect_Handler,
    +		},
    +	},
    +	Streams:  []grpc.StreamDesc{},
    +	Metadata: "handler.proto",
    +}
    +    Handler_ServiceDesc is the grpc.ServiceDesc for Handler service.
    +    It's only intended for direct use with grpc.RegisterService, and not to be
    +    introspected or modified (even as a copy)
    +
    +
    +FUNCTIONS
    +
    +func RegisterHandlerServer(s grpc.ServiceRegistrar, srv HandlerServer)
    +
    +TYPES
    +
    +type AnalyticsDataRequest struct {
    +	ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Data     string `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*AnalyticsDataRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use AnalyticsDataRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *AnalyticsDataRequest) GetClientId() string
    +
    +func (x *AnalyticsDataRequest) GetData() string
    +
    +func (*AnalyticsDataRequest) ProtoMessage()
    +
    +func (x *AnalyticsDataRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *AnalyticsDataRequest) Reset()
    +
    +func (x *AnalyticsDataRequest) String() string
    +
    +type ApiDefinitionsResponse struct {
    +	Definitions string `protobuf:"bytes,1,opt,name=definitions,proto3" json:"definitions,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*ApiDefinitionsResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use ApiDefinitionsResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *ApiDefinitionsResponse) GetDefinitions() string
    +
    +func (*ApiDefinitionsResponse) ProtoMessage()
    +
    +func (x *ApiDefinitionsResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *ApiDefinitionsResponse) Reset()
    +
    +func (x *ApiDefinitionsResponse) String() string
    +
    +type AppendToSetRequest struct {
    +	ClientId string       `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Data     *InboundData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*AppendToSetRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use AppendToSetRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *AppendToSetRequest) GetClientId() string
    +
    +func (x *AppendToSetRequest) GetData() *InboundData
    +
    +func (*AppendToSetRequest) ProtoMessage()
    +
    +func (x *AppendToSetRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *AppendToSetRequest) Reset()
    +
    +func (x *AppendToSetRequest) String() string
    +
    +type DefRequest struct {
    +	OrgId   string   `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
    +	Tags    []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"`
    +	LoadOas bool     `protobuf:"varint,3,opt,name=load_oas,json=loadOas,proto3" json:"load_oas,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*DefRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use DefRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *DefRequest) GetLoadOas() bool
    +
    +func (x *DefRequest) GetOrgId() string
    +
    +func (x *DefRequest) GetTags() []string
    +
    +func (*DefRequest) ProtoMessage()
    +
    +func (x *DefRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *DefRequest) Reset()
    +
    +func (x *DefRequest) String() string
    +
    +type DeleteKeysRequest struct {
    +	ClientId string   `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Keys     []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*DeleteKeysRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use DeleteKeysRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *DeleteKeysRequest) GetClientId() string
    +
    +func (x *DeleteKeysRequest) GetKeys() []string
    +
    +func (*DeleteKeysRequest) ProtoMessage()
    +
    +func (x *DeleteKeysRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *DeleteKeysRequest) Reset()
    +
    +func (x *DeleteKeysRequest) String() string
    +
    +type DeleteResponse struct {
    +	Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*DeleteResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *DeleteResponse) GetSuccess() bool
    +
    +func (*DeleteResponse) ProtoMessage()
    +
    +func (x *DeleteResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *DeleteResponse) Reset()
    +
    +func (x *DeleteResponse) String() string
    +
    +type ExpResponse struct {
    +	Expiration int64 `protobuf:"varint,1,opt,name=expiration,proto3" json:"expiration,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*ExpResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use ExpResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *ExpResponse) GetExpiration() int64
    +
    +func (*ExpResponse) ProtoMessage()
    +
    +func (x *ExpResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *ExpResponse) Reset()
    +
    +func (x *ExpResponse) String() string
    +
    +type GroupKeySpaceRequest struct {
    +	OrgId   string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
    +	GroupId string `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*GroupKeySpaceRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use GroupKeySpaceRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *GroupKeySpaceRequest) GetGroupId() string
    +
    +func (x *GroupKeySpaceRequest) GetOrgId() string
    +
    +func (*GroupKeySpaceRequest) ProtoMessage()
    +
    +func (x *GroupKeySpaceRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *GroupKeySpaceRequest) Reset()
    +
    +func (x *GroupKeySpaceRequest) String() string
    +
    +type GroupLoginRequest struct {
    +	UserKey   string `protobuf:"bytes,1,opt,name=user_key,json=userKey,proto3" json:"user_key,omitempty"`
    +	GroupId   string `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
    +	ForceSync bool   `protobuf:"varint,3,opt,name=force_sync,json=forceSync,proto3" json:"force_sync,omitempty"`
    +	Node      []byte `protobuf:"bytes,4,opt,name=node,proto3" json:"node,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*GroupLoginRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use GroupLoginRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *GroupLoginRequest) GetForceSync() bool
    +
    +func (x *GroupLoginRequest) GetGroupId() string
    +
    +func (x *GroupLoginRequest) GetNode() []byte
    +
    +func (x *GroupLoginRequest) GetUserKey() string
    +
    +func (*GroupLoginRequest) ProtoMessage()
    +
    +func (x *GroupLoginRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *GroupLoginRequest) Reset()
    +
    +func (x *GroupLoginRequest) String() string
    +
    +type HandlerClient interface {
    +	Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
    +	LoginWithGroup(ctx context.Context, in *GroupLoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
    +	GetKey(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*KeyResponse, error)
    +	SetKey(ctx context.Context, in *SetKeyRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +	GetExp(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*ExpResponse, error)
    +	GetKeys(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*KeysResponse, error)
    +	DeleteKey(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
    +	DeleteRawKey(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
    +	GetKeysAndValues(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*KeysValuesResponse, error)
    +	GetKeysAndValuesWithFilter(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*KeysValuesResponse, error)
    +	DeleteKeys(ctx context.Context, in *DeleteKeysRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
    +	Decrement(ctx context.Context, in *KeyRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +	IncrementWithExpire(ctx context.Context, in *IncrementRequest, opts ...grpc.CallOption) (*IncrementResponse, error)
    +	AppendToSet(ctx context.Context, in *AppendToSetRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +	SetRollingWindow(ctx context.Context, in *SetRollingWindowRequest, opts ...grpc.CallOption) (*SetRollingWindowResponse, error)
    +	GetApiDefinitions(ctx context.Context, in *DefRequest, opts ...grpc.CallOption) (*ApiDefinitionsResponse, error)
    +	GetPolicies(ctx context.Context, in *OrgIdRequest, opts ...grpc.CallOption) (*PoliciesResponse, error)
    +	PurgeAnalyticsData(ctx context.Context, in *AnalyticsDataRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +	PurgeAnalyticsDataAggregated(ctx context.Context, in *AnalyticsDataRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +	CheckReload(ctx context.Context, in *OrgIdRequest, opts ...grpc.CallOption) (*ReloadResponse, error)
    +	GetKeySpaceUpdate(ctx context.Context, in *OrgIdRequest, opts ...grpc.CallOption) (*KeySpaceUpdateResponse, error)
    +	GetGroupKeySpaceUpdate(ctx context.Context, in *GroupKeySpaceRequest, opts ...grpc.CallOption) (*KeySpaceUpdateResponse, error)
    +	Ping(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*PingResponse, error)
    +	Disconnect(ctx context.Context, in *GroupLoginRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
    +}
    +    HandlerClient is the client API for Handler service.
    +
    +    For semantics around ctx use and closing/ending streaming RPCs, please refer
    +    to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
    +
    +func NewHandlerClient(cc grpc.ClientConnInterface) HandlerClient
    +
    +type HandlerServer interface {
    +	Login(context.Context, *LoginRequest) (*LoginResponse, error)
    +	LoginWithGroup(context.Context, *GroupLoginRequest) (*LoginResponse, error)
    +	GetKey(context.Context, *KeyRequest) (*KeyResponse, error)
    +	SetKey(context.Context, *SetKeyRequest) (*emptypb.Empty, error)
    +	GetExp(context.Context, *KeyRequest) (*ExpResponse, error)
    +	GetKeys(context.Context, *KeyRequest) (*KeysResponse, error)
    +	DeleteKey(context.Context, *KeyRequest) (*DeleteResponse, error)
    +	DeleteRawKey(context.Context, *KeyRequest) (*DeleteResponse, error)
    +	GetKeysAndValues(context.Context, *SearchRequest) (*KeysValuesResponse, error)
    +	GetKeysAndValuesWithFilter(context.Context, *SearchRequest) (*KeysValuesResponse, error)
    +	DeleteKeys(context.Context, *DeleteKeysRequest) (*DeleteResponse, error)
    +	Decrement(context.Context, *KeyRequest) (*emptypb.Empty, error)
    +	IncrementWithExpire(context.Context, *IncrementRequest) (*IncrementResponse, error)
    +	AppendToSet(context.Context, *AppendToSetRequest) (*emptypb.Empty, error)
    +	SetRollingWindow(context.Context, *SetRollingWindowRequest) (*SetRollingWindowResponse, error)
    +	GetApiDefinitions(context.Context, *DefRequest) (*ApiDefinitionsResponse, error)
    +	GetPolicies(context.Context, *OrgIdRequest) (*PoliciesResponse, error)
    +	PurgeAnalyticsData(context.Context, *AnalyticsDataRequest) (*emptypb.Empty, error)
    +	PurgeAnalyticsDataAggregated(context.Context, *AnalyticsDataRequest) (*emptypb.Empty, error)
    +	CheckReload(context.Context, *OrgIdRequest) (*ReloadResponse, error)
    +	GetKeySpaceUpdate(context.Context, *OrgIdRequest) (*KeySpaceUpdateResponse, error)
    +	GetGroupKeySpaceUpdate(context.Context, *GroupKeySpaceRequest) (*KeySpaceUpdateResponse, error)
    +	Ping(context.Context, *emptypb.Empty) (*PingResponse, error)
    +	Disconnect(context.Context, *GroupLoginRequest) (*emptypb.Empty, error)
    +	// Has unexported methods.
    +}
    +    HandlerServer is the server API for Handler service. All implementations
    +    must embed UnimplementedHandlerServer for forward compatibility.
    +
    +type InboundData struct {
    +	KeyName      string `protobuf:"bytes,1,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
    +	Value        string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
    +	SessionState string `protobuf:"bytes,3,opt,name=session_state,json=sessionState,proto3" json:"session_state,omitempty"`
    +	Timeout      int64  `protobuf:"varint,4,opt,name=timeout,proto3" json:"timeout,omitempty"`
    +	Per          int64  `protobuf:"varint,5,opt,name=per,proto3" json:"per,omitempty"`
    +	Expire       int64  `protobuf:"varint,6,opt,name=expire,proto3" json:"expire,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*InboundData) Descriptor() ([]byte, []int)
    +    Deprecated: Use InboundData.ProtoReflect.Descriptor instead.
    +
    +func (x *InboundData) GetExpire() int64
    +
    +func (x *InboundData) GetKeyName() string
    +
    +func (x *InboundData) GetPer() int64
    +
    +func (x *InboundData) GetSessionState() string
    +
    +func (x *InboundData) GetTimeout() int64
    +
    +func (x *InboundData) GetValue() string
    +
    +func (*InboundData) ProtoMessage()
    +
    +func (x *InboundData) ProtoReflect() protoreflect.Message
    +
    +func (x *InboundData) Reset()
    +
    +func (x *InboundData) String() string
    +
    +type IncrementRequest struct {
    +	ClientId string       `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Data     *InboundData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*IncrementRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use IncrementRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *IncrementRequest) GetClientId() string
    +
    +func (x *IncrementRequest) GetData() *InboundData
    +
    +func (*IncrementRequest) ProtoMessage()
    +
    +func (x *IncrementRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *IncrementRequest) Reset()
    +
    +func (x *IncrementRequest) String() string
    +
    +type IncrementResponse struct {
    +	Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*IncrementResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use IncrementResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *IncrementResponse) GetValue() int64
    +
    +func (*IncrementResponse) ProtoMessage()
    +
    +func (x *IncrementResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *IncrementResponse) Reset()
    +
    +func (x *IncrementResponse) String() string
    +
    +type KeyRequest struct {
    +	ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	KeyName  string `protobuf:"bytes,2,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*KeyRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use KeyRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *KeyRequest) GetClientId() string
    +
    +func (x *KeyRequest) GetKeyName() string
    +
    +func (*KeyRequest) ProtoMessage()
    +
    +func (x *KeyRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *KeyRequest) Reset()
    +
    +func (x *KeyRequest) String() string
    +
    +type KeyResponse struct {
    +	Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*KeyResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use KeyResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *KeyResponse) GetValue() string
    +
    +func (*KeyResponse) ProtoMessage()
    +
    +func (x *KeyResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *KeyResponse) Reset()
    +
    +func (x *KeyResponse) String() string
    +
    +type KeySpaceUpdateResponse struct {
    +	Updates []string `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*KeySpaceUpdateResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use KeySpaceUpdateResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *KeySpaceUpdateResponse) GetUpdates() []string
    +
    +func (*KeySpaceUpdateResponse) ProtoMessage()
    +
    +func (x *KeySpaceUpdateResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *KeySpaceUpdateResponse) Reset()
    +
    +func (x *KeySpaceUpdateResponse) String() string
    +
    +type KeysResponse struct {
    +	Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*KeysResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use KeysResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *KeysResponse) GetKeys() []string
    +
    +func (*KeysResponse) ProtoMessage()
    +
    +func (x *KeysResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *KeysResponse) Reset()
    +
    +func (x *KeysResponse) String() string
    +
    +type KeysValuesResponse struct {
    +	Keys   []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"`
    +	Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*KeysValuesResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use KeysValuesResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *KeysValuesResponse) GetKeys() []string
    +
    +func (x *KeysValuesResponse) GetValues() []string
    +
    +func (*KeysValuesResponse) ProtoMessage()
    +
    +func (x *KeysValuesResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *KeysValuesResponse) Reset()
    +
    +func (x *KeysValuesResponse) String() string
    +
    +type LoginRequest struct {
    +	ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	UserKey  string `protobuf:"bytes,2,opt,name=user_key,json=userKey,proto3" json:"user_key,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*LoginRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *LoginRequest) GetClientId() string
    +
    +func (x *LoginRequest) GetUserKey() string
    +
    +func (*LoginRequest) ProtoMessage()
    +
    +func (x *LoginRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *LoginRequest) Reset()
    +
    +func (x *LoginRequest) String() string
    +
    +type LoginResponse struct {
    +	Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*LoginResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *LoginResponse) GetSuccess() bool
    +
    +func (*LoginResponse) ProtoMessage()
    +
    +func (x *LoginResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *LoginResponse) Reset()
    +
    +func (x *LoginResponse) String() string
    +
    +type OrgIdRequest struct {
    +	ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	OrgId    string `protobuf:"bytes,2,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*OrgIdRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use OrgIdRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *OrgIdRequest) GetClientId() string
    +
    +func (x *OrgIdRequest) GetOrgId() string
    +
    +func (*OrgIdRequest) ProtoMessage()
    +
    +func (x *OrgIdRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *OrgIdRequest) Reset()
    +
    +func (x *OrgIdRequest) String() string
    +
    +type PingResponse struct {
    +	Pong bool `protobuf:"varint,1,opt,name=pong,proto3" json:"pong,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*PingResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use PingResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *PingResponse) GetPong() bool
    +
    +func (*PingResponse) ProtoMessage()
    +
    +func (x *PingResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *PingResponse) Reset()
    +
    +func (x *PingResponse) String() string
    +
    +type PoliciesResponse struct {
    +	Policies string `protobuf:"bytes,1,opt,name=policies,proto3" json:"policies,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*PoliciesResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use PoliciesResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *PoliciesResponse) GetPolicies() string
    +
    +func (*PoliciesResponse) ProtoMessage()
    +
    +func (x *PoliciesResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *PoliciesResponse) Reset()
    +
    +func (x *PoliciesResponse) String() string
    +
    +type ReloadResponse struct {
    +	ReloadRequired bool `protobuf:"varint,1,opt,name=reload_required,json=reloadRequired,proto3" json:"reload_required,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*ReloadResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use ReloadResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *ReloadResponse) GetReloadRequired() bool
    +
    +func (*ReloadResponse) ProtoMessage()
    +
    +func (x *ReloadResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *ReloadResponse) Reset()
    +
    +func (x *ReloadResponse) String() string
    +
    +type SearchRequest struct {
    +	ClientId     string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	SearchString string `protobuf:"bytes,2,opt,name=search_string,json=searchString,proto3" json:"search_string,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*SearchRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use SearchRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *SearchRequest) GetClientId() string
    +
    +func (x *SearchRequest) GetSearchString() string
    +
    +func (*SearchRequest) ProtoMessage()
    +
    +func (x *SearchRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *SearchRequest) Reset()
    +
    +func (x *SearchRequest) String() string
    +
    +type SetKeyRequest struct {
    +	ClientId string       `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Data     *InboundData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*SetKeyRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use SetKeyRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *SetKeyRequest) GetClientId() string
    +
    +func (x *SetKeyRequest) GetData() *InboundData
    +
    +func (*SetKeyRequest) ProtoMessage()
    +
    +func (x *SetKeyRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *SetKeyRequest) Reset()
    +
    +func (x *SetKeyRequest) String() string
    +
    +type SetRollingWindowRequest struct {
    +	ClientId string       `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
    +	Data     *InboundData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*SetRollingWindowRequest) Descriptor() ([]byte, []int)
    +    Deprecated: Use SetRollingWindowRequest.ProtoReflect.Descriptor instead.
    +
    +func (x *SetRollingWindowRequest) GetClientId() string
    +
    +func (x *SetRollingWindowRequest) GetData() *InboundData
    +
    +func (*SetRollingWindowRequest) ProtoMessage()
    +
    +func (x *SetRollingWindowRequest) ProtoReflect() protoreflect.Message
    +
    +func (x *SetRollingWindowRequest) Reset()
    +
    +func (x *SetRollingWindowRequest) String() string
    +
    +type SetRollingWindowResponse struct {
    +	Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
    +	// Has unexported fields.
    +}
    +
    +func (*SetRollingWindowResponse) Descriptor() ([]byte, []int)
    +    Deprecated: Use SetRollingWindowResponse.ProtoReflect.Descriptor instead.
    +
    +func (x *SetRollingWindowResponse) GetCount() int32
    +
    +func (*SetRollingWindowResponse) ProtoMessage()
    +
    +func (x *SetRollingWindowResponse) ProtoReflect() protoreflect.Message
    +
    +func (x *SetRollingWindowResponse) Reset()
    +
    +func (x *SetRollingWindowResponse) String() string
    +
    +type UnimplementedHandlerServer struct{}
    +    UnimplementedHandlerServer must be embedded to have forward compatible
    +    implementations.
    +
    +    NOTE: this should be embedded by value instead of pointer to avoid a nil
    +    pointer dereference when methods are called.
    +
    +func (UnimplementedHandlerServer) AppendToSet(context.Context, *AppendToSetRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) CheckReload(context.Context, *OrgIdRequest) (*ReloadResponse, error)
    +
    +func (UnimplementedHandlerServer) Decrement(context.Context, *KeyRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) DeleteKey(context.Context, *KeyRequest) (*DeleteResponse, error)
    +
    +func (UnimplementedHandlerServer) DeleteKeys(context.Context, *DeleteKeysRequest) (*DeleteResponse, error)
    +
    +func (UnimplementedHandlerServer) DeleteRawKey(context.Context, *KeyRequest) (*DeleteResponse, error)
    +
    +func (UnimplementedHandlerServer) Disconnect(context.Context, *GroupLoginRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) GetApiDefinitions(context.Context, *DefRequest) (*ApiDefinitionsResponse, error)
    +
    +func (UnimplementedHandlerServer) GetExp(context.Context, *KeyRequest) (*ExpResponse, error)
    +
    +func (UnimplementedHandlerServer) GetGroupKeySpaceUpdate(context.Context, *GroupKeySpaceRequest) (*KeySpaceUpdateResponse, error)
    +
    +func (UnimplementedHandlerServer) GetKey(context.Context, *KeyRequest) (*KeyResponse, error)
    +
    +func (UnimplementedHandlerServer) GetKeySpaceUpdate(context.Context, *OrgIdRequest) (*KeySpaceUpdateResponse, error)
    +
    +func (UnimplementedHandlerServer) GetKeys(context.Context, *KeyRequest) (*KeysResponse, error)
    +
    +func (UnimplementedHandlerServer) GetKeysAndValues(context.Context, *SearchRequest) (*KeysValuesResponse, error)
    +
    +func (UnimplementedHandlerServer) GetKeysAndValuesWithFilter(context.Context, *SearchRequest) (*KeysValuesResponse, error)
    +
    +func (UnimplementedHandlerServer) GetPolicies(context.Context, *OrgIdRequest) (*PoliciesResponse, error)
    +
    +func (UnimplementedHandlerServer) IncrementWithExpire(context.Context, *IncrementRequest) (*IncrementResponse, error)
    +
    +func (UnimplementedHandlerServer) Login(context.Context, *LoginRequest) (*LoginResponse, error)
    +
    +func (UnimplementedHandlerServer) LoginWithGroup(context.Context, *GroupLoginRequest) (*LoginResponse, error)
    +
    +func (UnimplementedHandlerServer) Ping(context.Context, *emptypb.Empty) (*PingResponse, error)
    +
    +func (UnimplementedHandlerServer) PurgeAnalyticsData(context.Context, *AnalyticsDataRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) PurgeAnalyticsDataAggregated(context.Context, *AnalyticsDataRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) SetKey(context.Context, *SetKeyRequest) (*emptypb.Empty, error)
    +
    +func (UnimplementedHandlerServer) SetRollingWindow(context.Context, *SetRollingWindowRequest) (*SetRollingWindowResponse, error)
    +
    +type UnsafeHandlerServer interface {
    +	// Has unexported methods.
    +}
    +    UnsafeHandlerServer may be embedded to opt out of forward compatibility for
    +    this service. Use of this interface is not recommended, as added methods to
    +    HandlerServer will result in compilation errors.
    +
     # Package: ./dlpython
     
     package python // import "github.com/TykTechnologies/tyk/dlpython"
    @@ -7530,6 +8359,10 @@
     	ErrOAuthClientDeleted               = "oauth.client_deleted"
     )
     const (
    +	GRPCBackend = "grpc"
    +	LegacyRPC   = "rpc"
    +)
    +const (
     	ResetQuota              string = "resetQuota"
     	CertificateRemoved      string = "CertificateRemoved"
     	CertificateAdded        string = "CertificateAdded"
    @@ -7681,6 +8514,7 @@
     
     func GenerateTestBinaryData() (buf *bytes.Buffer)
     func GetAccessDefinitionByAPIIDOrSession(session *user.SessionState, api *APISpec) (accessDef *user.AccessDefinition, allowanceScope string, err error)
    +func GetRPCBackendHandler(name string, cfg *rpcInitConfig) storage.Handler
     func GetTLSClient(cert *tls.Certificate, caCert []byte) *http.Client
     func GetTLSConfig(cert *tls.Certificate, caCert []byte) *tls.Config
     func InitTestMain(ctx context.Context, m *testing.M) int
    @@ -8428,6 +9262,111 @@
     func (g *FileBundleGetter) Get() ([]byte, error)
         Get mocks an HTTP(S) GET request.
     
    +type GPCStorageHandler struct {
    +	KeyPrefix        string
    +	HashKeys         bool
    +	SuppressRegister bool
    +	DoReload         func()
    +	Gw               *Gateway `json:"-"`
    +
    +	// Has unexported fields.
    +}
    +    GPCStorageHandler is a storage manager that uses gRPC to communicate with
    +    the server.
    +
    +func (r *GPCStorageHandler) AddToSet(keyName string, value string)
    +
    +func (r *GPCStorageHandler) AddToSortedSet(keyName string, value string, score float64)
    +
    +func (r *GPCStorageHandler) AppendToSet(keyName, value string)
    +
    +func (r *GPCStorageHandler) CheckForReload(orgId string) bool
    +    CheckForReload checks if a reload is required for the given organization
    +
    +func (r *GPCStorageHandler) Connect() bool
    +
    +func (r *GPCStorageHandler) Decrement(keyName string)
    +
    +func (r *GPCStorageHandler) DeleteAllKeys() bool
    +
    +func (r *GPCStorageHandler) DeleteKey(keyName string) bool
    +
    +func (r *GPCStorageHandler) DeleteKeys(keys []string) bool
    +
    +func (r *GPCStorageHandler) DeleteRawKey(keyName string) bool
    +
    +func (r *GPCStorageHandler) DeleteScanMatch(pattern string) bool
    +
    +func (r *GPCStorageHandler) Disconnect() error
    +
    +func (r *GPCStorageHandler) Exists(keyName string) (bool, error)
    +
    +func (r *GPCStorageHandler) GetAndDeleteSet(keyName string) []interface{}
    +
    +func (r *GPCStorageHandler) GetApiDefinitions(orgId string, tags []string) string
    +    GetApiDefinitions retrieves API definitions for a given organization ID and
    +    set of tags
    +
    +func (r *GPCStorageHandler) GetExp(keyName string) (int64, error)
    +
    +func (r *GPCStorageHandler) GetKey(keyName string) (string, error)
    +
    +func (r *GPCStorageHandler) GetKeyPrefix() string
    +
    +func (r *GPCStorageHandler) GetKeys(filter string) []string
    +
    +func (r *GPCStorageHandler) GetKeysAndValues() map[string]string
    +
    +func (r *GPCStorageHandler) GetKeysAndValuesWithFilter(filter string) map[string]string
    +
    +func (r *GPCStorageHandler) GetListRange(keyName string, from, to int64) ([]string, error)
    +
    +func (r *GPCStorageHandler) GetMultiKey(keyNames []string) ([]string, error)
    +
    +func (r *GPCStorageHandler) GetPolicies(orgId string) string
    +    GetPolicies retrieves policies for a given organization ID
    +
    +func (r *GPCStorageHandler) GetRawKey(keyName string) (string, error)
    +
    +func (r *GPCStorageHandler) GetRollingWindow(key string, per int64, pipeline bool) (int, []interface{})
    +
    +func (r *GPCStorageHandler) GetSet(keyName string) (map[string]string, error)
    +
    +func (r *GPCStorageHandler) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error)
    +
    +func (r *GPCStorageHandler) IncrememntWithExpire(keyName string, expire int64) int64
    +
    +func (r *GPCStorageHandler) IsRetriableError(err error) bool
    +    IsRetriableError checks if the error is retriable
    +
    +func (r *GPCStorageHandler) Login(clientID, userKey string) bool
    +    Login handles the login process for a single client
    +
    +func (r *GPCStorageHandler) LoginWithGroup(clientID string, groupData *apidef.GroupLoginRequest) bool
    +    LoginWithGroup handles the login process for a client within a group
    +
    +func (r *GPCStorageHandler) Publish(channel, message string) error
    +
    +func (r *GPCStorageHandler) RemoveFromList(keyName string, value string) error
    +
    +func (r *GPCStorageHandler) RemoveFromSet(keyName string, value string)
    +
    +func (r *GPCStorageHandler) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error
    +
    +func (r *GPCStorageHandler) SetExp(keyName string, timeout int64) error
    +
    +func (r *GPCStorageHandler) SetKey(keyName, session string, timeout int64) error
    +
    +func (r *GPCStorageHandler) SetRawKey(keyName, session string, timeout int64) error
    +
    +func (r *GPCStorageHandler) SetRollingWindow(keyName string, per int64, val string, pipeline bool) (int, []interface{})
    +
    +func (r *GPCStorageHandler) StartPubSubHandler(channel string, callback func(*temporalmodel.Message)) error
    +
    +func (r *GPCStorageHandler) StartRPCKeepaliveWatcher()
    +
    +func (r *GPCStorageHandler) StartRPCLoopCheck(orgId string)
    +
     type GRPCDispatcher struct {
     	coprocess.Dispatcher
     }
    @@ -8457,7 +9396,7 @@
     	DefaultQuotaStore    DefaultSessionManager
     	GlobalSessionManager SessionHandler
     	MonitoringHandler    config.TykEventHandler
    -	RPCListener          RPCStorageHandler
    +	RPCListener          storage.RPCListener
     	DashService          DashboardServiceSender
     	CertificateManager   certs.CertificateManager
     	GlobalHostChecker    HostCheckerManager
    @@ -9117,8 +10056,6 @@
     
     func (l *LDAPStorageHandler) DeleteRawKey(cn string) bool
     
    -func (l *LDAPStorageHandler) DeleteRawKeys([]string) bool
    -
     func (l LDAPStorageHandler) DeleteScanMatch(pattern string) bool
     
     func (l LDAPStorageHandler) Exists(keyName string) (bool, error)
    @@ -9551,8 +10488,6 @@
         DeleteKey will remove a key from the database without prefixing, assumes
         user knows what they are doing
     
    -func (r *RPCStorageHandler) DeleteRawKeys(keys []string) bool
    -
     func (r *RPCStorageHandler) DeleteScanMatch(pattern string) bool
     
     func (r *RPCStorageHandler) Disconnect() error
    @@ -11097,40 +12032,19 @@
     
     FUNCTIONS
     
    -func CloseConnections()
    -func Connect(connConfig Config, suppressRegister bool, dispatcherFuncs map[string]interface{},
    -	getGroupLoginFunc func(string, string) interface{},
    -	emergencyModeFunc func(),
    -	emergencyModeLoadedFunc func()) bool
    -    Connect will establish a connection to the RPC server specified in
    -    connection options
    -
    -func Disconnect() bool
    -func EmitErrorEvent(jobName string, funcName string, err error)
    -func EmitErrorEventKv(jobName string, funcName string, err error, kv map[string]string)
     func ForceConnected(t *testing.T)
         ForceConnected only intended to be used in tests do not use it for any other
         thing
     
    -func FuncClientSingleton(funcName string, request interface{}) (result interface{}, err error)
    -    FuncClientSingleton performs RPC call. This might be called before we have
    -    established RPC connection, in that case we perform a retry with exponential
    -    backoff ensuring indeed we can't connect to the rpc, this will eventually
    -    fall into emergency mode( That is handled outside of this function call)
    -
    -func GroupLogin() bool
    +func GetRPCType() string
     func IsEmergencyMode() bool
    -func LoadCount() int
    -func Login() bool
    -    Login tries to login to the rpc sever. Returns true if it succeeds and false
    -    if it fails.
    -
    -func Reset()
     func ResetEmergencyMode()
    +func SetConnected(connected bool)
     func SetEmergencyMode(t *testing.T, value bool)
         SetEmergencyMode used in tests to force emergency mode
     
     func SetLoadCounts(t *testing.T, value int)
    +func SetRPCType(rpcType string)
     
     TYPES
     
    @@ -11148,6 +12062,43 @@
     	RPCPoolSize           int    `json:"rpc_pool_size"`
     }
     
    +type GRPCConnectionHandler struct{}
    +
    +func (g *GRPCConnectionHandler) CloseConnections()
    +
    +func (g *GRPCConnectionHandler) Connect(_ Config, _ bool, _ map[string]interface{}, _ func(string, string) interface{}, _ func(), _ func()) bool
    +
    +func (g *GRPCConnectionHandler) Disconnect() bool
    +
    +func (g *GRPCConnectionHandler) EmitErrorEvent(_ string, _ string, _ error)
    +
    +func (g *GRPCConnectionHandler) EmitErrorEventKv(_ string, _ string, _ error, _ map[string]string)
    +
    +func (g *GRPCConnectionHandler) FuncClientSingleton(_ string, _ interface{}) (interface{}, error)
    +
    +func (g *GRPCConnectionHandler) GroupLogin() bool
    +
    +func (g *GRPCConnectionHandler) LoadCount() int
    +
    +func (g *GRPCConnectionHandler) Login() bool
    +
    +func (g *GRPCConnectionHandler) Reset()
    +
    +type IRPCClient interface {
    +	Connect(Config, bool, map[string]interface{}, func(string, string) interface{}, func(), func()) bool
    +	Disconnect() bool
    +	FuncClientSingleton(string, interface{}) (interface{}, error)
    +	Login() bool
    +	GroupLogin() bool
    +	LoadCount() int
    +	Reset()
    +	EmitErrorEvent(string, string, error)
    +	EmitErrorEventKv(string, string, error, map[string]string)
    +	CloseConnections()
    +}
    +
    +func RPC() IRPCClient
    +
     type Purger struct {
     	Store storage.Handler
     }
    @@ -11358,10 +12309,6 @@
         DeleteRawKey removes a specified key from DummyStorage, returning success
         status; not yet implemented.
     
    -func (s *DummyStorage) DeleteRawKeys([]string) bool
    -    DeleteRawKeys removes a set of raw keys from DummyStorage, returning success
    -    status; not yet implemented.
    -
     func (s *DummyStorage) DeleteScanMatch(pattern string) bool
         DeleteScanMatch deletes keys matching a pattern from DummyStorage, returning
         true if successful.
    @@ -11477,7 +12424,6 @@
     	DeleteKey(string) bool
     	DeleteAllKeys() bool
     	DeleteRawKey(string) bool
    -	DeleteRawKeys([]string) bool
     	Connect() bool
     	GetKeysAndValues() map[string]string
     	GetKeysAndValuesWithFilter(string) map[string]string
    @@ -11528,8 +12474,6 @@
     
     func (m MdcbStorage) DeleteRawKey(string) bool
     
    -func (m MdcbStorage) DeleteRawKeys([]string) bool
    -
     func (m MdcbStorage) DeleteScanMatch(key string) bool
     
     func (m MdcbStorage) Exists(key string) (bool, error)
    @@ -11577,6 +12521,13 @@
     
     func (m MdcbStorage) SetRollingWindow(key string, per int64, val string, pipeline bool) (int, []interface{})
     
    +type RPCListener interface {
    +	Connect() bool
    +	CheckForReload(orgId string) bool
    +	StartRPCKeepaliveWatcher()
    +	StartRPCLoopCheck(orgId string)
    +}
    +
     type RedisCluster struct {
     	KeyPrefix   string
     	HashKeys    bool
    @@ -11627,8 +12578,6 @@
         DeleteKey will remove a key from the database without prefixing, assumes
         user knows what they are doing
     
    -func (r *RedisCluster) DeleteRawKeys(keys []string) bool
    -
     func (r *RedisCluster) DeleteScanMatch(pattern string) bool
         DeleteKeys will remove a group of keys in bulk
     

    Copy link
    Contributor

    PR Reviewer Guide 🔍

    ⏱️ Estimated effort to review: 5 🔵🔵🔵🔵🔵
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Key issues to review

    Missing Error Handling
    The Connect method in GPCStorageHandler does not handle potential errors from grpc.Dial. It's crucial to handle this to avoid runtime panics if the gRPC server is unreachable.

    Incomplete Implementation
    Several methods in GPCStorageHandler such as SetExp, GetAndDeleteSet, GetSet, etc., are marked as not implemented. This could lead to runtime errors if these methods are called.

    Configuration Handling
    The system checks for gwConfig.Storage.Type not being 'redis' or 'local' and logs a fatal error, which is inconsistent with the new gRPC storage option. This needs to be adjusted to accommodate the new gRPC storage handler.

    Inconsistent Storage Handler Initialization
    The prepareStorage method initializes gs.rpcAuthStore using GetRPCBackendHandler without checking if RPC should be used, unlike other initializations in the same context which conditionally initialize based on configuration.

    Copy link
    Contributor

    github-actions bot commented Aug 15, 2024

    PR Code Suggestions ✨

    CategorySuggestion                                                                                                                                    Score
    Possible bug
    Handle potential errors from GetRPCBackendHandler

    Ensure that the GetRPCBackendHandler function has proper error handling. If it can
    return an error, you should handle this potential error to prevent runtime panics or
    issues.

    gateway/api_loader.go [48-54]

    -gs.rpcAuthStore = GetRPCBackendHandler(
    +rpcAuthStore, err := GetRPCBackendHandler(
         gw.GetConfig().SlaveOptions.RPCType,
         &rpcInitConfig{
             KeyPrefix: "apikey-",
             HashKeys:  gw.GetConfig().HashKeys,
             Gw:        gw,
         })
    +if err != nil {
    +    log.Error("Failed to initialize RPC Auth Store: ", err)
    +    return nil
    +}
    +gs.rpcAuthStore = rpcAuthStore
     
    Suggestion importance[1-10]: 9

    Why: Ensuring that GetRPCBackendHandler has proper error handling is crucial to prevent runtime panics or issues, making the code more reliable.

    9
    Security
    Ensure TLS configurations are secure by default

    Use a more secure default setting for TLS configurations by setting
    InsecureSkipVerify to false unless explicitly required for development purposes.

    gateway/grpc_storage_handler.go [86-90]

     clientCfg := &tls.Config{
    -    InsecureSkipVerify: rpcConfig.SSLInsecureSkipVerify,
    +    InsecureSkipVerify: false, // Set to true only if necessary for development
         MinVersion:         rpcConfig.SSLMinVersion,
         MaxVersion:         rpcConfig.SSLMaxVersion,
     }
     
    Suggestion importance[1-10]: 9

    Why: Ensuring TLS configurations are secure by default is crucial for maintaining the security of the system. This suggestion addresses a potential security vulnerability by enforcing a more secure default setting.

    9
    Possible issue
    Add validation or documentation for new configuration options to prevent misconfiguration

    Ensure that the new configuration options RPCType and GRPCForceJSON are properly
    validated or documented to avoid misconfiguration. This could involve adding checks
    in the application startup or configuration parsing logic to ensure that RPCType is
    one of the expected values and that GRPCForceJSON is used appropriately based on the
    RPCType.

    config/config.go [313-315]

     UseRPC        bool   `json:"use_rpc"`
    -RPCType       string `json:"rpc_type"`
    -GRPCForceJSON bool   `json:"grpc_force_json"`
    +RPCType       string `json:"rpc_type"` // Ensure this is either 'gRPC' or 'goRPC'
    +GRPCForceJSON bool   `json:"grpc_force_json"` // Validate based on RPCType
     
    Suggestion importance[1-10]: 8

    Why: Adding validation or documentation for the new configuration options is important to prevent misconfiguration and ensure the correct usage of these options. This enhances the robustness of the configuration handling.

    8
    Add error handling after saving RPC definitions backup

    Consider checking for errors after calling
    gw.saveRPCDefinitionsBackup(apiCollection). This will ensure that any issues during
    the backup process are properly handled and not just logged.

    gateway/api_definition.go [676-678]

     if rpc.RPC().LoadCount() > 0 {
         if err := gw.saveRPCDefinitionsBackup(apiCollection); err != nil {
             log.Error(err)
    +        return err
         }
     }
     
    Suggestion importance[1-10]: 8

    Why: Adding error handling after saving RPC definitions backup ensures that any issues during the backup process are properly handled, improving the robustness of the code.

    8
    Enhancement
    Replace time.Sleep with a retry mechanism using exponential backoff

    Replace the direct use of time.Sleep with a more robust mechanism for handling
    delays or retries in Connect method. This could involve using a retry loop with
    exponential backoff or a context with a deadline.

    gateway/grpc_storage_handler.go [106]

    -time.Sleep(10 * time.Millisecond)
    +// Implement a retry mechanism with exponential backoff
    +// Example:
    +// for attempt := 0; attempt < maxRetries; attempt++ {
    +//     err = operation()
    +//     if err == nil {
    +//         return nil
    +//     }
    +//     time.Sleep(time.Duration(math.Pow(2, float64(attempt))) * time.Millisecond * 100)
    +// }
     
    Suggestion importance[1-10]: 8

    Why: Replacing time.Sleep with a retry mechanism using exponential backoff improves the robustness and reliability of the connection process, especially in distributed systems where transient errors are common. This suggestion addresses a significant enhancement in error handling and connection stability.

    8
    Maintainability
    Add package documentation to clarify the role of the dispatcher package

    Consider adding package documentation for the dispatcher package to explain its role
    and usage within the system, especially since it is likely to be a central part of
    the new gRPC implementation.

    dispatcher/handler.pb.go [7]

    +// Package dispatcher handles the gRPC service implementations for the system.
     package dispatcher
     
    Suggestion importance[1-10]: 7

    Why: Adding package documentation improves code maintainability and helps other developers understand the purpose and usage of the package. This is a good practice, especially for central components.

    7
    Use a more descriptive variable name for the RPC instance

    It's recommended to use a more descriptive variable name than rpc for the RPC
    instance to improve code readability and maintainability.

    gateway/api_definition.go [675-678]

    -if rpc.RPC().LoadCount() > 0 {
    +if rpcClient.RPC().LoadCount() > 0 {
         if err := gw.saveRPCDefinitionsBackup(apiCollection); err != nil {
             log.Error(err)
         }
     }
     
    Suggestion importance[1-10]: 6

    Why: Using a more descriptive variable name improves code readability and maintainability, but it is a minor enhancement.

    6
    Improve modularity by separating configuration setup from the connection logic

    Refactor the Connect method to separate the configuration and connection steps into
    distinct methods for better modularity and readability.

    gateway/grpc_storage_handler.go [60-76]

    -func (r *GPCStorageHandler) Connect() bool {
    +func (r *GPCStorageHandler) setupRPCConfig() *rpc.Config {
         slaveOptions := r.Gw.GetConfig().SlaveOptions
    -    rpcConfig := rpc.Config{
    +    return &rpc.Config{
             UseSSL:                slaveOptions.UseSSL,
             SSLInsecureSkipVerify: slaveOptions.SSLInsecureSkipVerify,
             SSLMinVersion:         r.Gw.GetConfig().HttpServerOptions.MinVersion,
             SSLMaxVersion:         r.Gw.GetConfig().HttpServerOptions.MaxVersion,
             ConnectionString:      slaveOptions.ConnectionString,
             RPCKey:                slaveOptions.RPCKey,
             APIKey:                slaveOptions.APIKey,
             GroupID:               slaveOptions.GroupID,
             CallTimeout:           slaveOptions.CallTimeout,
             PingTimeout:           slaveOptions.PingTimeout,
             RPCPoolSize:           slaveOptions.RPCPoolSize,
         }
    -    r.cfg = &rpcConfig
    +}
    +func (r *GPCStorageHandler) Connect() bool {
    +    r.cfg = r.setupRPCConfig()
         ...
     }
     
    Suggestion importance[1-10]: 6

    Why: Separating configuration setup from connection logic improves code modularity and readability. This refactor enhances maintainability but does not address a critical issue, hence a moderate score.

    6
    Best practice
    Use constants for repeated string literals to avoid errors and improve maintainability

    Consider using a constant for the key prefix "apikey-" and "orgkey." to avoid
    duplication and potential errors in future changes.

    gateway/api_loader.go [45-54]

    -gs.redisStore = &storage.RedisCluster{KeyPrefix: "apikey-", HashKeys: gw.GetConfig().HashKeys, ConnectionHandler: gw.StorageConnectionHandler}
    -gs.redisOrgStore = &storage.RedisCluster{KeyPrefix: "orgkey.", ConnectionHandler: gw.StorageConnectionHandler}
    +const apikeyPrefix = "apikey-"
    +const orgkeyPrefix = "orgkey."
    +gs.redisStore = &storage.RedisCluster{KeyPrefix: apikeyPrefix, HashKeys: gw.GetConfig().HashKeys, ConnectionHandler: gw.StorageConnectionHandler}
    +gs.redisOrgStore = &storage.RedisCluster{KeyPrefix: orgkeyPrefix, ConnectionHandler: gw.StorageConnectionHandler}
     gs.rpcAuthStore = GetRPCBackendHandler(
         gw.GetConfig().SlaveOptions.RPCType,
         &rpcInitConfig{
    -        KeyPrefix: "apikey-",
    +        KeyPrefix: apikeyPrefix,
             HashKeys:  gw.GetConfig().HashKeys,
             Gw:        gw,
         })
     
    Suggestion importance[1-10]: 7

    Why: Using constants for repeated string literals improves maintainability and reduces the risk of errors in future changes, though it is a minor improvement.

    7
    Error handling
    Add error handling and logging for JSON codec operations

    Implement error handling for the jsonCodec methods to ensure that any JSON
    marshalling or unmarshalling errors are properly logged and handled, rather than
    just returned.

    gateway/grpc_storage_handler.go [44-49]

     func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
    -    return json.Marshal(v)
    +    data, err := json.Marshal(v)
    +    if err != nil {
    +        log.Error("Failed to marshal data:", err)
    +        return nil, err
    +    }
    +    return data, nil
     }
     func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
    -    return json.Unmarshal(data, v)
    +    err := json.Unmarshal(data, v)
    +    if err != nil {
    +        log.Error("Failed to unmarshal data:", err)
    +    }
    +    return err
     }
     
    Suggestion importance[1-10]: 7

    Why: Adding error handling and logging for JSON codec operations improves the observability and debuggability of the system. This change enhances error tracking and provides better insights into potential issues during JSON processing.

    7

    Copy link

    sonarcloud bot commented Aug 15, 2024

    Quality Gate Failed Quality Gate failed

    Failed conditions
    0.0% Coverage on New Code (required ≥ 80%)

    See analysis details on SonarCloud

    @caroltyk caroltyk changed the title Adds gRPC support for Tyk and MDCB to replace goRPC TT-10623 Adds gRPC support for Tyk and MDCB to replace goRPC Aug 30, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    1 participant