diff --git a/Maat.Core/CONF/JobConfigConf.cs b/Maat.Core/CONF/JobConfigConf.cs index c99519c..ba9211d 100644 --- a/Maat.Core/CONF/JobConfigConf.cs +++ b/Maat.Core/CONF/JobConfigConf.cs @@ -21,6 +21,11 @@ namespace Maat.Core.CONF /// public MsSqlConf? MsSqlJobs { get; set; } = null; + /// + /// Area configurazione task RestApi (opzionale) + /// + public RestApiConf? RestApiJobs { get; set; } = null; + #endregion Public Properties } } \ No newline at end of file diff --git a/Maat.Core/CONF/RestApiConf.cs b/Maat.Core/CONF/RestApiConf.cs new file mode 100644 index 0000000..2feb679 --- /dev/null +++ b/Maat.Core/CONF/RestApiConf.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Maat.Core.Enums; + +namespace Maat.Core.CONF +{ + /// + /// Classe gestione configurazione parametri di base x gestione task da API REST + /// + public class RestApiConf + { + #region Public Properties + + /// + /// Elenco dei server configurati x chiamate REST Api, ogni server ha la stessa base ApiUrl + /// + public List ServerList { get; set; } = new List(); + + #endregion Public Properties + + #region Public Classes + + public class SrvConf + { + #region Public Properties + + + /// + /// Dizionario dei metodi configurati da chiamare + /// + public List CallList { get; set; } = new List(); + + /// + /// Path di base ApiUrl del servizio + /// + public string ApiUrl { get; set; } = ""; + + #endregion Public Properties + } + + /// + /// Configurazione singola chiamata + /// + public class CallConfig + { + /// + /// Modalità chiamata tra quelle disponibili + /// + [JsonConverter(typeof(StringEnumConverter))] + public RestCallType CallMode { get; set; } = RestCallType.Get; + + /// + /// Risorsa da chiamare + /// + public string Resource { get; set; } = ""; + + /// + /// Payload assocaito alla risorsa da chiamare + /// + public string Payload { get; set; } = ""; + + #endregion Public Classes + } + } +} \ No newline at end of file diff --git a/Maat.Core/Enums.cs b/Maat.Core/Enums.cs index de1642c..1ac6184 100644 --- a/Maat.Core/Enums.cs +++ b/Maat.Core/Enums.cs @@ -26,7 +26,17 @@ namespace Maat.Core /// /// Chiamata a SQL Stored Procedure /// - SqlStored + SqlStored, + + /// + /// Chiamata REST tipo Get + /// + RestCallGet, + + ///// + ///// Chiamata REST tipo Post + ///// + //RestCallPost } //[JsonConverter(typeof(StringEnumConverter))] @@ -74,7 +84,7 @@ namespace Maat.Core } /// - /// Tipologia di chiamata permessa + /// Tipologia di chiamata DB permessa /// [JsonConverter(typeof(StringEnumConverter))] public enum TaskCallType @@ -89,5 +99,33 @@ namespace Maat.Core /// TaskList } + + + /// + /// Tipologia di chiamata REST permessa + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum RestCallType + { + /// + /// Metodo Delete + /// + Delete, + + /// + /// Metodo Get + /// + Get, + + /// + /// Metodo Post + /// + Post, + + /// + /// Metodo Put + /// + Put + } } } diff --git a/Maat.Core/Maat.Core.csproj b/Maat.Core/Maat.Core.csproj index 9fbf8a6..a852b7c 100644 --- a/Maat.Core/Maat.Core.csproj +++ b/Maat.Core/Maat.Core.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/Maat.Data/Controllers/MsSqlController.cs b/Maat.Data/Controllers/MsSqlController.cs index 5a8b7b7..94f5ded 100644 --- a/Maat.Data/Controllers/MsSqlController.cs +++ b/Maat.Data/Controllers/MsSqlController.cs @@ -91,8 +91,9 @@ namespace Maat.Data.Controllers /// Chiamata esecuzione di un singolo task programmato /// /// + /// Se true rischedula successiva chiamata /// - public TaskResultModel ExecuteTask(int TaskId) + public TaskResultModel ExecuteSqlTask(int TaskId, bool SchedNext) { TaskResultModel callRes = new TaskResultModel(); using (var dbCtx = new TaskRunContext(connString)) @@ -139,8 +140,12 @@ namespace Maat.Data.Controllers currRec.LastResult = resRec.Result; currRec.LastIsError = resRec.IsError; currRec.LastDuration = dtEnd.Subtract(dtStart).TotalSeconds; - // calcolo prossima esecuzione... - currRec.DtNextExec = CalcNextExe(currRec); + // solo se richiesto rischedulazione ricalcola chiamata + if (SchedNext) + { + // calcolo prossima esecuzione... + currRec.DtNextExec = CalcNextExe(currRec); + } // segno modificato dbCtx.Entry(currRec).State = EntityState.Modified; @@ -150,7 +155,59 @@ namespace Maat.Data.Controllers } catch (Exception exc) { - Log.Error($"{tName} | Eccezione in ExecuteTask{Environment.NewLine}{exc}"); + Log.Error($"{tName} | Eccezione in ExecuteSqlTask{Environment.NewLine}{exc}"); + } + } + return callRes; + } + + /// + /// Esegue registrazione di un Task generico (NON SQL) + /// + /// + /// Se true rischedula successiva chiamata + /// Record esecuzione task esterno + /// + public TaskResultModel TaskExecSaveExecuted(int TaskId, bool SchedNext, TaskExecModel ResRec) + { + TaskResultModel callRes = new TaskResultModel(); + using (var dbCtx = new TaskRunContext(connString)) + { + try + { + // recupero i dati da richiamare... + var currRec = dbCtx + .DbSetTaskList + .Where(x => x.TaskId == TaskId) + .FirstOrDefault(); + if (currRec != null) + { + // registro task ricevuto + dbCtx + .DbSetTaskExe + .Add(ResRec); + + // aggiorno record chiamata... + currRec.DtLastExec = ResRec.DtStart; + currRec.LastResult = ResRec.Result; + currRec.LastIsError = ResRec.IsError; + currRec.LastDuration = ResRec.DtEnd.Subtract(ResRec.DtStart).TotalSeconds; + // solo se richiesto rischedulazione ricalcola chiamata + if (SchedNext) + { + // calcolo prossima esecuzione... + currRec.DtNextExec = CalcNextExe(currRec); + } + // segno modificato + dbCtx.Entry(currRec).State = EntityState.Modified; + + // salvo modifiche! + dbCtx.SaveChanges(); + } + } + catch (Exception exc) + { + Log.Error($"Eccezione in TaskExecSaveExecuted{Environment.NewLine}{exc}"); } } return callRes; diff --git a/Maat.Data/Maat.Data.csproj b/Maat.Data/Maat.Data.csproj index a8becef..e0c2b88 100644 --- a/Maat.Data/Maat.Data.csproj +++ b/Maat.Data/Maat.Data.csproj @@ -20,10 +20,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + + diff --git a/Maat.Data/Services/MsSqlTaskService.cs b/Maat.Data/Services/MsSqlTaskService.cs index af0ecf4..1f89d75 100644 --- a/Maat.Data/Services/MsSqlTaskService.cs +++ b/Maat.Data/Services/MsSqlTaskService.cs @@ -7,6 +7,7 @@ using static Maat.Core.Enums; using System.Diagnostics; using Newtonsoft.Json; using System.Xml.Linq; +using Newtonsoft.Json.Linq; namespace Maat.Data.Services { @@ -20,13 +21,16 @@ namespace Maat.Data.Services #region Public Constructors + private RestCallService RCallService { get; set; } = null!; + /// /// Servizio gestione Task su DB /// /// /// /// - public MsSqlTaskService(string threadName, string dbConnString, string redisConnString) + /// + public MsSqlTaskService(string threadName, string dbConnString, string redisConnString, string apiUrl) { Log.Info($"{tName} | Starting MsSqlTaskService"); tName = threadName; @@ -46,6 +50,9 @@ namespace Maat.Data.Services dbController = new MsSqlController(tName, dbConnString); Log.Info($"{tName} | DbController OK"); } + + // conf rest call service + RCallService = new RestCallService(apiUrl); } #endregion Public Constructors @@ -64,16 +71,16 @@ namespace Maat.Data.Services public List CheckExecute() { List answ = new List(); - List listTask = TaskListAll(Enums.Task2ExeType.ND, ""); + List listTask = TaskListAll(tName, Enums.Task2ExeType.ND, ""); // verifico SE ci siano task in scadenza... DateTime adesso = DateTime.Now; - var task2exe = listTask.Where(x => x.DtNextExec <= adesso).ToList(); + List task2exe = listTask.Where(x => x.DtNextExec <= adesso).ToList(); if (task2exe != null && task2exe.Count > 0) { Log.Info($"{tName} | Found {task2exe.Count} task to execute"); foreach (var taskRec in task2exe) { - TaskResultModel result = ExecuteTask(taskRec.TaskId); + TaskResultModel result = ExecuteTask(taskRec); answ.Add(result); } } @@ -93,16 +100,64 @@ namespace Maat.Data.Services redisConn.Dispose(); } + public string CheckRestServer() + { + return RCallService.CheckServer(); + } + /// /// Chiamata esecuzione di un singolo task programmato /// - /// Nome del thread - /// TaskId + /// Task richiesto /// - public TaskResultModel ExecuteTask(int TaskId) + public TaskResultModel ExecuteTask(TaskListModel TaskRec) { - TaskResultModel dbResult = dbController.ExecuteTask(TaskId); - Log.Info($"{tName} | Executed | TaskId: {TaskId}"); + TaskResultModel dbResult = new TaskResultModel() + { + Task = $"TaskId: {TaskRec.TaskId} | {TaskRec.TType}", + ExecResult = -1, + TextResult = "Task Not recognized" + }; + // verifico tipo di task ed eseguo di conseguenza... + switch (TaskRec.TType) + { + //case Task2ExeType.ND: + // break; + //case Task2ExeType.Exe: + // break; + //case Task2ExeType.SqlCommand: + // break; + case Task2ExeType.SqlStored: + dbResult = dbController.ExecuteSqlTask(TaskRec.TaskId, true); + Log.Info($"{tName} | Executed | TaskRec: {TaskRec}"); + break; + case Task2ExeType.RestCallGet: + // in primis testo la chiamata al servizio Health + string rAnsw = RCallService.CheckServer(); + DateTime dtStart = DateTime.Now; + // se ok effettuo vera chiamata... + if (rAnsw.ToUpper() == "OK") + { + var callResp = RCallService.CallRestGet(TaskRec.Command, TaskRec.Args); + DateTime dtEnd = DateTime.Now; + // da verificare... + string formattedJson = JValue.Parse(callResp.Content).ToString(Formatting.Indented); + TaskExecModel tExeMod = new TaskExecModel() + { + DtEnd = dtEnd, + DtStart = dtStart, + IsError = callResp.StatusCode != System.Net.HttpStatusCode.OK, + TaskId = TaskRec.TaskId, + // deserializzazione come json indentato?!? + Result = formattedJson// $"{callResp.Content}".Replace("\"", ""), + }; + // salvo su DB + dbResult = dbController.TaskExecSaveExecuted(TaskRec.TaskId, true, tExeMod); + } + break; + default: + break; + } // svuoto cache! FlushCache("Task"); return dbResult; @@ -150,7 +205,7 @@ namespace Maat.Data.Services /// /// /// - public List TaskListAll(Task2ExeType TType, string searchVal = "") + public List TaskListAll(string threadName, Task2ExeType TType, string searchVal = "") { // setup parametri costanti string source = "DB"; @@ -159,7 +214,7 @@ namespace Maat.Data.Services List result = new List(); // cerco in redis... DateTime adesso = DateTime.Now; - string currKey = $"{Const.RedisBaseKey}:Task:List:{TType}"; + string currKey = $"{Const.RedisBaseKey}:Task:{threadName}:List:{TType}"; RedisValue rawData = redisDb.StringGet(currKey); if (rawData.HasValue) { diff --git a/Maat.Data/Services/RestCallService.cs b/Maat.Data/Services/RestCallService.cs new file mode 100644 index 0000000..f8ca4b7 --- /dev/null +++ b/Maat.Data/Services/RestCallService.cs @@ -0,0 +1,124 @@ +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using RestSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Maat.Data.Services +{ + public class RestCallService + { + #region Public Constructors + + /// + /// Init classe + /// + /// + public RestCallService(string ApiUrl) + { + apiUrl = ApiUrl;// _configuration.GetValue("SrvConf:Prog.ApiUrl") ?? "http://office.egalware.com/MP7PROG"; + // fix opzioni base del RestClient + restOptStd = new RestClientOptions + { + Timeout = TimeSpan.FromSeconds(60), + BaseUrl = new Uri(apiUrl), + ThrowOnAnyError = true, + ThrowOnDeserializationError = true + }; + } + + private string apiUrl = ""; + + #endregion Public Constructors + + #region Public Methods + + /// + /// Stato server da chiamare x verifiche preliminari stato API REST + /// + /// + /// + public string CheckServer() + { + string answ = "ND"; + // cerco online + using (RestClient client = new RestClient(restOptStd)) + { + var request = new RestRequest($"api/health", Method.Get); + try + { + var response = client.ExecuteGet(request); + //var response = await client.GetAsync(request); + // controllo risposta + if (response.StatusCode == System.Net.HttpStatusCode.OK) + { + // verifico risposta + if (response.Content != null) + { + answ = response.Content.Replace("\"", ""); + //answ= JValue.Parse(response.Content).ToString(Formatting.Indented); + } + } + } + catch (Exception exc) + { + Log.Error($"Eccezione in CheckServer{Environment.NewLine}{exc}"); + } + } + return answ; + } + + /// + /// Effettua una generica chiamata ApiRest + /// + /// URL Api di base + /// Richiesta completa + /// + public RestResponse CallRestGet(string ApiUrl, string ApiRequest) + { + RestResponse response; + var currOpt = new RestClientOptions + { + Timeout = TimeSpan.FromSeconds(60), + BaseUrl = new Uri(ApiUrl), + ThrowOnAnyError = true, + ThrowOnDeserializationError = true + }; + // cerco online + using (RestClient client = new RestClient(currOpt)) + { + var request = new RestRequest(ApiRequest, Method.Get); + response = client.Get(request); + } + return response; + } + + #endregion Public Methods + + #region Private Fields + + + /// + /// Classe logger + /// + private static Logger Log = LogManager.GetCurrentClassLogger(); + + #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 + } +} diff --git a/Maat.Runner/Maat.Runner.csproj b/Maat.Runner/Maat.Runner.csproj index 63e546e..d56b9ef 100644 --- a/Maat.Runner/Maat.Runner.csproj +++ b/Maat.Runner/Maat.Runner.csproj @@ -5,7 +5,7 @@ net6.0 enable enable - 1.0.2404.1009 + 1.1.2410.2517 @@ -19,16 +19,15 @@ - - - - - - - + + + + + + - - + + @@ -41,7 +40,7 @@ Always - Never + PreserveNewest Always diff --git a/Maat.Runner/Program.cs b/Maat.Runner/Program.cs index 1a6b462..25fdc5f 100644 --- a/Maat.Runner/Program.cs +++ b/Maat.Runner/Program.cs @@ -29,6 +29,12 @@ string redisConf = config.GetConnectionString("Redis") ?? "????????????????????? string confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf"); Logger Log = LogManager.GetCurrentClassLogger(); +string apiUrlStd = config.GetValue("SrvConf:Prog.ApiUrl") ?? ""; +if (string.IsNullOrEmpty(apiUrlStd)) +{ + Log.Error($"Errore: ApiUrl vuota!"); +} + // gestore della configurazione principale da cui derivare gestione... JobConfigConf currConf = new JobConfigConf(); @@ -105,7 +111,7 @@ if (currConf != null) { // compongo connstring string dbConnStr = $"Server={currSrv.ServerName}; Database={dbName}; User ID={currSrv.DbUser}; Password={currSrv.DbPasswd}; integrated security=False; MultipleActiveResultSets=True; App={appName}"; - string threadName = $"ThdMsSql_{dbName}"; ; + string threadName = $"ThdMsSql_{dbName}"; Thread newThread = new Thread(() => doCronDB(threadName, dbConnStr)); newThread.Name = threadName; jobsThreadList.Add(newThread); @@ -242,10 +248,11 @@ void doCronDB(string threadName, string dbConnStr) Log.Info($"{tName} | Starting dbCronDb task"); // periodo standard 1 minuto int stepPeriod = 60000; - MsSqlTaskService tRun = new MsSqlTaskService(tName, dbConnStr, redisConf); + MsSqlTaskService tRun = new MsSqlTaskService(tName, dbConnStr, redisConf, apiUrlStd); // ciclo infinito esegue task poi attende quanto manca a prox scadenza... do { + //var testServer = tRun.CheckRestServer(); // eseguo i miei task e recupero esito var newStatus = tRun.CheckExecute(); diff --git a/Maat.Runner/appsettings.json b/Maat.Runner/appsettings.json index c6576e2..207faf8 100644 --- a/Maat.Runner/appsettings.json +++ b/Maat.Runner/appsettings.json @@ -30,6 +30,7 @@ "AppName": "Maat.Runner", "StepSec": 60, "MinSaveIntSec": 15, - "JobConfigFile": "JobConfig.json" + "JobConfigFile": "JobConfig.json", + "Prog.ApiUrl": "https://office.egalware.com/MP/PROG" } } diff --git a/Maat.Runner/conf/JobConfig-demo.json b/Maat.Runner/conf/JobConfig-demo.json index 44fc247..e8a6dab 100644 --- a/Maat.Runner/conf/JobConfig-demo.json +++ b/Maat.Runner/conf/JobConfig-demo.json @@ -4,10 +4,11 @@ { "CallMode": "TaskList", "DbList": [ + "MoonPro", "MoonPro_STATS" ], - "DbPasswd": "utente", - "DbUser": "password", + "DbPasswd": "viadante16", + "DbUser": "steamware", "ServerName": "SQL2016DEV" } ] diff --git a/Maat.Runner/conf/JobConfig.json b/Maat.Runner/conf/JobConfig.json index 3bd63a2..53f2949 100644 --- a/Maat.Runner/conf/JobConfig.json +++ b/Maat.Runner/conf/JobConfig.json @@ -4,7 +4,7 @@ { "CallMode": "TaskList", "DbList": [ - "MoonPro_STATS" + "MoonPro" ], "DbPasswd": "viadante16", "DbUser": "steamware", diff --git a/Resources/ChangeLog.html b/Resources/ChangeLog.html index aa07019..800ddce 100644 --- a/Resources/ChangeLog.html +++ b/Resources/ChangeLog.html @@ -1,6 +1,6 @@ - MagMan - Wood Warehouse Management System -

