Skip to content

Commit 0ade3ef

Browse files
authored
Source generate ShardedGatewayClient events and refactor (#111)
* Source generate ShardedGatewayClient events * Update tests * Add missing sharded gateway client method parameters and cleanup * Use PolySharp for source generators
1 parent 111978a commit 0ade3ef

File tree

13 files changed

+355
-1397
lines changed

13 files changed

+355
-1397
lines changed

Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ public ShardedGatewayClientHostedService(ShardedGatewayClient client, ILogger<Sh
2020

2121
public Task StartAsync(CancellationToken cancellationToken)
2222
{
23-
return _client.StartAsync();
23+
return _client.StartAsync(cancellationToken: cancellationToken);
2424
}
2525

2626
public Task StopAsync(CancellationToken cancellationToken)
2727
{
28-
return _client.CloseAsync();
28+
return _client.CloseAsync(cancellationToken: cancellationToken);
2929
}
3030

3131
private ValueTask LogAsync(GatewayClient client, LogMessage message)

NetCord.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<File Path="SourceGenerators/Directory.Build.targets" />
7272
<Project Path="SourceGenerators/MethodsForPropertiesGenerator/MethodsForPropertiesGenerator.csproj" />
7373
<Project Path="SourceGenerators/RestClientMethodAliasesGenerator/RestClientMethodAliasesGenerator.csproj" />
74+
<Project Path="SourceGenerators/ShardedGatewayClientEventsGenerator/ShardedGatewayClientEventsGenerator.csproj" Id="cb9012b4-aed0-4ab9-b182-aa167bdb9b96" />
7475
<Project Path="SourceGenerators/Shared/Shared.csproj" />
7576
<Project Path="SourceGenerators/UserAgentHeaderGenerator/UserAgentHeaderGenerator.csproj" />
7677
</Folder>

NetCord/Gateway/ShardedGatewayClient.cs

Lines changed: 111 additions & 1389 deletions
Large diffs are not rendered by default.

NetCord/Gateway/Voice/VoiceClientConfiguration.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using NetCord.Gateway.LatencyTimers;
22
using NetCord.Gateway.ReconnectStrategies;
3-
using NetCord.Gateway.Voice.Encryption;
43
using NetCord.Gateway.Voice.UdpSockets;
54
using NetCord.Gateway.WebSockets;
65

NetCord/NetCord.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<ProjectReference Include="..\SourceGenerators\MethodsForPropertiesGenerator\MethodsForPropertiesGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
55
<ProjectReference Include="..\SourceGenerators\UserAgentHeaderGenerator\UserAgentHeaderGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
66
<ProjectReference Include="..\SourceGenerators\RestClientMethodAliasesGenerator\RestClientMethodAliasesGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
7+
<ProjectReference Include="..\SourceGenerators\ShardedGatewayClientEventsGenerator\ShardedGatewayClientEventsGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
78
<ProjectReference Include="..\SourceGenerators\Shared\Shared.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
89
</ItemGroup>
910

SourceGenerators/Directory.Build.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
14+
<PackageReference Include="PolySharp" Version="1.15.0">
15+
<PrivateAssets>all</PrivateAssets>
16+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
</PackageReference>
1418
</ItemGroup>
1519

1620
</Project>

SourceGenerators/MethodsForPropertiesGenerator/MethodsForPropertiesGenerator.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<ItemGroup>
4-
<PackageReference Include="IndexRange" Version="1.0.3" />
54
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
65
</ItemGroup>
76

SourceGenerators/RestClientMethodAliasesGenerator/RestClientMethodAliasesGenerator.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<ItemGroup>
4-
<PackageReference Include="IndexRange" Version="1.0.3" />
54
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
65
</ItemGroup>
76

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
using System.Text;
2+
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
using Microsoft.CodeAnalysis.Text;
6+
7+
using Shared;
8+
9+
namespace ShardedGatewayClientEventsGenerator;
10+
11+
[Generator(LanguageNames.CSharp)]
12+
public class ShardedGatewayClientEventsGenerator : IIncrementalGenerator
13+
{
14+
private const string Namespace = "NetCord.Gateway";
15+
private const string ShardedGatewayClientName = "ShardedGatewayClient";
16+
private const string GatewayClientName = "GatewayClient";
17+
18+
public void Initialize(IncrementalGeneratorInitializationContext context)
19+
{
20+
var typeSymbols = context.SyntaxProvider
21+
.CreateSyntaxProvider((node, cancellationToken) => node is ClassDeclarationSyntax { Identifier.Text: GatewayClientName },
22+
(context, cancellationToken) => (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!)
23+
.Where(s => s.ContainingNamespace is { } namespaceSymbol && namespaceSymbol.ToDisplayString() is Namespace);
24+
25+
context.RegisterSourceOutput(typeSymbols, (context, source) => context.AddSource("ShardedGatewayClient.g.cs", SourceText.From(GenerateEvents(source), Encoding.UTF8)));
26+
}
27+
28+
private string GenerateEvents(INamedTypeSymbol typeSymbol)
29+
{
30+
StringWriter stringWriter = new();
31+
stringWriter.WriteAutoGeneratedComment();
32+
stringWriter.WriteLine();
33+
34+
stringWriter.WriteNullableDirective();
35+
stringWriter.WriteLine();
36+
37+
stringWriter.Write("namespace ");
38+
stringWriter.Write(Namespace);
39+
stringWriter.WriteLine(";");
40+
stringWriter.WriteLine();
41+
42+
stringWriter.Write("partial class ");
43+
stringWriter.WriteLine(ShardedGatewayClientName);
44+
stringWriter.WriteLine("{");
45+
46+
var events = GetEvents(typeSymbol);
47+
48+
WriteEvents(stringWriter, events);
49+
50+
WriteHookEventsMethod(stringWriter, events);
51+
52+
stringWriter.WriteLine("}");
53+
54+
return stringWriter.ToString();
55+
}
56+
57+
private void WriteEvents(StringWriter stringWriter, IEventSymbol[] events)
58+
{
59+
foreach (var eventSymbol in events)
60+
{
61+
var eventType = (INamedTypeSymbol)eventSymbol.Type;
62+
var hasArgs = eventType.Arity is 2;
63+
64+
stringWriter.WriteXmlComment(eventSymbol);
65+
66+
stringWriter.WriteIndentation(1);
67+
stringWriter.Write("public event ");
68+
69+
WriteEventType(stringWriter, eventType);
70+
71+
stringWriter.WriteLine(eventSymbol.Name);
72+
stringWriter.WriteIndentation(1);
73+
stringWriter.WriteLine("{");
74+
stringWriter.WriteIndentation(2);
75+
stringWriter.WriteLine("add");
76+
stringWriter.WriteIndentation(2);
77+
stringWriter.WriteLine("{");
78+
stringWriter.WriteIndentation(3);
79+
stringWriter.Write("HookEvent(");
80+
81+
var internalName = ToInternalName(eventSymbol.Name);
82+
83+
stringWriter.Write(internalName);
84+
stringWriter.Write("Lock, value, ref ");
85+
stringWriter.Write(internalName);
86+
stringWriter.Write(", client => ");
87+
88+
if (hasArgs)
89+
stringWriter.Write("a => ");
90+
else
91+
stringWriter.Write("() => ");
92+
93+
stringWriter.Write(internalName);
94+
95+
if (hasArgs)
96+
stringWriter.Write("!(client, a), (c, e) => c.");
97+
else
98+
stringWriter.Write("!(client), (c, e) => c.");
99+
100+
stringWriter.Write(eventSymbol.Name);
101+
stringWriter.WriteLine(" += e);");
102+
stringWriter.WriteIndentation(2);
103+
stringWriter.WriteLine("}");
104+
105+
stringWriter.WriteIndentation(2);
106+
stringWriter.WriteLine("remove");
107+
stringWriter.WriteIndentation(2);
108+
stringWriter.WriteLine("{");
109+
stringWriter.WriteIndentation(3);
110+
stringWriter.Write("UnhookEvent(");
111+
stringWriter.Write(internalName);
112+
stringWriter.Write("Lock, value, ref ");
113+
stringWriter.Write(internalName);
114+
stringWriter.Write(", (c, e) => c.");
115+
stringWriter.Write(eventSymbol.Name);
116+
stringWriter.WriteLine(" -= e);");
117+
stringWriter.WriteIndentation(2);
118+
stringWriter.WriteLine("}");
119+
stringWriter.WriteIndentation(1);
120+
stringWriter.WriteLine("}");
121+
122+
stringWriter.WriteIndentation(1);
123+
124+
stringWriter.Write("private ");
125+
WriteEventType(stringWriter, eventType);
126+
stringWriter.Write(internalName);
127+
stringWriter.WriteLine(";");
128+
129+
stringWriter.WriteIndentation(1);
130+
131+
stringWriter.Write("private readonly object ");
132+
stringWriter.Write(internalName);
133+
stringWriter.WriteLine("Lock = new();");
134+
stringWriter.WriteLine();
135+
}
136+
}
137+
138+
private void WriteHookEventsMethod(StringWriter stringWriter, IEventSymbol[] events)
139+
{
140+
stringWriter.WriteIndentation(1);
141+
142+
stringWriter.Write("private void HookEvents(");
143+
stringWriter.Write(GatewayClientName);
144+
stringWriter.WriteLine(" client)");
145+
146+
stringWriter.WriteIndentation(1);
147+
stringWriter.WriteLine("{");
148+
149+
foreach (var eventSymbol in events)
150+
{
151+
var eventType = (INamedTypeSymbol)eventSymbol.Type;
152+
var hasArgs = eventType.Arity is 2;
153+
154+
stringWriter.WriteIndentation(2);
155+
156+
stringWriter.Write("HookEvent(client, ");
157+
158+
var internalName = ToInternalName(eventSymbol.Name);
159+
160+
stringWriter.Write(internalName);
161+
stringWriter.Write("Lock, ref ");
162+
stringWriter.Write(internalName);
163+
164+
if (hasArgs)
165+
stringWriter.Write(", a => ");
166+
else
167+
stringWriter.Write(", () => ");
168+
169+
stringWriter.Write(internalName);
170+
171+
if (hasArgs)
172+
stringWriter.Write("!(client, a), (c, e) => c.");
173+
else
174+
stringWriter.Write("!(client), (c, e) => c.");
175+
176+
stringWriter.Write(eventSymbol.Name);
177+
stringWriter.WriteLine(" += e);");
178+
}
179+
180+
stringWriter.WriteIndentation(1);
181+
stringWriter.WriteLine("}");
182+
}
183+
184+
private static void WriteEventType(StringWriter stringWriter, INamedTypeSymbol eventType)
185+
{
186+
stringWriter.Write(eventType.ContainingNamespace.ToDisplayString());
187+
stringWriter.Write(".");
188+
stringWriter.Write(eventType.Name);
189+
stringWriter.Write("<");
190+
stringWriter.Write(GatewayClientName);
191+
192+
var typeArguments = eventType.TypeArguments;
193+
int length = typeArguments.Length;
194+
for (int i = 0; i < length; i++)
195+
{
196+
stringWriter.Write(", ");
197+
198+
var typeArgument = typeArguments[i];
199+
stringWriter.Write(typeArgument.ContainingNamespace.ToDisplayString());
200+
stringWriter.Write(".");
201+
stringWriter.Write(typeArgument.Name);
202+
}
203+
stringWriter.Write(">? ");
204+
}
205+
206+
private static IEventSymbol[] GetEvents(INamedTypeSymbol typeSymbol)
207+
{
208+
return
209+
[
210+
.. typeSymbol.BaseType!.GetMembers().OfType<IEventSymbol>(),
211+
.. typeSymbol.GetMembers().OfType<IEventSymbol>()
212+
];
213+
}
214+
215+
private static Span<char> ToInternalName(string name)
216+
{
217+
Span<char> copy = new char[name.Length + 1];
218+
copy[0] = '_';
219+
name.AsSpan(1).CopyTo(copy[2..]);
220+
copy[1] = char.ToLowerInvariant(name[0]);
221+
return copy;
222+
}
223+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<ItemGroup>
4+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
5+
</ItemGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="..\Shared\Shared.csproj" />
9+
</ItemGroup>
10+
11+
</Project>

0 commit comments

Comments
 (0)