github.com/msales/pkg/v3@v3.24.0/redisx/client.go (about)

     1  package redisx
     2  
     3  import (
     4  	"github.com/go-redis/redis"
     5  )
     6  
     7  // ScanIterator represents a generic redis scan iterator that works on both
     8  // redis Client and ClusterClient
     9  type ScanIterator interface {
    10  	Val() string
    11  	Next() bool
    12  	Err() error
    13  }
    14  
    15  // ClusterClient represents a redis ClusterClient
    16  type ClusterClient interface {
    17  	ForEachMaster(fn func(client *redis.Client) error) error
    18  }
    19  
    20  // ScanCmd represents redis ScanCmd
    21  type ScanCmd interface {
    22  	Iterator() ScanIterator
    23  }
    24  
    25  // NewScanIterator returns a scan operator regarding redis client type
    26  func NewScanIterator(c interface{}, cursor uint64, match string, count int64) (ScanIterator, error) {
    27  	_, isCluster := c.(ClusterClient)
    28  
    29  	if !isCluster {
    30  		return c.(redis.Cmdable).Scan(cursor, match, count).Iterator(), nil
    31  	}
    32  
    33  	iterators := make([]ScanIterator, 0)
    34  	err := c.(ClusterClient).ForEachMaster(func(client *redis.Client) error {
    35  		iterators = append(iterators, client.Scan(cursor, match, count).Iterator())
    36  
    37  		return nil
    38  	})
    39  
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return &ClusterScanIterator{
    45  		curr:      0,
    46  		iterators: iterators,
    47  	}, nil
    48  }
    49  
    50  // ClusterScanIterator represents redis cluster scan iterator
    51  type ClusterScanIterator struct {
    52  	iterators []ScanIterator
    53  
    54  	curr int
    55  }
    56  
    57  // Val returns current value pointed by the iterator
    58  func (cs *ClusterScanIterator) Val() string {
    59  	return cs.getCurrentIterator().Val()
    60  }
    61  
    62  // Next returns true if there is at least one more value in iterator
    63  func (cs *ClusterScanIterator) Next() bool {
    64  	i := cs.getCurrentIterator()
    65  
    66  	if i.Next() {
    67  		return true
    68  	}
    69  
    70  	for cs.nextIterator() {
    71  		i = cs.getCurrentIterator()
    72  
    73  		if i.Next() {
    74  			return true
    75  		}
    76  	}
    77  
    78  	return false
    79  }
    80  
    81  // Err returns an error for iterator
    82  func (cs *ClusterScanIterator) Err() error {
    83  	return cs.getCurrentIterator().Err()
    84  }
    85  
    86  func (cs *ClusterScanIterator) getCurrentIterator() ScanIterator {
    87  	return cs.iterators[0]
    88  }
    89  
    90  func (cs *ClusterScanIterator) nextIterator() bool {
    91  	cs.iterators = cs.iterators[1:]
    92  
    93  	return len(cs.iterators) > 0
    94  }