From 30daf382ba2b960b9f8c80a5aa501bbf719faa48 Mon Sep 17 00:00:00 2001 From: 00asdf Date: Fri, 26 Jul 2024 02:29:07 +0200 Subject: [PATCH] shared variables for checker attributes --- .../Types/BaseEndpointCheckAttribute.cs | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/SimpleHttpServer/Types/BaseEndpointCheckAttribute.cs b/SimpleHttpServer/Types/BaseEndpointCheckAttribute.cs index c4823f9..fdd2811 100644 --- a/SimpleHttpServer/Types/BaseEndpointCheckAttribute.cs +++ b/SimpleHttpServer/Types/BaseEndpointCheckAttribute.cs @@ -1,13 +1,103 @@ using System.Net; +using System.Reflection; namespace SimpleHttpServer.Types; public abstract class InternalEndpointCheckAttribute : Attribute { + public InternalEndpointCheckAttribute() { + CheckSharedVariables(); + } + + private void CheckSharedVariables() { + foreach (var f in GetType().GetRuntimeFields()) { + if (f.FieldType.IsAssignableTo(typeof(SharedVariable))) { + if (!f.IsInitOnly) { + throw new Exception($"Found non-readonly global field {f}!"); + } + if (f.GetValue(this) == null) { + throw new Exception("Global fields must be assigned in the CCTOR!"); + } + } + } + } + + private void Initialize(object? instance, Dictionary> globals) { + SetInstance(instance); + foreach (var f in GetType().GetRuntimeFields()) { + if (f.FieldType.IsAssignableTo(typeof(SharedVariable))) { + SharedVariable origVal = (SharedVariable) f.GetValue(this)!; + if (globals.TryGetValue(f, out var options)) { + bool foundMatch = false; + foreach ((var checker, var gv) in options) { + if (Match(checker)) { + foundMatch = true; + // we need to unify their global variables + f.SetValue(this, gv); + } + } + if (!foundMatch) { + options.Add((this, origVal)); + } + } else { + globals.Add(f, new List<(InternalEndpointCheckAttribute, SharedVariable)>() { (this, origVal) }); + } + } + } + } + + public static void Initialize(object? instance, IEnumerable endPointChecks) { + Dictionary> globals = new(); + foreach (var check in endPointChecks) { + check.Initialize(instance, globals); + } + } + + private interface SharedVariable { + // Tagging interface + } + + /// + /// Represents a Mutable Shared Variable. Fields of this type need to be initialized in the CCtor. + /// + protected sealed class MSV : SharedVariable { + private readonly V __default; + + public V Val { get; set; } = default!; + + public MSV() : this(default!) { } + + public MSV(V _default) { + __default = _default; + } + + public static implicit operator V(MSV v) => v.Val; + } + + /// + /// Represents an Immutable Shared Variable. Fields of this type need to be initialized in the CCtor. + /// + protected sealed class ISV : SharedVariable { + private readonly V __default; + + public V Val { get; } = default!; + + public ISV() : this(default!) { } + + public ISV(V _default) { + __default = _default; + } + + public static implicit operator V(ISV v) => v.Val; + } + /// /// Executed when the endpoint is invoked. The endpoint invocation is skipped if any of the checks fail. /// /// True to allow invocation, false to prevent. public abstract bool Check(HttpListenerRequest req); + + protected virtual bool Match(InternalEndpointCheckAttribute other) => true; + internal abstract void SetInstance(object? instance); } @@ -18,7 +108,9 @@ public abstract class BaseEndpointCheckAttribute : InternalEndpointCheckAttri /// Will be null iff an class factory was passed in . /// protected internal T? EndpointClassInstance { get; internal set; } = default; - public BaseEndpointCheckAttribute() { } + + public BaseEndpointCheckAttribute() : base() { } + internal override void SetInstance(object? instance) { if (instance != null) EndpointClassInstance = (T?) instance;