Packet Handler Generator
Trên trang này
PacketHandlerGenerator (analyzers/Nalix.Analyzers.Generators/PacketHandlerGenerator.cs) là một incremental Roslyn source generator, biên dịch các lớp được đánh dấu [PacketHandler] thành các implementation IPacketHandlerCompiler không dùng reflection, được đăng ký qua [ModuleInitializer].
Ánh xạ mã nguồn
analyzers/Nalix.Analyzers.Generators/PacketHandlerGenerator.csanalyzers/Nalix.Analyzers.Generators/Internal/GeneratorDiagnosticDescriptors.cs
Việc generator làm lúc biên dịch
- Tìm controller: Tìm mọi lớp cụ thể được đánh dấu
[PacketHandler]và kiểm tra các method[PacketOpcode]của chúng. - Nối constructor và
[Inject]:- Chọn constructor có thể truy cập (
publichoặcinternal) với nhiều tham số nhất để khởi tạo controller. Tham sốConfigurationLoaderđược lấy quaConfigurationManager.Instance.Get<TParam>(), còn tham số service được lấy quaInstanceManager.Instance.GetExistingInstance<TParam>()(nếu không có thì dùng giá trị mặc định của tham số, hoặc némInvalidOperationExceptionnếu tham số là bắt buộc). - Nếu controller khai báo field hoặc property có đánh dấu
[Inject](yêu cầu lớp controller được khai báopartial), generator sinh ra<Controller>_Inject.g.cschứaprivate void InitializeDependencies()và gọi nó bên trong factory được sinh ra.
- Chọn constructor có thể truy cập (
- Biên dịch metadata: Đọc
[PacketOpcode],[PacketTimeout],[PacketPermission],[PacketEncryption],[PacketRateLimit]và[PacketConcurrencyLimit]trên mỗi method handler (với giá trị dự phòng ở mức controller), rồi tạo một descriptorPacketMetadataquaPacketMetadataBuilder. - Biên dịch delegate: Sinh ra một lambda invoker có kiểu mạnh, ép
IPacketContext<TPacket>sangIPacketContext<TConcretePacket>, lấy các tham số[FromScope]quactx.Scope.GetRequiredService<TParam>()(hoặcctx.Scope.GetService<TParam>()khi kiểu tham số làTParam?nullable), rồi gọi handler mà không dùng reflection hay boxing. - Đăng ký Module Initializer: Sinh ra
PacketHandlersGenerated.Initialize()([ModuleInitializer]) gọiPacketHandlerRegistry.Register(typeof(TController), new TController_PacketHandlerCompiler()).
Chữ ký handler được hỗ trợ
Mọi method [PacketOpcode] phải tuân theo hợp đồng tham số sau:
| Vị trí tham số | Kiểu / Attribute bắt buộc | Cách cung cấp |
|---|---|---|
Tham số 0 (bắt buộc) | IPacketContext<TPacket> (với TPacket : IPacket) | Được truyền trực tiếp từ context điều phối pooled lúc chạy (context.Packet, context.Connection, context.Sender, context.Scope, context.CancellationToken). |
Tham số 1..N (tùy chọn) | Kiểu tham chiếu TService (hoặc TService?) được đánh dấu [FromScope] | TService không nullable được lấy qua context.Scope.GetRequiredService<TService>(); TService? nullable được lấy qua context.Scope.GetService<TService>(). |
Kiểu trả về được hỗ trợ
voidTaskValueTaskTResult(ví dụ trả về mộtIPacketphản hồi,stringhoặcbyte[])Task<TResult>ValueTask<TResult>IAsyncEnumerable<TElement>(phản hồi streaming từ server tới client)
Nội bộ, generator phân loại kiểu trả về của mỗi handler thành enum công khai Nalix.Analyzers.Generators.HandlerReturnKind (Void, NonGenericValueTask, GenericValueTask, NonGenericTask, GenericTask, AsyncEnumerable, SyncValue), hiển thị qua HandlerMethodModel.ReturnKind, và sinh ra một thân điều phối khác cho mỗi loại. Đây là chi tiết cài đặt nội bộ của generator, không phải API để bạn gọi.
Ví dụ
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Nalix.Abstractions.Injection;
using Nalix.Abstractions.Networking.Packets;
using Nalix.Abstractions.Security;
[PacketHandler("AuthController")]
public sealed partial class AuthController
{
[Inject]
private ILogger? _logger;
[PacketOpcode(0x1001)]
[PacketPermission(PermissionLevel.NONE)]
[PacketEncryption(true)]
public ValueTask HandleLoginAsync(
IPacketContext<LoginRequest> context,
[FromScope] IUserSessionTracker tracker)
{
_logger?.LogInformation("Login from {Id}", context.Connection.ConnectionId);
tracker.Track(context.Connection.ConnectionId);
return context.Sender.ReplyAsync(new LoginResponse { Success = true });
}
}
Chẩn đoán được phát ra
| ID | Tiêu đề | Mức độ | Nguyên nhân |
|---|---|---|---|
NALIX003 | Method handler của controller gói tin có chữ ký không được hỗ trợ | Cảnh báo | Tham số 0 bị thiếu hoặc không phải IPacketContext<TPacket>. |
NALIX067 | Method handler bị loại khỏi bảng điều phối | Lỗi | Tham số ở chỉ số >= 1 bị thiếu [FromScope] hoặc không phải kiểu tham chiếu. |
NALIX104 | Field [Inject] không được là readonly | Lỗi | Field được đánh dấu [Inject] được khai báo readonly. |