Files
Saxonite/SaxoniteCoreWeb/Base/Consoles/SaxDataCacheConsole_Web.cs
T
2022-02-16 10:47:45 +00:00

292 lines
11 KiB
C#

using Microsoft.IdentityModel.Tokens;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Consoles;
using System;
using System.Collections.Generic;
using System.Text;
namespace Saxonite.Net.Core.Web.Base.Consoles
{
//=======================================================================
public abstract class SaxDataCacheConsole_Web : SaxDataCacheConsole
{
//-------------------------------------------------------------------
// Data members.
private class DataMembers
{
public SaxInternals internals;
public Dictionary<Sax.DataItemType, Dictionary<SysId, String>> encryptedIdCache = new Dictionary<Sax.DataItemType, Dictionary<SysId, String>>();
}
private DataMembers data = new DataMembers();
//-------------------------------------------------------------------
// Protected construction.
protected SaxDataCacheConsole_Web(SaxSessionContext sessionContext) :
base(sessionContext)
{
data.internals = new SaxInternals(sessionContext, false);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
data.internals.Dispose();
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Utilities.
protected abstract void ForceRefresh();
public override void PopulateCachedDataToInternals(SaxInternals internals)
{
if (regionsData.regionDataMap == null) ForceRefresh();
// Regions.
List<SaxRegion.Data> activeRegionDataList = new List<SaxRegion.Data>();
lock (regionsData)
activeRegionDataList.AddRange(regionsData.activeRegionDataList);
internals.PopulateRegionCache(activeRegionDataList);
// Sports.
List<SaxSport.Data> activeSportDataList = new List<SaxSport.Data>();
lock (sportsData)
activeSportDataList.AddRange(sportsData.activeSportDataList);
internals.PopulateSportCache(activeSportDataList);
}
/// <summary>
/// Encrypted Ids are stored in cache to ensure that they are consistent throughout a user's session
/// by persisting them through the life of the cache (application restart).
/// <para>Required as the encrypted values are compared in javascript.</para>
/// <para>Candidate encrypted value supplied by calling routine as cache doesn't know how to encrypt - used if Id not previously encrypted.</para>
/// </summary>
public override String GetEncryptedId(Sax.DataItemType itemType, SysId id, String candidateValue)
{
// Invalid Id always has a blank encrypted value.
if (!SysId.IsValid(id)) return "";
// Only Regions and Sports are supported.
if (!(new List<Sax.DataItemType>() { Sax.DataItemType.Sport, Sax.DataItemType.Region }).Contains(itemType))
return candidateValue;
lock (data.encryptedIdCache)
{
Dictionary<SysId, String> itemIds = data.encryptedIdCache.GetValue(itemType, null);
if (itemIds == null)
{
// Add cache entry for this item type.
itemIds = new Dictionary<SysId, string>();
data.encryptedIdCache.Add(itemType, itemIds);
}
String encryptedId = itemIds.GetValue(id, null);
if (encryptedId == null && !StringUtil.IsEmpty(candidateValue))
{
// Use the candidate value and store it.
encryptedId = candidateValue;
itemIds.Add(id, encryptedId);
}
return encryptedId;
}
}
//-------------------------------------------------------------------
// Regions.
public bool RegionsSupported { get; protected set; } = false;
private class RegionsData
{
public Dictionary<SysId, SaxRegion.Data> regionDataMap = null;
public List<SaxRegion.Data> activeRegionDataList = null;
}
private readonly RegionsData regionsData = new RegionsData();
public override List<SaxRegion.Data> GetAllRegions()
{
String fn = GetType().Name + ".ActiveRegions";
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
List<SaxRegion.Data> activeRegions = new List<SaxRegion.Data>();
if (regionsData.regionDataMap == null) ForceRefresh();
lock (regionsData)
{
if (regionsData.regionDataMap == null) throw new NotSupportedException(fn + " Regions not populated.");
activeRegions.AddRange(regionsData.regionDataMap.Values);
}
return activeRegions;
}
public override List<SaxRegion.Data> GetActiveRegions()
{
String fn = GetType().Name + ".ActiveRegions";
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
List<SaxRegion.Data> activeRegions = new List<SaxRegion.Data>();
if (regionsData.regionDataMap == null) ForceRefresh();
lock (regionsData)
{
if (regionsData.regionDataMap == null) throw new NotSupportedException(fn + " Regions not populated.");
activeRegions.AddRange(regionsData.activeRegionDataList);
}
return activeRegions;
}
protected void RefreshRegions()
{
String fn = GetType().Name + ".RefreshRegions";
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
try
{
DateTime startedAt = DateTime.Now;
// Refreshed lists will be populated in isolation and then used to instantaneously replace the cache lists.
Dictionary<SysId, SaxRegion.Data> newRegionDataMap = new Dictionary<SysId, SaxRegion.Data>();
List<SaxRegion.Data> newActiveRegionDataList = new List<SaxRegion.Data>();
// Query Regions to replace cache.
SaxRegion.Params prmRegion = new SaxRegion.Params();
prmRegion.StatusCat = SaxRegion.StatusCat.NotDeleted;
foreach (SaxRegion region in data.internals.ReferenceMgr.GetRegionList(prmRegion))
{
// Only interested in retaining the Data objects.
newRegionDataMap[region.Id] = region.GetData();
region.Dispose();
}
// Populate replacement list of active regions.
foreach (SaxRegion.Data regionData in newRegionDataMap.GetValues())
{
if (IsRegionActive(newRegionDataMap, regionData))
newActiveRegionDataList.Add(regionData.Clone());
}
// Replace the list of Regions.
lock (regionsData)
{
// Assign the refreshed regions and active regions.
// NB The old regions don't need to be disposed as they are SaxRegion.Data objects.
regionsData.regionDataMap = newRegionDataMap;
regionsData.activeRegionDataList = newActiveRegionDataList;
}
SaLogger.Info(fn + " Regions found: " + regionsData.regionDataMap.Count + ". Elapsed: " + DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds));
}
catch (Exception exc)
{
SaLogger.Error(fn + ExceptionUtil.GetLogMessage(exc, "refreshing Regions cache"));
}
}
private static bool IsRegionActive(Dictionary<SysId, SaxRegion.Data> regionDataMap, SaxRegion.Data regionData)
{
if (regionData == null) return false;
if (!regionData.IsStatusActive) return false;
if (SysId.IsValid(regionData.RegionIdParent))
return IsRegionActive(regionDataMap, regionDataMap.GetValue(regionData.RegionIdParent, null));
return true;
}
private SaxRegion GetRegion(SaxRegion.Data regionData)
{
if (regionData == null) return null;
SaxRegion region = data.internals.ReferenceMgr.CreateRegion();
region.SetData(regionData);
return region;
}
//-------------------------------------------------------------------
// Sports.
public bool SportsSupported { get; protected set; } = false;
private class SportsData
{
public Dictionary<SysId, SaxSport.Data> sportDataMap = null;
public List<SaxSport.Data> activeSportDataList = null;
}
private readonly SportsData sportsData = new SportsData();
public override List<SaxSport.Data> GetAllSports()
{
String fn = GetType().Name + ".GetAllSports";
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
List<SaxSport.Data> sports = new List<SaxSport.Data>();
if (sportsData.sportDataMap == null) ForceRefresh();
lock (sportsData)
{
if (sportsData.sportDataMap == null) throw new NotSupportedException(fn + " Sports not populated.");
sports.AddRange(sportsData.sportDataMap.Values);
}
return sports;
}
public override List<SaxSport.Data> GetActiveSports()
{
String fn = GetType().Name + ".GetActiveSports";
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
List<SaxSport.Data> activeSports = new List<SaxSport.Data>();
if (sportsData.sportDataMap == null) ForceRefresh();
lock (sportsData)
{
if (sportsData.sportDataMap == null) throw new NotSupportedException(fn + " Sports not populated.");
activeSports.AddRange(sportsData.activeSportDataList);
}
return activeSports;
}
protected void RefreshSports()
{
String fn = GetType().Name + ".RefreshSports";
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
try
{
DateTime startedAt = DateTime.Now;
// Refreshed lists will be populated in isolation and then used to instantaneously replace the cache lists.
Dictionary<SysId, SaxSport.Data> newSportDataMap = new Dictionary<SysId, SaxSport.Data>();
List<SaxSport.Data> newActiveSportDataList = new List<SaxSport.Data>();
// Query Sports to replace cache.
SaxSport.Params prmSport = new SaxSport.Params();
prmSport.StatusCat = SaxSport.StatusCat.NotDeleted;
foreach (SaxSport sport in data.internals.ReferenceMgr.GetSportList(prmSport))
{
// Only interested in retaining the Data objects.
newSportDataMap[sport.Id] = sport.GetData();
sport.Dispose();
}
// Populate replacement list of active sports.
foreach (SaxSport.Data sportData in newSportDataMap.GetValues())
{
if (IsSportActive(newSportDataMap, sportData))
newActiveSportDataList.Add(sportData.Clone());
}
// Replace the list of Sports.
lock (sportsData)
{
// Assign the refreshed sports and active sports.
// NB The old sports don't need to be disposed as they are SaxSport.Data objects.
sportsData.sportDataMap = newSportDataMap;
sportsData.activeSportDataList = newActiveSportDataList;
}
SaLogger.Info(fn + " Sports found: " + sportsData.sportDataMap.Count + ". Elapsed: " + DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds));
}
catch (Exception exc)
{
SaLogger.Error(fn + ExceptionUtil.GetLogMessage(exc, "refreshing Sports cache"));
}
}
private static bool IsSportActive(Dictionary<SysId, SaxSport.Data> sportDataMap, SaxSport.Data sportData)
{
if (sportData == null) return false;
if (!sportData.IsStatusActive) return false;
return true;
}
private SaxSport GetSport(SaxSport.Data sportData)
{
if (sportData == null) return null;
SaxSport sport = data.internals.ReferenceMgr.CreateSport();
sport.SetData(sportData);
return sport;
}
//-------------------------------------------------------------------
}
//=======================================================================
}