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("ServerConf:HwOptChannel") ?? "Egw:hw"; pngChannel = _config.GetValue("ServerConf:PngChannel") ?? "Egw:png:img"; svgChannel = _config.GetValue("ServerConf:SvgChannel") ?? "Egw:svg:img"; bomChannel = _config.GetValue("ServerConf:BomChannel") ?? "Egw:bom"; hmlChannel = _config.GetValue("ServerConf:HwListChannel") ?? "Egw:hml"; profListChannel = _config.GetValue("ServerConf:ProfListChannel") ?? "Egw:prof"; shapeChannel = _config.GetValue("ServerConf:ShapeChannel") ?? "Egw:shape"; updateChannel = _config.GetValue("ServerConf:UpdateChannel") ?? "Egw:update"; // conf tag x cache liveTag = _config.GetValue("ServerConf:ImageLiveTag") ?? "svg"; cacheTag = _config.GetValue("ServerConf:ImageFileTag") ?? "svgfile"; calcTag = _config.GetValue("ServerConf:ImageCalcTag") ?? "svg-preview"; // verifico la url base apiUrl = _config.GetValue("ServerConf:Prog.ApiUrl") ?? "https://iis01.egalware.com/lux/srv/api"; imgBasePath = _config.GetValue("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 /// /// Effettua una generica chiamata ApiRest /// /// URL Api di base /// Richiesta completa /// public async Task 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; } /// #if false /// Effettua una generica chiamata ApiRest /// /// URL Api di base /// Richiesta completa /// Corpo Json trasmesso con richiesta /// public async Task 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 /// /// Effettua una generica chiamata ApiRest /// /// URL Api di base /// Richiesta completa /// Corpo Json trasmesso con richiesta /// public async Task 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; } /// /// Calcola URL immagine dato /// /// Base url IMG server (da config) /// Live = in fase di calcolo (cache REDIS), altrimenti da filesystem /// UID elemento/immagine /// Environment item /// public string ImageUrl(string baseUrl, bool isLive, string imgUID, EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW) { string tag = isLive ? liveTag : cacheTag; if (imgUID.EndsWith(".svg")) { imgUID.Replace(".svg", ""); } string rndImg = $"{DateTime.Now:HHmmssfff}"; string fullUrl = $"{baseUrl}/{tag}/{imgUID}-{rndImg}.svg?envir={envir}".Replace("////", "//"); return fullUrl; } /// /// Recupera img redis PNG x id item richiesto /// /// UID item /// Environment item 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}"; } /// /// Recupera img redis SVG x id item richiesto /// /// UID item /// Environment item 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}"; } /// /// Recupera img redis SVG x id item richiesto async /// /// UID item /// Environment item public async Task 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}"; } /// /// Salva e invia su channel richiesto un update x UID /// è attesao un refresh per chi sottoscrive il canale /// /// /// public async Task 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; } /// /// Calcola URL immagine dato /// /// Base url IMG server (da config) /// UID elemento/immagine /// JWD serializzato di cui si richiede l'immagine aggiornata /// 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; } /// /// Salva e invia su channel BOM redis il doc richiesto /// /// /// /// public async Task 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; } /// /// Salva e invia su channel dedicato HML l'elenco degli HarwareModel (conf preferiti) gestiti /// /// /// public async Task 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; } /// /// Salva e invia su channel l'XML delle HW options per il doc richiesto /// /// /// /// public async Task 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; } /// /// Salva e invia su channel img redis SVG per il doc richiesto /// /// /// contenuto PNG come string base64 /// 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; } /// /// Salva e invia su channel img redis PNG per il doc richiesto /// /// /// /// contenuto PNG come string base64 public async Task 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; } /// /// Salva e invia su channel profile list gestiti /// /// /// public async Task 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; } /// /// Salva e invia su channel shape per item (UID.GroupId) richiesto /// /// /// /// public async Task 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; } /// /// Salva e invia su channel img redis SVG per il doc richiesto /// /// /// /// 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; } /// /// Salva e invia su channel img redis SVG per il doc richiesto /// /// /// /// public async Task 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 /// /// Conf client RestSharp standard: /// - base URI al sito /// - timeout 1 min /// private RestClientOptions restOptStd { get; set; } = new RestClientOptions(); #endregion Private Properties } }