shared variables for checker attributes
This commit is contained in:
parent
2cf6cd4a7d
commit
30daf382ba
|
|
@ -1,13 +1,103 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace SimpleHttpServer.Types;
|
namespace SimpleHttpServer.Types;
|
||||||
|
|
||||||
public abstract class InternalEndpointCheckAttribute : Attribute {
|
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<FieldInfo, List<(InternalEndpointCheckAttribute, SharedVariable)>> 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<InternalEndpointCheckAttribute> endPointChecks) {
|
||||||
|
Dictionary<FieldInfo, List<(InternalEndpointCheckAttribute, SharedVariable)>> globals = new();
|
||||||
|
foreach (var check in endPointChecks) {
|
||||||
|
check.Initialize(instance, globals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface SharedVariable {
|
||||||
|
// Tagging interface
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Mutable Shared Variable. Fields of this type need to be initialized in the CCtor.
|
||||||
|
/// </summary>
|
||||||
|
protected sealed class MSV<V> : 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) => v.Val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an Immutable Shared Variable. Fields of this type need to be initialized in the CCtor.
|
||||||
|
/// </summary>
|
||||||
|
protected sealed class ISV<V> : 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) => v.Val;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executed when the endpoint is invoked. The endpoint invocation is skipped if any of the checks fail.
|
/// Executed when the endpoint is invoked. The endpoint invocation is skipped if any of the checks fail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True to allow invocation, false to prevent.</returns>
|
/// <returns>True to allow invocation, false to prevent.</returns>
|
||||||
public abstract bool Check(HttpListenerRequest req);
|
public abstract bool Check(HttpListenerRequest req);
|
||||||
|
|
||||||
|
protected virtual bool Match(InternalEndpointCheckAttribute other) => true;
|
||||||
|
|
||||||
internal abstract void SetInstance(object? instance);
|
internal abstract void SetInstance(object? instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,7 +108,9 @@ public abstract class BaseEndpointCheckAttribute<T> : InternalEndpointCheckAttri
|
||||||
/// Will be null iff an class factory was passed in <see cref="HttpServer.RegisterEndpointsFromType{T}(Func{T}?)"/>.
|
/// Will be null iff an class factory was passed in <see cref="HttpServer.RegisterEndpointsFromType{T}(Func{T}?)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal T? EndpointClassInstance { get; internal set; } = default;
|
protected internal T? EndpointClassInstance { get; internal set; } = default;
|
||||||
public BaseEndpointCheckAttribute() { }
|
|
||||||
|
public BaseEndpointCheckAttribute() : base() { }
|
||||||
|
|
||||||
internal override void SetInstance(object? instance) {
|
internal override void SetInstance(object? instance) {
|
||||||
if (instance != null)
|
if (instance != null)
|
||||||
EndpointClassInstance = (T?) instance;
|
EndpointClassInstance = (T?) instance;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user