mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-07-30 17:30:40 +00:00
Rate Policy
This commit is contained in:
@@ -38,6 +38,8 @@ namespace Esiur.Resource;
|
||||
AttributeTargets.Field,
|
||||
AllowMultiple = false,
|
||||
Inherited = true)]
|
||||
public sealed class AutoDeliveredAttribute : Attribute
|
||||
public class AutoDeliveryAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
using Esiur.Data.Types;
|
||||
using System;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface |
|
||||
AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property |
|
||||
AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class DescriptionAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public DescriptionAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface |
|
||||
AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property |
|
||||
AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter,
|
||||
AllowMultiple = true, Inherited = true)]
|
||||
public sealed class ExampleAttribute : Attribute
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public ExampleAttribute(object value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct |
|
||||
AttributeTargets.Interface | AttributeTargets.Enum,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class CategoryAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public CategoryAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct |
|
||||
AttributeTargets.Interface | AttributeTargets.Enum,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class SinceAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public SinceAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property |
|
||||
AttributeTargets.Field | AttributeTargets.Event,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class TagsAttribute : Attribute
|
||||
{
|
||||
public string[] Values { get; }
|
||||
|
||||
public TagsAttribute(params string[] values) => Values = values;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Method | AttributeTargets.Event,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class UnitAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public UnitAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Parameter,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class MinimumAttribute : Attribute
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public MinimumAttribute(object value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Parameter,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class MaximumAttribute : Attribute
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public MaximumAttribute(object value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Parameter,
|
||||
AllowMultiple = true, Inherited = true)]
|
||||
public sealed class AllowedValueAttribute : Attribute
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public AllowedValueAttribute(object value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Parameter,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class PatternAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public PatternAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
|
||||
AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Parameter,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class FormatAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public FormatAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method,
|
||||
AllowMultiple = true, Inherited = true)]
|
||||
public sealed class PreconditionAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public PreconditionAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method,
|
||||
AllowMultiple = true, Inherited = true)]
|
||||
public sealed class PostconditionAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public PostconditionAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class EffectsAttribute : Attribute
|
||||
{
|
||||
public OperationEffects Value { get; }
|
||||
|
||||
public EffectsAttribute(OperationEffects value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property |
|
||||
AttributeTargets.Field | AttributeTargets.Event,
|
||||
AllowMultiple = true, Inherited = true)]
|
||||
public sealed class WarningAttribute : Attribute
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public WarningAttribute(string value) => Value = value;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property |
|
||||
AttributeTargets.Field | AttributeTargets.Event,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public sealed class RelatedMembersAttribute : Attribute
|
||||
{
|
||||
public byte[] Indexes { get; }
|
||||
|
||||
public RelatedMembersAttribute(params byte[] indexes) => Indexes = indexes;
|
||||
}
|
||||
@@ -5,12 +5,13 @@ using System.Text;
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that previous values of an exported property are retained
|
||||
/// Indicates that previous property values or event occurrences are retained
|
||||
/// and may be fetched remotely.
|
||||
/// </summary>
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Property |
|
||||
AttributeTargets.Field,
|
||||
AttributeTargets.Field |
|
||||
AttributeTargets.Event,
|
||||
AllowMultiple = false,
|
||||
Inherited = true)]
|
||||
public sealed class HistoricalAttribute : Attribute
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// Applies a named Warehouse rate policy to an exported function or property setter.
|
||||
/// </summary>
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Method | AttributeTargets.Property,
|
||||
AllowMultiple = false,
|
||||
Inherited = true)]
|
||||
public sealed class RateControlAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name used to resolve the policy from the owning Warehouse.
|
||||
/// </summary>
|
||||
public string PolicyName { get; }
|
||||
|
||||
public RateControlAttribute(string policyName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(policyName))
|
||||
throw new ArgumentException("A rate policy name is required.", nameof(policyName));
|
||||
|
||||
PolicyName = policyName;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,9 @@ using System.Text;
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks an exported function as streaming and specifies its delivery mode.
|
||||
/// Marks an AsyncReply-returning exported function as streaming and specifies
|
||||
/// its delivery mode. IEnumerable and IAsyncEnumerable return types infer push
|
||||
/// and pull mode respectively and do not require this attribute.
|
||||
/// </summary>
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Method,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource.Attributes
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Class |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource.Attributes
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that an exported property has volatile synchronization
|
||||
|
||||
@@ -31,6 +31,7 @@ using Esiur.Protocol;
|
||||
using Esiur.Proxy;
|
||||
using Esiur.Security.Authority;
|
||||
using Esiur.Security.Permissions;
|
||||
using Esiur.Security.RateLimiting;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using System;
|
||||
using System.Collections;
|
||||
@@ -88,6 +89,8 @@ public class Warehouse
|
||||
|
||||
Map<string, IAuthenticationProvider> _authenticationProviders = new Map<string, IAuthenticationProvider>();
|
||||
List<IPermissionsManager> _permissionsManagers = new List<IPermissionsManager>();
|
||||
readonly ConcurrentDictionary<string, RatePolicy> _ratePolicies
|
||||
= new ConcurrentDictionary<string, RatePolicy>(StringComparer.Ordinal);
|
||||
|
||||
|
||||
object _typeDefsLock = new object();
|
||||
@@ -102,6 +105,11 @@ public class Warehouse
|
||||
|
||||
public KeyList<string, ProtocolInstance> Protocols { get; } = new KeyList<string, ProtocolInstance>();
|
||||
|
||||
/// <summary>
|
||||
/// Runtime settings for this Warehouse.
|
||||
/// </summary>
|
||||
public WarehouseConfiguration Configuration { get; }
|
||||
|
||||
private Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)");
|
||||
|
||||
|
||||
@@ -121,6 +129,41 @@ public class Warehouse
|
||||
_permissionsManagers.Add(manager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a named rate policy referenced by RateControl attributes.
|
||||
/// </summary>
|
||||
public void AddRatePolicy(RatePolicy policy)
|
||||
{
|
||||
if (policy == null)
|
||||
throw new ArgumentNullException(nameof(policy));
|
||||
if (string.IsNullOrWhiteSpace(policy.Name))
|
||||
throw new ArgumentException("The rate policy must have a name.", nameof(policy));
|
||||
if (!_ratePolicies.TryAdd(policy.Name, policy))
|
||||
throw new InvalidOperationException($"A rate policy named `{policy.Name}` is already registered.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a policy under the supplied name.
|
||||
/// </summary>
|
||||
public void AddRatePolicy(string name, RatePolicy policy)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("A rate policy name is required.", nameof(name));
|
||||
if (policy == null)
|
||||
throw new ArgumentNullException(nameof(policy));
|
||||
|
||||
policy.Name = name;
|
||||
AddRatePolicy(policy);
|
||||
}
|
||||
|
||||
public RatePolicy? TryGetRatePolicy(string name)
|
||||
=> !string.IsNullOrWhiteSpace(name) && _ratePolicies.TryGetValue(name, out var policy)
|
||||
? policy
|
||||
: null;
|
||||
|
||||
public bool RemoveRatePolicy(string name)
|
||||
=> !string.IsNullOrWhiteSpace(name) && _ratePolicies.TryRemove(name, out _);
|
||||
|
||||
public IAuthenticationProvider GetAuthenticationProvider(string name)
|
||||
{
|
||||
if (_authenticationProviders.ContainsKey(name))
|
||||
@@ -137,8 +180,14 @@ public class Warehouse
|
||||
}
|
||||
|
||||
|
||||
public Warehouse()
|
||||
public Warehouse() : this(new WarehouseConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
public Warehouse(WarehouseConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||
|
||||
Protocols.Add("EP",
|
||||
async (name, context)
|
||||
=> await New<EpConnection>(name, context));
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// Runtime configuration owned by a Warehouse instance.
|
||||
/// </summary>
|
||||
public sealed class WarehouseConfiguration
|
||||
{
|
||||
public RateControlConfiguration RateControl { get; set; } = new RateControlConfiguration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures how repeated rate-control denials affect an EP connection.
|
||||
/// </summary>
|
||||
public sealed class RateControlConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of denials within <see cref="DenialWindow"/> that blocks the connection.
|
||||
/// Set to zero to disable connection blocking.
|
||||
/// </summary>
|
||||
public int DenialsBeforeConnectionBlock { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Window in which denials are accumulated for connection blocking.
|
||||
/// </summary>
|
||||
public TimeSpan DenialWindow { get; set; } = TimeSpan.FromMinutes(1);
|
||||
|
||||
/// <summary>
|
||||
/// Delay before a blocked connection is closed, allowing its final error reply to flush.
|
||||
/// </summary>
|
||||
public TimeSpan ConnectionBlockDelay { get; set; } = TimeSpan.FromMilliseconds(100);
|
||||
}
|
||||
Reference in New Issue
Block a user