Versione: 1.0.2404.0412

+ Maat.Installer - Manager for Application & Applicative Task +

Versione: 1.1.2410.2517


Note di rilascio:
  • @@ -10,18 +10,18 @@
  • v.1.* →
      -
    • Prima release dotnet6
    • -
    • Integrazione EFCore
    • -
    • Integrazione EgtB&W
    • +
    • Prima release applicazione
    • +
    • Installer WIX
    • +
    • Integrazione processo gestione servizi
diff --git a/Resources/VersNum.txt b/Resources/VersNum.txt index 6a79875..d1647b3 100644 --- a/Resources/VersNum.txt +++ b/Resources/VersNum.txt @@ -1 +1 @@ -1.0.2404.0412 +1.1.2410.2517 diff --git a/Resources/manifest.xml b/Resources/manifest.xml index facc4bb..e772fa4 100644 --- a/Resources/manifest.xml +++ b/Resources/manifest.xml @@ -1,7 +1,7 @@ - 1.0.2404.0412 - http://nexus.steamware.net/repository/SWS/MagMan/stable/0/MagMan.UI.zip - http://nexus.steamware.net/repository/SWS/MagMan/stable/0/ChangeLog.html + 1.1.2410.2517 + http://nexus.steamware.net/repository/SWS/Maat.Installer/stable/LAST/Maat.Installer.msi + http://nexus.steamware.net/repository/SWS/Maat.Installer/stable/LAST/ChangeLog.html false