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();
}
}
}
///
/// Dizionario totale preferenze utente
///
public Dictionary UsersPrefDict
{
get => redisHashDictGet((RedisKey)$"{redisUserKey}");
set => redisHashDictSet((RedisKey)$"{redisUserKey}", value);
}
#endregion Public Properties
#region Public Methods
///
/// Refresh globale cache redis
///
///
public async Task 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;
}
///
/// Num record x la pagina corrente
///
public async Task NumRowGridGet(string gridName)
{
var answ = await localStore.GetItemAsync($"{gridName}_nRow");
answ = answ > 0 ? answ : 10;
return answ;
}
///
/// Imposta num record x la pagina corrente
///
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();
}
}
///
/// Preferenza utente salvata in local storage
///
public async ValueTask UserPrefGet(string userPref)
{
var sData = await localStore.GetItemAsync(userPref);
if (string.IsNullOrEmpty(sData))
{
return default(T);
}
else
{
return (T)Convert.ChangeType(sData, typeof(T));
}
}
///
/// Imposta pref utente
///
public async Task UserPrefSet(string userPref, string newVal)
{
await localStore.SetItemAsync(userPref, newVal);
}
///
/// Cerca un parametro utente salvato (se presente) e restituisce, se non trova restituisce ""
///
///
///
public string UsrParamGet(string key)
{
string answ = "";
var currDict = UsersPrefDict;
if (currDict.ContainsKey(key))
{
answ = currDict[key];
}
return answ;
}
///
/// Cerca un parametro utente salvato (se presente) e restituisce, se non trova restituisce 0
///
///
/// Valore da restituire se NON trovato
///
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;
}
///
/// Upsert di un parametro utente
///
///
///
///
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;
///
/// Oggetto per connessione a REDIS
///
protected IConnectionMultiplexer redisConn = null!;
///
/// Oggetto DB redis da impiegare x chiamate R/W
///
protected IDatabase redisDb = null!;
#endregion Protected Fields
#region Protected Properties
protected ILocalStorageService localStore { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
///
/// Esegue flush memoria redis dato pat2Flush
///
///
///
protected async Task 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();
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
///
/// Recupero HashSet redis come Dictionary
///
///
///
private Dictionary redisHashDictGet(RedisKey currKey)
{
Dictionary answ = new Dictionary();
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;
}
///
/// Salvataggio Dictionary come HashSet Redis
///
///
///
private bool redisHashDictSet(RedisKey currKey, Dictionary dict)
{
bool fatto = false;
try
{
HashEntry[] data2ins = new HashEntry[dict.Count];
int i = 0;
foreach (KeyValuePair 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
}
}