Skip to content

Commit 6a3873b

Browse files
author
Donald Gray
committed
Change default layout for appSetting keys. Allow delimiter and prefix to be set as static property
1 parent da969cc commit 6a3873b

File tree

4 files changed

+76
-19
lines changed

4 files changed

+76
-19
lines changed

src/ServiceStack.RateLimit.Redis/LimitKeyGenerator.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ namespace ServiceStack.RateLimit.Redis
1212

1313
public class LimitKeyGenerator : ILimitKeyGenerator
1414
{
15-
private const string DefaultConfigKey = "lmt:default";
16-
private const string DefaultUserConfigKey = "lmt:usr:default";
15+
public static string Delimiter = "/";
16+
public static string Prefix = "ss";
17+
18+
private readonly string defaultConfigKey = GenerateKey("lmt", "default");
19+
private readonly string defaultUserConfigKey = GenerateKey("lmt", "usr", "default");
20+
1721
private readonly ILog log = LogManager.GetLogger(typeof(LimitKeyGenerator));
1822

1923
// This is how we will generate the key that is used to lookup the LimitProvider
@@ -23,18 +27,18 @@ public virtual IEnumerable<string> GetConfigKeysForRequest(IRequest request)
2327
string requestId = GetRequestId(request);
2428

2529
// Build up a list of all keys in order of precedence
26-
string userRequestKey = $"lmt:{requestId}:{userId}";
27-
string requestKey = $"lmt:{requestId}";
30+
string userRequestKey = GenerateKey("lmt", requestId, userId);
31+
string requestKey = GenerateKey("lmt", requestId);
2832

29-
return new[] { userRequestKey, requestKey, DefaultConfigKey };
33+
return new[] { userRequestKey, requestKey, defaultConfigKey };
3034
}
3135

3236
public virtual IEnumerable<string> GetConfigKeysForUser(IRequest request)
3337
{
3438
string userId = GetConsumerId(request);
3539

36-
string userKey = $"lmt:usr:{userId}";
37-
return new[] { userKey, DefaultUserConfigKey };
40+
string userKey = GenerateKey("lmt", "usr", userId);
41+
return new[] { userKey, defaultUserConfigKey };
3842
}
3943

4044
public virtual string GetRequestId(IRequest request)
@@ -60,5 +64,12 @@ private static bool IsUserAuthenticated(IAuthSession userSession)
6064
{
6165
return userSession?.IsAuthenticated ?? false;
6266
}
67+
68+
private static string GenerateKey(params string[] keyParts)
69+
{
70+
var usablePrefix = string.IsNullOrWhiteSpace(Prefix) ? string.Empty : string.Concat(Prefix, Delimiter);
71+
72+
return $"{usablePrefix}{string.Join(Delimiter, keyParts)}";
73+
}
6374
}
6475
}

test/DemoService/App.config

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
<!-- Sample limits -->
1010

1111
<!-- lmt:default is fallback default -->
12-
<add key="lmt:default" value="{Limits:[{Limit:10,Seconds:60},{Limit:20,Seconds:3600},{Limit:30,Seconds:86400}]}"/>
12+
<add key="ss/lmt/default" value="{Limits:[{Limit:10,Seconds:60},{Limit:20,Seconds:3600},{Limit:30,Seconds:86400}]}"/>
1313

1414
<!-- lmt:usr:default is default for user across all requests -->
15-
<add key="lmt:usr:default" value="{Limits:[{Limit:30,Seconds:60},{Limit:100,Seconds:3600},{Limit:250,Seconds:86400}]}"/>
15+
<add key="ss/lmt/usr/default" value="{Limits:[{Limit:30,Seconds:60},{Limit:100,Seconds:3600},{Limit:250,Seconds:86400}]}"/>
1616

1717
<!-- lmt:2 is limit for user 2 across all requests -->
18-
<add key="lmt:usr:2" value="{Limits:[{Limit:7,Seconds:60},{Limit:15,Seconds:3600},{Limit:40,Seconds:86400}]}"/>
18+
<add key="ss/lmt/usr/2" value="{Limits:[{Limit:7,Seconds:60},{Limit:15,Seconds:3600},{Limit:40,Seconds:86400}]}"/>
1919

2020
<!-- lmt:demorequest is limits for all requests to /demorequest -->
21-
<add key="lmt:demorequest" value="{Limits:[{Limit:8,Seconds:60},{Limit:13,Seconds:3600},{Limit:21,Seconds:86400}]}"/>
21+
<add key="ss/lmt/demorequest" value="{Limits:[{Limit:8,Seconds:60},{Limit:13,Seconds:3600},{Limit:21,Seconds:86400}]}"/>
2222

2323
<!-- lmt:demorequest:2 is limits for requests to /demorequest (:demorequest) user 2 (:2) -->
24-
<add key="lmt:demorequest:2" value="{Limits:[{Limit:5,Seconds:60},{Limit:10,Seconds:3600},{Limit:30,Seconds:86400}]}"/>
24+
<add key="ss/lmt/demorequest/2" value="{Limits:[{Limit:5,Seconds:60},{Limit:10,Seconds:3600},{Limit:30,Seconds:86400}]}"/>
2525
</appSettings>
2626
</configuration>

