Files
lux/EgwCoreLib.Lux.Data/Services/BaseServ.cs
T
2025-09-20 10:16:03 +02:00

165 lines
6.6 KiB
C#

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using System.Text;
using System.Threading.Tasks;
namespace EgwCoreLib.Lux.Data.Services
{
/// <summary>
/// BaseServ class serves as a foundational service for handling Redis operations and message piping.
/// It provides common configurations, caching strategies, and message delivery mechanisms for derived services.
/// The class initializes Redis connections, sets up message channels, and manages JSON serialization with loop handling.
/// </summary>
public class BaseServ
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the BaseServ class.
/// </summary>
/// <param name="Configuration">Configuration object to retrieve application settings.</param>
/// <param name="RedisConn">Redis connection multiplexer for database operations.</param>
public BaseServ(IConfiguration Configuration, IConnectionMultiplexer RedisConn)
{
configuration = Configuration;
redisConn = RedisConn;
redisDb = redisConn.GetDatabase();
svgChannel = configuration.GetValue<string>("ServerConf:SvgChannel") ?? "svg:img";
// Appends ":*" to the SVG channel to enable wildcard subscription for dynamic events
if (!svgChannel.EndsWith(":*"))
{
svgChannel += ":*";
}
// JSON serializer settings to prevent circular reference errors during serialization
// ReferenceLoopHandling.Ignore ensures that circular references in objects are ignored instead of throwing exceptions
JSSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
// Initializes a message pipe for communication between calculation services and UI components
// Messages are sent via the specified Redis channel (svgChannel)
CalcDonePipe = new MessagePipe(redisConn, svgChannel);
}
#endregion Public Constructors
#region Protected Fields
/// <summary>
/// The Redis channel name used for subscribing to and publishing messages.
/// Default is "svg:img", with a wildcard suffix ":*" to enable dynamic message matching.
/// </summary>
private string svgChannel = "";
/// <summary>
/// Configuration object for accessing application settings (e.g., connection strings, service parameters).
/// This is a static instance shared across all instances of BaseServ.
/// </summary>
protected static IConfiguration configuration = null!;
/// <summary>
/// JSON serialization settings to handle circular references (e.g., object references to themselves).
/// Prevents exceptions during serialization by ignoring loops.
/// </summary>
protected JsonSerializerSettings? JSSettings;
/// <summary>
/// Message pipe for delivering completion messages from calculation services to the UI.
/// Uses Redis to publish messages on the svgChannel for real-time updates.
/// </summary>
public MessagePipe CalcDonePipe { get; set; } = null!;
/// <summary>
/// Redis connection multiplexer that provides access to Redis database operations.
/// Used for reading and writing data in Redis.
/// </summary>
protected IConnectionMultiplexer redisConn = null!;
/// <summary>
/// Redis database instance used for performing read/write operations.
/// This database is accessed via the redisConn.GetDatabase() method.
/// </summary>
protected IDatabase redisDb = null!;
#endregion Protected Fields
#region Protected Properties
/// <summary>
/// Cache duration for short-term operations (approximately 1 minute with ±10% variation).
/// The actual duration is calculated dynamically with a random factor to avoid fixed TTLs.
/// </summary>
protected TimeSpan FastCache
{
get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Cache duration for long-term operations (5 minutes with ±10% variation).
/// Used for data that should be cached for longer periods but still allow some flexibility.
/// </summary>
protected TimeSpan LongCache
{
get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Cache duration for very short-term operations (approximately 10 seconds with ±10% variation).
/// Used for transient data that needs to be refreshed frequently.
/// </summary>
protected TimeSpan UltraFastCache
{
get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Cache duration for very long-term operations (up to 50 minutes with ±10% variation).
/// Designed for data that changes infrequently and requires long-term persistence.
/// </summary>
protected TimeSpan UltraLongCache
{
get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
}
#endregion Protected Properties
#region Private Fields
/// <summary>
/// Logger instance for logging events and errors at the class level.
/// Used to track application behavior and diagnose issues.
/// </summary>
private static Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Duration of long-term cache in seconds (default: 5 minutes).
/// Used in the LongCache property to define how long data should be cached.
/// </summary>
private int cacheTtlLong = 60 * 5;
/// <summary>
/// Duration of short-term cache in seconds (default: 1 minute).
/// Used in the FastCache and UltraFastCache properties to define short-term cache durations.
/// </summary>
private int cacheTtlShort = 60 * 1;
/// <summary>
/// Random number generator for introducing dynamic variability in cache durations.
/// Used to simulate real-world variations in data freshness and TTL.
/// </summary>
private Random rnd = new Random();
#endregion Private Fields
}
}