Skip to content
This repository was archived by the owner on Apr 29, 2022. It is now read-only.

Commit 3fcf7a8

Browse files
author
Anton Vorontsov
committed
Added WildcardExtensions and created tests project.
1 parent c0d723a commit 3fcf7a8

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

RabbitMQ.Client.Core.DependencyInjection.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ ProjectSection(SolutionItems) = preProject
3838
docs\images\delayed-message-model.png = docs\images\delayed-message-model.png
3939
EndProjectSection
4040
EndProject
41+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9D0289B2-C566-46CC-A53A-471BCBA0F277}"
42+
EndProject
43+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RabbitMQ.Client.Core.DependencyInjection.Tests", "tests\RabbitMQ.Client.Core.DependencyInjection.Tests\RabbitMQ.Client.Core.DependencyInjection.Tests.csproj", "{85907F19-00B0-4BA6-9B7C-0452A174903D}"
44+
EndProject
4145
Global
4246
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4347
Debug|Any CPU = Debug|Any CPU
@@ -60,6 +64,10 @@ Global
6064
{1F81E848-7781-448F-BBBB-6A1E509B76CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
6165
{1F81E848-7781-448F-BBBB-6A1E509B76CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
6266
{1F81E848-7781-448F-BBBB-6A1E509B76CC}.Release|Any CPU.Build.0 = Release|Any CPU
67+
{85907F19-00B0-4BA6-9B7C-0452A174903D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68+
{85907F19-00B0-4BA6-9B7C-0452A174903D}.Debug|Any CPU.Build.0 = Debug|Any CPU
69+
{85907F19-00B0-4BA6-9B7C-0452A174903D}.Release|Any CPU.ActiveCfg = Release|Any CPU
70+
{85907F19-00B0-4BA6-9B7C-0452A174903D}.Release|Any CPU.Build.0 = Release|Any CPU
6371
EndGlobalSection
6472
GlobalSection(SolutionProperties) = preSolution
6573
HideSolutionNode = FALSE
@@ -70,6 +78,7 @@ Global
7078
{6E75E157-373A-4056-898B-3713CDD5C06C} = {04EFD8F7-5120-4072-9728-64203F6F4873}
7179
{1F81E848-7781-448F-BBBB-6A1E509B76CC} = {04EFD8F7-5120-4072-9728-64203F6F4873}
7280
{93D59B0E-856C-4260-B50E-57FE5C0F5073} = {BC4CDBDE-4AEE-44B3-B00B-380EB1AC5E62}
81+
{85907F19-00B0-4BA6-9B7C-0452A174903D} = {9D0289B2-C566-46CC-A53A-471BCBA0F277}
7382
EndGlobalSection
7483
GlobalSection(ExtensibilityGlobals) = postSolution
7584
SolutionGuid = {0EBBD182-65B2-47F9-ABBE-64B5B8C9652F}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Collections.Generic;
2+
3+
namespace RabbitMQ.Client.Core.DependencyInjection
4+
{
5+
internal class TreeNode
6+
{
7+
public string KeyPartition { get; set; }
8+
9+
public TreeNode Parent { get; set; }
10+
11+
public List<TreeNode> Nodes { get; set; } = new List<TreeNode>();
12+
13+
public bool IsLastNode { get; set; }
14+
}
15+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace RabbitMQ.Client.Core.DependencyInjection
5+
{
6+
internal static class WildcardExtensions
7+
{
8+
private const string Separator = ".";
9+
private const string SingleWordPattern = "*";
10+
private const string MultipleWordsPattern = "#";
11+
12+
internal static IEnumerable<TreeNode> ConstructTree(IEnumerable<string> routingKeyBindings)
13+
{
14+
var tree = new List<TreeNode>();
15+
16+
foreach (var binding in routingKeyBindings)
17+
{
18+
var keyParts = binding.Split(Separator);
19+
TreeNode parentTreeNode = null;
20+
var currentTreeNode = tree;
21+
for (var index = 0; index < keyParts.Length; index++)
22+
{
23+
var part = keyParts[index];
24+
25+
var existingNode = index == keyParts.Length - 1
26+
? currentTreeNode.FirstOrDefault(x => x.KeyPartition == part && x.IsLastNode)
27+
: currentTreeNode.FirstOrDefault(x => x.KeyPartition == part && !x.IsLastNode);
28+
29+
if (existingNode is null)
30+
{
31+
var node = new TreeNode
32+
{
33+
Parent = parentTreeNode,
34+
KeyPartition = part,
35+
IsLastNode = index == keyParts.Length - 1
36+
};
37+
currentTreeNode.Add(node);
38+
currentTreeNode = node.Nodes;
39+
parentTreeNode = node;
40+
}
41+
else
42+
{
43+
currentTreeNode = existingNode.Nodes;
44+
parentTreeNode = existingNode;
45+
}
46+
}
47+
}
48+
49+
return tree;
50+
}
51+
52+
internal static IEnumerable<string> GetMatchingRoutingKeys(IEnumerable<TreeNode> bindingsTree, string[] routingKeyParts, int depth = 0)
53+
{
54+
foreach (var node in bindingsTree)
55+
{
56+
var matchingPart = routingKeyParts[depth];
57+
if (node.KeyPartition == MultipleWordsPattern)
58+
{
59+
if (!node.Nodes.Any())
60+
{
61+
yield return CollectRoutingKeyInReverseOrder(node);
62+
}
63+
else
64+
{
65+
var tails = CollectRoutingKeyTails(routingKeyParts, depth);
66+
foreach (var tail in tails)
67+
{
68+
var routes = GetMatchingRoutingKeys(node.Nodes, tail, depth: 0);
69+
foreach (var route in routes)
70+
{
71+
yield return route;
72+
}
73+
}
74+
}
75+
}
76+
else if(node.KeyPartition == SingleWordPattern || node.KeyPartition == matchingPart)
77+
{
78+
if (routingKeyParts.Length == depth + 1 && !node.Nodes.Any())
79+
{
80+
yield return CollectRoutingKeyInReverseOrder(node);
81+
}
82+
else if (routingKeyParts.Length != depth + 1 && node.Nodes.Any())
83+
{
84+
var routes = GetMatchingRoutingKeys(node.Nodes, routingKeyParts, depth + 1).ToList();
85+
foreach (var route in routes)
86+
{
87+
yield return route;
88+
}
89+
}
90+
}
91+
}
92+
}
93+
94+
private static IEnumerable<string[]> CollectRoutingKeyTails(IReadOnlyCollection<string> routingKeyParts, int depthStart)
95+
{
96+
for (var index = depthStart; index < routingKeyParts.Count; index++)
97+
{
98+
yield return routingKeyParts.Skip(index).ToArray();
99+
}
100+
}
101+
102+
private static string CollectRoutingKeyInReverseOrder(TreeNode node, string routingKey = "")
103+
{
104+
routingKey = string.IsNullOrEmpty(routingKey) ? node.KeyPartition : $"{node.KeyPartition}.{routingKey}";
105+
return node.Parent != null ? CollectRoutingKeyInReverseOrder(node.Parent, routingKey) : routingKey;
106+
}
107+
}
108+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<ProjectReference Include="..\..\src\RabbitMQ.Client.Core.DependencyInjection\RabbitMQ.Client.Core.DependencyInjection.csproj" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
14+
<PackageReference Include="xunit" Version="2.4.1" />
15+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Xunit;
2+
3+
namespace RabbitMQ.Client.Core.DependencyInjection.Tests
4+
{
5+
public class WildcardExtensionsTests
6+
{
7+
[Fact]
8+
public void Test()
9+
{
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)