@@ -23,24 +23,114 @@ func SetLogger(logger *log.Logger) {
2323 internal .Logger = logger
2424}
2525
26+ //------------------------------------------------------------------------------
27+
28+ type Hook interface {
29+ BeforeProcess (ctx context.Context , cmd Cmder ) (context.Context , error )
30+ AfterProcess (ctx context.Context , cmd Cmder ) (context.Context , error )
31+
32+ BeforeProcessPipeline (ctx context.Context , cmds []Cmder ) (context.Context , error )
33+ AfterProcessPipeline (ctx context.Context , cmds []Cmder ) (context.Context , error )
34+ }
35+
36+ type hooks struct {
37+ hooks []Hook
38+ }
39+
40+ func (hs * hooks ) AddHook (hook Hook ) {
41+ hs .hooks = append (hs .hooks , hook )
42+ }
43+
44+ func (hs * hooks ) copy () {
45+ hs .hooks = hs .hooks [:len (hs .hooks ):len (hs .hooks )]
46+ }
47+
48+ func (hs hooks ) process (ctx context.Context , cmd Cmder , fn func (Cmder ) error ) error {
49+ ctx , err := hs .beforeProcess (ctx , cmd )
50+ if err != nil {
51+ return err
52+ }
53+
54+ cmdErr := fn (cmd )
55+
56+ _ , err = hs .afterProcess (ctx , cmd )
57+ if err != nil {
58+ return err
59+ }
60+
61+ return cmdErr
62+ }
63+
64+ func (hs hooks ) beforeProcess (ctx context.Context , cmd Cmder ) (context.Context , error ) {
65+ for _ , h := range hs .hooks {
66+ var err error
67+ ctx , err = h .BeforeProcess (ctx , cmd )
68+ if err != nil {
69+ return nil , err
70+ }
71+ }
72+ return ctx , nil
73+ }
74+
75+ func (hs hooks ) afterProcess (ctx context.Context , cmd Cmder ) (context.Context , error ) {
76+ for _ , h := range hs .hooks {
77+ var err error
78+ ctx , err = h .AfterProcess (ctx , cmd )
79+ if err != nil {
80+ return nil , err
81+ }
82+ }
83+ return ctx , nil
84+ }
85+
86+ func (hs hooks ) processPipeline (ctx context.Context , cmds []Cmder , fn func ([]Cmder ) error ) error {
87+ ctx , err := hs .beforeProcessPipeline (ctx , cmds )
88+ if err != nil {
89+ return err
90+ }
91+
92+ cmdsErr := fn (cmds )
93+
94+ _ , err = hs .afterProcessPipeline (ctx , cmds )
95+ if err != nil {
96+ return err
97+ }
98+
99+ return cmdsErr
100+ }
101+
102+ func (hs hooks ) beforeProcessPipeline (ctx context.Context , cmds []Cmder ) (context.Context , error ) {
103+ for _ , h := range hs .hooks {
104+ var err error
105+ ctx , err = h .BeforeProcessPipeline (ctx , cmds )
106+ if err != nil {
107+ return nil , err
108+ }
109+ }
110+ return ctx , nil
111+ }
112+
113+ func (hs hooks ) afterProcessPipeline (ctx context.Context , cmds []Cmder ) (context.Context , error ) {
114+ for _ , h := range hs .hooks {
115+ var err error
116+ ctx , err = h .AfterProcessPipeline (ctx , cmds )
117+ if err != nil {
118+ return nil , err
119+ }
120+ }
121+ return ctx , nil
122+ }
123+
124+ //------------------------------------------------------------------------------
125+
26126type baseClient struct {
27127 opt * Options
28128 connPool pool.Pooler
29129 limiter Limiter
30130
31- process func (Cmder ) error
32- processPipeline func ([]Cmder ) error
33- processTxPipeline func ([]Cmder ) error
34-
35131 onClose func () error // hook called when client is closed
36132}
37133
38- func (c * baseClient ) init () {
39- c .process = c .defaultProcess
40- c .processPipeline = c .defaultProcessPipeline
41- c .processTxPipeline = c .defaultProcessTxPipeline
42- }
43-
44134func (c * baseClient ) String () string {
45135 return fmt .Sprintf ("Redis<%s db:%d>" , c .getAddr (), c .opt .DB )
46136}
@@ -159,22 +249,11 @@ func (c *baseClient) initConn(cn *pool.Conn) error {
159249// Do creates a Cmd from the args and processes the cmd.
160250func (c * baseClient ) Do (args ... interface {}) * Cmd {
161251 cmd := NewCmd (args ... )
162- _ = c .Process (cmd )
252+ _ = c .process (cmd )
163253 return cmd
164254}
165255
166- // WrapProcess wraps function that processes Redis commands.
167- func (c * baseClient ) WrapProcess (
168- fn func (oldProcess func (cmd Cmder ) error ) func (cmd Cmder ) error ,
169- ) {
170- c .process = fn (c .process )
171- }
172-
173- func (c * baseClient ) Process (cmd Cmder ) error {
174- return c .process (cmd )
175- }
176-
177- func (c * baseClient ) defaultProcess (cmd Cmder ) error {
256+ func (c * baseClient ) process (cmd Cmder ) error {
178257 for attempt := 0 ; attempt <= c .opt .MaxRetries ; attempt ++ {
179258 if attempt > 0 {
180259 time .Sleep (c .retryBackoff (attempt ))
@@ -249,18 +328,11 @@ func (c *baseClient) getAddr() string {
249328 return c .opt .Addr
250329}
251330
252- func (c * baseClient ) WrapProcessPipeline (
253- fn func (oldProcess func ([]Cmder ) error ) func ([]Cmder ) error ,
254- ) {
255- c .processPipeline = fn (c .processPipeline )
256- c .processTxPipeline = fn (c .processTxPipeline )
257- }
258-
259- func (c * baseClient ) defaultProcessPipeline (cmds []Cmder ) error {
331+ func (c * baseClient ) processPipeline (cmds []Cmder ) error {
260332 return c .generalProcessPipeline (cmds , c .pipelineProcessCmds )
261333}
262334
263- func (c * baseClient ) defaultProcessTxPipeline (cmds []Cmder ) error {
335+ func (c * baseClient ) processTxPipeline (cmds []Cmder ) error {
264336 return c .generalProcessPipeline (cmds , c .txPipelineProcessCmds )
265337}
266338
@@ -388,6 +460,7 @@ type Client struct {
388460 cmdable
389461
390462 ctx context.Context
463+ hooks
391464}
392465
393466// NewClient returns a client to the Redis Server specified by Options.
@@ -400,7 +473,6 @@ func NewClient(opt *Options) *Client {
400473 connPool : newConnPool (opt ),
401474 },
402475 }
403- c .baseClient .init ()
404476 c .init ()
405477
406478 return & c
@@ -427,9 +499,22 @@ func (c *Client) WithContext(ctx context.Context) *Client {
427499}
428500
429501func (c * Client ) clone () * Client {
430- cp := * c
431- cp .init ()
432- return & cp
502+ clone := * c
503+ clone .hooks .copy ()
504+ clone .init ()
505+ return & clone
506+ }
507+
508+ func (c * Client ) Process (cmd Cmder ) error {
509+ return c .hooks .process (c .ctx , cmd , c .baseClient .process )
510+ }
511+
512+ func (c * Client ) processPipeline (cmds []Cmder ) error {
513+ return c .hooks .processPipeline (c .ctx , cmds , c .baseClient .processPipeline )
514+ }
515+
516+ func (c * Client ) processTxPipeline (cmds []Cmder ) error {
517+ return c .hooks .processPipeline (c .ctx , cmds , c .baseClient .processTxPipeline )
433518}
434519
435520// Options returns read-only Options that were used to create the client.
@@ -547,11 +632,14 @@ func newConn(opt *Options, cn *pool.Conn) *Conn {
547632 connPool : pool .NewSingleConnPool (cn ),
548633 },
549634 }
550- c .baseClient .init ()
551635 c .statefulCmdable .setProcessor (c .Process )
552636 return & c
553637}
554638
639+ func (c * Conn ) Process (cmd Cmder ) error {
640+ return c .baseClient .process (cmd )
641+ }
642+
555643func (c * Conn ) Pipelined (fn func (Pipeliner ) error ) ([]Cmder , error ) {
556644 return c .Pipeline ().Pipelined (fn )
557645}
0 commit comments