11package redis
22
33import (
4+ "log"
45 "sync"
56 "time"
67)
78
89type TokenManager struct {
9- token string
10- expiresAt time.Time
11- mutex sync.Mutex
10+ token string
11+ expiresAt time.Time
12+ mutex sync.Mutex
13+ refreshFunc func () (string , time.Duration , error )
14+ stopChan chan struct {}
1215}
1316
14- func NewTokenManager () * TokenManager {
15- return & TokenManager {}
17+ // NewTokenManager initializes a new TokenManager.
18+ func NewTokenManager (refreshFunc func () (string , time.Duration , error )) * TokenManager {
19+ return & TokenManager {
20+ refreshFunc : refreshFunc ,
21+ stopChan : make (chan struct {}),
22+ }
1623}
1724
25+ // SetToken updates the token and its expiration.
1826func (tm * TokenManager ) SetToken (token string , ttl time.Duration ) {
1927 tm .mutex .Lock ()
2028 defer tm .mutex .Unlock ()
2129 tm .token = token
2230 tm .expiresAt = time .Now ().Add (ttl )
31+ log .Printf ("Token updated with TTL: %s" , ttl )
2332}
2433
34+ // GetToken returns the current token if it's still valid.
2535func (tm * TokenManager ) GetToken () (string , bool ) {
2636 tm .mutex .Lock ()
2737 defer tm .mutex .Unlock ()
@@ -31,11 +41,73 @@ func (tm *TokenManager) GetToken() (string, bool) {
3141 return tm .token , true
3242}
3343
34- func (tm * TokenManager ) RefreshToken (fetchToken func () (string , time.Duration , error )) error {
35- token , ttl , err := fetchToken ()
44+ // RefreshToken fetches a new token using the provided refresh function.
45+ func (tm * TokenManager ) RefreshToken () error {
46+ if tm .refreshFunc == nil {
47+ return nil
48+ }
49+ token , ttl , err := tm .refreshFunc ()
3650 if err != nil {
3751 return err
3852 }
3953 tm .SetToken (token , ttl )
4054 return nil
4155}
56+
57+ // StartAutoRefresh starts a goroutine to proactively refresh the token.
58+ func (tm * TokenManager ) StartAutoRefresh () {
59+ go func () {
60+ ticker := time .NewTicker (1 * time .Minute ) // Check periodically
61+ defer ticker .Stop ()
62+
63+ for {
64+ select {
65+ case <- ticker .C :
66+ if tm .shouldRefresh () {
67+ log .Println ("Proactively refreshing token..." )
68+ if err := tm .RefreshToken (); err != nil {
69+ log .Printf ("Failed to refresh token: %v" , err )
70+ }
71+ }
72+ case <- tm .stopChan :
73+ log .Println ("Stopping auto-refresh..." )
74+ return
75+ }
76+ }
77+ }()
78+ }
79+
80+ // StopAutoRefresh stops the auto-refresh goroutine.
81+ func (tm * TokenManager ) StopAutoRefresh () {
82+ close (tm .stopChan )
83+ }
84+
85+ // shouldRefresh checks if the token is nearing expiration.
86+ func (tm * TokenManager ) shouldRefresh () bool {
87+ tm .mutex .Lock ()
88+ defer tm .mutex .Unlock ()
89+ remaining := time .Until (tm .expiresAt )
90+ return remaining < 5 * time .Minute // Refresh if less than 5 minutes remain
91+ }
92+
93+ // MonitorTelemetry adds monitoring for token usage and expiration.
94+ func (tm * TokenManager ) MonitorTelemetry () {
95+ go func () {
96+ ticker := time .NewTicker (30 * time .Second ) // Adjust as needed
97+ defer ticker .Stop ()
98+
99+ for {
100+ select {
101+ case <- ticker .C :
102+ token , valid := tm .GetToken ()
103+ if ! valid {
104+ log .Println ("Token has expired." )
105+ } else {
106+ log .Printf ("Token is valid: %s, expires in: %s" , token , time .Until (tm .expiresAt ))
107+ }
108+ case <- tm .stopChan :
109+ return
110+ }
111+ }
112+ }()
113+ }
0 commit comments