test/DemoService/AppHost.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ private void SetupPlugins()
4343
new BasicAuthProvider()
4444
}));
4545

46+
LimitKeyGenerator.Delimiter = ":";
47+
LimitKeyGenerator.Prefix = null;
4648
Plugins.Add(new RateLimitFeature(Container.Resolve<IRedisClientsManager>()));
4749
}
4850

@@ -52,8 +54,6 @@ private void SetupDependencies()
5254
var redisConnection = AppSettings.GetString("RedisConnectionString");
5355
Container.Register<IRedisClientsManager>(new BasicRedisClientManager(redisConnection));
5456

55-
Container.Register(AppSettings);
56-
5757
// Setup basic auth
5858
Container.Register<ICacheClient>(new MemoryCacheClient());
5959
var userRep = new InMemoryAuthRepository();

test/ServiceStack.RateLimit.Redis.Tests/LimitKeyGeneratorTests.cs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,34 @@ public void GetConfigKeysForRequest_ReturnsCorrectNumberOfKeys()
7272
keys.Count().Should().Be(3);
7373
}
7474

75+
[Theory]
76+
[InlineData("ss/lmt/opname/userId", 0)]
77+
[InlineData("ss/lmt/opname", 1)]
78+
[InlineData("ss/lmt/default", 2)]
79+
public void GetConfigKeysForRequest_ReturnsResultsInOrder(string key, int index)
80+
{
81+
const string operationName = "opname";
82+
const string userAuthId = "userId";
83+
84+
var request = new MockHttpRequest(operationName, "GET", "text/json", string.Empty, null, null, null);
85+
SetupAuthenticatedSession(userAuthId, request);
86+
87+
var keyGenerator = GetGenerator();
88+
var keys = keyGenerator.GetConfigKeysForRequest(request);
89+
90+
keys.ToList()[index].Should().Be(key.ToLower());
91+
}
92+
7593
[Theory]
7694
[InlineData("lmt:opname:userId", 0)]
7795
[InlineData("lmt:opname", 1)]
7896
[InlineData("lmt:default", 2)]
79-
public void GetConfigKeysForRequest_ReturnsResultsInOrder(string key, int index)
97+
public void GetConfigKeysForRequest_ReturnsResultsInOrder_ObeyDelimiterAndPrefix(string key, int index)
8098
{
8199
const string operationName = "opname";
82100
const string userAuthId = "userId";
101+
LimitKeyGenerator.Delimiter = ":";
102+
LimitKeyGenerator.Prefix = null;
83103

84104
var request = new MockHttpRequest(operationName, "GET", "text/json", string.Empty, null, null, null);
85105
SetupAuthenticatedSession(userAuthId, request);
@@ -88,10 +108,14 @@ public void GetConfigKeysForRequest_ReturnsResultsInOrder(string key, int index)
88108
var keys = keyGenerator.GetConfigKeysForRequest(request);
89109

90110
keys.ToList()[index].Should().Be(key.ToLower());
111+
112+
// Now set the values back as they're static (avoid breaking tests)
113+
LimitKeyGenerator.Delimiter = "/";
114+
LimitKeyGenerator.Prefix = "ss";
91115
}
92116

93117
[Fact]
94-
public void GetConfigKeysForUser_ReturnsCorrectNumberOfKeys_def()
118+
public void GetConfigKeysForUser_ReturnsCorrectNumberOfKeys()
95119
{
96120
MockHttpRequest request = new MockHttpRequest();
97121
SetupAuthenticatedSession("123", request);
@@ -103,9 +127,31 @@ public void GetConfigKeysForUser_ReturnsCorrectNumberOfKeys_def()
103127
}
104128

105129
[Theory]
106-
[InlineData("lmt:usr:userid", 0)]
107-
[InlineData("lmt:usr:default", 1)]
108-
public void GetConfigKeysForUser_ReturnsCorrectNumberOfKeys(string key, int index)
130+
[InlineData("test|lmt|usr|userid", 0)]
131+
[InlineData("test|lmt|usr|default", 1)]
132+
public void GetConfigKeysForUser_ReturnsResultsInOrder_ObeyDelimiterAndPrefix(string key, int index)
133+
{
134+
const string userAuthId = "userId";
135+
MockHttpRequest request = new MockHttpRequest();
136+
SetupAuthenticatedSession(userAuthId, request);
137+
138+
LimitKeyGenerator.Delimiter = "|";
139+
LimitKeyGenerator.Prefix = "test";
140+
141+
var keyGenerator = GetGenerator();
142+
var keys = keyGenerator.GetConfigKeysForUser(request);
143+
144+
keys.ToList()[index].Should().Be(key);
145+
146+
// Now set the values back as they're static (avoid breaking tests)
147+
LimitKeyGenerator.Delimiter = "/";
148+
LimitKeyGenerator.Prefix = "ss";
149+
}
150+
151+
[Theory]
152+
[InlineData("ss/lmt/usr/userid", 0)]
153+
[InlineData("ss/lmt/usr/default", 1)]
154+
public void GetConfigKeysForUser_ReturnsResultsInOrder(string key, int index)
109155
{
110156
const string userAuthId = "userId";
111157
MockHttpRequest request = new MockHttpRequest();

0 commit comments

Comments
 (0)