Files
magman/MagMan.Data.Admin/Services/MTAdminService.cs
T
2024-01-24 10:08:54 +01:00

575 lines
19 KiB
C#

using MagMan.Core;
using MagMan.Core.Services;
using MagMan.Data.Admin.Controllers;
using MagMan.Data.Admin.DbModels;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System.Diagnostics;
namespace MagMan.Data.Admin.Services
{
public class MTAdminService : BaseServ
{
#region Public Constructors
public MTAdminService(IConfiguration configuration, IConnectionMultiplexer redisConnMult, IEmailSender emailSender)
{
Log.Info("MTAdminService starting...");
_configuration = configuration;
_emailSender = emailSender;
// Conf cache
redisConn = redisConnMult;
redisDb = this.redisConn.GetDatabase();
// json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/
JSSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
// cod app
CodApp = _configuration["CodApp"];
dbController = new MTAdminController(configuration);
// chiudo log
Log.Info("MTAdminService started!");
}
#endregion Public Constructors
#region Public Properties
public string CodApp { get; set; } = "";
#endregion Public Properties
#region Public Methods
/// <summary>
/// Lista AuthKey
/// </summary>
/// <param name="CustomerId">0 = tutti</param>
/// <returns></returns>
public async Task<List<AuthKeyModel>> AuthKeyByCustId(int CustomerId)
{
string source = "DB";
List<AuthKeyModel>? dbResult = new List<AuthKeyModel>();
try
{
string currKey = $"{Const.rKeyConfig}:AuthKeyList:{CustomerId}";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
if (!string.IsNullOrEmpty(rawData))
{
source = "REDIS";
var tempResult = JsonConvert.DeserializeObject<List<AuthKeyModel>>(rawData);
if (tempResult == null)
{
dbResult = new List<AuthKeyModel>();
}
else
{
dbResult = tempResult;
}
}
else
{
dbResult = dbController.AuthKeyByCustId(CustomerId);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
}
if (dbResult == null)
{
dbResult = new List<AuthKeyModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"AuthKeyByCustId | {source} in: {ts.TotalMilliseconds} ms");
}
catch (Exception exc)
{
Log.Error($"Error during AuthKeyByCustId:{Environment.NewLine}{exc}");
}
return dbResult;
}
/// <summary>
/// Delete record AuthKey + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> AuthKeyDelete(AuthKeyModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.AuthKeyDelete(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during AuthKeyDelete:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Lista AuthKey da Rest Token
/// </summary>
/// <param name="RestToken">token di auth del cliente</param>
/// <returns></returns>
public async Task<List<AuthKeyModel>> AuthKeyGetByToken(string RestToken)
{
List<AuthKeyModel>? dbResult = new List<AuthKeyModel>();
// cerco in primis customer ID...
int CustomerId = await CustomerIdByToken(RestToken);
if (CustomerId >= 0)
{
dbResult = await AuthKeyByCustId(CustomerId);
}
return dbResult;
}
/// <summary>
/// Update record AuthKey + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> AuthKeyUpdate(AuthKeyModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.AuthKeyUpdate(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during AuthKeyUpdate:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Delete record customer + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> CustomerDelete(CustomerModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.CustomerDelete(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during CustomerDelete:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Lista Customers
/// </summary>
/// <returns></returns>
public async Task<List<CustomerModel>> CustomerGetAll()
{
string source = "DB";
List<CustomerModel>? dbResult = new List<CustomerModel>();
try
{
string currKey = $"{Const.rKeyConfig}:CustomersList";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
if (!string.IsNullOrEmpty(rawData))
{
source = "REDIS";
var tempResult = JsonConvert.DeserializeObject<List<CustomerModel>>(rawData);
if (tempResult == null)
{
dbResult = new List<CustomerModel>();
}
else
{
dbResult = tempResult;
}
}
else
{
dbResult = dbController.CustomerGetAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
}
if (dbResult == null)
{
dbResult = new List<CustomerModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"CustomerGetAll | {source} in: {ts.TotalMilliseconds} ms");
}
catch (Exception exc)
{
Log.Error($"Error during CustomerGetAll:{Environment.NewLine}{exc}");
}
return dbResult;
}
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> CustomerIdByToken(string RestToken)
{
int answ = -1;
if (TokenCustList.ContainsKey(RestToken))
{
answ = TokenCustList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.CustomerID;
TokenCustList.Add(RestToken, answ);
Log.Info($"TokenCustList: added {RestToken} --> {answ}");
}
}
return answ;
}
/// <summary>
/// Update record customer + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> CustomerUpdate(CustomerModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.CustomerUpdate(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during CustomerUpdate:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Refresh globale cache redis
/// </summary>
/// <returns></returns>
public async Task<bool> FlushRedisCache()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await Task.Delay(1);
RedisValue pattern = new RedisValue($"{Const.rKeyConfig}:*");
bool answ = await ExecFlushRedisPattern(pattern);
stopWatch.Stop();
Log.Debug($"FlushRedisCache in {stopWatch.Elapsed.TotalMilliseconds} ms");
return answ;
}
/// <summary>
/// Delete record Machine + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> MachineDelete(MachineModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.MachineDelete(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during MachineDelete:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Lista Macchine
/// </summary>
/// <param name="CustomerId">0 = tutti</param>
/// <returns></returns>
public async Task<List<MachineModel>> MachineGetByCustId(int CustomerId)
{
string source = "DB";
List<MachineModel>? dbResult = new List<MachineModel>();
try
{
string currKey = $"{Const.rKeyConfig}:MachineList:{CustomerId}";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
if (!string.IsNullOrEmpty(rawData))
{
source = "REDIS";
var tempResult = JsonConvert.DeserializeObject<List<MachineModel>>(rawData);
if (tempResult == null)
{
dbResult = new List<MachineModel>();
}
else
{
dbResult = tempResult;
}
}
else
{
dbResult = dbController.MachineGetByCustId(CustomerId);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
// per evitare loopback uso deserialize...
var tempResult = JsonConvert.DeserializeObject<List<MachineModel>>(rawData);
if (tempResult != null)
{
dbResult = tempResult;
}
}
if (dbResult == null)
{
dbResult = new List<MachineModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MachineGetByCustId | {source} in: {ts.TotalMilliseconds} ms");
}
catch (Exception exc)
{
Log.Error($"Error during MachineGetByCustId:{Environment.NewLine}{exc}");
}
return dbResult;
}
/// <summary>
/// Lista Macchine da Rest Token
/// </summary>
/// <param name="RestToken">token di auth del cliente</param>
/// <returns></returns>
public async Task<List<MachineModel>> MachineGetByToken(string RestToken)
{
List<MachineModel>? dbResult = new List<MachineModel>();
// cerco in primis customer ID...
int CustomerId = await CustomerIdByToken(RestToken);
if (CustomerId >= 0)
{
dbResult = await MachineGetByCustId(CustomerId);
}
return dbResult;
}
/// <summary>
/// Update record Machine + refresh cache
/// </summary>
/// <param name="currItem"></param>
/// <returns></returns>
public async Task<bool> MachineUpdate(MachineModel currItem)
{
bool fatto = false;
try
{
fatto = dbController.MachineUpdate(currItem);
if (fatto)
{
await FlushRedisCache();
}
}
catch (Exception exc)
{
Log.Error($"Error during MachineUpdate:{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="CustID"></param>
/// <returns></returns>
public async Task<int> MainKeyByCustomer(int CustID)
{
int answ = -1;
if (CustMKeyList.ContainsKey(CustID))
{
answ = CustMKeyList[CustID];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.CustomerID == CustID);
// se trovato salvo
if (custRow != null)
{
answ = custRow.MainKey;
try
{
CustMKeyList.Add(CustID, answ);
}
catch
{ }
Log.Info($"TokenMKeyList: added {CustID} --> {answ}");
}
}
return answ;
}
/// <summary>
/// Recupera MainKey dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> MainKeyByToken(string RestToken)
{
int answ = -1;
if (TokenMKeyList.ContainsKey(RestToken))
{
answ = TokenMKeyList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.MainKey;
TokenMKeyList.Add(RestToken, answ);
Log.Info($"TokenMKeyList: added {RestToken} --> {answ}");
}
}
return answ;
}
#endregion Public Methods
#region Protected Fields
protected static MTAdminController dbController = null!;
#endregion Protected Fields
#region Private Fields
private static JsonSerializerSettings? JSSettings;
private static Logger Log = LogManager.GetCurrentClassLogger();
private readonly IEmailSender _emailSender;
/// <summary>
/// Durata cache lunga IN SECONDI
/// </summary>
private int cacheTtlLong = 60 * 5;
/// <summary>
/// Durata cache breve IN SECONDI
/// </summary>
private int cacheTtlShort = 60 * 1;
/// <summary>
/// Oggetto per connessione a REDIS
/// </summary>
private IConnectionMultiplexer redisConn;
/// <summary>
/// Oggetto DB redis da impiegare x chiamate R/W
/// </summary>
private IDatabase redisDb = null!;
/// <summary>
/// Generatore random
/// </summary>
private Random rnd = new Random();
#endregion Private Fields
#region Private Properties
/// <summary>
/// Dizionario customer 2 MainKey (x calcolo DB)
/// </summary>
private Dictionary<int, int> CustMKeyList { get; set; } = new Dictionary<int, int>();
/// <summary>
/// Dizionario dei token 2 customer
/// </summary>
private Dictionary<string, int> TokenCustList { get; set; } = new Dictionary<string, int>();
/// <summary>
/// Dizionario dei token 2 MainKey (x calcolo DB)
/// </summary>
private Dictionary<string, int> TokenMKeyList { get; set; } = new Dictionary<string, int>();
#endregion Private Properties
#region Private Methods
/// <summary>
/// Esegue flush memoria redis dato pattern
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private async Task<bool> ExecFlushRedisPattern(RedisValue pattern)
{
bool answ = false;
var listEndpoints = redisConn.GetEndPoints();
foreach (var endPoint in listEndpoints)
{
//var server = redisConnAdmin.GetServer(listEndpoints[0]);
var server = redisConn.GetServer(endPoint);
if (server != null)
{
var keyList = server.Keys(redisDb.Database, pattern);
foreach (var item in keyList)
{
await redisDb.KeyDeleteAsync(item);
}
answ = true;
}
}
return answ;
}
#endregion Private Methods
}
}