mirror of
https://github.com/redis/go-redis.git
synced 2025-07-18 00:20:57 +03:00
Convert HandlerContext from struct to interface with strongly typed getters for different client types. This provides better type safety and a cleaner API for push notification handlers while maintaining flexibility. Key Changes: 1. HandlerContext Interface Design: - Converted HandlerContext from struct to interface - Added strongly typed getters for different client types - GetClusterClient() returns ClusterClientInterface - GetSentinelClient() returns SentinelClientInterface - GetFailoverClient() returns FailoverClientInterface - GetRegularClient() returns RegularClientInterface - GetPubSub() returns PubSubInterface 2. Client Type Interfaces: - Defined ClusterClientInterface for cluster client access - Defined SentinelClientInterface for sentinel client access - Defined FailoverClientInterface for failover client access - Defined RegularClientInterface for regular client access - Defined PubSubInterface for pub/sub access - Each interface provides String() method for basic operations 3. Concrete Implementation: - Created handlerContext struct implementing HandlerContext interface - Added NewHandlerContext constructor function - Implemented type-safe getters with interface casting - Returns nil for incorrect client types (type safety) 4. Updated All Usage: - Updated Handler interface to use HandlerContext interface - Updated ProcessorInterface to use HandlerContext interface - Updated all processor implementations (Processor, VoidProcessor) - Updated all handler context creation sites - Updated test handlers and test context creation 5. Helper Methods: - Updated pushNotificationHandlerContext() in baseClient - Updated pushNotificationHandlerContext() in PubSub - Consistent context creation across all client types - Proper parameter passing for different connection types 6. Type Safety Benefits: - Handlers can safely cast to specific client types - Compile-time checking for client type access - Clear API for accessing different client capabilities - No runtime panics from incorrect type assertions 7. API Usage Example: ```go func (h *MyHandler) HandlePushNotification( ctx context.Context, handlerCtx HandlerContext, notification []interface{}, ) bool { // Strongly typed access if clusterClient := handlerCtx.GetClusterClient(); clusterClient != nil { // Handle cluster-specific logic } if sentinelClient := handlerCtx.GetSentinelClient(); sentinelClient != nil { // Handle sentinel-specific logic } return true } ``` 8. Backward Compatibility: - Interface maintains same functionality as original struct - All existing handler patterns continue to work - No breaking changes to handler implementations - Smooth migration path for existing code Benefits: - Strong type safety for client access in handlers - Clear API with explicit client type getters - Compile-time checking prevents runtime errors - Flexible interface allows future extensions - Better separation of concerns between client types - Enhanced developer experience with IntelliSense support This enhancement provides handlers with strongly typed access to different Redis client types while maintaining the flexibility and context information needed for sophisticated push notification handling, particularly important for hitless upgrades and cluster management operations.
151 lines
5.6 KiB
Go
151 lines
5.6 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/redis/go-redis/v9/internal/proto"
|
|
"github.com/redis/go-redis/v9/internal/pushnotif"
|
|
)
|
|
|
|
type PushNotificationHandlerContext = pushnotif.HandlerContext
|
|
|
|
// PushNotificationHandler defines the interface for push notification handlers.
|
|
// This is an alias to the internal push notification handler interface.
|
|
type PushNotificationHandler = pushnotif.Handler
|
|
|
|
// PushNotificationProcessorInterface defines the interface for push notification processors.
|
|
// This is an alias to the internal push notification processor interface.
|
|
type PushNotificationProcessorInterface = pushnotif.ProcessorInterface
|
|
|
|
// PushNotificationRegistry manages push notification handlers.
|
|
type PushNotificationRegistry struct {
|
|
registry *pushnotif.Registry
|
|
}
|
|
|
|
// NewPushNotificationRegistry creates a new push notification registry.
|
|
func NewPushNotificationRegistry() *PushNotificationRegistry {
|
|
return &PushNotificationRegistry{
|
|
registry: pushnotif.NewRegistry(),
|
|
}
|
|
}
|
|
|
|
// RegisterHandler registers a handler for a specific push notification name.
|
|
func (r *PushNotificationRegistry) RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error {
|
|
return r.registry.RegisterHandler(pushNotificationName, handler, protected)
|
|
}
|
|
|
|
// UnregisterHandler removes a handler for a specific push notification name.
|
|
func (r *PushNotificationRegistry) UnregisterHandler(pushNotificationName string) error {
|
|
return r.registry.UnregisterHandler(pushNotificationName)
|
|
}
|
|
|
|
// GetHandler returns the handler for a specific push notification name.
|
|
func (r *PushNotificationRegistry) GetHandler(pushNotificationName string) PushNotificationHandler {
|
|
return r.registry.GetHandler(pushNotificationName)
|
|
}
|
|
|
|
// GetRegisteredPushNotificationNames returns a list of all registered push notification names.
|
|
func (r *PushNotificationRegistry) GetRegisteredPushNotificationNames() []string {
|
|
return r.registry.GetRegisteredPushNotificationNames()
|
|
}
|
|
|
|
// PushNotificationProcessor handles push notifications with a registry of handlers.
|
|
type PushNotificationProcessor struct {
|
|
processor *pushnotif.Processor
|
|
}
|
|
|
|
// NewPushNotificationProcessor creates a new push notification processor.
|
|
func NewPushNotificationProcessor() *PushNotificationProcessor {
|
|
return &PushNotificationProcessor{
|
|
processor: pushnotif.NewProcessor(),
|
|
}
|
|
}
|
|
|
|
// GetHandler returns the handler for a specific push notification name.
|
|
func (p *PushNotificationProcessor) GetHandler(pushNotificationName string) PushNotificationHandler {
|
|
return p.processor.GetHandler(pushNotificationName)
|
|
}
|
|
|
|
// RegisterHandler registers a handler for a specific push notification name.
|
|
func (p *PushNotificationProcessor) RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error {
|
|
return p.processor.RegisterHandler(pushNotificationName, handler, protected)
|
|
}
|
|
|
|
// UnregisterHandler removes a handler for a specific push notification name.
|
|
func (p *PushNotificationProcessor) UnregisterHandler(pushNotificationName string) error {
|
|
return p.processor.UnregisterHandler(pushNotificationName)
|
|
}
|
|
|
|
// ProcessPendingNotifications checks for and processes any pending push notifications.
|
|
// The handlerCtx provides context about the client, connection pool, and connection.
|
|
func (p *PushNotificationProcessor) ProcessPendingNotifications(ctx context.Context, handlerCtx PushNotificationHandlerContext, rd *proto.Reader) error {
|
|
return p.processor.ProcessPendingNotifications(ctx, handlerCtx, rd)
|
|
}
|
|
|
|
// VoidPushNotificationProcessor discards all push notifications without processing them.
|
|
type VoidPushNotificationProcessor struct {
|
|
processor *pushnotif.VoidProcessor
|
|
}
|
|
|
|
// NewVoidPushNotificationProcessor creates a new void push notification processor.
|
|
func NewVoidPushNotificationProcessor() *VoidPushNotificationProcessor {
|
|
return &VoidPushNotificationProcessor{
|
|
processor: pushnotif.NewVoidProcessor(),
|
|
}
|
|
}
|
|
|
|
// GetHandler returns nil for void processor since it doesn't maintain handlers.
|
|
func (v *VoidPushNotificationProcessor) GetHandler(pushNotificationName string) PushNotificationHandler {
|
|
return nil
|
|
}
|
|
|
|
// RegisterHandler returns an error for void processor since it doesn't maintain handlers.
|
|
func (v *VoidPushNotificationProcessor) RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error {
|
|
return v.processor.RegisterHandler(pushNotificationName, nil, protected)
|
|
}
|
|
|
|
// ProcessPendingNotifications reads and discards any pending push notifications.
|
|
func (v *VoidPushNotificationProcessor) ProcessPendingNotifications(ctx context.Context, handlerCtx PushNotificationHandlerContext, rd *proto.Reader) error {
|
|
return v.processor.ProcessPendingNotifications(ctx, handlerCtx, rd)
|
|
}
|
|
|
|
// Redis Cluster push notification names
|
|
const (
|
|
PushNotificationMoving = "MOVING"
|
|
PushNotificationMigrating = "MIGRATING"
|
|
PushNotificationMigrated = "MIGRATED"
|
|
PushNotificationFailingOver = "FAILING_OVER"
|
|
PushNotificationFailedOver = "FAILED_OVER"
|
|
)
|
|
|
|
// PushNotificationInfo contains metadata about a push notification.
|
|
type PushNotificationInfo struct {
|
|
Name string
|
|
Args []interface{}
|
|
}
|
|
|
|
// ParsePushNotificationInfo extracts information from a push notification.
|
|
func ParsePushNotificationInfo(notification []interface{}) *PushNotificationInfo {
|
|
if len(notification) == 0 {
|
|
return nil
|
|
}
|
|
|
|
name, ok := notification[0].(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
return &PushNotificationInfo{
|
|
Name: name,
|
|
Args: notification[1:],
|
|
}
|
|
}
|
|
|
|
// String returns a string representation of the push notification info.
|
|
func (info *PushNotificationInfo) String() string {
|
|
if info == nil {
|
|
return "<nil>"
|
|
}
|
|
return info.Name
|
|
}
|