diff --git a/src/pdns-dhcp/PowerDns/Methods.cs b/src/pdns-dhcp/PowerDns/Methods.cs index bc823e6..37f5928 100644 --- a/src/pdns-dhcp/PowerDns/Methods.cs +++ b/src/pdns-dhcp/PowerDns/Methods.cs @@ -1,21 +1,12 @@ -using System.Text.Json.Serialization; - namespace pdns_dhcp.PowerDns; public interface IMethod; -[JsonPolymorphic(TypeDiscriminatorPropertyName = "method")] -[JsonDerivedType(typeof(InitializeMethod), "initialize")] -[JsonDerivedType(typeof(LookupMethod), "lookup")] -public class Method; +public record MethodBase(string Method); -public abstract class Method(TParam parameters) : Method - where TParam : MethodParameters -{ - [JsonPropertyName("parameters")] - public TParam Parameters => parameters; -} +public abstract record Method(string Method, TParam Parameters) : MethodBase(Method) + where TParam : MethodParameters; -public class InitializeMethod(InitializeParameters parameters) : Method(parameters), IMethod; +public record InitializeMethod(InitializeParameters Parameters) : Method("initialize", Parameters), IMethod; -public class LookupMethod(LookupParameters parameters) : Method(parameters), IMethod; +public record LookupMethod(LookupParameters Parameters) : Method("lookup", Parameters), IMethod; diff --git a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs index e2ee4c6..795b9a9 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs @@ -1,4 +1,5 @@ using System.Buffers; +using System.Collections.ObjectModel; using System.IO.Pipelines; using System.Net.Sockets; using System.Text.Json; @@ -15,9 +16,34 @@ namespace pdns_dhcp.PowerDns; public class PowerDnsHandler : ConnectionHandler { + delegate MethodBase? HandlerConverter(in JsonElement element); + + private static readonly ReadOnlyDictionary Converters; + private readonly ILogger _logger; private readonly DnsRepository _repository; + static PowerDnsHandler() + { + Dictionary converters = new(StringComparer.OrdinalIgnoreCase) + { + ["initialize"] = ToInitialize, + ["lookup"] = ToLookup + }; + + Converters = converters.AsReadOnly(); + + static InitializeMethod ToInitialize(in JsonElement element) + { + return new(element.Deserialize(PowerDnsSerializerContext.Default.InitializeParameters)!); + } + + static LookupMethod ToLookup(in JsonElement element) + { + return new(element.Deserialize(PowerDnsSerializerContext.Default.LookupParameters)!); + } + } + public PowerDnsHandler(DnsRepository repository, ILogger logger) { _logger = logger; @@ -41,22 +67,43 @@ public class PowerDnsHandler : ConnectionHandler foreach (var memory in read.Buffer) { buffer.Write(memory.Span); - if (ConsumeJson(buffer, json, ref state)) + if (!ConsumeJson(buffer, json, ref state)) + { + continue; + } + + MethodBase method; + try + { + using var jsonDocument = JsonDocument.Parse(json.WrittenMemory); + var root = jsonDocument.RootElement; + if (!root.TryGetProperty("method", out var methodElement)) + { + continue; + } + + if (Parse(methodElement, root.GetProperty("parameters")) is not { } methodLocal) + { + continue; + } + + method = methodLocal; + } + finally { - var method = JsonSerializer.Deserialize(json.WrittenSpan, PowerDnsSerializerContext.Default.Method)!; json.Clear(); state = default; - - Reply reply = BoolReply.False; - try - { - reply = await Handle(method, connection.ConnectionClosed).ConfigureAwait(false); - } - catch (Exception e) { } - - await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) - .ConfigureAwait(continueOnCapturedContext: false); } + + Reply reply = BoolReply.False; + try + { + reply = await Handle(method, connection.ConnectionClosed).ConfigureAwait(false); + } + catch (Exception e) { } + + await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) + .ConfigureAwait(continueOnCapturedContext: false); } input.AdvanceTo(read.Buffer.End); @@ -111,9 +158,20 @@ public class PowerDnsHandler : ConnectionHandler return final; } + + static MethodBase? Parse(in JsonElement element, in JsonElement parameters) + { + HandlerConverter? converter = default; + return element.GetString() switch + { + null => null, + { } methodName when !Converters.TryGetValue(methodName, out converter) => new MethodBase(methodName), + _ => converter(parameters) + }; + } } - private ValueTask Handle(Method method, CancellationToken cancellationToken = default) + private ValueTask Handle(MethodBase method, CancellationToken cancellationToken = default) { return method switch { @@ -123,7 +181,7 @@ public class PowerDnsHandler : ConnectionHandler _ => LogUnhandled(_logger, method) }; - static ValueTask LogUnhandled(ILogger logger, Method method) + static ValueTask LogUnhandled(ILogger logger, MethodBase method) { logger.LogWarning("Unhandled Method {Method}", method); return ValueTask.FromResult(BoolReply.False); diff --git a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs index 20fddce..84c3085 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs @@ -3,7 +3,6 @@ using System.Text.Json.Serialization; namespace pdns_dhcp.PowerDns; [JsonSerializable(typeof(Reply))] -[JsonSerializable(typeof(Method))] [JsonSerializable(typeof(Parameters))] [JsonSourceGenerationOptions( DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,