4ee2ef1eb9
- ok cancella - ok metodi API x check + approva salvando senza user - ok procedure insomnia salvate
572 lines
21 KiB
C#
572 lines
21 KiB
C#
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Logging;
|
|
using MP.FileData;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Diagnostics;
|
|
using MP.FileData.Controllers;
|
|
using MP.FileData.DTO;
|
|
using StackExchange.Redis;
|
|
using MP.FileData.DatabaseModels;
|
|
|
|
namespace MP.Prog.Data
|
|
{
|
|
public class FileArchDataService : IDisposable
|
|
{
|
|
#region Public Fields
|
|
|
|
public static FileData.Controllers.FileController dbController;
|
|
|
|
#endregion Public Fields
|
|
|
|
#region Public Constructors
|
|
|
|
public FileArchDataService(IConfiguration configuration, ILogger<FileArchDataService> logger, IConnectionMultiplexer redisConnMult)
|
|
{
|
|
_logger = logger;
|
|
_configuration = configuration;
|
|
|
|
// 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
|
|
};
|
|
|
|
// conf DB
|
|
string connStr = _configuration.GetConnectionString("MP.Prog");
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
_logger.LogError("ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
dbController = new FileData.Controllers.FileController(configuration);
|
|
_logger.LogInformation("DbController OK");
|
|
}
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Esegue Upsert record ArchivioMacchina
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ArchivioMaccUpsert(ArchMaccModel currRec)
|
|
{
|
|
bool fatto = await dbController.ArchMaccUpsert(currRec);
|
|
await ResetArchiveCache();
|
|
return fatto;
|
|
}
|
|
|
|
public async Task<List<ArchMaccModel>> ArchMaccGetAll()
|
|
{
|
|
string source = "DB";
|
|
List<ArchMaccModel> dbResult = new List<ArchMaccModel>();
|
|
string currKey = $"{redisBaseAddr}:ArchMacc:ALL";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<List<ArchMaccModel>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new List<ArchMaccModel>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.ArchMaccGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<ArchMaccModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Info($"ArchMaccGetAll | {source} in: {ts.TotalMilliseconds} ms");
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<ArchMaccModel> ArchMaccGetByKey(string idxMacchina)
|
|
{
|
|
string source = "DB";
|
|
ArchMaccModel dbResult = new ArchMaccModel();
|
|
string currKey = $"{redisBaseAddr}:ArchMacc:{idxMacchina}";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<ArchMaccModel>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new ArchMaccModel();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.ArchMaccGetByKey(idxMacchina);
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new ArchMaccModel();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Info($"ArchMaccGetByKey | {source} in: {ts.TotalMilliseconds} ms");
|
|
return dbResult;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Clear database controller
|
|
dbController.Dispose();
|
|
}
|
|
|
|
public async Task<int> FileCountFilt(SelectData CurrFilter)
|
|
{
|
|
int numCount = 0;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
numCount = dbController.FileCountFilt(CurrFilter.IdxMacchina, CurrFilter.OnlyActive, CurrFilter.OnlyMod, CurrFilter.OnlyNoTag, CurrFilter.FileName, CurrFilter.UserName, CurrFilter.Tag, CurrFilter.SearchVal);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB per FileCountFilt: {ts.TotalMilliseconds} ms");
|
|
return await Task.FromResult(numCount);
|
|
}
|
|
|
|
public Task<FileModel> FileGetByKey(int FileId)
|
|
{
|
|
return Task.FromResult(dbController.FileGetByKey(FileId));
|
|
}
|
|
/// <summary>
|
|
/// Restituisce il file dato un ID + revisione
|
|
/// cerca a pari nome, macchina + REV specifica)
|
|
/// </summary>
|
|
/// <param name="FileId">Id del file originale</param>
|
|
/// <param name="Rev">Rev specifica richiesta</param>
|
|
/// <returns></returns>
|
|
public Task<FileModel> FileGetByKeyRev(int FileId, int Rev)
|
|
{
|
|
return Task.FromResult(dbController.FileGetByKeyRev(FileId, Rev));
|
|
}
|
|
|
|
public async Task<List<FileModel>> FileGetFilt(SelectData CurrFilter)
|
|
{
|
|
List<FileModel> dbResult = new List<FileModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.FileGetFilt(CurrFilter.IdxMacchina, CurrFilter.OnlyActive, CurrFilter.OnlyMod, CurrFilter.OnlyNoTag, CurrFilter.FileName, CurrFilter.UserName, CurrFilter.Tag, CurrFilter.SearchVal, CurrFilter.NumSkip, CurrFilter.PageSize).ToList();
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB per FileGetFilt: {ts.TotalMilliseconds} ms");
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task FlushRedisCache()
|
|
{
|
|
RedisValue pattern = new RedisValue($"{redisBaseAddr}:*");
|
|
bool answ = await ExecFlushRedisPattern(pattern);
|
|
}
|
|
|
|
public async Task<List<ArchiveStatusDTO>> GetArchiveStatus()
|
|
{
|
|
string source = "DB";
|
|
List<ArchiveStatusDTO> dbResult = new List<ArchiveStatusDTO>();
|
|
string currKey = $"{redisBaseAddr}:ArchStatus:ALL";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<List<ArchiveStatusDTO>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new List<ArchiveStatusDTO>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.GetArchiveStatus();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<ArchiveStatusDTO>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Info($"GetArchiveStatus | {source} in: {ts.TotalMilliseconds} ms");
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<List<AutocompleteModel>> MachineList()
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
answ.AddRange(dbController.ArchMaccGetAll().Select(x => new AutocompleteModel { LabelField = $"{x.IdxMacchina} | {x.Nome} {x.Descrizione} ", ValueField = x.IdxMacchina }).ToList());
|
|
return await Task.FromResult(answ);
|
|
}
|
|
|
|
public void rollBackEdit(object item)
|
|
{
|
|
dbController.RollBackEntity(item);
|
|
}
|
|
|
|
public async Task<List<TagModel>> TagGetFilt(string SearchVal)
|
|
{
|
|
return await Task.FromResult(dbController.TagGetFilt(SearchVal, 200).ToList());
|
|
}
|
|
|
|
public Task<List<AutocompleteModel>> TagGetSearch(string searchVal, int numRecord)
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
if (numRecord > -1)
|
|
{
|
|
answ.AddRange(dbController.TagGetFilt(searchVal, numRecord).Select(x => new AutocompleteModel { LabelField = $"{x.TagId}", ValueField = x.TagId }).ToList());
|
|
}
|
|
return Task.FromResult(answ);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiorna intero archivio scansionando dati x tutte le macchine che hanno un path valido
|
|
/// </summary>
|
|
/// <param name="numDayPre">Numero giorni x ricerca all'indietro da data corrente / 0 = nessun limite</param>
|
|
/// <param name="forceTag">Indica se forzare il tag</param>
|
|
/// <param name="UserName">Utente attivo</param>
|
|
/// <param name="DoApprove">indica se vada approvata la modifica o lasciato "in sospeso"</param>
|
|
/// <returns></returns>
|
|
public async Task<int> UpdateAllArchive(int numDayPre, bool forceTag, string UserName, bool DoApprove)
|
|
{
|
|
int checkDone = 0;
|
|
var listaMacchine = await ArchMaccGetAll();
|
|
foreach (var item in listaMacchine.Where(x => !string.IsNullOrEmpty(x.BasePath)).ToList())
|
|
{
|
|
checkDone += await UpdateMachineArchive(item.IdxMacchina, numDayPre, forceTag, false, UserName, DoApprove);
|
|
}
|
|
|
|
return checkDone;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiorna archivio di una amcchina scansionando path relativo
|
|
/// </summary>
|
|
/// <param name="idxMacchina">Codice macchina</param>
|
|
/// <param name="numDayPre">
|
|
/// Numero giorni x ricerca all'indietro da data corrente / 0 = nessun limite
|
|
/// </param>
|
|
/// <param name="forceTag">Forza la riverifica dei tags (x update da setup)</param>
|
|
/// <param name="fullLog">Scrittura log verboso macchina</param>
|
|
/// <param name="UserName">Utente attivo</param>
|
|
/// <param name="DoApprove">indica se vada approvata la modifica o lasciato "in sospeso"</param>
|
|
/// <returns></returns>
|
|
public async Task<int> UpdateMachineArchive(string idxMacchina, int numDayPre, bool forceTag, bool fullLog, string UserName, bool DoApprove)
|
|
{
|
|
int checkDone = 0;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string ruleName = "Rule00.json";
|
|
try
|
|
{
|
|
ArchMaccModel macchina = await ArchMaccGetByKey(idxMacchina);
|
|
if (macchina != null && !string.IsNullOrEmpty(macchina.BasePath))
|
|
{
|
|
if (!string.IsNullOrEmpty(macchina.RuleName))
|
|
{
|
|
ruleName = macchina.RuleName;
|
|
// gestione confRule...
|
|
SearchRules currRule = new SearchRules();
|
|
try
|
|
{
|
|
string rawData = File.ReadAllText(FileController.rulePath(ruleName));
|
|
currRule = JsonConvert.DeserializeObject<SearchRules>(rawData);
|
|
//Log.Info($"Conf rule acquisito da file {ruleName}:{Environment.NewLine}{rawData}");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in deserializzazione conf rule{Environment.NewLine}{exc}");
|
|
}
|
|
|
|
// se NON deserializzato inizializzo hard-coded
|
|
if (currRule.Name == "ND")
|
|
{
|
|
// fare: lettura conf rule x recupero tag x singola macchina
|
|
//$"\\b{fileName}" + @".{0,2}\([\w\d\s.]+\)";
|
|
|
|
Dictionary<string, string> confReplace = new Dictionary<string, string>();
|
|
confReplace.Add("(", " ");
|
|
confReplace.Add(")", " ");
|
|
|
|
Dictionary<string, string> fileExtReplace = new Dictionary<string, string>();
|
|
fileExtReplace.Add(".P-2", "");
|
|
// hard coded + salvataggio conf x creare json
|
|
currRule = new SearchRules()
|
|
{
|
|
Name = "Commento Filename",
|
|
Mode = SearchMode.StringOnFile,
|
|
MaxChar2Search = 100,
|
|
ReplaceCR = true,
|
|
RegExPattern = "\\b{{fileName}}" + @".{0,2}\([\w\d\s./]+\)",
|
|
RegExRepFileName = true,
|
|
FileNameExtReplace = fileExtReplace,
|
|
ExcludedTags = new List<string>() { "M4", "M5", "M4+A", "M4+B", "M5+A", "M5+B" },
|
|
OutReplace = confReplace,
|
|
OutExcludeFileName = true
|
|
};
|
|
if (fullLog)
|
|
{
|
|
// serializzo
|
|
string rawRule = JsonConvert.SerializeObject(currRule, Formatting.Indented);
|
|
Log.Trace($"Conf rule generato:{Environment.NewLine}{rawRule}");
|
|
}
|
|
}
|
|
checkDone = dbController.CheckFileArchived(macchina.IdxMacchina, macchina.BasePath, numDayPre, "*.*", forceTag, currRule, UserName, DoApprove);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in UpdateMachineArchive{Environment.NewLine}{exc}{Environment.NewLine}{exc.InnerException}");
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Info($"Effettuato update archivio file MACCHINA | last {numDayPre} days | {checkDone} checked | {ts.TotalMilliseconds} ms");
|
|
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
// restituisco conteggio
|
|
return checkDone;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Internal Methods
|
|
|
|
/// <summary>
|
|
/// Approvazione modifica file
|
|
/// </summary>
|
|
/// <param name="currItem"></param>
|
|
/// <param name="UserName"></param>
|
|
/// <returns></returns>
|
|
internal async Task<bool> FileModApprove(FileModel currItem, string UserName)
|
|
{
|
|
bool answ = dbController.FileModApprove(currItem, UserName);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Forza registrazione della sola approvazione utente + data
|
|
/// </summary>
|
|
/// <param name="currItem"></param>
|
|
/// <param name="UserName"></param>
|
|
/// <returns></returns>
|
|
internal async Task<bool> FileSetUserApp(FileModel currItem, string UserName)
|
|
{
|
|
bool answ = dbController.FileSetUserApp(currItem, UserName);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Eliminazione file (x rifiuto modifica)
|
|
/// </summary>
|
|
/// <param name="currItem"></param>
|
|
/// <returns></returns>
|
|
internal async Task<bool> FileDelete(FileModel currItem)
|
|
{
|
|
bool answ = dbController.FileDelete(currItem);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
internal async Task<bool> FileExport(FileModel currItem)
|
|
{
|
|
bool answ = dbController.FileExport(currItem);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
internal async Task<bool> FileReject(FileModel currItem)
|
|
{
|
|
bool answ = dbController.FileModReject(currItem);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
internal async Task<bool> FileUpdate(FileModel updItem)
|
|
{
|
|
bool answ = dbController.FileUpdate(updItem);
|
|
// svuoto cache!
|
|
await ResetArchiveCache();
|
|
return answ;
|
|
}
|
|
|
|
internal void ResetController()
|
|
{
|
|
dbController.ResetController();
|
|
}
|
|
|
|
#endregion Internal Methods
|
|
|
|
#region Protected Fields
|
|
|
|
protected static string connStringBBM = "";
|
|
|
|
protected static string connStringFatt = "";
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Private Fields
|
|
|
|
/// <summary>
|
|
/// gestione key Redis
|
|
/// </summary>
|
|
private const string redisBaseAddr = "MP:PROG";
|
|
|
|
private static IConfiguration _configuration;
|
|
|
|
private static ILogger<FileArchDataService> _logger;
|
|
|
|
private static List<ArchMaccModel> ElencoMacchine = new List<ArchMaccModel>();
|
|
|
|
private static JsonSerializerSettings? JSSettings;
|
|
|
|
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
/// <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!;
|
|
|
|
private Random rnd = new Random();
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan FastCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan LongCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan UltraLongCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset della cache dati ArchivioMacchine in redis
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task ResetArchiveCache()
|
|
{
|
|
await ExecFlushRedisPattern($"{redisBaseAddr}:ArchMacc:*");
|
|
await ExecFlushRedisPattern($"{redisBaseAddr}:ArchStatus:*");
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |