You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Haoliang.Models.System;
namespace Haoliang.Core.Services
{
public interface ISystemConfigService
{
Task<SystemConfig> GetConfigAsync(string configKey);
Task<Dictionary<string, string>> GetAllConfigsAsync();
Task<SystemConfig> SetConfigAsync(string configKey, string configValue);
Task<bool> DeleteConfigAsync(string configKey);
Task<bool> ConfigExistsAsync(string configKey);
Task<IEnumerable<SystemConfig>> GetConfigsByCategoryAsync(string category);
Task<bool> ValidateConfigAsync(SystemConfig config);
Task RefreshConfigCacheAsync();
Task<T> GetConfigValueAsync<T>(string configKey, T defaultValue = default);
}
public interface ILoggingService
{
Task LogAsync(LogLevel logLevel, string message, Exception exception = null, Dictionary<string, object> properties = null);
Task LogErrorAsync(string message, Exception exception = null, Dictionary<string, object> properties = null);
Task LogWarningAsync(string message, Dictionary<string, object> properties = null);
Task LogInfoAsync(string message, Dictionary<string, object> properties = null);
Task LogDebugAsync(string message, Dictionary<string, object> properties = null);
Task LogTraceAsync(string message, Dictionary<string, object> properties = null);
Task<IEnumerable<LogEntry>> GetLogsAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null, string category = null);
Task<IEnumerable<LogEntry>> GetErrorLogsAsync(DateTime? startDate = null, DateTime? endDate = null);
Task<int> GetLogCountAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null);
Task ArchiveLogsAsync(int daysToKeep = 30);
Task ClearLogsAsync();
}
public interface ISchedulerService
{
Task StartSchedulerAsync();
Task StopSchedulerAsync();
Task ScheduleTaskAsync(ScheduledTask task);
Task<bool> RemoveTaskAsync(string taskId);
Task<IEnumerable<ScheduledTask>> GetAllScheduledTasksAsync();
Task<ScheduledTask> GetTaskByIdAsync(string taskId);
Task ExecuteTaskAsync(string taskId);
Task<TaskExecutionResult> GetTaskExecutionResultAsync(string taskId);
Task<bool> IsTaskRunningAsync(string taskId);
Task<string> ScheduleRecurringTaskAsync(string taskName, Action taskAction, TimeSpan interval);
}
public interface ICachingService
{
Task<T> GetAsync<T>(string key);
Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
Task<bool> RemoveAsync(string key);
Task<bool> ExistsAsync(string key);
Task ClearAsync();
Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null);
Task<IEnumerable<string>> GetAllKeysAsync();
Task<bool> RefreshAsync<T>(string key);
}
public class SystemConfigManager : ISystemConfigService
{
private readonly ISystemConfigRepository _configRepository;
private readonly ICachingService _cachingService;
public SystemConfigManager(
ISystemConfigRepository configRepository,
ICachingService cachingService)
{
_configRepository = configRepository;
_cachingService = cachingService;
}
public async Task<SystemConfig> GetConfigAsync(string configKey)
{
// 先从缓存获取
var cachedConfig = await _cachingService.GetAsync<SystemConfig>($"config_{configKey}");
if (cachedConfig != null)
{
return cachedConfig;
}
// 缓存未命中,从数据库获取
var config = await _configRepository.GetByKeyAsync(configKey);
if (config != null)
{
// 存入缓存
await _cachingService.SetAsync($"config_{configKey}", config, TimeSpan.FromMinutes(30));
}
return config;
}
public async Task<Dictionary<string, string>> GetAllConfigsAsync()
{
var configs = await _configRepository.GetAllAsync();
var configDict = new Dictionary<string, string>();
foreach (var config in configs)
{
configDict[config.ConfigKey] = config.ConfigValue;
}
return configDict;
}
public async Task<SystemConfig> SetConfigAsync(string configKey, string configValue)
{
// 验证配置
var config = new SystemConfig
{
ConfigKey = configKey,
ConfigValue = configValue,
Category = "General",
LastUpdated = DateTime.Now
};
var validationErrors = await ValidateConfigAsync(config);
if (validationErrors.Count > 0)
{
throw new InvalidOperationException($"Config validation failed: {string.Join(", ", validationErrors)}");
}
// 检查配置是否已存在
var existingConfig = await _configRepository.GetByKeyAsync(configKey);
if (existingConfig != null)
{
config.ConfigId = existingConfig.ConfigId;
config.CreateTime = existingConfig.CreateTime;
}
config.LastUpdated = DateTime.Now;
var updatedConfig = await _configRepository.UpsertAsync(config);
// 更新缓存
await _cachingService.SetAsync($"config_{configKey}", updatedConfig, TimeSpan.FromMinutes(30));
await _cachingService.RemoveAsync("all_configs");
return updatedConfig;
}
public async Task<bool> DeleteConfigAsync(string configKey)
{
var result = await _configRepository.DeleteByKeyAsync(configKey);
if (result)
{
// 清除缓存
await _cachingService.RemoveAsync($"config_{configKey}");
await _cachingService.RemoveAsync("all_configs");
}
return result;
}
public async Task<bool> ConfigExistsAsync(string configKey)
{
// 先检查缓存
var existsInCache = await _cachingService.ExistsAsync($"config_{configKey}");
if (existsInCache)
{
return true;
}
return await _configRepository.KeyExistsAsync(configKey);
}
public async Task<IEnumerable<SystemConfig>> GetConfigsByCategoryAsync(string category)
{
return await _configRepository.GetByCategoryAsync(category);
}
public async Task<bool> ValidateConfigAsync(SystemConfig config)
{
var errors = new List<string>();
// 验证配置键
if (string.IsNullOrWhiteSpace(config.ConfigKey))
{
errors.Add("Config key cannot be empty");
}
// 验证配置值
if (config.ConfigValue == null)
{
errors.Add("Config value cannot be null");
}
// 根据不同的配置键进行特定验证
switch (config.ConfigKey)
{
case "Database.ConnectionString":
if (!IsValidConnectionString(config.ConfigValue))
{
errors.Add("Invalid database connection string");
}
break;
case "Logging.Level":
if (!IsValidLogLevel(config.ConfigValue))
{
errors.Add("Invalid log level");
}
break;
case "Collection.Interval":
if (!IsValidInterval(config.ConfigValue))
{
errors.Add("Invalid collection interval");
}
break;
case "Security.JwtSecret":
if (string.IsNullOrWhiteSpace(config.ConfigValue) || config.ConfigValue.Length < 16)
{
errors.Add("JWT secret must be at least 16 characters long");
}
break;
}
return errors.Count == 0;
}
public async Task RefreshConfigCacheAsync()
{
// 清除所有配置缓存
await _cachingService.RemoveAsync("all_configs");
// 重新加载常用配置
var commonKeys = new[] { "Database.ConnectionString", "Logging.Level", "Collection.Interval" };
foreach (var key in commonKeys)
{
await GetConfigAsync(key);
}
}
public async Task<T> GetConfigValueAsync<T>(string configKey, T defaultValue = default)
{
var config = await GetConfigAsync(configKey);
if (config == null)
{
return defaultValue;
}
try
{
return (T)Convert.ChangeType(config.ConfigValue, typeof(T));
}
catch
{
return defaultValue;
}
}
private bool IsValidConnectionString(string connectionString)
{
// 简单的连接字符串验证
return !string.IsNullOrWhiteSpace(connectionString) &&
(connectionString.Contains("Server=") || connectionString.Contains("Host="));
}
private bool IsValidLogLevel(string logLevel)
{
var validLevels = new[] { "Trace", "Debug", "Information", "Warning", "Error", "Critical", "None" };
return Array.Exists(validLevels, level => level.Equals(logLevel, StringComparison.OrdinalIgnoreCase));
}
private bool IsValidInterval(string interval)
{
if (int.TryParse(interval, out int seconds))
{
return seconds >= 5 && seconds <= 3600; // 5秒到1小时
}
return false;
}
}
public class LoggingManager : ILoggingService
{
private readonly ILogRepository _logRepository;
private readonly ICachingService _cachingService;
public LoggingManager(
ILogRepository logRepository,
ICachingService cachingService)
{
_logRepository = logRepository;
_cachingService = cachingService;
}
public async Task LogAsync(LogLevel logLevel, string message, Exception exception = null, Dictionary<string, object> properties = null)
{
var logEntry = new LogEntry
{
LogLevel = logLevel,
Message = message,
ExceptionMessage = exception?.Message,
StackTrace = exception?.StackTrace,
Properties = properties,
Timestamp = DateTime.Now,
Category = "General"
};
// 异步保存到数据库
await _logRepository.AddAsync(logEntry);
// 控制台输出(开发环境)
if (IsDevelopmentEnvironment())
{
Console.WriteLine($"[{logLevel}] {message}");
if (exception != null)
{
Console.WriteLine(exception.ToString());
}
}
}
public async Task LogErrorAsync(string message, Exception exception = null, Dictionary<string, object> properties = null)
{
await LogAsync(LogLevel.Error, message, exception, properties);
}
public async Task LogWarningAsync(string message, Dictionary<string, object> properties = null)
{
await LogAsync(LogLevel.Warning, message, null, properties);
}
public async Task LogInfoAsync(string message, Dictionary<string, object> properties = null)
{
await LogAsync(LogLevel.Information, message, null, properties);
}
public async Task LogDebugAsync(string message, Dictionary<string, object> properties = null)
{
await LogAsync(LogLevel.Debug, message, null, properties);
}
public async Task LogTraceAsync(string message, Dictionary<string, object> properties = null)
{
await LogAsync(LogLevel.Trace, message, null, properties);
}
public async Task<IEnumerable<LogEntry>> GetLogsAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null, string category = null)
{
return await _logRepository.GetLogsAsync(logLevel, startDate, endDate, category);
}
public async Task<IEnumerable<LogEntry>> GetErrorLogsAsync(DateTime? startDate = null, DateTime? endDate = null)
{
return await _logRepository.GetLogsAsync(LogLevel.Error, startDate, endDate, null);
}
public async Task<int> GetLogCountAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null)
{
return await _logRepository.GetLogCountAsync(logLevel, startDate, endDate);
}
public async Task ArchiveLogsAsync(int daysToKeep = 30)
{
var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
await _logRepository.ArchiveLogsAsync(cutoffDate);
}
public async Task ClearLogsAsync()
{
await _logRepository.ClearLogsAsync();
}
private bool IsDevelopmentEnvironment()
{
// 简单判断是否为开发环境
return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
}
}
}