using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace TechSec602.Advanced { /// /// Advanced 602TechSec client implementation with caching, logging, and performance optimizations /// public class TechSec602AdvancedClient : TechSec602Client { private readonly ConcurrentDictionary _cache; private readonly TechSec602Config _config; private readonly ILogger _logger; private readonly TechSec602CircuitBreaker _circuitBreaker; /// /// Parameterless constructor - reads configuration from web.config /// public TechSec602AdvancedClient() : this(TechSec602Config.FromAppSettings()) { } public TechSec602AdvancedClient(TechSec602Config config, ILogger logger = null) : base(config) { _config = config; _cache = new ConcurrentDictionary(); _logger = logger; _circuitBreaker = new TechSec602CircuitBreaker(); // Start cache cleanup timer if (config.CacheResults) { StartCacheCleanup(); } } /// /// Enhanced verification with caching and performance monitoring /// public new async Task VerifyRequestAsync(string url, string ipAddress = null, string apiKey = null) { var cacheKey = $"{url}|{ipAddress}|{apiKey}"; // Check cache first if (_config.CacheResults && _cache.TryGetValue(cacheKey, out var cachedResult) && !cachedResult.IsExpired) { _logger?.LogDebug($"Cache hit for {url}"); return cachedResult.Result; } // Check circuit breaker if (_circuitBreaker.IsOpen) { _logger?.LogInfo("Circuit breaker is open, failing open"); return new VerificationResult { IsAllowed = _config.FailOpen, Reason = "Service unavailable (circuit breaker open)", Success = false }; } var startTime = DateTime.UtcNow; // Call base verification var result = await base.VerifyRequestAsync(url, ipAddress, apiKey); var endTime = DateTime.UtcNow; var duration = (endTime - startTime).TotalMilliseconds; // Update circuit breaker if (result.Success) { _circuitBreaker.RecordSuccess(); } else { _circuitBreaker.RecordFailure(); } // Log the request if (_config.EnableLogging) { _logger?.LogInfo($"Verification: {url} | IP: {ipAddress} | Result: {result.IsAllowed} | Duration: {duration}ms | Reason: {result.Reason}"); } // Cache successful results if (_config.CacheResults && result.Success) { var expiry = DateTime.UtcNow.AddMinutes(_config.CacheTimeoutMinutes); _cache.TryAdd(cacheKey, new CachedResult { Result = result, Expiry = expiry }); } return result; } /// /// Batch verification for multiple URLs /// public async Task> VerifyBatchAsync(List requests) { var tasks = requests.Select(req => VerifyRequestAsync(req.Url, req.IpAddress, req.ApiKey)).ToArray(); var results = await Task.WhenAll(tasks); return results.ToList(); } /// /// Pre-warm cache with common URLs /// public async Task PreWarmCacheAsync(List urls) { var tasks = urls.Select(url => VerifyRequestAsync(url)).ToArray(); await Task.WhenAll(tasks); _logger?.LogInfo($"Pre-warmed cache with {urls.Count} URLs"); } /// /// Get cache statistics /// public CacheStats GetCacheStats() { return new CacheStats { TotalEntries = _cache.Count, ExpiredEntries = _cache.Values.Count(c => c.IsExpired) }; } /// /// Clear expired cache entries /// public void ClearExpiredCache() { var expiredKeys = _cache.Where(kvp => kvp.Value.IsExpired).Select(kvp => kvp.Key).ToList(); foreach (var key in expiredKeys) { _cache.TryRemove(key, out _); } _logger?.LogDebug($"Cleared {expiredKeys.Count} expired cache entries"); } private void StartCacheCleanup() { Task.Run(async () => { while (true) { await Task.Delay(TimeSpan.FromMinutes(1)); ClearExpiredCache(); } }); } } /// /// Cached verification result /// public class CachedResult { public VerificationResult Result { get; set; } public DateTime Expiry { get; set; } public bool IsExpired => DateTime.UtcNow > Expiry; } /// /// Batch verification request /// public class BatchVerificationRequest { public string Url { get; set; } public string IpAddress { get; set; } public string ApiKey { get; set; } } /// /// Cache statistics /// public class CacheStats { public int TotalEntries { get; set; } public int ExpiredEntries { get; set; } } /// /// Simple logging interface /// public interface ILogger { void LogInfo(string message); void LogDebug(string message); void LogError(string message); } /// /// Basic console logger implementation /// public class ConsoleLogger : ILogger { public void LogInfo(string message) { Console.WriteLine($"[INFO] {DateTime.Now}: {message}"); } public void LogDebug(string message) { Console.WriteLine($"[DEBUG] {DateTime.Now}: {message}"); } public void LogError(string message) { Console.WriteLine($"[ERROR] {DateTime.Now}: {message}"); } } /// /// Circuit breaker pattern for fault tolerance /// public class TechSec602CircuitBreaker { private int _failureCount = 0; private DateTime _lastFailureTime = DateTime.MinValue; private readonly int _failureThreshold; private readonly int _resetTimeoutMinutes; public TechSec602CircuitBreaker(int failureThreshold = 5, int resetTimeoutMinutes = 5) { _failureThreshold = failureThreshold; _resetTimeoutMinutes = resetTimeoutMinutes; } public bool IsOpen { get { if (_failureCount >= _failureThreshold) { return DateTime.UtcNow.Subtract(_lastFailureTime).TotalMinutes < _resetTimeoutMinutes; } return false; } } public void RecordSuccess() { _failureCount = 0; } public void RecordFailure() { _failureCount++; _lastFailureTime = DateTime.UtcNow; } } }