Update x gestione mandata/ritorno messaggio redis con calcolo SVG
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.5.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.3" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.8.41" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using RestSharp;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -21,6 +22,15 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
svgChannel = _config.GetValue<string>("ServerConf:SvgChannel") ?? "svg:img";
|
||||
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/window";
|
||||
// fix opzioni base del RestClient
|
||||
restOptStd = new RestClientOptions
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(60),
|
||||
BaseUrl = new Uri(apiUrl)
|
||||
};
|
||||
Log.Info("ImageCache Service Started");
|
||||
}
|
||||
|
||||
@@ -28,6 +38,45 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
|
||||
#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>
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola URL immagine dato
|
||||
/// </summary>
|
||||
@@ -70,6 +119,41 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
return $"{rawVal}";
|
||||
}
|
||||
|
||||
/// <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 img redis SVG per il doc richiesto
|
||||
/// </summary>
|
||||
/// <param name="imgId"></param>
|
||||
/// <param name="bomContent"></param>
|
||||
public async Task<bool> SaveBomAsync(string imgId, string bomContent)
|
||||
{
|
||||
// salvo img in cache
|
||||
string currKey = $"{redisBaseKey}:BOM:{imgId.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}:{imgId}";
|
||||
long numSent = await _redisService.PublishAsync(notifyChannel, bomContent);
|
||||
return done;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva e invia su channel img redis SVG per il doc richiesto
|
||||
/// </summary>
|
||||
@@ -103,36 +187,43 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
return done;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva e invia su channel img redis SVG per il doc richiesto
|
||||
/// </summary>
|
||||
/// <param name="imgId"></param>
|
||||
/// <param name="bomContent"></param>
|
||||
public async Task<bool> SaveBomAsync(string imgId, string bomContent)
|
||||
{
|
||||
// salvo img in cache
|
||||
string currKey = $"{redisBaseKey}:BOM:{imgId.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}:{imgId}";
|
||||
long numSent = await _redisService.PublishAsync(notifyChannel, bomContent);
|
||||
return done;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly IRedisService _redisService;
|
||||
private readonly string cacheTag = "svgfile";
|
||||
private readonly string liveTag = "svg";
|
||||
private readonly string svgChannel = "svg:img";
|
||||
|
||||
private readonly string apiUrl = "";
|
||||
|
||||
private readonly string bomChannel = "bom:item";
|
||||
|
||||
private readonly string cacheTag = "svgfile";
|
||||
|
||||
private readonly string calcTag = "svgpreview";
|
||||
|
||||
private readonly string liveTag = "svg";
|
||||
|
||||
private readonly string svgChannel = "svg:img";
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace Lux.API.Controllers
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata POST: riceve Json in formato JWD serializzato, invia richeista calcolo modo 2 (BOM)
|
||||
/// PUT: api/svgPreview/svg/00000000-0000-0000-0000-000000000000
|
||||
/// PUT: api/window/bom/00000000-0000-0000-0000-000000000000
|
||||
/// </summary>
|
||||
/// <param name="id">id oggetto</param>
|
||||
/// <returns></returns>
|
||||
@@ -77,7 +77,7 @@ namespace Lux.API.Controllers
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata POST: riceve Json in formato JWD serializzato, lo ripete come risposta
|
||||
/// PUT: api/svgPreview/svg/00000000-0000-0000-0000-000000000000
|
||||
/// PUT: api/window/svg/00000000-0000-0000-0000-000000000000
|
||||
/// </summary>
|
||||
/// <param name="id">id oggetto</param>
|
||||
/// <returns></returns>
|
||||
@@ -99,7 +99,7 @@ namespace Lux.API.Controllers
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata POST: riceve Json in formato JWD serializzato, lo ripete come risposta
|
||||
/// PUT: api/svgPreview/svg/00000000-0000-0000-0000-000000000000
|
||||
/// PUT: api/window/svg-file/00000000-0000-0000-0000-000000000000
|
||||
/// </summary>
|
||||
/// <param name="id">id oggetto</param>
|
||||
/// <returns></returns>
|
||||
@@ -130,10 +130,11 @@ namespace Lux.API.Controllers
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata POST: riceve Json in formato JWD serializzato, lo ripete come risposta
|
||||
/// PUT: api/svg-preview/svg/00000000-0000-0000-0000-000000000000
|
||||
/// PUT: api/window/svg-preview/00000000-0000-0000-0000-000000000000
|
||||
/// </summary>
|
||||
/// <param name="id">id oggetto</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("svgpreview/{id}")]
|
||||
[HttpPost("svg-preview/{id}")]
|
||||
public async Task<ActionResult<string>> svgPreview(string id, [FromBody] string currJwd)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>0.9.2508.0411</Version>
|
||||
<Version>0.9.2508.0412</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="weather">
|
||||
<span class="bi bi-cloud-moon px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Weather</span>
|
||||
<NavLink class="nav-link" href="scratch">
|
||||
<span class="bi bi-cloud-moon px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Scratch</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
@page "/scratch"
|
||||
|
||||
<h3>Scratch Test</h3>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" placeholder="UID Finestra" @bind="@windowUid">
|
||||
<label for="floatingInput">UID Finestra</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mb-3">
|
||||
<textarea class="form-control small" style="min-height: 20rem;">@demoJwd</textarea>
|
||||
<label for="floatingInput">JWD demo</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary" @onclick="() => SendCalc()">Req Calc</button>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
@outSvg
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,66 @@
|
||||
using EgwCoreLib.Lux.Data;
|
||||
using EgwCoreLib.Lux.Data.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Lux.UI.Components.Pages
|
||||
{
|
||||
public partial class Scratch
|
||||
{
|
||||
private string windowUid = "TestWindow";
|
||||
/// <summary>
|
||||
/// Demorichiesta jwd x fare test richiesta calcolo
|
||||
/// </summary>
|
||||
private string demoJwd = "{\r\n\"ProfilePath\":\"Profilo78\",\r\n\"AreaList\":[\r\n{\r\n\"Shape\":\"RECTANGLE\",\r\n\"DimensionList\":[\r\n{\r\n\"nIndex\":1,\r\n\"sName\":\"Width\",\r\n\"dValue\":1200.0\r\n},\r\n{\r\n\"nIndex\":2,\r\n\"sName\":\"Height\",\r\n\"dValue\":1500.0\r\n}\r\n],\r\n\"JointList\":[\r\n{\r\n\"nIndex\":1,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":2,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":3,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":4,\r\n\"JointType\":\"FULL_V\"\r\n}\r\n],\r\n\"BottomRail\":false,\r\n\"BottomRailQty\":0,\r\n\"AreaList\":[\r\n{\r\n\"bIsSashVertical\":true,\r\n\"SashList\":[\r\n{\r\n\"OpeningType\":\"TURNONLY_LEFT\",\r\n\"bHasHandle\":false,\r\n\"dDimension\":50.0\r\n},\r\n{\r\n\"OpeningType\":\"TILTTURN_RIGHT\",\r\n\"bHasHandle\":true,\r\n\"dDimension\":50.0\r\n}\r\n],\r\n\"SashType\":\"NULL\",\r\n\"JointList\":[\r\n{\r\n\"nIndex\":1,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":2,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":3,\r\n\"JointType\":\"FULL_V\"\r\n},\r\n{\r\n\"nIndex\":4,\r\n\"JointType\":\"FULL_V\"\r\n}\r\n],\r\n\"Hardware\":\"000000\",\r\n\"AreaList\":[\r\n{\r\n\"AreaList\":[\r\n{\r\n\"FillType\":\"GLASS\",\r\n\"AreaList\":[],\r\n\"AreaType\":\"FILL\"\r\n}\r\n],\r\n\"AreaType\":\"SPLITTED\"\r\n},\r\n{\r\n\"AreaList\":[\r\n{\r\n\"FillType\":\"GLASS\",\r\n\"AreaList\":[],\r\n\"AreaType\":\"FILL\"\r\n}\r\n],\r\n\"AreaType\":\"SPLITTED\"\r\n}\r\n],\r\n\"AreaType\":\"SASH\"\r\n}\r\n],\r\n\"AreaType\":\"FRAME\"\r\n}\r\n]\r\n}";
|
||||
|
||||
|
||||
[Inject]
|
||||
protected ImageCacheService ICService { get; set; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
protected IRedisService RedServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IConfiguration Config { get; set; } = null!;
|
||||
|
||||
private string apiUrl = "";
|
||||
private string calcTag = "";
|
||||
private string subChannel = "";
|
||||
private string currChannel = "";
|
||||
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
apiUrl = Config.GetValue<string>("ServerConf:Prog.ApiUrl") ?? "";
|
||||
calcTag = Config.GetValue<string>("ServerConf:ImageCalcTag") ?? "";
|
||||
subChannel = Config.GetValue<string>("ServerConf:SvgChannel") ?? "";
|
||||
RedServ.Subscribe($"{subChannel}:*", (ch, msg) =>
|
||||
{
|
||||
saveSvg($"{ch}", $"{msg}");
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void saveSvg(string channel, string newSvg)
|
||||
{
|
||||
// se è la mia immagine
|
||||
if (channel.EndsWith(windowUid) || true)
|
||||
{
|
||||
currSvg = newSvg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected async Task SendCalc()
|
||||
{
|
||||
await ICService.CallRestPost(apiUrl, $"{calcTag}/{windowUid}", demoJwd);
|
||||
}
|
||||
|
||||
|
||||
protected MarkupString outSvg { get; set; } = (MarkupString)"";
|
||||
|
||||
private string currSvg = "";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
@page "/weather"
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<p>This component demonstrates showing data.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(500);
|
||||
|
||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50</UserSecretsId>
|
||||
<Version>0.9.2508.0411</Version>
|
||||
<Version>0.9.2508.0412</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NLog;
|
||||
using NLog.Web;
|
||||
using StackExchange.Redis;
|
||||
using System.Globalization;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -50,8 +51,19 @@ builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.Requ
|
||||
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
|
||||
|
||||
// costruzione connectionMultiplexer redis...
|
||||
string connStr = configuration.GetConnectionString("Redis") ?? "localhost";
|
||||
ConnectionMultiplexer redisConn = ConnectionMultiplexer.Connect(connStr);
|
||||
// registro connMultiplexer REDIS
|
||||
builder.Services.AddSingleton<IConnectionMultiplexer>(redisConn);
|
||||
// registro wrapper servizi REDIS
|
||||
builder.Services.AddSingleton<IRedisService, RedisService>();
|
||||
builder.Services.AddSingleton<RedisSubscriptionManager>();
|
||||
|
||||
// Aggiunta servizi specifici
|
||||
builder.Services.AddSingleton<DataLayerServices>();
|
||||
builder.Services.AddSingleton<ImageCacheService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"Redis": "redis.ufficio:26379, serviceName=devel, DefaultDatabase=6, keepAlive=180, connectTimeout=15000, syncTimeout=15000, asyncTimeout=15000, abortConnect=false, ssl=false, allowAdmin=true"
|
||||
},
|
||||
"ServerConf": {
|
||||
"ImageCalcTag": "svg-preview",
|
||||
"Prog.ApiUrl": "https://iis01.egalware.com/lux/srv/api/window",
|
||||
"PubChannel": "EgwEngineInput",
|
||||
"SubChannel": "EgwEngineOutput",
|
||||
"SvgChannel": "svg:img",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>LUX - Web Windows MES</i>
|
||||
<h4>Versione: 0.9.2508.0411</h4>
|
||||
<h4>Versione: 0.9.2508.0412</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.9.2508.0411
|
||||
0.9.2508.0412
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>0.9.2508.0411</version>
|
||||
<version>0.9.2508.0412</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user