Files
lux/EgwCoreLib.Lux.Data/Services/ImageCacheService.cs
T
2025-11-04 17:39:59 +01:00

425 lines
18 KiB
C#

using EgwCoreLib.Lux.Core.RestPayload;
using EgwMultiEngineManager.Data;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using NLog;
using RestSharp;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EgwCoreLib.Lux.Data.Services
{
public class ImageCacheService
{
#region Public Constructors
public ImageCacheService(IConfiguration config, IRedisService redisService)
{
_config = config;
_redisService = redisService;
// conf channels x comunicazione broadcast
hwOptChannel = _config.GetValue<string>("ServerConf:HwOptChannel") ?? "Egw:hw";
pngChannel = _config.GetValue<string>("ServerConf:PngChannel") ?? "Egw:png:img";
svgChannel = _config.GetValue<string>("ServerConf:SvgChannel") ?? "Egw:svg:img";
bomChannel = _config.GetValue<string>("ServerConf:BomChannel") ?? "Egw:bom";
hmlChannel = _config.GetValue<string>("ServerConf:HwListChannel") ?? "Egw:hml";
profListChannel = _config.GetValue<string>("ServerConf:ProfListChannel") ?? "Egw:prof";
shapeChannel = _config.GetValue<string>("ServerConf:ShapeChannel") ?? "Egw:shape";
updateChannel = _config.GetValue<string>("ServerConf:UpdateChannel") ?? "Egw:update";
// conf tag x cache
liveTag = _config.GetValue<string>("ServerConf:ImageLiveTag") ?? "svg";
cacheTag = _config.GetValue<string>("ServerConf:ImageFileTag") ?? "svgfile";
calcTag = _config.GetValue<string>("ServerConf:ImageCalcTag") ?? "svg-preview";
// verifico la url base
apiUrl = _config.GetValue<string>("ServerConf:Prog.ApiUrl") ?? "https://iis01.egalware.com/lux/srv/api";
imgBasePath = _config.GetValue<string>("ServerConf:ImageBaseUrl") ?? "window";
// fix opzioni base del RestClient
restOptStd = new RestClientOptions
{
Timeout = TimeSpan.FromSeconds(60),
BaseUrl = new Uri($"{apiUrl}/{imgBasePath}")
};
Log.Info("ImageCache Service Started");
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Effettua una generica chiamata ApiRest
/// </summary>
/// <param name="ApiUrl">URL Api di base</param>
/// <param name="ApiRequest">Richiesta completa</param>
/// <returns></returns>
public async Task<RestResponse> CallRestGet(string ApiUrl, string ApiRequest)
{
RestResponse response;
// cerco online
using (RestClient client = new RestClient(ApiUrl))
{
var request = new RestRequest(ApiRequest, Method.Get);
response = await client.GetAsync(request);
}
return response;
}
/// <summary>
#if false
/// Effettua una generica chiamata ApiRest
/// </summary>
/// <param name="ApiUrl">URL Api di base</param>
/// <param name="ApiRequest">Richiesta completa</param>
/// <param name="JsonBody">Corpo Json trasmesso con richiesta</param>
/// <returns></returns>
public async Task<RestResponse> CallRestPost(string ApiUrl, string ApiRequest, string JsonBody)
{
RestResponse response;
// cerco online
using (RestClient client = new RestClient(ApiUrl))
{
var request = new RestRequest(ApiRequest, Method.Post);
string rawData = JsonConvert.SerializeObject(JsonBody);
request.AddJsonBody(rawData);
response = await client.ExecutePostAsync(request);
}
return response;
}
#endif
/// <summary>
/// Effettua una generica chiamata ApiRest
/// </summary>
/// <param name="ApiUrl">URL Api di base</param>
/// <param name="ApiRequest">Richiesta completa</param>
/// <param name="rawBody">Corpo Json trasmesso con richiesta</param>
/// <returns></returns>
public async Task<RestResponse> CallRestPost(string ApiUrl, string ApiRequest, object rawBody)
{
RestResponse response;
// cerco online
using (RestClient client = new RestClient(ApiUrl))
{
var request = new RestRequest(ApiRequest, Method.Post);
string rawData = JsonConvert.SerializeObject(rawBody);
request.AddJsonBody(rawData);
response = await client.ExecutePostAsync(request);
}
return response;
}
/// <summary>
/// Calcola URL immagine dato
/// </summary>
/// <param name="baseUrl">Base url IMG server (da config)</param>
/// <param name="isLive">Live = in fase di calcolo (cache REDIS), altrimenti da filesystem</param>
/// <param name="imgUID">UID elemento/immagine</param>
/// <param name="envir">Environment item</param>
/// <returns></returns>
public string ImageUrl(string baseUrl, bool isLive, string imgUID, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW)
{
string tag = isLive ? liveTag : cacheTag;
string fType = "undef";
if (imgUID.EndsWith(".svg"))
{
fType = "svg";
imgUID.Replace(".svg", "");
}
else if (imgUID.EndsWith(".png"))
{
fType = "png";
imgUID.Replace(".png", "");
}
switch (envir)
{
case Constants.EXECENVIRONMENTS.NULL:
break;
case Constants.EXECENVIRONMENTS.WINDOW:
fType = "svg";
break;
case Constants.EXECENVIRONMENTS.BEAM:
case Constants.EXECENVIRONMENTS.WALL:
case Constants.EXECENVIRONMENTS.CABINET:
default:
fType = "png";
break;
}
string rndImg = $"{DateTime.Now:HHmmssfff}";
string fullUrl = $"{baseUrl}/{tag}/{imgUID}-{rndImg}.{fType}?envir={envir}".Replace("////", "//");
return fullUrl;
}
/// <summary>
/// Recupera img redis PNG x id item richiesto
/// </summary>
/// <param name="imgUid">UID item</param>
/// <param name="envir">Environment item</param>
public string LoadPng(string imgUid, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW)
{
// recupero img da cache
string currKey = $"{redisBaseKey}:{envir}:Img:Png:{imgUid.Replace("/", ":")}";
var rawVal = _redisService.Get(currKey);
return $"{rawVal}";
}
/// <summary>
/// Recupera img redis SVG x id item richiesto
/// </summary>
/// <param name="imgUid">UID item</param>
/// <param name="envir">Environment item</param>
public string LoadSvg(string imgUid, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW)
{
// recupero img da cache
string currKey = $"{redisBaseKey}:{envir}:Img:Svg:{imgUid.Replace("/", ":")}";
var rawVal = _redisService.Get(currKey);
return $"{rawVal}";
}
/// <summary>
/// Recupera img redis SVG x id item richiesto async
/// </summary>
/// <param name="imgId">UID item</param>
/// <param name="envir">Environment item</param>
public async Task<string> LoadSvgAsync(string imgId, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW)
{
// recupero img da cache
string currKey = $"{redisBaseKey}:{envir}:Img:Svg:{imgId.Replace("/", ":")}";
var rawVal = await _redisService.GetAsync(currKey);
return $"{rawVal}";
}
/// <summary>
/// Salva e invia su channel richiesto un update x UID
/// è attesao un refresh per chi sottoscrive il canale
/// </summary>
/// <param name="env"></param>
/// <param name="uid"></param>
public async Task<bool> PublishUpdateAsync(string uid, Constants.EXECENVIRONMENTS env)
{
bool done = false;
// invio notifica sul canale di update generale...
string notifyChannel = $"{updateChannel}:{env}";
// contenuto è UID
long numSent = await _redisService.PublishAsync(notifyChannel, $"{uid}");
done = numSent > 0;
return done;
}
/// <summary>
/// Calcola URL immagine dato
/// </summary>
/// <param name="baseUrl">Base url IMG server (da config)</param>
/// <param name="imgUID">UID elemento/immagine</param>
/// <param name="serJwd">JWD serializzato di cui si richiede l'immagine aggiornata</param>
/// <returns></returns>
public string ReqUpdateSvg(string baseUrl, string imgUID, string serJwd)
{
string answ = "";
if (imgUID.EndsWith(".svg"))
{
imgUID.Replace(".svg", "");
}
string fullUrl = $"{baseUrl}/svg-preview/{imgUID}".Replace("////", "//");
return answ;
}
/// <summary>
/// Salva e invia su channel BOM redis il doc richiesto
/// </summary>
/// <param name="uid"></param>
/// <param name="env"></param>
/// <param name="bomContent"></param>
public async Task<bool> SaveBomAsync(string uid, Constants.EXECENVIRONMENTS env, string bomContent)
{
// salvo in cache
string currKey = $"{redisBaseKey}:{env}:BOM:{uid.Replace("/", ":")}";
var done = await _redisService.SetAsync(currKey, bomContent);
// invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale
string notifyChannel = $"{bomChannel}:{uid}";
long numSent = await _redisService.PublishAsync(notifyChannel, bomContent);
return done;
}
/// <summary>
/// Salva e invia su channel dedicato HML l'elenco degli HarwareModel (conf preferiti) gestiti
/// </summary>
/// <param name="uid"></param>
/// <param name="rawData"></param>
public async Task<bool> SaveHmlAsync(string uid, Constants.EXECENVIRONMENTS env, string rawData)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:HML:{uid.Replace("/", ":")}";
var done = await _redisService.SetAsync(currKey, rawData);
// invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale
string notifyChannel = $"{hmlChannel}:{uid}";
long numSent = await _redisService.PublishAsync(notifyChannel, rawData);
return done;
}
/// <summary>
/// Salva e invia su channel l'XML delle HW options per il doc richiesto
/// </summary>
/// <param name="uid"></param>
/// <param name="env"></param>
/// <param name="xmlContent"></param>
public async Task<bool> SaveHwOptAsync(string uid, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string xmlContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:HwOpt:{uid.Replace("/", ":")}";
// lascio in cache 15 min x poterlo verificare
var done = await _redisService.SetAsync(currKey, xmlContent, TimeSpan.FromMinutes(15));
// invio notifica nuova XML sul canale (inviato solo XML pulito con ID nel canale)
string notifyChannel = $"{hwOptChannel}:{uid}";
long numSent = await _redisService.PublishAsync(notifyChannel, xmlContent);
return done;
}
/// <summary>
/// Salva e invia su channel img redis SVG per il doc richiesto
/// </summary>
/// <param name="imgId"></param>
/// <param name="pngContent">contenuto PNG come string base64</param>
/// <returns></returns>
public bool SavePng(string imgId, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string pngContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:Img:Png:{imgId.Replace("/", ":")}";
var done = _redisService.Set(currKey, pngContent);
// invio notifica nuova imgsvg sul canale... viene "reimbustata"
string notifyChannel = $"png-gen:{imgId}";
long numSent = _redisService.Publish(notifyChannel, pngContent);
return done;
}
/// <summary>
/// Salva e invia su channel img redis PNG per il doc richiesto
/// </summary>
/// <param name="imgId"></param>
/// <param name="env"></param>
/// <param name="pngContent">contenuto PNG come string base64</param>
public async Task<bool> SavePngAsync(string imgId, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string pngContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:Img:Png:{imgId.Replace("/", ":")}";
var done = await _redisService.SetAsync(currKey, pngContent);
// invio notifica nuova png generata sul canale... viene inviato solo contenuto con ID nel canale
string notifyChannel = $"{pngChannel}:{imgId}";
long numSent = await _redisService.PublishAsync(notifyChannel, pngContent);
return done;
}
/// <summary>
/// Salva e invia su channel profile list gestiti
/// </summary>
/// <param name="uid"></param>
/// <param name="rawData"></param>
public async Task<bool> SaveProfileListAsync(string uid, Constants.EXECENVIRONMENTS env, string rawData)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:PROFLIST:{uid.Replace("/", ":")}";
var done = await _redisService.SetAsync(currKey, rawData);
// invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale
string notifyChannel = $"{profListChannel}:{uid}";
long numSent = await _redisService.PublishAsync(notifyChannel, rawData);
return done;
}
/// <summary>
/// Salva e invia su channel shape per item (UID.GroupId) richiesto
/// </summary>
/// <param name="uid"></param>
/// <param name="env"></param>
/// <param name="shapeContent"></param>
public async Task<bool> SaveShapeAsync(string uid, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string shapeContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:Shape:{uid}";
var done = await _redisService.SetAsync(currKey, shapeContent);
// invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale
string notifyChannel = $"{shapeChannel}:{uid}";
long numSent = await _redisService.PublishAsync(notifyChannel, shapeContent);
return done;
}
/// <summary>
/// Salva e invia su channel img redis SVG per il doc richiesto
/// </summary>
/// <param name="imgId"></param>
/// <param name="svgContent"></param>
/// <returns></returns>
public bool SaveSvg(string imgId, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string svgContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:Img:Svg:{imgId.Replace("/", ":")}";
var done = _redisService.Set(currKey, svgContent);
// invio notifica nuova imgsvg sul canale... viene "reimbustata"
string notifyChannel = $"svg-gen:{imgId}";
long numSent = _redisService.Publish(notifyChannel, svgContent);
return done;
}
/// <summary>
/// Salva e invia su channel img redis SVG per il doc richiesto
/// </summary>
/// <param name="imgId"></param>
/// <param name="env"></param>
/// <param name="svgContent"></param>
public async Task<bool> SaveSvgAsync(string imgId, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS env, string svgContent)
{
// salvo img in cache
string currKey = $"{redisBaseKey}:{env}:Img:Svg:{imgId.Replace("/", ":")}";
var done = await _redisService.SetAsync(currKey, svgContent);
// invio notifica nuova svg generata sul canale... viene inviato solo contenuto con ID nel canale
string notifyChannel = $"{svgChannel}:{imgId}";
long numSent = await _redisService.PublishAsync(notifyChannel, svgContent);
return done;
}
#endregion Public Methods
#region Private Fields
private static Logger Log = LogManager.GetCurrentClassLogger();
private readonly IRedisService _redisService;
private readonly string apiUrl = "";
private readonly string bomChannel = "bom:item";
private readonly string cacheTag = "svgfile";
private readonly string calcTag = "svgpreview";
private readonly string hmlChannel = "hml:item";
private readonly string hwOptChannel = "hw:opt";
private readonly string imgBasePath = "";
private readonly string liveTag = "svg";
private readonly string pngChannel = "png:img";
private readonly string profListChannel = "prof:list";
private readonly string shapeChannel = "shape:curr";
private readonly string svgChannel = "svg:img";
private readonly string updateChannel = "ui:update";
private IConfiguration _config;
private string imageBaseUrl = "";
private string redisBaseKey = "Lux";
#endregion Private Fields
#region Private Properties
/// <summary>
/// Conf client RestSharp standard:
/// - base URI al sito
/// - timeout 1 min
/// </summary>
private RestClientOptions restOptStd { get; set; } = new RestClientOptions();
#endregion Private Properties
}
}