11using System ;
2+ using System . Linq ;
23using System . Net ;
34using Nop . Core . Configuration ;
5+ using RedLock ;
46using StackExchange . Redis ;
57
68namespace Nop . Core . Caching
79{
810 /// <summary>
9- /// Redis connection wrapper
11+ /// Redis connection wrapper implementation
1012 /// </summary>
1113 public class RedisConnectionWrapper : IRedisConnectionWrapper
1214 {
15+ #region Fields
16+
1317 private readonly NopConfig _config ;
1418 private readonly Lazy < string > _connectionString ;
1519
1620 private volatile ConnectionMultiplexer _connection ;
21+ private volatile RedisLockFactory _redisLockFactory ;
1722 private readonly object _lock = new object ( ) ;
1823
24+ #endregion
25+
26+ #region Ctor
27+
1928 public RedisConnectionWrapper ( NopConfig config )
2029 {
2130 this . _config = config ;
2231 this . _connectionString = new Lazy < string > ( GetConnectionString ) ;
32+ this . _redisLockFactory = CreateRedisLockFactory ( ) ;
2333 }
2434
25- private string GetConnectionString ( )
35+ #endregion
36+
37+ #region Utilities
38+
39+ /// <summary>
40+ /// Get connection string to Redis cache from configuration
41+ /// </summary>
42+ /// <returns></returns>
43+ protected string GetConnectionString ( )
2644 {
2745 return _config . RedisCachingConnectionString ;
2846 }
2947
30- private ConnectionMultiplexer GetConnection ( )
48+ /// <summary>
49+ /// Get connection to Redis servers
50+ /// </summary>
51+ /// <returns></returns>
52+ protected ConnectionMultiplexer GetConnection ( )
3153 {
3254 if ( _connection != null && _connection . IsConnected ) return _connection ;
3355
@@ -48,37 +70,120 @@ private ConnectionMultiplexer GetConnection()
4870 return _connection ;
4971 }
5072
51- public IDatabase Database ( int ? db = null )
73+ /// <summary>
74+ /// Create instance of RedisLockFactory
75+ /// </summary>
76+ /// <returns>RedisLockFactory</returns>
77+ protected RedisLockFactory CreateRedisLockFactory ( )
78+ {
79+ //get password and value whether to use ssl from connection string
80+ var password = string . Empty ;
81+ var useSsl = false ;
82+ foreach ( var option in GetConnectionString ( ) . Split ( ',' ) . Where ( option => option . Contains ( '=' ) ) )
83+ {
84+ switch ( option . Substring ( 0 , option . IndexOf ( '=' ) ) . Trim ( ) . ToLowerInvariant ( ) )
85+ {
86+ case "password" :
87+ password = option . Substring ( option . IndexOf ( '=' ) + 1 ) . Trim ( ) ;
88+ break ;
89+ case "ssl" :
90+ bool . TryParse ( option . Substring ( option . IndexOf ( '=' ) + 1 ) . Trim ( ) , out useSsl ) ;
91+ break ;
92+ }
93+ }
94+
95+ //create RedisLockFactory for using Redlock distributed lock algorithm
96+ return new RedisLockFactory ( GetEndPoints ( ) . Select ( endPoint => new RedisLockEndPoint
97+ {
98+ EndPoint = endPoint ,
99+ Password = password ,
100+ Ssl = useSsl
101+ } ) ) ;
102+ }
103+
104+ #endregion
105+
106+ #region Methods
107+
108+ /// <summary>
109+ /// Obtain an interactive connection to a database inside redis
110+ /// </summary>
111+ /// <param name="db">Database number; pass null to use the default value</param>
112+ /// <returns>Redis cache database</returns>
113+ public IDatabase GetDatabase ( int ? db = null )
52114 {
53115 return GetConnection ( ) . GetDatabase ( db ?? - 1 ) ; //_settings.DefaultDb);
54116 }
55117
56- public IServer Server ( EndPoint endPoint )
118+ /// <summary>
119+ /// Obtain a configuration API for an individual server
120+ /// </summary>
121+ /// <param name="endPoint">The network endpoint</param>
122+ /// <returns>Redis server</returns>
123+ public IServer GetServer ( EndPoint endPoint )
57124 {
58125 return GetConnection ( ) . GetServer ( endPoint ) ;
59126 }
60127
61- public EndPoint [ ] GetEndpoints ( )
128+ /// <summary>
129+ /// Gets all endpoints defined on the server
130+ /// </summary>
131+ /// <returns>Array of endpoints</returns>
132+ public EndPoint [ ] GetEndPoints ( )
62133 {
63134 return GetConnection ( ) . GetEndPoints ( ) ;
64135 }
65136
66- public void FlushDb ( int ? db = null )
137+ /// <summary>
138+ /// Delete all the keys of the database
139+ /// </summary>
140+ /// <param name="db">Database number; pass null to use the default value<</param>
141+ public void FlushDatabase ( int ? db = null )
67142 {
68- var endPoints = GetEndpoints ( ) ;
143+ var endPoints = GetEndPoints ( ) ;
69144
70145 foreach ( var endPoint in endPoints )
71146 {
72- Server ( endPoint ) . FlushDatabase ( db ?? - 1 ) ; //_settings.DefaultDb);
147+ GetServer ( endPoint ) . FlushDatabase ( db ?? - 1 ) ; //_settings.DefaultDb);
73148 }
74149 }
75150
151+ /// <summary>
152+ /// Perform some action with Redis distributed lock
153+ /// </summary>
154+ /// <param name="resource">The thing we are locking on</param>
155+ /// <param name="expirationTime">The time after which the lock will automatically be expired by Redis</param>
156+ /// <param name="action">Action to be performed with locking</param>
157+ /// <returns>True if lock was acquired and action was performed; otherwise false</returns>
158+ public bool PerformActionWithLock ( string resource , TimeSpan expirationTime , Action action )
159+ {
160+ //use RedLock library
161+ using ( var redisLock = _redisLockFactory . Create ( resource , expirationTime ) )
162+ {
163+ //ensure that lock is acquired
164+ if ( ! redisLock . IsAcquired )
165+ return false ;
166+
167+ //perform action
168+ action ( ) ;
169+ return true ;
170+ }
171+ }
172+
173+ /// <summary>
174+ /// Release all resources associated with this object
175+ /// </summary>
76176 public void Dispose ( )
77177 {
178+ //dispose ConnectionMultiplexer
78179 if ( _connection != null )
79- {
80180 _connection . Dispose ( ) ;
81- }
181+
182+ //dispose RedisLockFactory
183+ if ( _redisLockFactory != null )
184+ _redisLockFactory . Dispose ( ) ;
82185 }
186+
187+ #endregion
83188 }
84189}
0 commit comments