546 lines
15 KiB
C#
546 lines
15 KiB
C#
using Blazored.LocalStorage;
|
|
using Core;
|
|
using LiMan.DB;
|
|
using LiMan.GLS;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using StackExchange.Redis;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LiMan.UI.Data
|
|
{
|
|
public class MessageService
|
|
{
|
|
#region Public Constructors
|
|
|
|
public MessageService(ILocalStorageService genLocalStorage, IConnectionMultiplexer redisConnMult)
|
|
{
|
|
// gestione sessioni in browser
|
|
localStore = genLocalStorage;
|
|
// 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
|
|
};
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Events
|
|
|
|
public event Action EA_FilterUpdated;
|
|
|
|
public event Action EA_HideSearch;
|
|
|
|
public event Action EA_PageUpdated;
|
|
|
|
public event Action EA_SearchUpdated;
|
|
|
|
public event Action EA_SelCodApp;
|
|
|
|
public event Action EA_SelCodImp;
|
|
|
|
public event Action EA_SelCodInst;
|
|
|
|
public event Action EA_ShowSearch;
|
|
|
|
public event Action EA_TaskUpdate;
|
|
|
|
public event Action EA_UserNameUpd;
|
|
|
|
#endregion Public Events
|
|
|
|
#region Public Properties
|
|
|
|
public SelectNext DetailDBFilter
|
|
{
|
|
get => _detailFilterNext;
|
|
set
|
|
{
|
|
if (_detailFilterNext != value)
|
|
{
|
|
_detailFilterNext = value;
|
|
|
|
if (EA_FilterUpdated != null)
|
|
{
|
|
EA_FilterUpdated?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public SelectData DetailFilter
|
|
{
|
|
get => _detailFilter;
|
|
set
|
|
{
|
|
if (_detailFilter != value)
|
|
{
|
|
_detailFilter = value;
|
|
|
|
if (EA_FilterUpdated != null)
|
|
{
|
|
EA_FilterUpdated?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public SelectGLS DetailGLSFilter
|
|
{
|
|
get => _detailFilterGLS;
|
|
set
|
|
{
|
|
if (_detailFilterGLS != value)
|
|
{
|
|
_detailFilterGLS = value;
|
|
|
|
if (EA_FilterUpdated != null)
|
|
{
|
|
EA_FilterUpdated?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PageIcon
|
|
{
|
|
get => _pageIcon;
|
|
set
|
|
{
|
|
if (_pageIcon != value)
|
|
{
|
|
_pageIcon = value;
|
|
ReportPageUpd();
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PageName
|
|
{
|
|
get => _pageName;
|
|
set
|
|
{
|
|
if (_pageName != value)
|
|
{
|
|
_pageName = value;
|
|
//ReportPageUpd();
|
|
}
|
|
}
|
|
}
|
|
|
|
public int PageNum { get; set; } = 1;
|
|
public int PageSize { get; set; } = 10;
|
|
|
|
public string SearchVal
|
|
{
|
|
get => _searchVal;
|
|
set
|
|
{
|
|
if (_searchVal != value)
|
|
{
|
|
_searchVal = value;
|
|
|
|
if (EA_SearchUpdated != null)
|
|
{
|
|
EA_SearchUpdated?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool ShowSearch
|
|
{
|
|
get => showSearch;
|
|
set
|
|
{
|
|
if (showSearch != value)
|
|
{
|
|
showSearch = value;
|
|
if (showSearch)
|
|
{
|
|
if (EA_ShowSearch != null)
|
|
{
|
|
EA_ShowSearch?.Invoke();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EA_HideSearch != null)
|
|
{
|
|
EA_HideSearch?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public string UserName
|
|
{
|
|
get => _userName;
|
|
set
|
|
{
|
|
if (_userName != value)
|
|
{
|
|
_userName = value;
|
|
ReportUserUpd();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dizionario totale preferenze utente
|
|
/// </summary>
|
|
public Dictionary<string, string> UsersPrefDict
|
|
{
|
|
get => redisHashDictGet((RedisKey)$"{redisUserKey}");
|
|
set => redisHashDictSet((RedisKey)$"{redisUserKey}", value);
|
|
}
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Refresh globale cache redis
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<bool> FlushRedisCache()
|
|
{
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
await Task.Delay(1);
|
|
RedisValue pattern = new RedisValue($"{redisBaseKey}:*");
|
|
bool answ = await ExecFlushRedisPattern(pattern);
|
|
sw.Stop();
|
|
Log.Debug($"FlushRedisCache in {sw.Elapsed.TotalMilliseconds} ms");
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Num record x la pagina corrente
|
|
/// </summary>
|
|
public async Task<int> NumRowGridGet(string gridName)
|
|
{
|
|
var answ = await localStore.GetItemAsync<int>($"{gridName}_nRow");
|
|
answ = answ > 0 ? answ : 10;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imposta num record x la pagina corrente
|
|
/// </summary>
|
|
public async Task NumRowGridSet(string gridName, int newVal)
|
|
{
|
|
await localStore.SetItemAsync($"{gridName}_nRow", newVal);
|
|
}
|
|
|
|
public void ReportSelCodApp()
|
|
{
|
|
if (EA_SelCodApp != null)
|
|
{
|
|
EA_SelCodApp?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void ReportSelCodImp()
|
|
{
|
|
if (EA_SelCodImp != null)
|
|
{
|
|
EA_SelCodImp?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void ReportSelCodInst()
|
|
{
|
|
if (EA_SelCodInst != null)
|
|
{
|
|
EA_SelCodInst?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void ReportTaskChange()
|
|
{
|
|
if (EA_TaskUpdate != null)
|
|
{
|
|
EA_TaskUpdate?.Invoke();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Preferenza utente salvata in local storage
|
|
/// </summary>
|
|
public async ValueTask<T?> UserPrefGet<T>(string userPref)
|
|
{
|
|
var sData = await localStore.GetItemAsync<string>(userPref);
|
|
if (string.IsNullOrEmpty(sData))
|
|
{
|
|
return default(T);
|
|
}
|
|
else
|
|
{
|
|
return (T)Convert.ChangeType(sData, typeof(T));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imposta pref utente
|
|
/// </summary>
|
|
public async Task UserPrefSet(string userPref, string newVal)
|
|
{
|
|
await localStore.SetItemAsync(userPref, newVal);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cerca un parametro utente salvato (se presente) e restituisce, se non trova restituisce ""
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public string UsrParamGet(string key)
|
|
{
|
|
string answ = "";
|
|
var currDict = UsersPrefDict;
|
|
if (currDict.ContainsKey(key))
|
|
{
|
|
answ = currDict[key];
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cerca un parametro utente salvato (se presente) e restituisce, se non trova restituisce 0
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <param name="nullVal">Valore da restituire se NON trovato</param>
|
|
/// <returns></returns>
|
|
public int UsrParamGetUInt(string key, int nullVal)
|
|
{
|
|
int answ = nullVal;
|
|
var sVal = UsrParamGet(key);
|
|
if (!string.IsNullOrEmpty(sVal))
|
|
{
|
|
int.TryParse(sVal, out answ);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Upsert di un parametro utente
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public string UsrParamSet(string key, string value)
|
|
{
|
|
string answ = "";
|
|
var currDict = UsersPrefDict;
|
|
if (currDict.ContainsKey(key))
|
|
{
|
|
currDict[key] = value;
|
|
}
|
|
else
|
|
{
|
|
currDict.Add(key, value);
|
|
}
|
|
UsersPrefDict = currDict;
|
|
return answ;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Fields
|
|
|
|
protected static JsonSerializerSettings? JSSettings;
|
|
|
|
/// <summary>
|
|
/// Oggetto per connessione a REDIS
|
|
/// </summary>
|
|
protected IConnectionMultiplexer redisConn = null!;
|
|
|
|
/// <summary>
|
|
/// Oggetto DB redis da impiegare x chiamate R/W
|
|
/// </summary>
|
|
protected IDatabase redisDb = null!;
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Protected Properties
|
|
|
|
protected ILocalStorageService localStore { get; set; } = null!;
|
|
|
|
#endregion Protected Properties
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Esegue flush memoria redis dato pat2Flush
|
|
/// </summary>
|
|
/// <param name="pat2Flush"></param>
|
|
/// <returns></returns>
|
|
protected async Task<bool> ExecFlushRedisPattern(RedisValue pat2Flush)
|
|
{
|
|
bool answ = false;
|
|
var masterEndpoint = redisConn.GetEndPoints()
|
|
.Where(ep => redisConn.GetServer(ep).IsConnected && !redisConn.GetServer(ep).IsReplica)
|
|
.FirstOrDefault();
|
|
|
|
// sepattern è "*" elimino intero DB...
|
|
if (masterEndpoint != null && (pat2Flush.Equals(new RedisValue("*")) || pat2Flush == RedisValue.Null))
|
|
{
|
|
redisConn.GetServer(masterEndpoint).FlushDatabase(database: redisDb.Database);
|
|
}
|
|
else
|
|
{
|
|
var server = redisConn.GetServer(masterEndpoint);
|
|
var keys = server.Keys(database: redisDb.Database, pattern: pat2Flush, pageSize: 1000);
|
|
|
|
var deleteTasks = new List<Task>();
|
|
foreach (var key in keys)
|
|
{
|
|
deleteTasks.Add(redisDb.KeyDeleteAsync(key));
|
|
if (deleteTasks.Count >= 1000)
|
|
{
|
|
await Task.WhenAll(deleteTasks);
|
|
deleteTasks.Clear();
|
|
}
|
|
}
|
|
if (deleteTasks.Count > 0)
|
|
{
|
|
await Task.WhenAll(deleteTasks);
|
|
}
|
|
}
|
|
answ = true;
|
|
#if 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;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return answ;
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Private Fields
|
|
|
|
private SelectData _detailFilter = SelectData.Init(5, 15);
|
|
private SelectGLS _detailFilterGLS = SelectGLS.Init(60, -30);
|
|
private SelectNext _detailFilterNext = SelectNext.Init(60, -30);
|
|
private string _pageIcon;
|
|
private string _pageName;
|
|
private string _searchVal;
|
|
private string _userName;
|
|
private Logger Log = LogManager.GetCurrentClassLogger();
|
|
private string redisBaseKey = "LiMan:Ui:UserPref";
|
|
private bool showSearch;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
private string redisUserKey
|
|
{
|
|
get => $"{redisBaseKey}:{UserName.Replace("\\", ":")}";
|
|
}
|
|
|
|
#endregion Private Properties
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Recupero HashSet redis come Dictionary
|
|
/// </summary>
|
|
/// <param name="currKey"></param>
|
|
/// <param name="dict"></param>
|
|
private Dictionary<string, string> redisHashDictGet(RedisKey currKey)
|
|
{
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
try
|
|
{
|
|
answ = redisDb
|
|
.HashGetAll(currKey)
|
|
.ToDictionary(x => $"{x.Name}", x => $"{x.Value}");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Info($"Errore redisHashDictGet | currKey: {currKey}{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Salvataggio Dictionary come HashSet Redis
|
|
/// </summary>
|
|
/// <param name="currKey"></param>
|
|
/// <param name="dict"></param>
|
|
private bool redisHashDictSet(RedisKey currKey, Dictionary<string, string> dict)
|
|
{
|
|
bool fatto = false;
|
|
try
|
|
{
|
|
HashEntry[] data2ins = new HashEntry[dict.Count];
|
|
int i = 0;
|
|
foreach (KeyValuePair<string, string> kvp in dict)
|
|
{
|
|
data2ins[i] = new HashEntry(kvp.Key, kvp.Value);
|
|
i++;
|
|
}
|
|
// salvo!
|
|
redisDb.HashSet(currKey, data2ins);
|
|
redisDb.KeyExpire(currKey, DateTime.Now.AddMinutes(10));
|
|
fatto = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in redisHashDictSet | currKey: {currKey}{Environment.NewLine}{exc}");
|
|
}
|
|
return fatto;
|
|
}
|
|
|
|
private void ReportPageUpd()
|
|
{
|
|
if (EA_PageUpdated != null)
|
|
{
|
|
EA_PageUpdated?.Invoke();
|
|
}
|
|
}
|
|
|
|
private void ReportSearch()
|
|
{
|
|
if (EA_SearchUpdated != null)
|
|
{
|
|
EA_SearchUpdated?.Invoke();
|
|
}
|
|
}
|
|
|
|
private void ReportUserUpd()
|
|
{
|
|
if (EA_UserNameUpd != null)
|
|
{
|
|
EA_UserNameUpd?.Invoke();
|
|
}
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |