7620 lines
360 KiB
C#
7620 lines
360 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Common;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security.Claims;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Principal;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.DirectoryServices.AccountManagement;
|
|
using System.DirectoryServices.ActiveDirectory;
|
|
using System.IO;
|
|
|
|
using Microsoft.IdentityModel.Tokens;
|
|
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
using C4IT.Configuration;
|
|
using C4IT.FASD.Base;
|
|
using C4IT.FASD.Licensing;
|
|
using C4IT.Logging;
|
|
using C4IT.Security;
|
|
using C4IT.XML;
|
|
using C4IT.Matrix42.WebClient;
|
|
|
|
using C4IT_DataHistoryProvider_Base;
|
|
using C4IT_DataHistoryProvider_Base.DataSources;
|
|
using C4IT_DataHistoryProvider_Base.Services;
|
|
|
|
using static C4IT.Logging.cLogManager;
|
|
|
|
|
|
|
|
namespace C4IT.DataHistoryProvider
|
|
{
|
|
public delegate void DataHistoryUiMessageFunc(cDataHistoryUiStatusMessage Message);
|
|
|
|
public abstract class cDataHistoryCollectorModule
|
|
{
|
|
public cDataHistoryCollector Collector { get; protected set; }
|
|
public readonly List<enumDataHistoryOrigin> Origins;
|
|
|
|
public readonly string Name = "";
|
|
|
|
public readonly Guid LicenseId = Guid.Empty;
|
|
|
|
public cDataHistoryCollectorModule(cDataHistoryCollector Collector, enumDataHistoryOrigin Origin, string Name, string LicenseId)
|
|
{
|
|
this.Name = Name;
|
|
Guid.TryParse(LicenseId, out this.LicenseId);
|
|
this.Collector = Collector;
|
|
this.Origins = new List<enumDataHistoryOrigin>() { Origin };
|
|
}
|
|
|
|
public cDataHistoryCollectorModule(cDataHistoryCollector Collector, List<enumDataHistoryOrigin> Origin, string Name, string LicenseId)
|
|
{
|
|
this.Name = Name;
|
|
Guid.TryParse(LicenseId, out this.LicenseId);
|
|
this.Collector = Collector;
|
|
this.Origins = Origin;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name;
|
|
}
|
|
|
|
public abstract Task<cScanTimeInfo> GetScanTimeInfoAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token);
|
|
|
|
public async Task<cScanTimeInfo> GetScanTimeInfoAsync(cDataHistoryScanTiming ScanTiming, string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var LastScan = await Collector.GetLastScanTime(ScanName, requestInfo, LogDeep + 1, Token);
|
|
if (LastScan == null || LastScan == new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
|
|
return null;
|
|
|
|
var retVal = new cScanTimeInfo((DateTime)LastScan);
|
|
try
|
|
{
|
|
retVal.NextScan = retVal.GetScanTime(DateTime.UtcNow, ScanTiming);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
public abstract Task<bool> DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false);
|
|
|
|
public abstract Task<List<object>> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep);
|
|
|
|
public virtual List<object> GetFilterValues(List<object> IDs, enumFasdInformationClass InfoClass)
|
|
{
|
|
return IDs;
|
|
}
|
|
|
|
public virtual async Task<List<string>> GetQuickActionList()
|
|
{
|
|
await Task.CompletedTask;
|
|
var result = new List<string>();
|
|
return result;
|
|
}
|
|
|
|
public virtual bool CheckIfLateDelivery(cDataHistoryConfigTable Table)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public void AddTableResultVirtualSuccessorTasks(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, List<Int64> UsageInfo, Guid CacheId, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var lstTables = new List<string>();
|
|
var myTables = new List<cDataHistoryConfigTable>();
|
|
foreach (var Table in Tables)
|
|
{
|
|
if (!this.Origins.Contains(Table.ParentCluster.Origin))
|
|
continue;
|
|
|
|
if (!CheckIfLateDelivery(Table))
|
|
continue;
|
|
|
|
myTables.Add(Table);
|
|
lstTables.Add(Table.Name);
|
|
}
|
|
|
|
if (lstTables.Count > 0)
|
|
{
|
|
var ct = new CancellationTokenSource().Token;
|
|
var tsk = GetTableResultsVirtualAsync(myTables, Identities, RefTime, MaxAge, false, CacheId, ct, requestInfo, LogDeep + 1);
|
|
SuccessorCache.AddTask(CacheId, lstTables, tsk, UsageInfo, ct);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public virtual async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> GetTableResultsVirtualAsync(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, bool instantly, Guid? CacheId, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
|
|
public virtual async Task<List<cF4SDHealthCardRawData.cHealthCardDetailsTable>> GetDetailsTableResultsVirtualAsync(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
|
|
public virtual async Task<Int64> GetSelectionTableResultCountAsync(cDataHistoryConfigTable Table, List<cF4sdIdentityEntry> Identities, string search, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List<string> filterParams = null)
|
|
{
|
|
await Task.CompletedTask;
|
|
return -1;
|
|
}
|
|
|
|
public virtual async Task<cF4SDHealthCardRawData.cHealthCardTable> GetSelectionTableResultAsync(cDataHistoryConfigTable Table, List<cF4sdIdentityEntry> Identities, string search, int PageSize, int Page, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List<string> filterParams = null)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
|
|
public virtual async Task<bool> ValidateMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return true;
|
|
}
|
|
|
|
public virtual async Task<bool> ColumnUpatePostProcessingAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return false;
|
|
}
|
|
|
|
public virtual void TablePostConfig(cDataHistoryConfigTable Table)
|
|
{
|
|
|
|
}
|
|
|
|
public virtual async Task<bool> WritePropertyAsync(cF4SDWriteParameters PropertiesToWrite, cF4sdWebRequestInfo requestInfo, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return false;
|
|
}
|
|
|
|
public virtual async Task<cF4SdUserInfoChange> ValidateTokenAsync(cF4SDTokenRegistration TokenRegistration, cF4sdWebRequestInfo RequestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
|
|
public virtual async Task<cF4SDAdditionalUserInfo> GetAdditionalUserInfo(enumAdditionalAuthentication Type, cF4sdWebRequestInfo RequestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class cDataHistoryCollector : cDataHistoryCollectorModule, IConfigNodeValidation, ISearchResultRelationProvider
|
|
{
|
|
public const string constConnectorName = "F4SD collector";
|
|
public const string constLicenseId = "00000000-0000-0000-0000-000000000000";
|
|
|
|
public const int constMinutesUntilTokenIsInvalid = 5;
|
|
|
|
public static readonly Guid ConfigId = new Guid("0FCE8005-81BD-4F06-82FF-55DD9364FBE5");
|
|
public static readonly string JwtTokenIssuer = "https://login.f4sdcockpit.consulting4it.de";
|
|
public static readonly string JwtTokenAudience = "urn:Cockpit.F4SD";
|
|
|
|
public Guid getId() { return ConfigId; }
|
|
|
|
|
|
public const string constFileNameClusterConfig = "F4SD-DataClusters-Configuration.xml";
|
|
public const string constFileNameInfrastructureConfig = "F4SD-Infrastructure-Configuration.xml";
|
|
|
|
public bool IsValid { get; private set; } = false;
|
|
|
|
public cDataHistoryConfigClusters ClusterConfig { get; private set; } = null;
|
|
public cDataHistoryConfigInfrastructure InfrastructureConfig { get; private set; } = null;
|
|
|
|
private cDataHistoryConfigGolabalParameters GlobalParametersConfigFile = null;
|
|
private cF4sdGlobalConfig GlobalConfig { get; set; } = null;
|
|
private DateTime GlobalParametersConfigTimestamp = DateTime.MinValue;
|
|
private object GlobalParametersConfigLock = new object();
|
|
|
|
public readonly Dictionary<enumDataHistoryOrigin, cDataHistoryCollectorModule> Connectors = new Dictionary<enumDataHistoryOrigin, cDataHistoryCollectorModule>();
|
|
public readonly cDataHistoryCollectorActiveDirectory ActiveDirectory = null;
|
|
public readonly cDataHistoryCollectorClientAgent F4sdAgent = null;
|
|
public cDataHistoryCollectorM42Wpm M42WpmCollector { get; private set; } = null;
|
|
public cDataHistoryCollectorNxql NxqlCollector { get; private set; } = null;
|
|
public cDataHistoryCollectorCitrix CitrixCollector { get; private set; } = null;
|
|
public bool F4SDAnalyticsValid = false;
|
|
public cF4SDAnalyticsConfigDatabase F4SDAnalyticsDb { get; private set; } = null;
|
|
public event DataHistoryUiMessageFunc ProcessUiMessage;
|
|
|
|
public readonly bool autoConnectionCheck = false;
|
|
public Dictionary<enumFasdConfigurationType, cFasdBaseConfig> ClientConfigs = null;
|
|
|
|
public Dictionary<string, string> GlobalConfigValues = new Dictionary<string, string>();
|
|
|
|
public readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
|
|
public SymmetricSecurityKey BearerSecurityKey { get; private set; } = null;
|
|
public TokenValidationParameters JwtTokenValidationParameters { get; private set; } = null;
|
|
|
|
public Dictionary<Guid, DateTime> SessionValues = new Dictionary<Guid, DateTime>();
|
|
public Dictionary<Guid, DateTime> CaseValues = new Dictionary<Guid, DateTime>();
|
|
|
|
public cDataHistoryCollectorTokenCache TokenCache;
|
|
|
|
public enumWebServerStatus ServerStatus = enumWebServerStatus.starting;
|
|
|
|
private readonly List<ISearchResultRelationProvider> _searchResultRelationProviders = new List<ISearchResultRelationProvider>();
|
|
|
|
public bool RunningInIISExpress = false;
|
|
|
|
#region Services
|
|
|
|
private IStagedRelationService _stagedRelationService;
|
|
|
|
public IStagedRelationService GetStagedRelationService()
|
|
{
|
|
if (_stagedRelationService is null)
|
|
_stagedRelationService = new StagedRelationService(_searchResultRelationProviders);
|
|
|
|
return _stagedRelationService;
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal class cDetailsComputationInfo
|
|
{
|
|
internal cDataHistoryConfigComputationBase Computation;
|
|
internal int[] ValueIndexes;
|
|
}
|
|
|
|
public cDataHistoryConfigSqlConnection mainDbConnection { get; private set; } = null;
|
|
|
|
public cDataHistoryCollector(bool autoConnectionCheck, cF4sdWebRequestInfo requestInfo, int LogDeep) : base(null, enumDataHistoryOrigin.Main, constConnectorName, constLicenseId)
|
|
{
|
|
this.Collector = this;
|
|
this.autoConnectionCheck = autoConnectionCheck;
|
|
|
|
TokenCache = new cDataHistoryCollectorTokenCache(this, requestInfo, LogDeep + 1);
|
|
|
|
Connectors.Add(enumDataHistoryOrigin.Main, this);
|
|
|
|
try
|
|
{
|
|
var _process = Process.GetCurrentProcess();
|
|
if (_process?.ProcessName != null && _process.ProcessName.ToLower().StartsWith("iisexpress"))
|
|
RunningInIISExpress = true;
|
|
}
|
|
catch (Exception e1)
|
|
{
|
|
LogException(e1);
|
|
}
|
|
|
|
var _ActiveDirectory = new cDataHistoryCollectorActiveDirectory(this);
|
|
if (cF4SDLicense.Instance?.Modules != null)
|
|
{
|
|
if (cF4SDLicense.Instance.Modules.ContainsKey(_ActiveDirectory.LicenseId))
|
|
{
|
|
ActiveDirectory = _ActiveDirectory;
|
|
Connectors.Add(enumDataHistoryOrigin.ActiveDirectory, ActiveDirectory);
|
|
}
|
|
|
|
var _F4sdAgent = new cDataHistoryCollectorClientAgent(this);
|
|
if (cF4SDLicense.Instance.Modules.ContainsKey(_F4sdAgent.LicenseId))
|
|
{
|
|
F4sdAgent = _F4sdAgent;
|
|
Connectors.Add(enumDataHistoryOrigin.F4sdAgent, F4sdAgent);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public List<cDataHistoryCollectorModule> GetConnectors()
|
|
{
|
|
var _connectors = Connectors.Values.Distinct().ToList();
|
|
return _connectors;
|
|
}
|
|
|
|
public bool RefreshGlobalConfigurationParameters()
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
lock (GlobalParametersConfigLock)
|
|
{
|
|
var _currentTimeStamp = DateTime.MaxValue;
|
|
if (GlobalParametersConfigFile != null)
|
|
_currentTimeStamp = File.GetLastWriteTimeUtc(GlobalParametersConfigFile.FilePath);
|
|
|
|
if (_currentTimeStamp <= GlobalParametersConfigTimestamp)
|
|
{
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(1, "Global parameters are already loaded and are up to date...");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(1, "loading the global parameters...");
|
|
|
|
var _cfgGlobalParameters = new cDataHistoryConfigGolabalParameters(this.InfrastructureConfig);
|
|
_cfgGlobalParameters.LoadFromFile(out var PMs);
|
|
|
|
if (PMs != null && PMs.Count > 0)
|
|
DoProcessUiMessage(2, PMs);
|
|
|
|
if (_cfgGlobalParameters == null || !_cfgGlobalParameters.IsValid)
|
|
{
|
|
DoProcessUiMessage(1, "error on loading the global parameters.");
|
|
return false;
|
|
}
|
|
|
|
GlobalParametersConfigFile = _cfgGlobalParameters;
|
|
|
|
GlobalConfig = new cF4sdGlobalConfig(regPath: null);
|
|
if (GlobalParametersConfigFile.Parameters != null)
|
|
GlobalConfig.Load(CentralParameters: GlobalParametersConfigFile.Parameters);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> LoadConfigurationAsync(bool checkServerEnvironment, bool checkCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, Assembly ExecutingAssembly = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
IsValid = false;
|
|
|
|
DoProcessUiMessage(0, "start loading the collector configuration...");
|
|
|
|
// load the SqlHelper
|
|
if (!DataHistorySqlHelper.LoadWellKnownSqlStatements(out var PMs, ExecutingAssembly))
|
|
{
|
|
if (PMs != null && PMs.Count > 0)
|
|
{
|
|
DoProcessUiMessage(1, "loading the well defined SQL statements...");
|
|
DoProcessUiMessage(2, PMs);
|
|
DoProcessUiMessage(1, "error on loading the well defined SQL statement.");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// load the infrastructure
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(1, "loading the the infrastructure definitions...");
|
|
var _cfgInfrastructure = new cDataHistoryConfigInfrastructure();
|
|
_cfgInfrastructure.LoadFromFile(out PMs);
|
|
|
|
if (PMs != null && PMs.Count > 0)
|
|
DoProcessUiMessage(2, PMs);
|
|
|
|
if (_cfgInfrastructure == null || !_cfgInfrastructure.IsValid)
|
|
{
|
|
DoProcessUiMessage(1, "error on loading the infrastructure definitions.");
|
|
return false;
|
|
}
|
|
InfrastructureConfig = _cfgInfrastructure;
|
|
DoProcessUiMessage(1, "the infrastructure configuration loaded successful.");
|
|
DoProcessUiMessage(0, "");
|
|
|
|
var HasM42Config = _cfgInfrastructure.M42Wpm != null;
|
|
var HasIntuneConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true);
|
|
var HasMobileDeviceConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true);
|
|
var HasCitrixConfig = (InfrastructureConfig.Citrix != null);
|
|
|
|
DoProcessUiMessage(1, "resolving the ad membership groups");
|
|
ActiveDirectory.ResolveWinAuthenticationGroups();
|
|
|
|
// check the server environment
|
|
if (checkServerEnvironment)
|
|
await CheckServerEnvironmentAsync(checkCurrentUser, Token, requestInfo, LogDeep + 1);
|
|
|
|
// load the data clusters
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(1, "loading the data cluster definitions...");
|
|
var _cfgDataClusters = new cDataHistoryConfigClusters();
|
|
_cfgDataClusters.LoadFromFile(out PMs, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig,withMobileDeviceConfig:HasMobileDeviceConfig,withCitrixConfig:HasCitrixConfig);
|
|
|
|
if (PMs != null && PMs.Count > 0)
|
|
DoProcessUiMessage(2, PMs);
|
|
|
|
if (_cfgDataClusters == null || !_cfgDataClusters.IsValid)
|
|
{
|
|
DoProcessUiMessage(1, "error on loading the data cluster definitions.");
|
|
return false;
|
|
}
|
|
ClusterConfig = _cfgDataClusters;
|
|
DoProcessUiMessage(1, "the data cluster configuration loaded successful.");
|
|
DoProcessUiMessage(0, "");
|
|
|
|
// load the global parameters
|
|
if (!RefreshGlobalConfigurationParameters())
|
|
return false;
|
|
|
|
mainDbConnection = InfrastructureConfig.HistoryDB.Connection;
|
|
|
|
if (InfrastructureConfig.M42Wpm != null)
|
|
{
|
|
var _M42WpmCollector = new cDataHistoryCollectorM42Wpm(this);
|
|
if (cF4SDLicense.Instance?.Modules != null)
|
|
if (cF4SDLicense.Instance.Modules.ContainsKey(_M42WpmCollector.LicenseId))
|
|
{
|
|
M42WpmCollector = _M42WpmCollector;
|
|
Connectors.Add(enumDataHistoryOrigin.M42Wpm, M42WpmCollector);
|
|
RegisterSearchRelationProvider(_M42WpmCollector);
|
|
}
|
|
}
|
|
|
|
if (InfrastructureConfig.Nexthink != null)
|
|
{
|
|
var _NxqlCollector = new cDataHistoryCollectorNxql(this);
|
|
if (cF4SDLicense.Instance?.Modules != null)
|
|
if (cF4SDLicense.Instance.Modules.ContainsKey(_NxqlCollector.LicenseId))
|
|
{
|
|
NxqlCollector = _NxqlCollector;
|
|
Connectors.Add(enumDataHistoryOrigin.NexthinkNxql, NxqlCollector);
|
|
}
|
|
}
|
|
|
|
if (HasCitrixConfig)
|
|
{
|
|
var _CitrixCollector = new cDataHistoryCollectorCitrix(this);
|
|
if (cF4SDLicense.Instance?.Modules != null)
|
|
//if (cF4SDLicense.Instance.Modules.ContainsKey(_CitrixCollector.LicenseId))
|
|
//{
|
|
CitrixCollector = _CitrixCollector;
|
|
Connectors.Add(enumDataHistoryOrigin.Citrix, _CitrixCollector);
|
|
RegisterSearchRelationProvider(_CitrixCollector);
|
|
//}
|
|
}
|
|
|
|
if(HasIntuneConfig)
|
|
{
|
|
Connectors.Add(enumDataHistoryOrigin.Intune, ActiveDirectory);
|
|
|
|
}
|
|
//if (HasIntuneConfig && HasMobileDeviceConfig)
|
|
//{
|
|
// RegisterSearchRelationProvider(ActiveDirectory);
|
|
//}
|
|
|
|
// do the post configuration tasks afer the infrastructure was loaded
|
|
DoProcessUiMessage(1, "processing post configuration tasks");
|
|
foreach (var Table in _cfgDataClusters.Tables.Values)
|
|
{
|
|
if (Connectors.TryGetValue(Table.ParentCluster.Origin, out var _module))
|
|
_module?.TablePostConfig(Table);
|
|
}
|
|
|
|
RegisterSearchRelationProvider(this);
|
|
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(0, "the collector configuration loaded successful.");
|
|
|
|
IsValid = true;
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void RegisterSearchRelationProvider(ISearchResultRelationProvider provider)
|
|
{
|
|
_searchResultRelationProviders.Add(provider);
|
|
}
|
|
|
|
public cF4sdGlobalConfig GetGlobalConfig()
|
|
{
|
|
RefreshGlobalConfigurationParameters();
|
|
cF4sdGlobalConfig _result = null;
|
|
lock (GlobalParametersConfigLock)
|
|
{
|
|
_result = GlobalConfig;
|
|
}
|
|
return GlobalConfig;
|
|
}
|
|
|
|
private void RegisterSearchRelationProviders(IEnumerable<ISearchResultRelationProvider> providers)
|
|
{
|
|
_searchResultRelationProviders.AddRange(providers);
|
|
}
|
|
|
|
public async Task CheckServerEnvironmentAsync(bool CheckCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
DoProcessUiMessage(1, "");
|
|
DoProcessUiMessage(1, "checking the server environment...");
|
|
|
|
var _issConfig = IisConfigHelper.CheckIISConfiguration();
|
|
|
|
if (!_issConfig.IsWebSocketInstalled)
|
|
DoProcessUiMessage(2, " Warning: The IIS feature 'WebSocket' is not installed. This is needed for use of direct connections.", LogLevels.Warning);
|
|
if (!_issConfig.IsIssWindowsAuthenticationInstalled)
|
|
DoProcessUiMessage(2, " Warning: The IIS feature 'WindowsAuthentication' is not installed. This is mandatory for the use of authorization.", LogLevels.Warning);
|
|
if (!_issConfig.IsIssWindowsAuthenticationEnabled)
|
|
DoProcessUiMessage(2, " Warning: The 'WindowsAuthentication' is not enabled for the WEB application F4SDCockpit. This is mandatory for the use of authorization.", LogLevels.Warning);
|
|
|
|
await CheckAuthorisationConfigurationAsync(CheckCurrentUser, Token, requestInfo, LogDeep + 1);
|
|
|
|
|
|
|
|
DoProcessUiMessage(1, "server environment check finished.");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task CheckAuthorisationConfigurationAsync(bool CheckCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (InfrastructureConfig?.Authorisation == null || !InfrastructureConfig.Authorisation.IsValid)
|
|
{
|
|
DoProcessUiMessage(2, " Warning: Authentication is not configured properly in the file 'F4SD-Infrastructure-Configuration.xml'. It is strongly recommended not to use F4SD Cockpit without configured authentication.", LogLevels.Warning);
|
|
return;
|
|
}
|
|
|
|
if (CheckCurrentUser)
|
|
{
|
|
var _userInfo = await GetCurrentUserInfoAsync(Token, requestInfo, LogDeep + 1);
|
|
if (_userInfo?.Roles == null || _userInfo.Roles.Count == 0)
|
|
{
|
|
DoProcessUiMessage(2, $" Warning: The current user {_userInfo?.AdAccount} is not member of any F4SD role. Please check the authentication configuration and the ad group memberships.", LogLevels.Warning);
|
|
}
|
|
else
|
|
{
|
|
if (!_userInfo.Roles.Contains("Cockpit.User"))
|
|
DoProcessUiMessage(2, $" Warning: The current user {_userInfo.AdAccount} is not member of the F4SD role 'Cockpit.User'. Please check the authentication configuration and the ad group memberships.", LogLevels.Warning);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public void ValidateClientConfiguration()
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
DoProcessUiMessage(0, "start validating the client configuration files...");
|
|
DoProcessUiMessage(0, "");
|
|
|
|
var _Configs = new Dictionary<enumFasdConfigurationType, cFasdBaseConfig>();
|
|
var _lst = Enum.GetValues(typeof(enumFasdConfigurationType)).Cast<enumFasdConfigurationType>();
|
|
foreach (var _item in _lst)
|
|
{
|
|
if (_item != enumFasdConfigurationType.unknown)
|
|
{
|
|
var _msg = new List<cXmlParserNodeMessage>();
|
|
var HasM42Config = InfrastructureConfig.M42Wpm != null;
|
|
var HasIntuneConfig = (InfrastructureConfig.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true);
|
|
var HasMobileDeviceConfig = (InfrastructureConfig.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true);
|
|
var HasCitrixConfig = (InfrastructureConfig.Citrix != null);
|
|
|
|
var _cfg = cFasdBaseConfig.GetConfigByType(_item, null, _msg, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig, withMobileDeviceConfig: HasMobileDeviceConfig, withCitrixConfig:HasCitrixConfig);
|
|
if (_cfg.IsValid)
|
|
{
|
|
_Configs[_item] = _cfg;
|
|
if (_msg.Count == 0)
|
|
DoProcessUiMessage(1, $"the {_item} configuration is valid.");
|
|
else
|
|
DoProcessUiMessage(1, $"the {_item} configuration is valid but has some annotations:");
|
|
}
|
|
else
|
|
DoProcessUiMessage(1, $"the the {_item} configuration is invalid!");
|
|
if (_msg.Count > 0)
|
|
DoProcessUiMessage(2, _msg);
|
|
|
|
DoProcessUiMessage(0, "");
|
|
}
|
|
}
|
|
|
|
ClientConfigs = _Configs;
|
|
|
|
DoProcessUiMessage(0, "the validation of the client configuration files finished.");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
}
|
|
|
|
public async Task UpdateF4SDAnalyticsConfigInfosAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken _token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (this.F4SDAnalyticsValid && this.F4SDAnalyticsDb?.Connection != null)
|
|
{
|
|
if (ClientConfigs != null && ClientConfigs.TryGetValue(enumFasdConfigurationType.quickActions, out var _quickActionsBase))
|
|
{
|
|
if (_quickActionsBase is cFasdQuickActionConfig _quickActions)
|
|
{
|
|
if (DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateQActionInfo", out var Query))
|
|
if (DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateQActionInfoLang", out var Query2))
|
|
{
|
|
using (var Conn = new cDbConnection(this.F4SDAnalyticsDb.Connection))
|
|
{
|
|
foreach (var _quickAction in _quickActions.F4SDQuickActions.QuickActions.Values)
|
|
{
|
|
if (_quickAction.Id == Guid.Empty)
|
|
continue;
|
|
|
|
var _params = new Dictionary<string, object>()
|
|
{
|
|
{ "Id", _quickAction.Id},
|
|
{ "Name", _quickAction.Name},
|
|
{ "Type", _quickAction.GetTypeName()}
|
|
};
|
|
await DataHistorySqlHelper.ExecuteAsync(Conn, Query, _params, requestInfo, _token);
|
|
|
|
foreach (var _langEntry in _quickAction.Names)
|
|
{
|
|
_params = new Dictionary<string, object>()
|
|
{
|
|
{ "Id", _quickAction.Id},
|
|
{ "Name", _langEntry.Value},
|
|
{ "Lang", _langEntry.Key.ToUpperInvariant()}
|
|
};
|
|
await DataHistorySqlHelper.ExecuteAsync(Conn, Query2, _params, requestInfo, _token);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task ValidateDatabaseAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var DbName = InfrastructureConfig.HistoryDB.Connection.Database;
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(1, $"start validating the data history database '{DbName}' itself...");
|
|
|
|
using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 10, WithoutDatabase: true))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Database", out var Query))
|
|
return;
|
|
var Params = new Dictionary<string, object>() { { "DbName", DbName } };
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the data history database '{DbName}' itself finished successful.");
|
|
}
|
|
else
|
|
{
|
|
DoProcessUiMessage(2, $"the database {DbName} coud not be found.");
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_Database", out Query))
|
|
return;
|
|
var Query2 = Query.Clone(string.Format(Query.Query, mainDbConnection.Database));
|
|
var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, null, requestInfo, Token);
|
|
if (n2 == null)
|
|
{
|
|
DoProcessUiMessage(2, $"the data history database '{DbName}' could not be created.");
|
|
return;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the database {DbName} is created successful.");
|
|
}
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_DbCollation", out Query))
|
|
return;
|
|
|
|
var strQuery = string.Format(Query.Query, DbName);
|
|
var _startTime2 = DateTime.UtcNow;
|
|
n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn.Connection, strQuery, null, Token);
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime2, DbName, 0, requestInfo?.requestName);
|
|
if (n != 1)
|
|
DoProcessUiMessage(2, $"Warning: the collation of database {DbName} is not 'Latin1_General_CI_AI'");
|
|
}
|
|
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the data history database itself aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public override async Task<bool> ValidateMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate if fulltext search is enabled for the server instance
|
|
DoProcessUiMessage(1, $"start validating the full text feature...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Fulltext_Installed", out var Query))
|
|
return false;
|
|
if (await DataHistorySqlHelper.GetScalarResultAsync<int?>(DbConn, Query, null, requestInfo, Token) != 1)
|
|
{
|
|
DoProcessUiMessage(1, $"the sql server instance {DbConn.Connection.DataSource} is not enabled for full text.");
|
|
return false;
|
|
}
|
|
|
|
// validate if fulltext search is enabled for the database
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Fulltext", out Query))
|
|
return false;
|
|
if (!(await DataHistorySqlHelper.GetScalarResultAsync<bool?>(DbConn, Query, null, requestInfo, Token) == true))
|
|
{
|
|
DoProcessUiMessage(1, $"the database '{DbConn.Connection.Database}' is not enabled for full text.");
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(1, $"the full text feature is activated for the database.");
|
|
DoProcessUiMessage(1, "");
|
|
|
|
// validate the main tables
|
|
DoProcessUiMessage(1, $"start validating the main tables...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_MainTables", out Query))
|
|
return false;
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the main tables finished successful.");
|
|
return true;
|
|
}
|
|
|
|
// create the main tables
|
|
DoProcessUiMessage(2, $"the main tables are not complete, creating them...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_MainTables", out Query))
|
|
return false;
|
|
var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token);
|
|
|
|
// validate the creates main tables
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_MainTables", out Query))
|
|
return false;
|
|
n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(2, $"the main tables were created successfull.");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, "An error occurred when creating the main tables.");
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> ValidateF4SDAnalyticsDatabaseAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool ForceCreate = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
|
|
DoProcessUiMessage(0, "");
|
|
|
|
DoProcessUiMessage(1, $"start validating the data database '{DbConnection.Database}' itself...");
|
|
|
|
|
|
using (var DbConn = new cDbConnection(DbConnection, WithoutDatabase: true))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Database", out var Query))
|
|
return false;
|
|
var Params = new Dictionary<string, object>() { { "DbName", DbConnection.Database } };
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the data F4SDAnalytics database '{DbConnection.Database}' itself finished successful.");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the database {DbConnection.Database} coud not be found.");
|
|
if (ForceCreate)
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_Database", out Query))
|
|
return false;
|
|
var Query2 = Query.Clone(string.Format(Query.Query, DbConnection.Database));
|
|
var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, null, requestInfo, Token);
|
|
if (n2 != null)
|
|
{
|
|
DoProcessUiMessage(2, $"the database {DbConnection.Database} is created successful.");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"Error: the database '{DbConnection.Database}' could not be created.");
|
|
return false;
|
|
}
|
|
}
|
|
DoProcessUiMessage(1, $"Error: the connection on the database '{DbConnection.Database}' is not available.");
|
|
|
|
return false;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(0, $"the validation of the data F4SDAnalytics database itself aborted with an exceptional error.");
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task<bool> ValidateF4SDAnalyticsMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate the main tables
|
|
DoProcessUiMessage(1, $"start validating the main tables...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsMainTables", out var Query))
|
|
return false;
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the main tables finished successful.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
if (!ForceCreate && n < 1)
|
|
{
|
|
DoProcessUiMessage(2, $"the main tables are not complete...");
|
|
return false;
|
|
}
|
|
if (ForceCreate)
|
|
{
|
|
// create the main tables
|
|
DoProcessUiMessage(2, $"the main tables are not complete, creating them...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsMainTables", out Query))
|
|
return false;
|
|
await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token);
|
|
|
|
// validate the creates main tables
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsMainTables", out Query))
|
|
return false;
|
|
n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(2, $"the main tables were created successfull.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, "An error occurred when creating the main tables.");
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error.");
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> ValidateF4SDAnalyticsFunctionsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate the functions
|
|
DoProcessUiMessage(1, $"start validating the functions...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsFunctions", out var Query))
|
|
return false;
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the functions finished successful.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
if (!ForceCreate && n < 1)
|
|
{
|
|
DoProcessUiMessage(2, $"the functions are not complete...");
|
|
return false;
|
|
}
|
|
if (ForceCreate)
|
|
{
|
|
// create the functions
|
|
DoProcessUiMessage(2, $"the functions are not complete, creating them...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsFunctions", out Query))
|
|
return false;
|
|
await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token);
|
|
|
|
// validate the creates functions
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsFunctions", out Query))
|
|
return false;
|
|
n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(2, $"the functions were created successfull.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, "An error occurred when creating the functions.");
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the funtions aborted with an exceptional error.");
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> ValidateF4SDAnalyticsViewsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate the view tables
|
|
DoProcessUiMessage(1, $"start validating the view tables...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsViews", out var Query))
|
|
return false;
|
|
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the view tables finished successful.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
|
|
if (!ForceCreate && n < 1)
|
|
{
|
|
DoProcessUiMessage(2, $"the view tables are not complete...");
|
|
return false;
|
|
}
|
|
|
|
if (ForceCreate)
|
|
{
|
|
// create the view tables
|
|
DoProcessUiMessage(2, $"the view tables are not complete, creating them...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsViews", out Query))
|
|
return false;
|
|
Query.Query = Query.Query.Replace("$DatabaseHistory$", InfrastructureConfig.HistoryDB.Connection.Database);
|
|
await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token);
|
|
|
|
// validate the creates view tables
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsViews", out Query))
|
|
return false;
|
|
n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(2, $"the view tables were created successfull.");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, "An error occurred when creating the view tables.");
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the view tables aborted with an exceptional error.");
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> UpdateF4SDAnalyticsMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate the main tables
|
|
DoProcessUiMessage(1, $"start update the main tables...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Update_F4SDAnalyticsMainTables", out var Query))
|
|
return false;
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, Query, null, requestInfo, Token);
|
|
if (n == 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the update of the main tables was successfull, nothing updated.");
|
|
return true;
|
|
}
|
|
if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the update of the main tables finished successful.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
DoProcessUiMessage(2, $"the main tables could not be updated.");
|
|
LogEntry($"the main tables could not be updated.", LogLevels.Fatal);
|
|
return false;
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
private async Task<bool> UpdateF4SDAnalyticsViewsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// validate the main tables
|
|
DoProcessUiMessage(1, $"start update the views...");
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Update_F4SDAnalyticsViews", out var Query))
|
|
return false;
|
|
Query.Query = Query.Query.Replace("$DatabaseHistory$", InfrastructureConfig.HistoryDB.Connection.Database);
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token);
|
|
if (n != null)
|
|
{
|
|
DoProcessUiMessage(1, $"the update of the view tables finished successful.");
|
|
DoProcessUiMessage(0, "");
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(1, $"the view tables could not be updated.");
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the update of the views aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<Version> GetDatabaseTableVersion(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetDbTablesVersion", out var Query))
|
|
return null;
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(DbConn, Query, null, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
if (await Reader.ReadAsync())
|
|
{
|
|
try
|
|
{
|
|
var iVersion = Reader.GetInt32(0);
|
|
var iRevision = Reader.GetInt32(1);
|
|
var RetVal = new Version(iVersion, iRevision);
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private async Task InsertDbVersionAsync(cDbConnection DbConn, Version version, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateDbVersion", out var Query))
|
|
return;
|
|
|
|
var Params = new Dictionary<string, object>(2) { { "version", version.Major }, { "revision", version.Minor } };
|
|
|
|
await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task<bool> ValidatePostUpdates(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
// get the actual db table version
|
|
var currentVersion = await GetDatabaseTableVersion(DbConn, requestInfo, LogDeep + 1, Token);
|
|
|
|
// get all db table updates not done
|
|
var Updates = new SortedList<Version, cDbQuery>();
|
|
foreach (var Entry in DataHistorySqlHelper.wellDefinedSqlStatements.Values)
|
|
{
|
|
const string constUpdateName = "UpdateDbTablesV";
|
|
if (Entry.Name.StartsWith(constUpdateName))
|
|
{
|
|
var strVersion = Entry.Name.Remove(0, constUpdateName.Length);
|
|
if (Version.TryParse(strVersion, out var entryVersion))
|
|
if (entryVersion > currentVersion)
|
|
Updates.Add(entryVersion, Entry);
|
|
}
|
|
}
|
|
|
|
// do the updates
|
|
var IsOk = true;
|
|
foreach (var updateQuery in Updates)
|
|
{
|
|
var n = await DataHistorySqlHelper.GetScalarResultAsync<int>(DbConn, updateQuery.Value, null, requestInfo, Token);
|
|
if (n == 0)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the post update V{updateQuery.Key} was successfull, nothing updated.");
|
|
await InsertDbVersionAsync(DbConn, updateQuery.Key, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
else if (n > 0)
|
|
{
|
|
DoProcessUiMessage(1, $"{n} updates where processed by post update V{updateQuery.Key}.");
|
|
}
|
|
else
|
|
{
|
|
LogEntry($"the post update V01 is not successful.", LogLevels.Fatal);
|
|
IsOk = false;
|
|
}
|
|
}
|
|
|
|
if (IsOk)
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the post updates aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
LogEntry($"the post updates could not be validated sucessfull.", LogLevels.Fatal);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
private async Task ValidateAgentApiConnection()
|
|
{
|
|
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
const int maxRetryCount = 3;
|
|
TimeSpan delay = TimeSpan.FromSeconds(5);
|
|
|
|
bool loggedInToAgentApi = false;
|
|
for (int i = 0; i < maxRetryCount; i++)
|
|
{
|
|
loggedInToAgentApi = await F4sdAgent.LogonToAgentApiAsync();
|
|
if (loggedInToAgentApi)
|
|
break;
|
|
|
|
LogEntry("Logon to agent API failed.", LogLevels.Warning);
|
|
await Task.Delay(delay);
|
|
}
|
|
|
|
if (!loggedInToAgentApi)
|
|
{
|
|
DoProcessUiMessage(0, $"ERROR: Could not connect to the F4SD Agent API. Maybe there are invalid credentials configured.", LogLevels.Error);
|
|
return;
|
|
}
|
|
|
|
var _remoteScript = await F4sdAgent.GetRemoteScriptsAsync();
|
|
if (_remoteScript == null)
|
|
{
|
|
DoProcessUiMessage(0, $"ERROR: Retrieve remote scripts from Agent API.", LogLevels.Error);
|
|
return;
|
|
}
|
|
|
|
DoProcessUiMessage(0, $"Successful connection to the F4SD Agent API established. {_remoteScript.Count} remote scripts found.", LogLevels.Info);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(0, $"ERROR: Unknown error while validating Agent API.", LogLevels.Error);
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public async Task<bool> ValidateHistoryDatabasesAsync(bool isWebservice, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var RetVal = true;
|
|
var DbName = InfrastructureConfig.HistoryDB.Connection.Database;
|
|
try
|
|
{
|
|
DoProcessUiMessage(0, $"start validating the data history database '{DbName}'...");
|
|
|
|
DoProcessUiMessage(0, "");
|
|
await ValidateDatabaseAsync(requestInfo, LogDeep + 1, Token);
|
|
if (Token.IsCancellationRequested) return false;
|
|
|
|
using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 3 * 60 * 60))
|
|
{
|
|
if (!DbConn.IsOpen)
|
|
return false;
|
|
|
|
//DoProcessUiMessage(0, "");
|
|
//RetVal = await ValidateMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token);
|
|
//if (Token.IsCancellationRequested || !RetVal) return false;
|
|
|
|
DoProcessUiMessage(0, "");
|
|
foreach (var Connector in GetConnectors())
|
|
{
|
|
RetVal = await Connector.ValidateMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token);
|
|
if (Token.IsCancellationRequested || !RetVal) return false;
|
|
DoProcessUiMessage(0, "");
|
|
}
|
|
|
|
RetVal = await ValidatePostUpdates(DbConn, requestInfo, LogDeep + 1, Token);
|
|
DoProcessUiMessage(0, "");
|
|
|
|
var _Ok = true;
|
|
// check the existance of the tables and create them
|
|
foreach (var DbTable in ClusterConfig.Tables.Values)
|
|
{
|
|
if (DbTable.IsVirtual && DbTable.Cached != eDataHistoryTableCached.Yes)
|
|
continue;
|
|
_Ok &= await ValidateDbTableAsync(DbConn, DbTable, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
|
|
// check the table references and create them
|
|
var lst = "";
|
|
foreach (var DbTable in ClusterConfig.Tables.Values)
|
|
{
|
|
if (DbTable.IsVirtual && DbTable.Cached != eDataHistoryTableCached.Yes)
|
|
continue;
|
|
|
|
var _sqlRefs = await DataHistorySqlHelper.GetTableReferences(DbConn.Connection, DbTable.SourceName, Token);
|
|
if (DbTable.HasScanId)
|
|
{
|
|
lst += DbTable.Name + "\n";
|
|
_Ok &= await ValidateDbTableReferenceScanHistoryAsync(DbConn, DbTable, _sqlRefs, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
foreach (var Ref in DbTable.References.Values)
|
|
_Ok &= await ValidateDbTableReferencesAsync(DbConn, DbTable, Ref, _sqlRefs, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
|
|
if (Token.IsCancellationRequested || !RetVal) return false;
|
|
|
|
await LoadGloablConfigValuesAsync(DbConn, requestInfo, LogDeep + 1, Token);
|
|
|
|
if (isWebservice)
|
|
await TokenCache.LoadAsync(DbConn, Token, requestInfo, LogDeep + 1);
|
|
}
|
|
|
|
DoProcessUiMessage(0, $"the validation of the data history database '{DbName}' finished.");
|
|
|
|
if (!await F4sdAgent.CheckAndInitializeDbAccess(requestInfo, LogDeep + 1, CancellationToken.None))
|
|
{
|
|
DoProcessUiMessage(0, $"Could not initialize the F4SD agent database correctly '{InfrastructureConfig.ClientAgent.Organization}'.");
|
|
return false;
|
|
}
|
|
|
|
await ValidateAgentApiConnection();
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the data history database '{DbName}' aborted with an exceptional error.");
|
|
RetVal = false;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
private async Task<bool> ValidateDbTableAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var _TableExist = await DataHistorySqlHelper.CheckIfTableExistAsync(DbConn.Connection, DbTable.SourceName, requestInfo, LogDeep + 1);
|
|
if (_TableExist)
|
|
LogEntry($"The database '{DbTable.SourceName}' already exist.", LogLevels.Debug);
|
|
else
|
|
{
|
|
LogEntry($"The database '{DbTable.SourceName}' does not exist, creating it...", LogLevels.Debug);
|
|
var Query = DataHistorySqlHelper.GetSqlCreateStatement(DbTable, cDataHistoryConfigClusters.confUseBinValuesAsPrimaryKey, true);
|
|
var _startTime2 = DateTime.UtcNow;
|
|
var CRes = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, Query, null, Token);
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableAsync.CreateTable", _startTime2, DbTable.SourceName, 0, requestInfo?.requestName);
|
|
}
|
|
|
|
// validate & create additional table columns
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CheckAndCreateTableColumn", out var Query2))
|
|
return false;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CheckScanIdTableColumn", out var QueryScanId))
|
|
return false;
|
|
|
|
bool ColumnCreated = false;
|
|
foreach (var Column in DbTable.Columns.Values)
|
|
{
|
|
try
|
|
{
|
|
var strNull = "NULL";
|
|
if (!DbTable.IsNullable(Column))
|
|
strNull = "NOT " + strNull;
|
|
|
|
var strQuery = string.Format(Query2.Query, DbTable.SourceName, Column.Name, Column.SqlType, strNull);
|
|
var _startTime2 = DateTime.UtcNow;
|
|
var RV = await DataHistorySqlHelper.GetScalarResultAsync<int?>(DbConn.Connection, strQuery, null, Token);
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query2.Name, _startTime2, DbTable.SourceName + "." + Column.Name, 0, requestInfo?.requestName);
|
|
if (RV == 1)
|
|
ColumnCreated = true;
|
|
|
|
if (Column.SqlTypeBin != null)
|
|
{
|
|
strQuery = string.Format(Query2.Query, DbTable.SourceName, Column.Name + DataHistorySqlHelper.constBinValueNameAdd, Column.SqlTypeBin, strNull);
|
|
_startTime2 = DateTime.UtcNow;
|
|
RV = await DataHistorySqlHelper.GetScalarResultAsync<int?>(DbConn.Connection, strQuery, null, Token);
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query2.Name, _startTime2, DbTable.SourceName + "." + Column.Name + DataHistorySqlHelper.constBinValueNameAdd, 0, requestInfo?.requestName);
|
|
if (RV == 1)
|
|
ColumnCreated = true;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
var strQueryScanId = string.Format(QueryScanId.Query, DbTable.SourceName);
|
|
var _startTime3 = DateTime.UtcNow;
|
|
var _n = await DataHistorySqlHelper.GetScalarResultAsync<int?>(DbConn.Connection, strQueryScanId, null, Token);
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(QueryScanId.Name, _startTime3, DbTable.SourceName, 0, requestInfo?.requestName);
|
|
DbTable.HasScanId = _n == 1;
|
|
|
|
if (ColumnCreated)
|
|
{
|
|
var isOk = await Connectors[DbTable.ParentCluster.Origin].ColumnUpatePostProcessingAsync(DbConn, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> ValidateDbTableReferenceScanHistoryAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, Dictionary<string, cSqlReferenceInfo> _sqlRefs, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
if (DbTable.Type != eDataHistoryTableType.Events && DbTable.Type != eDataHistoryTableType.History)
|
|
return true;
|
|
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (_sqlRefs.ContainsKey($"FK_{DbTable.SourceName}_scan-history"))
|
|
return true;
|
|
|
|
var sqlCmd = $"ALTER TABLE [{DbTable.SourceName}] WITH CHECK ADD CONSTRAINT [FK_{DbTable.SourceName}_scan-history] FOREIGN KEY([ScanId]) REFERENCES [main-scan-history] ([ScanId]) ON DELETE CASCADE;";
|
|
var _Res = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, sqlCmd, null, Token);
|
|
return (_Res == -1);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableReferenceScanHistoryAsync", _startTime, "DbTable.SourceName", 0, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private async Task<bool> ValidateDbTableReferencesAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, cDataHistoryConfigTableReferenceInfo Ref, Dictionary<string, cSqlReferenceInfo> _sqlRefs, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var RetVal = true;
|
|
var _RefName = DataHistorySqlHelper.GetReferencingName(DbTable, Ref);
|
|
var _exists = false;
|
|
foreach (var _refInfo in _sqlRefs.Values)
|
|
{
|
|
if (_refInfo.Name == _RefName)
|
|
{
|
|
_exists = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!_exists)
|
|
{
|
|
var _Query = DataHistorySqlHelper.GetReferencingStatements(DbTable, Ref);
|
|
var _Res = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, _Query, null, Token);
|
|
if (_Res != -1)
|
|
RetVal = false;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableReferencesAsync", _startTime, "DbTable.SourceName", 0, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> ValidateAgentDbUpdates(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var cmdList = DataHistorySqlHelper.wellDefinedSqlStatements.Where(v => v.Key.StartsWith("AgentDbUpdate")).ToDictionary(v => v.Key, v => v.Value);
|
|
var cmdSorted = new SortedList<string, cDbQuery>(cmdList);
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(0, "Start validating Agent DB");
|
|
using (var DbConn = new cDbConnection(this.InfrastructureConfig.ClientAgent.Connection, Timeout: 3 * 60 * 60))
|
|
{
|
|
foreach (var DbCmd in cmdSorted.Values)
|
|
{
|
|
try
|
|
{
|
|
if (String.IsNullOrWhiteSpace(DbCmd.Description))
|
|
DoProcessUiMessage(1, $"Processing SQL query {DbCmd.Name}...");
|
|
else
|
|
DoProcessUiMessage(1, DbCmd.Description + "...");
|
|
|
|
var resInt = await DataHistorySqlHelper.ExecuteAsync(DbConn, DbCmd, null, requestInfo, Token, Timeout: 3 * 60 * 60);
|
|
|
|
DoProcessUiMessage(2, $"...finished.");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
DoProcessUiMessage(0, "Validating Agent DB finished.");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> ValidateF4SDAnalyticsDBAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var RetVal = true;
|
|
F4SDAnalyticsValid = false;
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(0, $"start validating the data '{DbConnection.Database}' database...");
|
|
|
|
var isValid = await ValidateF4SDAnalyticsDatabaseAsync(Token, requestInfo, LogDeep + 1, ForceCreate);
|
|
|
|
if (!isValid)
|
|
{
|
|
DoProcessUiMessage(0, "");
|
|
DoProcessUiMessage(0, $"the validation of the data database '{DbConnection.Database}' finished.");
|
|
return false;
|
|
}
|
|
if (Token.IsCancellationRequested) return false;
|
|
|
|
using (var DbConn = new cDbConnection(DbConnection, Timeout: 3 * 60 * 60))
|
|
{
|
|
if (!DbConn.IsOpen)
|
|
{
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(0, "");
|
|
RetVal = await ValidateF4SDAnalyticsMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate);
|
|
if (Token.IsCancellationRequested || !RetVal)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RetVal = await ValidateF4SDAnalyticsFunctionsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate);
|
|
if (Token.IsCancellationRequested || !RetVal)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RetVal = await ValidateF4SDAnalyticsViewsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate);
|
|
if (Token.IsCancellationRequested || !RetVal)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RetVal = await UpdateF4SDAnalyticsViewsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate);
|
|
if (Token.IsCancellationRequested || !RetVal)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DoProcessUiMessage(0, "");
|
|
F4SDAnalyticsValid = true;
|
|
F4SDAnalyticsDb = InfrastructureConfig.F4SDAnalyticsDB;
|
|
}
|
|
|
|
DoProcessUiMessage(0, $"the validation of the data analytics database '{DbConnection.Database}' finished.");
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"the validation of the data analytics database '{DbConnection.Database}' aborted with an exceptional error.");
|
|
RetVal = false;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
public async void CheckSessionsAsync(object sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var currentTimeStamp = DateTime.UtcNow;
|
|
var _toClose = new List<cF4SDUserSessionParameters>();
|
|
lock (SessionValues)
|
|
{
|
|
foreach (var v in SessionValues)
|
|
{
|
|
var diff = (int)currentTimeStamp.Subtract(SessionValues[v.Key]).TotalMinutes;
|
|
if (diff >= F4SDAnalyticsDb.SessionTimeout)
|
|
{
|
|
var userSessions = new cF4SDUserSessionParameters();
|
|
userSessions.SessionId = v.Key;
|
|
userSessions.SessionDate = currentTimeStamp;
|
|
_toClose.Add(userSessions);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var s in _toClose)
|
|
{
|
|
var _requestInfo = new cF4sdWebRequestInfo("CheckSessionsAsync", s.SessionId.ToString());
|
|
await CloseUserSessionAsync(s, _requestInfo, 1, CancellationToken.None);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async void CheckCasesAsync(object sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
var requestInfo = new cF4sdWebRequestInfo("CheckCasesAsync", null);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceStart(0, requestInfo.requestName, requestInfo.id, requestInfo.created); }
|
|
var apiError = 0;
|
|
|
|
try
|
|
{
|
|
var currentTimeStamp = DateTime.UtcNow;
|
|
var _toClose = new List<cF4SDCaseTimeParameters>();
|
|
lock (CaseValues)
|
|
{
|
|
foreach (var v in CaseValues)
|
|
{
|
|
var diff = (int)currentTimeStamp.Subtract(CaseValues[v.Key]).TotalMinutes;
|
|
if (diff > F4SDAnalyticsDb.CaseTimeout)
|
|
{
|
|
var caseData = new cF4SDCaseTimeParameters();
|
|
caseData.CaseId = v.Key;
|
|
caseData.StatusId = CaseStatus.Canceled;
|
|
_toClose.Add(caseData);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var s in _toClose)
|
|
{
|
|
var requestInfo2 = new cF4sdWebRequestInfo("CheckCasesAsync", s.CaseId?.ToString());
|
|
await UpdateCaseStateAsync(s, requestInfo2, 1, CancellationToken.None);
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(0, requestInfo.requestName, requestInfo.id, requestInfo.created, requestInfo.created, ErrorCode: apiError); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task LoadGloablConfigValuesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
DoProcessUiMessage(1, $"start loading database config values...");
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetConfigValues", out var Query))
|
|
return;
|
|
|
|
GlobalConfigValues.Clear();
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
using (var _reader = await DataHistorySqlHelper.GetDataReaderAsync(DbConn, Query, null, Token))
|
|
{
|
|
if (_reader != null)
|
|
try
|
|
{
|
|
if (_reader.HasRows)
|
|
{
|
|
while (await _reader.ReadAsync())
|
|
{
|
|
try
|
|
{
|
|
var Key = _reader.GetString(0);
|
|
var Value = _reader.GetString(1);
|
|
GlobalConfigValues[Key] = Value;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
|
|
if (Token.IsCancellationRequested)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName);
|
|
}
|
|
|
|
await GetSecTokenKeyAsync(DbConn, requestInfo, LogDeep + 1, Token);
|
|
|
|
DoProcessUiMessage(1, "loading database config values finished.");
|
|
DoProcessUiMessage(0, "");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
DoProcessUiMessage(1, $"loading global configuraton aborted with an exceptional error.");
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task GetSecTokenKeyAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (GlobalConfigValues.TryGetValue("Security.AccessTokenKey", out var _encKey))
|
|
{
|
|
var _sec = cSecurePassword.Instance.Decode(_encKey);
|
|
BearerSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_sec));
|
|
}
|
|
else
|
|
{
|
|
var _sec = Guid.NewGuid().ToString() + Guid.NewGuid().ToString() + Guid.NewGuid().ToString() + Guid.NewGuid().ToString();
|
|
_sec = _sec.Replace("-", "");
|
|
BearerSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_sec));
|
|
|
|
_sec = cSecurePassword.Instance.Encode(_sec);
|
|
await UpdateConfigValueAsync("Security.AccessTokenKey", _sec, DbConn, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
|
|
JwtTokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuerSigningKey = true,
|
|
ValidateIssuer = true,
|
|
ValidateAudience = true,
|
|
ValidIssuer = JwtTokenIssuer,
|
|
ValidAudience = JwtTokenAudience,
|
|
IssuerSigningKey = BearerSecurityKey
|
|
};
|
|
}
|
|
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public string GenerateJsonWebToken(cF4sdUserInfo UserInfo)
|
|
{
|
|
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (BearerSecurityKey == null)
|
|
return null;
|
|
|
|
var credentials = new SigningCredentials(BearerSecurityKey, SecurityAlgorithms.HmacSha256);
|
|
|
|
var claims = new List<Claim> {
|
|
new Claim(JwtRegisteredClaimNames.NameId, UserInfo.Id.ToString()),
|
|
new Claim(JwtRegisteredClaimNames.UniqueName, UserInfo.Name),
|
|
new Claim(JwtRegisteredClaimNames.AuthTime, UserInfo.LogonTime.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'z'")),
|
|
new Claim("login_method", UserInfo.AccountType.ToString()),
|
|
new Claim("login_account", UserInfo.AdAccount.ToString()),
|
|
new Claim("account_sid", UserInfo.AdSid),
|
|
new Claim("language", UserInfo.Language ?? "")
|
|
};
|
|
if (UserInfo.Roles?.Count > 0)
|
|
foreach (var _roleEntry in UserInfo.Roles)
|
|
claims.Add(new Claim("roles", _roleEntry));
|
|
|
|
UserInfo.LogonTime = DateTime.UtcNow;
|
|
UserInfo.RenewUntil = UserInfo.LogonTime.AddMinutes(90);
|
|
UserInfo.ValidUntil = UserInfo.LogonTime.AddMinutes(120);
|
|
var token = new JwtSecurityToken(JwtTokenIssuer,
|
|
JwtTokenAudience,
|
|
claims,
|
|
notBefore: UserInfo.LogonTime.AddMinutes(-1),
|
|
expires: UserInfo.ValidUntil,
|
|
signingCredentials: credentials);
|
|
|
|
var retVal2 = JwtTokenHandler.WriteToken(token);
|
|
return retVal2;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task UpdateConfigValueAsync(string Key, string Value, cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateConfigValue", out var Query))
|
|
return;
|
|
|
|
var _params = new Dictionary<string, object>()
|
|
{
|
|
{ "Key", Key},
|
|
{ "Value", Value},
|
|
};
|
|
|
|
await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, _params, requestInfo, Token);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> CreateCaseAsync(cF4SDCaseParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser;
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateCase", out var Query))
|
|
return false;
|
|
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (anonymous != null && (bool)anonymous)
|
|
{
|
|
Param.UserId = GetUserHashGuid((Guid)Param.UserId);
|
|
}
|
|
if (Param.SessionId != null && Param.SessionId != Guid.Empty)
|
|
{
|
|
if (Param.CaseId != null && Param.CaseId != Guid.Empty)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "SessionId", Param.SessionId }, { "CaseId", Param.CaseId }, { "UserId", Param.UserId } };
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(2, $"Case is started. CaseId: " + Param.CaseId.ToString(), LogLevels.Debug);
|
|
lock (CaseValues)
|
|
CaseValues.Add((Guid)Param.CaseId, DateTime.UtcNow);
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the insert of the Case-data into F4SDAnalytics database with exception error.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call - CreateCase Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call - CreateCase - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> UpdateCaseStateAsync(cF4SDCaseTimeParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateCaseState", out var Query))
|
|
return false;
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (Param.CaseId != null && Param.CaseId != Guid.Empty)
|
|
{
|
|
XElement ParamState = null;
|
|
if (Param.CaseTimes != null && Param.CaseTimes.Count > 0)
|
|
{
|
|
ParamState = new XElement("Root",
|
|
from prm in Param.CaseTimes
|
|
select new XElement("Item",
|
|
new XElement("StatusId", (int)prm.StatusId),
|
|
new XElement("TimeStamp", prm.CaseTime)
|
|
));
|
|
}
|
|
|
|
var Params = new Dictionary<string, object>() { { "CaseId", Param.CaseId }, { "StatusId", Param.StatusId }, { "ActiveTime", Param.ActiveTime }, { "StatusXML", ParamState?.ToString() ?? String.Empty } };
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
if (Param.StatusId == CaseStatus.Canceled || Param.StatusId == CaseStatus.Finished)
|
|
{
|
|
DoProcessUiMessage(2, $"Case is closed. CaseId: " + Param.CaseId.ToString(), LogLevels.Debug);
|
|
lock (CaseValues)
|
|
CaseValues.Remove((Guid)Param.CaseId);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"Current CaseId: " + Param.CaseId.ToString() + " could not be found", LogLevels.Debug);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call UpdateCaseState - Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ReportQuickActionExecutionAsync(cF4SDQuickActionParameters Param, cDataHistoryConfigSqlConnection DBConnection, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (DBConnection != null && DBConnection.Database == InfrastructureConfig.F4SDAnalyticsDB?.Connection.Database
|
|
&& DataHistorySqlHelper.GetWellKnownSqlStatement("AnalyticsReportQuickActionExecution", out var Query))
|
|
{
|
|
|
|
using (var DbConn = new cDbConnection(DBConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (Param.CaseId != null && Param.CaseId != Guid.Empty)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "CaseId", Param.CaseId }, { "QActionId", Param.QuickActionId },
|
|
{ "DeviceId", Param.DeviceId },
|
|
{ "Start", Param.Start }, { "Finish", Param.Finish },
|
|
{ "Parameters", Param.Paramaters }, { "Result", Param.Result },
|
|
{ "ErrorCode", Param.ErrorCode }, { "ErrorDescription", Param.ErrorDescription },
|
|
{ "ExecutionType", Param.ExecutionType.ToString() },{ "ResultType", Param.ResultType.ToString() }};
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the insert of the QuickActionExecution-data into F4SDAnalytics database with exception error.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call ReportQuickActionExecution - Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the QuickActionExecution-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
if (DBConnection != null && DBConnection.Database == InfrastructureConfig.HistoryDB.Connection.Database
|
|
&& DataHistorySqlHelper.GetWellKnownSqlStatement("ReportQuickActionExecution", out var Query2))
|
|
{
|
|
using (var DbConn = new cDbConnection(DBConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "UserId", Param.UserId }, { "QActionId", Param.QuickActionId },
|
|
{ "DeviceId", Param.DeviceId },{ "QActionName", Param.QuickActionName },
|
|
{ "Start", Param.Start }, { "Finish", Param.Finish },
|
|
{ "Parameters", Param.Paramaters }, { "Result", Param.Result },
|
|
{ "ErrorCode", Param.ErrorCode }, { "ErrorDescription", Param.ErrorDescription },
|
|
{ "ExecutionType", Param.ExecutionType.ToString() },{ "ResultType", Param.ResultType.ToString() }};
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the insert of the QuickActionExecution-data into History database with exception error.");
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> CreateUserSessionAsync(cF4SDUserSessionParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser;
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
|
|
if (anonymous != null && (bool)anonymous)
|
|
{
|
|
Param.UserId = GetUserHashGuid((Guid)Param.UserId);
|
|
}
|
|
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateUserSession", out var Query))
|
|
return false;
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (Param.SessionId != null && Param.SessionId != Guid.Empty)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "SessionId", Param.SessionId }, { "UserId", Param.UserId }, { "SessionDate", Param.SessionDate } };
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(2, $"Session is started. SessionId: " + Param.SessionId.ToString(), LogLevels.Debug);
|
|
lock (SessionValues)
|
|
SessionValues[(Guid)Param.SessionId] = DateTime.UtcNow;
|
|
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the insert of the Usersession-data into F4SDAnalytics database with exception error.", LogLevels.Warning);
|
|
return false;
|
|
|
|
}
|
|
DoProcessUiMessage(2, $"API Call CreateUserSession - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Usersession-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> CloseUserSessionAsync(cF4SDUserSessionParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CloseUserSession", out var Query))
|
|
return false;
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (Param.SessionId != null && Param.SessionId != Guid.Empty)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "SessionId", Param.SessionId }, { "SessionDate", Param.SessionDate } };
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(2, $"Session is closed. SessionId: " + Param.SessionId.ToString(), LogLevels.Debug);
|
|
lock (SessionValues)
|
|
SessionValues.Remove((Guid)Param.SessionId);
|
|
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the update of the Usersession-data into F4SDAnalytics database with exception error.", LogLevels.Warning);
|
|
if (cLogManager.DefaultLogger.IsDebug)
|
|
{
|
|
var _msg = new List<string>()
|
|
{
|
|
$"query: {Query}",
|
|
$"session id: {Param.SessionId}",
|
|
$"session date: {Param.SessionDate}",
|
|
};
|
|
cLogManager.DefaultLogger.LogList(LogLevels.Debug, _msg);
|
|
}
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call CreateUserSession - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Usersession-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> UpdateCaseAsync(Guid CaseId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateCases", out var Query))
|
|
return false;
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
if (CaseId != null && CaseId != Guid.Empty)
|
|
{
|
|
var Params = new Dictionary<string, object>() { { "CaseId", CaseId } };
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(2, $"Casestatus is updated. CaseId: " + CaseId.ToString(), LogLevels.Debug);
|
|
lock (CaseValues)
|
|
CaseValues.Add(CaseId, DateTime.UtcNow);
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the update of the CaseStatus with CaseId '{CaseId}' into F4SDAnalytics database returned no legal update count ({n}).", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 to update of the CaseStatus into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ReportTicketAsync(cApiM42Ticket Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser;
|
|
Guid.TryParse(requestInfo.userInfo?.Id.ToString(), out Guid userGuid);
|
|
if (anonymous != null && (bool)anonymous)
|
|
Param.User = GetUserHashGuid(userGuid).ToString();
|
|
else
|
|
Param.User = userGuid.ToString();
|
|
|
|
var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection;
|
|
if (DbConnection == null)
|
|
return false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertTicket", out var Query))
|
|
return false;
|
|
|
|
|
|
using (var DbConn = new cDbConnection(DbConnection))
|
|
if (DbConn.IsOpen)
|
|
{
|
|
|
|
if (Param.Ticket != null && Param.Ticket != Guid.Empty)
|
|
{
|
|
if (Param.CaseId != null && Param.CaseId != Guid.Empty)
|
|
{
|
|
var startTime = Param.workTimes.FirstOrDefault(x => x.Key == "StartTime").Value;
|
|
var endTime = Param.workTimes.FirstOrDefault(x => x.Key == "EndTime").Value;
|
|
var workingTime = Param.workTimes.FirstOrDefault(x => x.Key == "NettoWorkingTime").Value;
|
|
|
|
var Params = new Dictionary<string, object>() { { "TicketId", Param.Ticket }, { "Status", Param.StatusIdValue }, { "CaseId", Param.CaseId }, { "UserId", Param.User }, { "Start", startTime }, { "Finish", endTime }, { "ActiveTime", workingTime } };
|
|
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token);
|
|
if (n >= 1)
|
|
{
|
|
DoProcessUiMessage(2, $"Ticket-Data is saved . TicketNumber: " + Param.Ticket, LogLevels.Debug);
|
|
lock (CaseValues)
|
|
CaseValues.Add((Guid)Param.CaseId, DateTime.UtcNow);
|
|
return true;
|
|
}
|
|
|
|
DoProcessUiMessage(2, $"the insert of the Ticket-data into F4SDAnalytics database with exception error.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call - InsertTicket Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Ticket-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
DoProcessUiMessage(2, $"API Call - InsertTicket - Invalid TicketId: 00000000-0000-0000-0000-000000000000 of the Ticket-data into F4SDAnalytics database.", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public bool KeepAliveSession(Guid SessionId, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (SessionId != null && SessionId != Guid.Empty)
|
|
{
|
|
lock (SessionValues)
|
|
SessionValues[SessionId] = DateTime.UtcNow;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (cLogManager.DefaultLogger.IsDebug) LogEntry($"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 ", LogLevels.Warning);
|
|
return false;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<bool> KeepAliveCase(Guid CaseId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (CaseId != null && CaseId != Guid.Empty)
|
|
{
|
|
if (CaseValues.ContainsKey(CaseId))
|
|
{
|
|
lock (CaseValues)
|
|
CaseValues[CaseId] = DateTime.UtcNow;
|
|
}
|
|
else
|
|
{
|
|
await UpdateCaseAsync(CaseId, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
return true;
|
|
}
|
|
if (cLogManager.DefaultLogger.IsDebug) LogEntry($"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 ", LogLevels.Warning);
|
|
return false;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void DoProcessUiMessage(int Indent, string Message, LogLevels logLevel = LogLevels.Info)
|
|
{
|
|
try
|
|
{
|
|
var strIndent = new string(' ', Indent * 2);
|
|
cLogManager.DefaultLogger.LogEntry(logLevel, strIndent + Message);
|
|
|
|
ProcessUiMessage?.Invoke(cDataHistoryUiStatusMessage.Create(Indent, Message));
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void DoProcessUiMessage(int Indent, cXmlParserNodeMessage Message)
|
|
{
|
|
DoProcessUiMessage(Indent, cXmlParser.GetMessageString(Message));
|
|
}
|
|
|
|
public void DoProcessUiMessage(int Indent, List<cXmlParserNodeMessage> Messages)
|
|
{
|
|
foreach (var Entry in Messages)
|
|
DoProcessUiMessage(Indent, Entry);
|
|
}
|
|
|
|
public void CleanupUiMessageHandler()
|
|
{
|
|
if (ProcessUiMessage != null)
|
|
{
|
|
foreach (var Entry in ProcessUiMessage.GetInvocationList())
|
|
try
|
|
{
|
|
ProcessUiMessage -= Entry as DataHistoryUiMessageFunc;
|
|
}
|
|
catch { }
|
|
ProcessUiMessage = null;
|
|
}
|
|
|
|
}
|
|
|
|
internal class cFasdApiSearchResultExt
|
|
{
|
|
internal cFasdApiSearchResultEntry Result = new cFasdApiSearchResultEntry();
|
|
internal string upn_internal = null;
|
|
internal int? IdAgent;
|
|
}
|
|
|
|
public class cUsageData
|
|
{
|
|
internal Int32 id;
|
|
internal Int64 duration;
|
|
internal DateTime lastEvent;
|
|
}
|
|
|
|
|
|
public async Task<cF4sdUserInfo> GetCurrentUserInfoAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var _user = WindowsIdentity.GetCurrent();
|
|
var _res = await GetWinUserInfoAsync(_user, CultureInfo.CurrentCulture.DisplayName, true, Token, requestInfo, LogDeep + 1);
|
|
return _res;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
public async Task<cF4sdUserInfo> GetWinUserInfoAsync(IIdentity Identity, string Language, bool justWinRoles, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (Identity == null)
|
|
return null;
|
|
|
|
if (!(Identity is WindowsIdentity _winUser))
|
|
{
|
|
LogEntry($"could not logon with specified identity due to incompatible authentication type (name={Identity.Name}, type={Identity.AuthenticationType}");
|
|
return null;
|
|
}
|
|
if (!_winUser.IsAuthenticated)
|
|
{
|
|
LogEntry($"the specified winuser is not authenticated (name={Identity.Name}, type={Identity.AuthenticationType}");
|
|
return null;
|
|
}
|
|
|
|
var _sid = _winUser.User.ToString();
|
|
var _retVal = new cF4sdUserInfo()
|
|
{
|
|
Id = Guid.Empty,
|
|
LogonTime = DateTime.UtcNow,
|
|
AccountType = cF4sdUserInfo.enumAccountType.AdUser,
|
|
AdAccount = _winUser.Name,
|
|
Name = _winUser.Name,
|
|
AdSid = _sid,
|
|
Language = Language
|
|
};
|
|
|
|
LogEntry($"The authenticated user is: name={Identity.Name}, type={Identity.AuthenticationType}");
|
|
|
|
bool IsEntraIdDevelop = false;
|
|
|
|
if (!justWinRoles)
|
|
{
|
|
if (!string.IsNullOrEmpty(_sid))
|
|
{
|
|
Dictionary<string, List<cFasdApiSearchResultExt>> _ids = null;
|
|
if (RunningInIISExpress)
|
|
{
|
|
// check if we are in EntraID develop mode (running in IIS Express and the user is an Entra ID User)
|
|
Guid azureId = Guid.Empty;
|
|
azureId = cDataHistoryCollectorActiveDirectory.ConvertAzureSidToGuid(_sid);
|
|
if (azureId != Guid.Empty)
|
|
_ids = await UserSearchByEntraIdDevelopAsync(azureId, Token, requestInfo, LogDeep + 1);
|
|
}
|
|
if (_ids == null || _ids.Count == 0)
|
|
_ids = await UserSearchBySidsAsync(new List<string> { _sid }, Token, requestInfo, LogDeep + 1);
|
|
else
|
|
IsEntraIdDevelop = true;
|
|
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
if (_ids?.Count > 0)
|
|
{
|
|
var _entry = _ids?.First().Value;
|
|
if (_entry?.Count > 0)
|
|
{
|
|
var _result = _entry.First().Result;
|
|
if (_result != null)
|
|
{
|
|
_retVal.Name = _result.Name;
|
|
_retVal.Id = _result.id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_retVal.Id == Guid.Empty)
|
|
{
|
|
LogEntry($"Could not find user {_winUser.Name} with SID {_sid} for authentication in table 'main-user'.", LogLevels.Warning);
|
|
LogEntry($"Please check, if at least one of the defined AD user scan nodes contains this user.", LogLevels.Warning);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
var _membershipGroups = InfrastructureConfig?.Authorisation?.MembershipGroups?.GroupsAd;
|
|
var _resMembershipGroups = new List<cF4SDMembershipGroup>();
|
|
|
|
if (IsEntraIdDevelop)
|
|
{
|
|
// if we are in EntraID develop mode, we have fake all ad group memberships
|
|
if (_membershipGroups != null)
|
|
foreach (var _entryDom in _membershipGroups.Values)
|
|
foreach (var _entryGroup in _entryDom.Values)
|
|
_resMembershipGroups.Add(_entryGroup);
|
|
}
|
|
else
|
|
{
|
|
var _dom = Domain.GetComputerDomain();
|
|
var _pc = new PrincipalContext(ContextType.Domain);
|
|
var _groups = _winUser.Groups;
|
|
|
|
|
|
var _msgLog = new List<string>();
|
|
if (cLogManager.DefaultLogger.IsDebug)
|
|
{
|
|
_msgLog.Add($"the winuser {_retVal.AdAccount} logged on");
|
|
_msgLog.Add($" is member of ad security groups:");
|
|
}
|
|
foreach (var _group in _groups)
|
|
{
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
if (_group is SecurityIdentifier _si)
|
|
{
|
|
cF4SDMembershipGroupAd _memGrp = null;
|
|
if (_membershipGroups != null)
|
|
foreach (var _entryDom in _membershipGroups.Values)
|
|
{
|
|
foreach (var _entryGroup in _entryDom.Values)
|
|
{
|
|
if (_si.Value == _entryGroup.SID)
|
|
{
|
|
_resMembershipGroups.Add(_entryGroup);
|
|
_memGrp = _entryGroup;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DefaultLogger.IsDebug)
|
|
{
|
|
try
|
|
{
|
|
var _gp = GroupPrincipal.FindByIdentity(_pc, IdentityType.Sid, _si.Value);
|
|
if (_gp != null)
|
|
{
|
|
if (_memGrp != null)
|
|
_msgLog.Add($" {_gp.SamAccountName} ({_gp.DistinguishedName}) is member of '{_memGrp.Name}'");
|
|
else
|
|
_msgLog.Add($" {_gp.SamAccountName} ({_gp.DistinguishedName})");
|
|
}
|
|
else
|
|
_msgLog.Add($" could not find group {_si.Value}");
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cLogManager.DefaultLogger.IsDebug)
|
|
cLogManager.DefaultLogger.LogList(LogLevels.Debug, _msgLog);
|
|
|
|
}
|
|
|
|
if (_membershipGroups?.Count > 0)
|
|
AddRolesByMembership(_retVal, _resMembershipGroups);
|
|
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
if (!string.IsNullOrEmpty(_retVal.AdSid) && (M42WpmCollector != null))
|
|
await M42WpmCollector.AddM42UserInfosAsync(_retVal, Token, requestInfo, LogDeep + 1);
|
|
|
|
var _token = GenerateJsonWebToken(_retVal);
|
|
|
|
_retVal.Token = _token;
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
private async Task<Dictionary<string, List<cFasdApiSearchResultExt>>> searchSqlAsync(string strQuery, Dictionary<string, object> SqlParam, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string QueryName, string PhoneSearch = null, bool SupportCancellation = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
if (strQuery == null)
|
|
return null;
|
|
|
|
using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 10))
|
|
{
|
|
if (!DbConn.IsOpen)
|
|
return null;
|
|
|
|
using (var Reader = await DataHistorySqlHelper.GetTableResultAsync(DbConn.Connection, strQuery, SqlParam, Token, SupportCancellation: SupportCancellation))
|
|
{
|
|
var output = new Dictionary<string, List<cFasdApiSearchResultExt>>();
|
|
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Max<int>();
|
|
var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Min<int>();
|
|
|
|
while (await Reader.ReadAsync(Token))
|
|
{
|
|
try
|
|
{
|
|
var Entry = new cFasdApiSearchResultExt();
|
|
var intType = Reader.GetInt32(0);
|
|
Entry.Result.Type = (enumF4sdSearchResultClass)intType;
|
|
|
|
Entry.upn_internal = Reader.IsDBNull(4) ? null : Reader.GetString(4);
|
|
|
|
Entry.IdAgent = Reader.IsDBNull(5) ? (int?)null : Reader.GetInt32(5);
|
|
|
|
var strName = Reader.GetString(1);
|
|
if (PhoneSearch != null && Entry.Result.Type == enumF4sdSearchResultClass.Phone) // phone type
|
|
{
|
|
string strPhone = null;
|
|
var strPh = Reader.IsDBNull(8) ? null : Reader.GetString(8);
|
|
if (strPh != null)
|
|
{
|
|
var arrPh = strPh.Split(' ');
|
|
foreach (var str in arrPh)
|
|
{
|
|
if (str.EndsWith(PhoneSearch))
|
|
{
|
|
strPhone = str;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (strPhone != null)
|
|
{
|
|
Entry.Result.Name = strName + " (" + strPhone + ")";
|
|
Entry.Result.DisplayName = strName + " (" + strPhone + ")";
|
|
}
|
|
else
|
|
{
|
|
Entry.Result.Name = strName;
|
|
Entry.Result.DisplayName = strName;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
Entry.Result.Name = strName;
|
|
Entry.Result.DisplayName = strName;
|
|
}
|
|
Entry.Result.id = Reader.GetFieldValue<Guid>(2);
|
|
|
|
if (!Reader.IsDBNull(3))
|
|
{
|
|
var intStatus = Reader.GetInt32(3);
|
|
if (intStatus <= maxStateVal && intStatus >= minStateVal)
|
|
Entry.Result.Status = (enumF4sdSearchResultStatus)intStatus;
|
|
}
|
|
|
|
var account = Reader.IsDBNull(6) ? null : Reader.GetString(6);
|
|
var domain = Reader.IsDBNull(7) ? null : Reader.GetString(7);
|
|
Entry.Result.Infos = new Dictionary<string, string>(2)
|
|
{
|
|
{"account", account },
|
|
{"domain", domain },
|
|
};
|
|
|
|
if (output.TryGetValue(strName, out var lst))
|
|
{
|
|
lst.Add(Entry);
|
|
}
|
|
else
|
|
{
|
|
if (output.Count > 11)
|
|
break;
|
|
|
|
lst = new List<cFasdApiSearchResultExt> { Entry };
|
|
output.Add(strName, lst);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
if (!Token.IsCancellationRequested || !SupportCancellation)
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(QueryName, _startTime, SqlParam, apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
private async Task<Dictionary<string, List<cFasdApiSearchResultExt>>> searchStringAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string Field = null, bool Reverse = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
|
|
var IsPhone = this.InfrastructureConfig.HistoryDB.SearchForPhoneNumbers && isDigits(search);
|
|
|
|
string strQuery = null;
|
|
if (Field == null)
|
|
{
|
|
if (IsPhone)
|
|
{
|
|
strQuery = "SearchFulltextRev";
|
|
Reverse = true;
|
|
}
|
|
else
|
|
#if SIMULATE_SLOW_SEARCH
|
|
strQuery = "SearchFulltextWithDelay";
|
|
#else
|
|
strQuery = "SearchFulltext";
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (Reverse)
|
|
strQuery = "SearchByFieldRev";
|
|
else
|
|
strQuery = "SearchByField";
|
|
}
|
|
|
|
var SqlParam = new Dictionary<string, object>();
|
|
|
|
if (Field == null || !Reverse)
|
|
{
|
|
var searchMask = $"\"{search}*\"";
|
|
SqlParam.Add("SEARCH", searchMask);
|
|
}
|
|
|
|
if (Reverse)
|
|
{
|
|
char[] arrRev = (search + 'x').ToArray();
|
|
Array.Reverse(arrRev);
|
|
var strRev = new string(arrRev);
|
|
strRev = $"\"{strRev}*\"";
|
|
SqlParam.Add("REV", strRev);
|
|
}
|
|
|
|
SqlParam.Add("DAYS", this.InfrastructureConfig.ClientAgent.MaxDeviceAge);
|
|
|
|
if (strQuery == null)
|
|
return null;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query))
|
|
return null;
|
|
|
|
strQuery = Query.Query;
|
|
if (Field != null)
|
|
strQuery = string.Format(strQuery, Field);
|
|
|
|
string strPhoneSearch = null;
|
|
if (IsPhone)
|
|
strPhoneSearch = search;
|
|
|
|
return await searchSqlAsync(strQuery, SqlParam, Token, requestInfo, LogDeep + 1, Query.Name, strPhoneSearch, true);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<Dictionary<string, List<cFasdApiSearchResultExt>>> searchComputerNameAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string Field = null, bool Reverse = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
string strQuery = "SearchComputerByName";
|
|
var SqlParam = new Dictionary<string, object>();
|
|
|
|
if (Field == null || !Reverse)
|
|
{
|
|
var searchMask = $"\'{search}%\'";
|
|
SqlParam.Add("name", search + "%");
|
|
}
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query))
|
|
return null;
|
|
|
|
strQuery = Query.Query;
|
|
if (Field != null)
|
|
strQuery = string.Format(strQuery, Field);
|
|
|
|
return await searchSqlAsync(strQuery, SqlParam, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: true);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cFasdApiSearchResultEntry>> DefaultSearchAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
List<Task<bool>> taskList = new List<Task<bool>>();
|
|
var RetVal = new List<cFasdApiSearchResultEntry>();
|
|
var SearchWithLike = this.InfrastructureConfig.HistoryDB.SearchWithLike;
|
|
if (SearchWithLike)
|
|
{
|
|
var T1 = Task.Run(() => { return searchComputerNameAsync(search, Token, requestInfo, LogDeep + 1); });
|
|
var T2 = Task.Run(() => { return searchStringAsync(search, Token, requestInfo, LogDeep + 1); });
|
|
var output = await Task.WhenAll(T1, T2);
|
|
|
|
foreach (var Entry in output[0].Values)
|
|
{
|
|
if (Entry.Count == 1)
|
|
RetVal.Add(Entry[0].Result);
|
|
else if (Entry.Count > 1)
|
|
{
|
|
foreach (var Entry2 in Entry)
|
|
{
|
|
CompleteSearchEntry(Entry2);
|
|
RetVal.Add(Entry2.Result);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var Entry in output[1].Values)
|
|
{
|
|
if (RetVal.Count >= 11)
|
|
break;
|
|
bool alreadyExists = RetVal.Any(x => x.id == Entry[0].Result.id);
|
|
if (!alreadyExists)
|
|
{
|
|
if (Entry.Count == 1)
|
|
RetVal.Add(Entry[0].Result);
|
|
else if (Entry.Count > 1)
|
|
{
|
|
foreach (var Entry2 in Entry)
|
|
{
|
|
CompleteSearchEntry(Entry2);
|
|
RetVal.Add(Entry2.Result);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var output = await searchStringAsync(search, Token, requestInfo, LogDeep + 1);
|
|
|
|
foreach (var Entry in output.Values)
|
|
{
|
|
if (Entry.Count == 1)
|
|
RetVal.Add(Entry[0].Result);
|
|
else if (Entry.Count > 1)
|
|
{
|
|
foreach (var Entry2 in Entry)
|
|
{
|
|
CompleteSearchEntry(Entry2);
|
|
RetVal.Add(Entry2.Result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal cFasdApiSearchResultExt CompleteSearchEntry(cFasdApiSearchResultExt entry)
|
|
{
|
|
var strDomain = "";
|
|
if (entry.upn_internal != null)
|
|
{
|
|
var arr1 = entry.upn_internal.Split('@');
|
|
if (arr1.Length > 1)
|
|
{
|
|
var arr2 = arr1[1].Split('.');
|
|
if (arr2.Length > 0)
|
|
strDomain = arr2[0];
|
|
}
|
|
}
|
|
|
|
var strDead = "";
|
|
if (entry.IdAgent == null)
|
|
strDead = "⚠ ";
|
|
if (!string.IsNullOrEmpty(strDomain))
|
|
{
|
|
string c = strDomain[0].ToString().ToUpperInvariant();
|
|
strDomain = c + strDomain.Remove(0, 1);
|
|
entry.Result.Name += $" (" + strDead + strDomain + ")";
|
|
entry.Result.DisplayName += $" (" + strDead + strDomain + ")";
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
public Guid? DetailedSearchStart(string search, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var cancellationToken = new CancellationTokenSource();
|
|
var _task = Task<cFasdApiSearchResultCollection>.Run(async () =>
|
|
{
|
|
return await DetailedSearchAsync(search, cancellationToken.Token, requestInfo, LogDeep);
|
|
});
|
|
|
|
var RetVal = cDataHistoryCollectorSearchTaskCache.AddTask(cancellationToken, _task);
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<cFasdApiSearchResultCollection> DetailedSearchResultAsync(Guid taskID, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var _result = await cDataHistoryCollectorSearchTaskCache.GetResultAsync(taskID);
|
|
return _result;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<cFasdApiSearchResultCollection> DetailedSearchAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var RetVal = new cFasdApiSearchResultCollection();
|
|
var SearchWithLike = this.InfrastructureConfig.HistoryDB.SearchWithLike;
|
|
if (SearchWithLike)
|
|
{
|
|
var T1 = Task.Run(() => { return searchComputerNameAsync(search, Token, requestInfo, LogDeep + 1); });
|
|
var T2 = Task.Run(() => { return searchStringAsync(search, Token, requestInfo, LogDeep + 1); });
|
|
var output = await Task.WhenAll(T1, T2);
|
|
|
|
foreach (var Entry in output[0])
|
|
{
|
|
if (!RetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new List<cFasdApiSearchResultEntry>();
|
|
RetVal.Add(Entry.Key, lst);
|
|
}
|
|
|
|
foreach (var Entry2 in Entry.Value)
|
|
lst.Add(Entry2.Result);
|
|
}
|
|
|
|
foreach (var Entry in output[1])
|
|
{
|
|
if (RetVal.Count >= 11)
|
|
break;
|
|
if (!RetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new List<cFasdApiSearchResultEntry>();
|
|
RetVal.Add(Entry.Key, lst);
|
|
foreach (var Entry2 in Entry.Value)
|
|
lst.Add(Entry2.Result);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var output = await searchStringAsync(search, Token, requestInfo, LogDeep + 1);
|
|
|
|
foreach (var Entry in output)
|
|
{
|
|
if (!RetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new List<cFasdApiSearchResultEntry>();
|
|
RetVal.Add(Entry.Key, lst);
|
|
}
|
|
|
|
foreach (var Entry2 in Entry.Value)
|
|
lst.Add(Entry2.Result);
|
|
}
|
|
}
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<cFasdApiSearchResultCollection> PhoneSearchAsync(string searchPhone, string searchName, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
Dictionary<string, List<cFasdApiSearchResultExt>>[] output;
|
|
|
|
if (string.IsNullOrEmpty(searchName))
|
|
{
|
|
var res1 = await searchStringAsync(searchPhone, Token, requestInfo, LogDeep + 1, "phone_rev", true);
|
|
output = new Dictionary<string, List<cFasdApiSearchResultExt>>[] { res1 };
|
|
}
|
|
else
|
|
{
|
|
var T1 = Task.Run(() => { return searchStringAsync(searchPhone, Token, requestInfo, LogDeep + 1, "phone_rev", true); });
|
|
var T2 = Task.Run(() => { return searchStringAsync(searchName, Token, requestInfo, LogDeep + 1, "full_name", false); });
|
|
output = await Task.WhenAll(T1, T2);
|
|
}
|
|
|
|
var _tmpRetVal = new Dictionary<string, Dictionary<Guid, cFasdApiSearchResultEntry>>();
|
|
foreach (var Entry3 in output)
|
|
foreach (var Entry in Entry3)
|
|
{
|
|
if (!_tmpRetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new Dictionary<Guid, cFasdApiSearchResultEntry>();
|
|
_tmpRetVal.Add(Entry.Key, lst);
|
|
}
|
|
|
|
foreach (var Entry2 in Entry.Value)
|
|
{
|
|
bool replace = true;
|
|
if (lst.TryGetValue(Entry2.Result.id, out var _e))
|
|
{
|
|
if (_e.Type > Entry2.Result.Type)
|
|
replace = false;
|
|
}
|
|
if (replace)
|
|
lst[Entry2.Result.id] = Entry2.Result;
|
|
}
|
|
}
|
|
|
|
var RetVal = new cFasdApiSearchResultCollection();
|
|
foreach (var Entry in _tmpRetVal)
|
|
{
|
|
var lst = Entry.Value.Values.ToList();
|
|
RetVal[Entry.Key] = lst;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
public async Task<Dictionary<string, List<cFasdApiSearchResultEntry>>> ComputerSearchByNameAsync(string Name, string Domain, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
string strQuery = null;
|
|
var SqlParams = new Dictionary<string, object>(2) { { "name", Name } };
|
|
if (string.IsNullOrWhiteSpace(Domain))
|
|
strQuery = "SearchComputerByName";
|
|
else
|
|
{
|
|
strQuery = "SearchComputerByNameAndDomain";
|
|
SqlParams.Add("domain", Domain);
|
|
}
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query))
|
|
return null;
|
|
|
|
var output = await searchSqlAsync(Query.Query, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false);
|
|
|
|
var RetVal = new Dictionary<string, List<cFasdApiSearchResultEntry>>();
|
|
foreach (var Entry in output)
|
|
{
|
|
if (!RetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new List<cFasdApiSearchResultEntry>();
|
|
RetVal.Add(Entry.Key, lst);
|
|
}
|
|
|
|
foreach (var Entry2 in Entry.Value)
|
|
lst.Add(Entry2.Result);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal async Task<Dictionary<string, List<cFasdApiSearchResultExt>>> UserSearchByEntraIdDevelopAsync(Guid AzureId, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var SqlParams = new Dictionary<string, object> { { "AzureId", AzureId } };
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SearchUserByAzureIdDevelop", out var Query))
|
|
return null;
|
|
|
|
var res = await searchSqlAsync(Query.Query, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false);
|
|
|
|
return res;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal async Task<Dictionary<string, List<cFasdApiSearchResultExt>>> UserSearchBySidsAsync(List<string> Sids, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var SqlParams = new Dictionary<string, object>(Sids.Count);
|
|
var strIn = "";
|
|
int i = 0;
|
|
foreach (var Entry in Sids)
|
|
{
|
|
var objSid = new SecurityIdentifier(Entry);
|
|
var arrB = new byte[objSid.BinaryLength];
|
|
objSid.GetBinaryForm(arrB, 0);
|
|
if (strIn != "")
|
|
strIn += ",";
|
|
strIn += "@SID" + i.ToString();
|
|
SqlParams.Add("SID" + i.ToString(), arrB);
|
|
i++;
|
|
}
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SearchUserBySid", out var Query))
|
|
return null;
|
|
|
|
var strQuery = string.Format(Query.Query, strIn);
|
|
var res = await searchSqlAsync(strQuery, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false);
|
|
|
|
return res;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<Guid?> GetUserIdFromAccountAsync(string Account, string Domain, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(Account) || string.IsNullOrEmpty(Domain))
|
|
return null;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetUserIdFromAccount", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>()
|
|
{
|
|
{ "account", Account},
|
|
{ "domain", Domain}
|
|
};
|
|
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
var res = await DataHistorySqlHelper.GetScalarResultAsync<Guid?>(Conn, Query, Params, requestInfo, Token);
|
|
|
|
return res;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<cFasdApiSearchResultCollection> UserSearchByNameAndSidsAsync(string Name, List<string> SIDs, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
Dictionary<string, List<cFasdApiSearchResultExt>> output = null;
|
|
|
|
if (SIDs != null && SIDs.Count != 0)
|
|
output = await UserSearchBySidsAsync(SIDs, Token, requestInfo, LogDeep + 1);
|
|
|
|
if (output == null || output.Count == 0)
|
|
output = await searchStringAsync(Name, Token, requestInfo, LogDeep + 1);
|
|
|
|
|
|
var RetVal = new cFasdApiSearchResultCollection();
|
|
foreach (var Entry in output)
|
|
{
|
|
if (!RetVal.TryGetValue(Entry.Key, out var lst))
|
|
{
|
|
lst = new List<cFasdApiSearchResultEntry>();
|
|
RetVal.Add(Entry.Key, lst);
|
|
}
|
|
|
|
foreach (var Entry2 in Entry.Value)
|
|
lst.Add(Entry2.Result);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool isDigits(string s)
|
|
{
|
|
if (s == null || s == "") return false;
|
|
|
|
for (int i = 0; i < s.Length; i++)
|
|
if ((s[i] ^ '0') > 9)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task<List<cDataHistoryInfoClassListEntry>> GetInfoClassListTest(enumFasdInformationClass infoClass, bool filtered, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var IsValid = false;
|
|
var RetVal = new List<cDataHistoryInfoClassListEntry>();
|
|
try
|
|
{
|
|
DoProcessUiMessage(0, $"Retrieving the {infoClass} list for testing purposes.");
|
|
|
|
var queryName = $"Get{infoClass}ListTest";
|
|
if (filtered)
|
|
queryName += "Filtered";
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement(queryName, out var Query))
|
|
return RetVal;
|
|
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return RetVal;
|
|
}
|
|
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
using (var Reader = await DataHistorySqlHelper.GetTableResultAsync(Conn, Query, null, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
IsValid = true;
|
|
if (Reader.HasRows)
|
|
{
|
|
while (await Reader.ReadAsync())
|
|
{
|
|
try
|
|
{
|
|
var Entry = new cDataHistoryInfoClassListEntry
|
|
{
|
|
Name = Reader.GetString(0),
|
|
id = Reader.GetGuid(1)
|
|
};
|
|
if (!string.IsNullOrWhiteSpace(Entry.Name) && (Entry.id != Guid.Empty))
|
|
RetVal.Add(Entry);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
IsValid = false;
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName);
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
if (!IsValid)
|
|
DoProcessUiMessage(1, $"Error while retrieving the {infoClass} list for testing purposes.");
|
|
else
|
|
DoProcessUiMessage(1, $"{RetVal.Count} {infoClass} entries found.");
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
public async Task<List<cF4sdApiSearchResultRelation>> GetUsageFromAgentData(enumFasdInformationClass infoClass, List<Guid> Ids, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null;
|
|
if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var Age2 = Age;
|
|
if (Ids.Count == 1)
|
|
Age2 = 365;
|
|
var AgentLimit = DateTime.UtcNow + TimeSpan.FromDays(-Age2);
|
|
|
|
var idInput = Ids.Select(v => new cF4sdIdentityEntry() { Id = v, Class = infoClass }).ToList();
|
|
var listIds = await getConnectorIdList(idInput, Token, requestInfo, LogDeep + 1);
|
|
|
|
if (listIds == null || listIds.Count == 0)
|
|
return null;
|
|
|
|
var lstAgentIds = new Dictionary<int, cDataHistoryUsageIdInfo>(Ids.Count);
|
|
var lstTicketIds = new List<cF4sdConnectorIds>(Ids.Count);
|
|
|
|
foreach (var Entry in listIds)
|
|
{
|
|
if (M42WpmCollector != null && infoClass == enumFasdInformationClass.User)
|
|
{
|
|
if (Entry.sid != null)
|
|
lstTicketIds.Add(Entry);
|
|
}
|
|
if (Entry.lastSeenByAgent != null && Entry.lastSeenByAgent >= AgentLimit)
|
|
{
|
|
if (Entry.agentId2 != null)
|
|
lstAgentIds[(int)Entry.agentId2] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Azure };
|
|
if (Entry.agentId != null)
|
|
lstAgentIds[(int)Entry.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.AD };
|
|
}
|
|
if (Entry.localAgentIds != null)
|
|
{
|
|
foreach (var entryLocal in Entry.localAgentIds)
|
|
{
|
|
if (entryLocal.lastSeenByAgent >= AgentLimit)
|
|
lstAgentIds[entryLocal.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Local, account = entryLocal.account, domain = "" };
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (DefaultLogger.IsDebug)
|
|
{
|
|
var _msgDebug = new List<string>()
|
|
{
|
|
$"{lstAgentIds?.Count} agent ids found by usage determination:"
|
|
};
|
|
foreach (var dbgEntry in lstAgentIds)
|
|
_msgDebug.Add($"{dbgEntry.Key}: accountType={dbgEntry.Value.AccountType}, account={dbgEntry.Value.account}, domain={dbgEntry.Value.domain}, id={dbgEntry.Value.Id}");
|
|
DefaultLogger.LogList(LogLevels.Debug, _msgDebug);
|
|
}
|
|
|
|
var taskList = new List<Task<List<cF4sdApiSearchResultRelation>>>(2);
|
|
if (lstAgentIds.Count > 0)
|
|
taskList.Add(Task.Run<List<cF4sdApiSearchResultRelation>>(async () => { return await GetUsedInfoFromAgentData(infoClass, lstAgentIds, Age, Token, requestInfo, LogDeep + 1); }));
|
|
if (lstTicketIds.Count > 0)
|
|
taskList.Add(Task.Run<List<cF4sdApiSearchResultRelation>>(async () => { return await getTicketUsage(infoClass, lstTicketIds, Age, Token, requestInfo, LogDeep + 1); }));
|
|
|
|
if (taskList.Count == 0)
|
|
return null;
|
|
|
|
var arrTask = taskList.ToArray();
|
|
var RetVal = await Task.WhenAll<List<cF4sdApiSearchResultRelation>>(arrTask);
|
|
|
|
var RetVal2 = new List<cF4sdApiSearchResultRelation>();
|
|
foreach (var Entry in RetVal)
|
|
{
|
|
if (Entry != null)
|
|
RetVal2.AddRange(Entry);
|
|
}
|
|
|
|
if (RetVal2.Count > 0)
|
|
return RetVal2;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cF4sdApiSearchResultRelation>> GetUsageFromOnlyAgentData(enumFasdInformationClass infoClass, List<Guid> Ids, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null;
|
|
if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var Age2 = Age;
|
|
if (Ids.Count == 1)
|
|
Age2 = 365;
|
|
var AgentLimit = DateTime.UtcNow + TimeSpan.FromDays(-Age2);
|
|
|
|
var idInput = Ids.Select(v => new cF4sdIdentityEntry() { Id = v, Class = infoClass }).ToList();
|
|
var listIds = await getConnectorIdList(idInput, Token, requestInfo, LogDeep + 1);
|
|
|
|
if (listIds == null || listIds.Count == 0)
|
|
return null;
|
|
|
|
var lstAgentIds = new Dictionary<int, cDataHistoryUsageIdInfo>(Ids.Count);
|
|
|
|
foreach (var Entry in listIds)
|
|
{
|
|
if (Entry.lastSeenByAgent != null && Entry.lastSeenByAgent >= AgentLimit)
|
|
{
|
|
if (Entry.agentId2 != null)
|
|
lstAgentIds[(int)Entry.agentId2] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Azure };
|
|
if (Entry.agentId != null)
|
|
lstAgentIds[(int)Entry.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.AD };
|
|
}
|
|
if (Entry.localAgentIds != null)
|
|
{
|
|
foreach (var entryLocal in Entry.localAgentIds)
|
|
{
|
|
if (entryLocal.lastSeenByAgent >= AgentLimit)
|
|
lstAgentIds[entryLocal.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Local, account = entryLocal.account, domain = "" };
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (DefaultLogger.IsDebug)
|
|
{
|
|
var _msgDebug = new List<string>()
|
|
{
|
|
$"{lstAgentIds?.Count} agent ids found by usage determination:"
|
|
};
|
|
foreach (var dbgEntry in lstAgentIds)
|
|
_msgDebug.Add($"{dbgEntry.Key}: accountType={dbgEntry.Value.AccountType}, account={dbgEntry.Value.account}, domain={dbgEntry.Value.domain}, id={dbgEntry.Value.Id}");
|
|
DefaultLogger.LogList(LogLevels.Debug, _msgDebug);
|
|
}
|
|
|
|
var taskList = new List<Task<List<cF4sdApiSearchResultRelation>>>(2);
|
|
if (lstAgentIds.Count > 0)
|
|
taskList.Add(Task.Run<List<cF4sdApiSearchResultRelation>>(async () => { return await GetUsedInfoFromAgentData(infoClass, lstAgentIds, Age, Token, requestInfo, LogDeep + 1); }));
|
|
|
|
if (taskList.Count == 0)
|
|
return null;
|
|
|
|
var arrTask = taskList.ToArray();
|
|
var RetVal = await Task.WhenAll<List<cF4sdApiSearchResultRelation>>(arrTask);
|
|
|
|
var RetVal2 = new List<cF4sdApiSearchResultRelation>();
|
|
foreach (var Entry in RetVal)
|
|
{
|
|
if (Entry != null)
|
|
RetVal2.AddRange(Entry);
|
|
}
|
|
|
|
if (RetVal2.Count > 0)
|
|
return RetVal2;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<List<cF4sdApiSearchResultRelation>> getTicketUsage(enumFasdInformationClass infoClass, List<cF4sdConnectorIds> lstTicketIds, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
return await M42WpmCollector?.getTicketUsage(lstTicketIds, Token, requestInfo, LogDeep);
|
|
}
|
|
|
|
private enumFasdInformationClass getResultClassForAgentUsage(enumFasdInformationClass infoClass)
|
|
{
|
|
switch (infoClass)
|
|
{
|
|
case enumFasdInformationClass.User:
|
|
return enumFasdInformationClass.Computer;
|
|
case enumFasdInformationClass.Computer:
|
|
return enumFasdInformationClass.User;
|
|
}
|
|
return enumFasdInformationClass.Unknown;
|
|
}
|
|
|
|
private async Task<List<cF4sdApiSearchResultRelation>> GetUsedInfoFromAgentData(enumFasdInformationClass infoClass, Dictionary<int, cDataHistoryUsageIdInfo> AgentIdInfos, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var lstTasks = new List<Task<List<cF4sdApiSearchResultRelation>>>(AgentIdInfos.Count);
|
|
foreach (var AgentId in AgentIdInfos)
|
|
lstTasks.Add(GetSingleUsedInfoFromAgentData(infoClass, AgentId.Value, AgentId.Key, Age, Token, requestInfo, LogDeep + 1));
|
|
|
|
var res = await Task.WhenAll(lstTasks.ToArray());
|
|
|
|
var RetVal = new List<cF4sdApiSearchResultRelation>();
|
|
double _sumDuration = 0;
|
|
for (int i = 0; i < res.Length; i++)
|
|
{
|
|
var Entry = res[i];
|
|
if (Entry == null)
|
|
continue;
|
|
|
|
foreach (var Entry2 in Entry)
|
|
{
|
|
if (Entry2 == null)
|
|
continue;
|
|
RetVal.Add(Entry2);
|
|
_sumDuration += Entry2.UsingLevel;
|
|
}
|
|
}
|
|
|
|
if (_sumDuration == 0)
|
|
_sumDuration = 1;
|
|
|
|
foreach (var Entry in RetVal)
|
|
Entry.UsingLevel /= _sumDuration;
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private async Task<List<cF4sdApiSearchResultRelation>> GetSingleUsedInfoFromAgentData(enumFasdInformationClass infoClass, cDataHistoryUsageIdInfo Id, int AgentId, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var _usageData = await F4sdAgent.GetSingleUsedInfoFromAgentData(infoClass, AgentId, Age, Token, requestInfo, LogDeep + 1);
|
|
if (_usageData == null)
|
|
return null;
|
|
|
|
var _infoClass = getResultClassForAgentUsage(infoClass);
|
|
|
|
var RetVal = new List<cF4sdApiSearchResultRelation>();
|
|
foreach (var _entry in _usageData)
|
|
{
|
|
var deviceInfo = await GetMainInfoFromAgentId(_infoClass, _entry.id, requestInfo, LogDeep + 1, Token);
|
|
if (deviceInfo == null && infoClass == enumFasdInformationClass.Computer && _infoClass == enumFasdInformationClass.User && InfrastructureConfig.ClientAgent?.localAccountAssignments != null)
|
|
deviceInfo = await GetLocalUserInfoFromAgentId(_entry.id, requestInfo, LogDeep + 1, Token);
|
|
|
|
if (deviceInfo != null)
|
|
{
|
|
var _at = enumAccountType.unknow;
|
|
if (infoClass == enumFasdInformationClass.User)
|
|
_at = Id.AccountType;
|
|
deviceInfo.Identities?.Add(new cF4sdIdentityEntry() { Class = infoClass, Id = Id.Id, agentId = AgentId, AccountType = _at });
|
|
deviceInfo.UsingLevel = (double)_entry.duration;
|
|
deviceInfo.LastUsed = _entry.lastEvent;
|
|
if (deviceInfo.Infos == null)
|
|
deviceInfo.Infos = new Dictionary<string, string>();
|
|
if (!deviceInfo.Infos.ContainsKey("UserAccountType"))
|
|
deviceInfo.Infos.Add("UserAccountType", Id.AccountType.ToString());
|
|
if (infoClass == enumFasdInformationClass.User)
|
|
{
|
|
if (!string.IsNullOrEmpty(Id.account))
|
|
deviceInfo.Infos.Add("UserAccount", Id.account);
|
|
if (!string.IsNullOrEmpty(Id.domain))
|
|
deviceInfo.Infos.Add("UserDommain", Id.domain);
|
|
}
|
|
RetVal.Add(deviceInfo);
|
|
|
|
if (DefaultLogger.IsDebug)
|
|
deviceInfo.LogIt(LogLevels.Debug);
|
|
}
|
|
}
|
|
|
|
if (RetVal.Count > 0)
|
|
return RetVal;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<cF4sdApiSearchResultRelation> GetMainInfoFromAgentId(enumFasdInformationClass infoClass, int agentID, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cF4sdApiSearchResultRelation SearchEntry = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"Get{infoClass}InfoFromAgentId", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "id", agentID } };
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
using (var ConnMain = new cDbConnection(mainDbConnection))
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(ConnMain, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Max<int>();
|
|
var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Min<int>();
|
|
|
|
if (await Reader.ReadAsync())
|
|
{
|
|
try
|
|
{
|
|
var Id = Reader.GetGuid(0);
|
|
var Name = Reader.GetString(1);
|
|
var Status = enumF4sdSearchResultStatus.Unknown;
|
|
if (!Reader.IsDBNull(2))
|
|
{
|
|
var intStatus = Reader.GetInt32(2);
|
|
if (intStatus <= maxStateVal && intStatus >= minStateVal)
|
|
Status = (enumF4sdSearchResultStatus)intStatus;
|
|
}
|
|
|
|
var account = Reader.IsDBNull(3) ? null : Reader.GetString(3);
|
|
var domain = Reader.IsDBNull(4) ? null : Reader.GetString(4);
|
|
var IsAzure = Reader.GetInt32(5);
|
|
var AccountType = enumAccountType.unknow;
|
|
if (infoClass == enumFasdInformationClass.User)
|
|
{
|
|
if (IsAzure == 1)
|
|
AccountType = enumAccountType.Azure;
|
|
else
|
|
AccountType = enumAccountType.AD;
|
|
}
|
|
|
|
var RetVal = new cF4sdApiSearchResultRelation()
|
|
{
|
|
Type = cFasdApiSearchResultEntry.getSearchClass(infoClass),
|
|
id = Id,
|
|
Name = Name,
|
|
DisplayName = Name,
|
|
Status = Status,
|
|
LastUsed = DateTime.UtcNow,
|
|
UsingLevel = 1.0,
|
|
};
|
|
|
|
RetVal.Identities = new cF4sdIdentityList { new cF4sdIdentityEntry() { Class = infoClass, Id = RetVal.id, agentId = agentID, AccountType = AccountType } };
|
|
|
|
RetVal.Infos = new Dictionary<string, string>
|
|
{
|
|
["account"] = account,
|
|
["domain"] = domain
|
|
};
|
|
if (infoClass == enumFasdInformationClass.User)
|
|
RetVal.Infos["UserAccountType"] = AccountType.ToString();
|
|
|
|
if (SearchEntry != null)
|
|
{
|
|
RetVal.UsingLevel = SearchEntry.UsingLevel;
|
|
RetVal.LastUsed = SearchEntry.LastUsed;
|
|
if (SearchEntry.Identities != null)
|
|
RetVal.Identities?.AddRange(SearchEntry.Identities);
|
|
}
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<cF4sdApiSearchResultRelation> GetLocalUserInfoFromAgentId(int agentID, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug)
|
|
{
|
|
CM = MethodBase.GetCurrentMethod();
|
|
LogMethodBegin(CM);
|
|
LogEntry($"agentId={agentID}", LogLevels.Debug);
|
|
}
|
|
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"GetLocalUserInfoFromAgentId", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "id", agentID } };
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
|
|
using (var ConnMain = new cDbConnection(mainDbConnection))
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(ConnMain, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Max<int>();
|
|
var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast<int>().Min<int>();
|
|
|
|
if (await Reader.ReadAsync())
|
|
{
|
|
try
|
|
{
|
|
var Id = Reader.GetGuid(0);
|
|
var Name = Reader.GetString(1);
|
|
var Status = enumF4sdSearchResultStatus.Unknown;
|
|
if (!Reader.IsDBNull(2))
|
|
{
|
|
var intStatus = Reader.GetInt32(2);
|
|
if (intStatus <= maxStateVal && intStatus >= minStateVal)
|
|
Status = (enumF4sdSearchResultStatus)intStatus;
|
|
}
|
|
|
|
var account = Reader.IsDBNull(3) ? null : Reader.GetString(3);
|
|
|
|
var RetVal = new cF4sdApiSearchResultRelation()
|
|
{
|
|
Type = enumF4sdSearchResultClass.User,
|
|
id = Id,
|
|
Name = Name,
|
|
DisplayName = Name,
|
|
Status = Status,
|
|
LastUsed = DateTime.UtcNow,
|
|
UsingLevel = 1.0,
|
|
};
|
|
|
|
RetVal.Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Id, agentId = agentID, AccountType = enumAccountType.Local } };
|
|
|
|
RetVal.Infos = new Dictionary<string, string>
|
|
{
|
|
["account"] = account,
|
|
["UserAccountType"] = "Local"
|
|
};
|
|
|
|
LogEntry($"Local account info found: id={Id}, account={account} ", LogLevels.Debug);
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> GetTableResultsMainDb(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
Task<List<cF4SDHealthCardRawData.cHealthCardTable>>[] tasks = new Task<List<cF4SDHealthCardRawData.cHealthCardTable>>[Tables.Count];
|
|
for (int i = 0; i < Tables.Count; i++)
|
|
{
|
|
tasks[i] = getTableRawData(Tables[i], Identities, RefTime, MaxAge, instantly, IsSecondCall, Token, requestInfo, LogDeep + 1);
|
|
}
|
|
|
|
var Results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
|
|
var RetVal = new List<cF4SDHealthCardRawData.cHealthCardTable>();
|
|
foreach (var Entry in Results)
|
|
{
|
|
if (Entry == null)
|
|
continue;
|
|
RetVal.AddRange(Entry);
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<cF4SDHealthCardRawData.cHealthCardDetailsTable> GetDetailsTableSingleResultMainDb(cDataHistoryConfigTable Table, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
var Cols = new List<string>();
|
|
foreach (var col in Table.Columns.Values)
|
|
{
|
|
Cols.Add(col.Name);
|
|
if (col.SqlTypeBin != null)
|
|
Cols.Add(col.Name + "_bin");
|
|
}
|
|
|
|
if (!Identities.TryGetValue(Table.ParentCluster.InformationClass, out var _ids))
|
|
return null;
|
|
|
|
var _valId = _ids.Id;
|
|
var _rowId = Table.KeyColumns.First()?.SourceName;
|
|
var _rowTime = Table.EventTimeColumn?.SourceName;
|
|
|
|
if (string.IsNullOrEmpty(_rowId) || string.IsNullOrEmpty(_rowTime))
|
|
return null;
|
|
|
|
var Filter = new Dictionary<string, object>(1) { { _rowId, _valId } };
|
|
using (var _reader = await DataHistorySqlHelper.getDbReaderDetailTable(Conn, Table.SourceName, Filter, _rowTime, MaxAge, Token))
|
|
{
|
|
if (_reader == null)
|
|
return null;
|
|
|
|
if (_reader.HasRows)
|
|
{
|
|
var retVal = new cF4SDHealthCardRawData.cHealthCardDetailsTable
|
|
{
|
|
Name = Table.Name,
|
|
Columns = Table.Columns.Values.Select(v => v.Name).ToList(),
|
|
Values = new Dictionary<int, List<object[]>>()
|
|
};
|
|
|
|
var _colInfos = Table.Columns.Values.ToList();
|
|
Dictionary<string, int> _dic = new Dictionary<string, int>(Table.Columns.Count);
|
|
var _idx = 0;
|
|
foreach (var _colInfo in Table.Columns.Values)
|
|
{
|
|
_dic[_colInfo.SourceName] = _idx;
|
|
_idx++;
|
|
}
|
|
|
|
var _arrIdxAssign = Enumerable.Repeat<int>(-1, Table.Columns.Count).ToArray();
|
|
for (int i = 0; i < _reader.FieldCount; i++)
|
|
{
|
|
var _n = _reader.GetName(i);
|
|
if (_dic.TryGetValue(_n, out var _ix))
|
|
_arrIdxAssign[_ix] = i;
|
|
}
|
|
|
|
while (await _reader.ReadAsync(Token))
|
|
{
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
var _row = Enumerable.Repeat<object>(null, Table.Columns.Count).ToArray();
|
|
|
|
DateTime? EventTime = null;
|
|
for (int i = 0; i < Table.Columns.Count; i++)
|
|
{
|
|
var _n = _arrIdxAssign[i];
|
|
if (_n >= 0)
|
|
{
|
|
var obj = _reader.GetValue(_n);
|
|
var _obj2 = DataHistorySqlHelper.GetSqlDataValueFromHistoryType(obj, _colInfos[i].ValueType, _colInfos[i].Cardinal);
|
|
_row[i] = _obj2[0];
|
|
if (_reader.GetName(_n) == Table.EventTimeColumn.SourceName)
|
|
if (_row[i] is DateTime dt)
|
|
EventTime = dt;
|
|
}
|
|
}
|
|
|
|
if (EventTime != null)
|
|
{
|
|
var indexDay = cDataHistoryCollector.getDayIndex((DateTime)EventTime, RefTime, MaxAge + 1);
|
|
if (!retVal.Values.TryGetValue(indexDay, out var entryDay))
|
|
{
|
|
entryDay = new List<object[]>();
|
|
retVal.Values.Add(indexDay, entryDay);
|
|
}
|
|
entryDay.Add(_row);
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
public async Task<List<cF4SDHealthCardRawData.cHealthCardDetailsTable>> GetDetailsTableResultsMainDb(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var _lstTsk = new List<Task<cF4SDHealthCardRawData.cHealthCardDetailsTable>>(Tables.Count);
|
|
foreach (var _table in Tables)
|
|
_lstTsk.Add(GetDetailsTableSingleResultMainDb(_table, Identities, RefTime, MaxAge, Token));
|
|
|
|
var arrRet = await Task.WhenAll(_lstTsk);
|
|
|
|
return arrRet.Where(v => v != null).ToList();
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public static void CorrectUsage(cDataHistoryCollector Collector, cF4SDHealthCardRawData data, List<Int64> Usage)
|
|
{
|
|
try
|
|
{
|
|
if (data?.Tables == null || Usage == null)
|
|
return;
|
|
|
|
foreach (var _table in data.Tables.Values)
|
|
{
|
|
if (_table.IsStatic)
|
|
continue;
|
|
|
|
if (Collector.ClusterConfig.Tables.TryGetValue(_table.Name, out var _configTable) && _configTable.Type != eDataHistoryTableType.History)
|
|
continue;
|
|
|
|
foreach (var _column in _table.Columns.Values)
|
|
{
|
|
if (_column.Values == null || _column.Values.Count == 0)
|
|
continue;
|
|
int _l = 0;
|
|
if (_table.StartingIndex < 0)
|
|
_l = Math.Min(_column.Values.Count + _table.StartingIndex, Usage.Count);
|
|
else
|
|
_l = Math.Min(_column.Values.Count, Usage.Count - _table.StartingIndex);
|
|
|
|
for (int i = 0; i < _l; i++)
|
|
{
|
|
int i1 = 0;
|
|
int i2 = 0;
|
|
if (_table.StartingIndex < 0)
|
|
{
|
|
i1 = i;
|
|
i2 = i - _table.StartingIndex;
|
|
}
|
|
else
|
|
{
|
|
i1 = i + _table.StartingIndex;
|
|
i2 = i;
|
|
}
|
|
|
|
if (Usage[i1] <= 0)
|
|
_column.Values[i2] = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
public async Task<cF4SDHealthCardRawData> GetTableResults(List<string> Tables, List<cF4sdIdentityEntry> Identities, DateTime RefTime, int MaxAge, bool instantly, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var _tables = new List<string>();
|
|
foreach (var t in Tables)
|
|
{
|
|
if (!_tables.Contains(t))
|
|
_tables.Add(t);
|
|
}
|
|
|
|
var Ids = await getConntectorIds(Identities, Token, requestInfo, LogDeep + 1).ConfigureAwait(false);
|
|
|
|
var dicVirtualTables = new Dictionary<enumDataHistoryOrigin, List<cDataHistoryConfigTable>>();
|
|
var lstDbTables = new List<cDataHistoryConfigTable>();
|
|
|
|
foreach (var strTable in _tables)
|
|
{
|
|
var tableConfig = this.GetTableFromName(strTable);
|
|
if (tableConfig == null)
|
|
{
|
|
LogEntry($"The table '{strTable}' could not be found in the data clusters definitions", LogLevels.Warning);
|
|
continue;
|
|
}
|
|
|
|
if (lstDbTables.Contains(tableConfig))
|
|
continue;
|
|
|
|
if (tableConfig.Type == eDataHistoryTableType.Events || tableConfig.Type == eDataHistoryTableType.Selection)
|
|
continue;
|
|
|
|
if (tableConfig.IsVirtual)
|
|
{
|
|
if (Connectors.ContainsKey(tableConfig.ParentCluster.Origin))
|
|
{
|
|
if (!dicVirtualTables.TryGetValue(tableConfig.ParentCluster.Origin, out var lstTables))
|
|
{
|
|
lstTables = new List<cDataHistoryConfigTable>();
|
|
dicVirtualTables.Add(tableConfig.ParentCluster.Origin, lstTables);
|
|
}
|
|
if (!lstTables.Contains(tableConfig))
|
|
lstTables.Add(tableConfig);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lstDbTables.Add(tableConfig);
|
|
}
|
|
|
|
}
|
|
|
|
var c = dicVirtualTables.Count;
|
|
var idx = 0;
|
|
if (lstDbTables.Count > 0)
|
|
{
|
|
c++;
|
|
idx = 1;
|
|
}
|
|
|
|
Task<List<cF4SDHealthCardRawData.cHealthCardTable>>[] tasks = new Task<List<cF4SDHealthCardRawData.cHealthCardTable>>[c];
|
|
if (lstDbTables.Count > 0)
|
|
tasks[0] = GetTableResultsMainDb(lstDbTables, Ids, RefTime, MaxAge, instantly, false, Token, requestInfo, LogDeep + 1);
|
|
|
|
foreach (var Entry in dicVirtualTables)
|
|
{
|
|
var C = Connectors[Entry.Key];
|
|
tasks[idx] = Task.Run(() => { return C.GetTableResultsVirtualAsync(Entry.Value, Ids, RefTime, MaxAge, instantly, null, Token, requestInfo, LogDeep + 1); });
|
|
idx++;
|
|
}
|
|
|
|
var Results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
|
|
var RetVal = new cF4SDHealthCardRawData();
|
|
var IsIncompleted = false;
|
|
foreach (var Entry in Results)
|
|
{
|
|
if (Entry == null)
|
|
continue;
|
|
foreach (var subEntry in Entry)
|
|
if (!RetVal.Tables.ContainsKey(subEntry.Name))
|
|
{
|
|
RetVal.Tables.Add(subEntry.Name, subEntry);
|
|
if (instantly)
|
|
subEntry.IsIncomplete = false;
|
|
else
|
|
IsIncompleted |= subEntry.IsIncomplete;
|
|
}
|
|
}
|
|
|
|
// detect the usage information
|
|
List<Int64> _usage = null;
|
|
if (RetVal.Tables.TryGetValue("agnt-computer-event-numerical", out var usageTable))
|
|
{
|
|
cF4SDHealthCardRawData.cHealthCardTableColumn usageCol1;
|
|
if (!usageTable.Columns.TryGetValue("DeviceActivity", out usageCol1))
|
|
usageCol1 = null;
|
|
|
|
cF4SDHealthCardRawData.cHealthCardTableColumn usageCol2;
|
|
if (!usageTable.Columns.TryGetValue("UserActivity", out usageCol2))
|
|
usageCol2 = null;
|
|
|
|
if (usageCol1 == null)
|
|
{
|
|
usageCol1 = usageCol2;
|
|
usageCol2 = null;
|
|
}
|
|
|
|
|
|
if (usageCol1?.Values != null)
|
|
{
|
|
var _l = usageCol1.Values.Count;
|
|
if (usageCol2?.Values != null)
|
|
_l = Math.Max(_l, usageCol2.Values.Count);
|
|
|
|
_usage = new List<Int64>(_l);
|
|
foreach (var _entry in usageCol1.Values)
|
|
{
|
|
Int64 _v = 0;
|
|
try
|
|
{
|
|
_v = Convert.ToInt64(_entry);
|
|
}
|
|
catch { }
|
|
_usage.Add(_v);
|
|
}
|
|
|
|
if (usageCol2?.Values != null)
|
|
{
|
|
var _i = 0;
|
|
foreach (var _entry in usageCol1.Values)
|
|
{
|
|
Int64 _v = 0;
|
|
try
|
|
{
|
|
_v = Convert.ToInt64(_entry);
|
|
}
|
|
catch { }
|
|
if (_i < _usage.Count)
|
|
_usage[_i] = Math.Max(_usage[_i], _v);
|
|
else
|
|
_usage.Add(_v);
|
|
_i++;
|
|
}
|
|
|
|
}
|
|
CorrectUsage(this, RetVal, _usage);
|
|
}
|
|
}
|
|
|
|
if (IsIncompleted && !instantly)
|
|
{
|
|
RetVal.Id = Guid.NewGuid();
|
|
foreach (var Entry in dicVirtualTables)
|
|
{
|
|
var C = Connectors[Entry.Key];
|
|
C.AddTableResultVirtualSuccessorTasks(Entry.Value, Ids, RefTime, MaxAge, _usage, RetVal.Id, requestInfo, LogDeep + 1);
|
|
}
|
|
AddTableResultSuccessorTasks(lstDbTables, Ids, RefTime, MaxAge, _usage, RetVal.Id, requestInfo, LogDeep + 1);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public cDataHistoryConfigTable GetTableFromName(string Name)
|
|
{
|
|
try
|
|
{
|
|
if (ClusterConfig.AlternateTableNames.TryGetValue(Name, out var _aln))
|
|
Name = _aln;
|
|
if (ClusterConfig.Tables.TryGetValue(Name, out var _retVal))
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cF4SDHealthCardRawData.cHealthCardDetailsTable>> GetDetailsTableResultsAsync(List<string> Tables, List<cF4sdIdentityEntry> Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var Ids = await getConntectorIds(Identities, Token, requestInfo, LogDeep + 1).ConfigureAwait(false);
|
|
|
|
var dicVirtualTables = new Dictionary<enumDataHistoryOrigin, List<cDataHistoryConfigTable>>();
|
|
var lstDbTables = new List<cDataHistoryConfigTable>();
|
|
foreach (var strTable in Tables)
|
|
{
|
|
var tableConfig = GetTableFromName(strTable);
|
|
if (tableConfig == null)
|
|
{
|
|
LogEntry($"The table '{strTable}' could not be found in the data clusters definitions", LogLevels.Warning);
|
|
continue;
|
|
}
|
|
|
|
if (lstDbTables.Contains(tableConfig))
|
|
continue;
|
|
|
|
if (tableConfig.Type != eDataHistoryTableType.Events && tableConfig.Type != eDataHistoryTableType.StaticDetails)
|
|
continue;
|
|
|
|
if (tableConfig.IsVirtual)
|
|
{
|
|
if (Connectors.ContainsKey(tableConfig.ParentCluster.Origin))
|
|
{
|
|
if (!dicVirtualTables.TryGetValue(tableConfig.ParentCluster.Origin, out var lstTables))
|
|
{
|
|
lstTables = new List<cDataHistoryConfigTable>();
|
|
dicVirtualTables.Add(tableConfig.ParentCluster.Origin, lstTables);
|
|
}
|
|
lstTables.Add(tableConfig);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lstDbTables.Add(tableConfig);
|
|
}
|
|
|
|
}
|
|
|
|
var c = dicVirtualTables.Count;
|
|
var idx = 0;
|
|
if (lstDbTables.Count > 0)
|
|
{
|
|
c++;
|
|
idx = 1;
|
|
}
|
|
|
|
Task<List<cF4SDHealthCardRawData.cHealthCardDetailsTable>>[] tasks = new Task<List<cF4SDHealthCardRawData.cHealthCardDetailsTable>>[c];
|
|
if (lstDbTables.Count > 0)
|
|
tasks[0] = GetDetailsTableResultsMainDb(lstDbTables, Ids, RefTime, MaxAge, Token, requestInfo, LogDeep + 1);
|
|
|
|
foreach (var Entry in dicVirtualTables)
|
|
{
|
|
var C = Connectors[Entry.Key];
|
|
tasks[idx] = C.GetDetailsTableResultsVirtualAsync(Entry.Value, Ids, RefTime, MaxAge, Token, requestInfo, LogDeep + 1);
|
|
idx++;
|
|
}
|
|
|
|
var Results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
|
|
var RetVal = new List<cF4SDHealthCardRawData.cHealthCardDetailsTable>();
|
|
foreach (var Entry in Results)
|
|
{
|
|
if (Entry == null)
|
|
continue;
|
|
RetVal.AddRange(Entry);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<Int64> GetSelectionTableResultCountAsync(string Table, List<cF4sdIdentityEntry> Identities, string search, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List<string> filterParams = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (!ClusterConfig.Tables.TryGetValue(Table, out var _table))
|
|
{
|
|
LogEntry($"Could not find table '{Table}' in table list.", LogLevels.Warning);
|
|
return -1;
|
|
}
|
|
|
|
if (!this.Connectors.TryGetValue(_table.ParentCluster.Origin, out var _module))
|
|
{
|
|
LogEntry($"Could not find module '{_table.ParentCluster.Origin}' in module list.", LogLevels.Warning);
|
|
return -1;
|
|
}
|
|
|
|
var _retVal = await _module.GetSelectionTableResultCountAsync(_table, Identities, search, requestInfo, Token, resetFilter, filterParams);
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public async Task<cF4SDHealthCardRawData.cHealthCardTable> GetSelectionTableResultAsync(string Table, List<cF4sdIdentityEntry> Identities, string search, int PageSize, int Page, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List<string> filterParams = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (!ClusterConfig.Tables.TryGetValue(Table, out var _table))
|
|
return null;
|
|
|
|
if (!this.Connectors.TryGetValue(_table.ParentCluster.Origin, out var _module))
|
|
return null;
|
|
|
|
var _retVal = await _module.GetSelectionTableResultAsync(_table, Identities, search, PageSize, Page, requestInfo, Token, resetFilter, filterParams);
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> GetCachedHistoricTable(cDataHistoryConfigTable tableConfig, Dictionary<string, object> Filter, DateTime RefTime, int MaxAge, cDataHistoryScanTiming Timing, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
using (var _reader = await DataHistorySqlHelper.getDbReaderHistoricTable(Conn, tableConfig.SourceName, Filter, RefTime + TimeSpan.FromDays(-MaxAge - 1), Token))
|
|
{
|
|
if (_reader == null)
|
|
return null;
|
|
|
|
if (_reader.FieldCount > 2)
|
|
{
|
|
var retVal = new cF4SDHealthCardRawData.cHealthCardTable()
|
|
{
|
|
Name = tableConfig.Name,
|
|
InformationClass = tableConfig.ParentCluster.InformationClass,
|
|
Origin = tableConfig.ParentCluster.Origin,
|
|
StartingIndex = int.MaxValue,
|
|
IsStatic = false,
|
|
TableType = tableConfig.Type
|
|
};
|
|
var maxIndex = int.MinValue;
|
|
|
|
var Cols = new Dictionary<int, cF4SDHealthCardRawData.cHealthCardTableColumn>(_reader.FieldCount);
|
|
for (int i = 0; i < _reader.FieldCount; i++)
|
|
{
|
|
var _propName = _reader.GetName(i);
|
|
if (tableConfig.Columns.TryGetValue(_propName, out var _col))
|
|
{
|
|
var _ci = new cF4SDHealthCardRawData.cHealthCardTableColumn(retVal) { ColumnName = _col.Name };
|
|
Cols[i] = _ci;
|
|
retVal.Columns[_col.Name] = _ci;
|
|
}
|
|
if (tableConfig.Columns.TryGetValue(_propName + "_bin", out var _col2))
|
|
{
|
|
var _ci = new cF4SDHealthCardRawData.cHealthCardTableColumn(retVal) { ColumnName = _col.Name + "_bin" };
|
|
Cols[i] = _ci;
|
|
retVal.Columns[_col.Name + "_bin"] = _ci;
|
|
}
|
|
}
|
|
|
|
|
|
var TimeFrames = new Dictionary<int, KeyValuePair<DateTime, DateTime>>();
|
|
|
|
if (_reader.HasRows)
|
|
{
|
|
while (await _reader.ReadAsync())
|
|
{
|
|
DateTime timeFrom = _reader.GetDateTime(0);
|
|
DateTime timeTo = _reader.GetDateTime(1);
|
|
|
|
var indexTimeFrame = cScanTimeInfo.GetScanIntervalIndex(RefTime, timeFrom, timeTo, Timing);
|
|
|
|
if (maxIndex == int.MinValue)
|
|
{
|
|
maxIndex = indexTimeFrame - 1;
|
|
}
|
|
|
|
if (TimeFrames.ContainsKey(indexTimeFrame))
|
|
continue;
|
|
TimeFrames.Add(indexTimeFrame, new KeyValuePair<DateTime, DateTime>(timeFrom, timeTo));
|
|
|
|
foreach (var entryCol in Cols)
|
|
{
|
|
var colInfo = entryCol.Value;
|
|
var colIndex = entryCol.Key;
|
|
var objValue = _reader[colIndex];
|
|
objValue = objValue == DBNull.Value ? null : objValue;
|
|
|
|
if (Cols.TryGetValue(colIndex, out var _col))
|
|
{
|
|
if (indexTimeFrame > maxIndex)
|
|
{
|
|
for (int j = maxIndex + 1; j < indexTimeFrame; j++)
|
|
_col.Values.Add(null);
|
|
_col.Values.Add(objValue);
|
|
}
|
|
else if (indexTimeFrame < retVal.StartingIndex)
|
|
{
|
|
for (int j = indexTimeFrame + 1; j < retVal.StartingIndex; j++)
|
|
_col.Values.Insert(0, null);
|
|
_col.Values.Insert(0, objValue);
|
|
}
|
|
else
|
|
{
|
|
_col.Values[indexTimeFrame - retVal.StartingIndex] = objValue;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
retVal.StartingIndex = Math.Min(retVal.StartingIndex, indexTimeFrame);
|
|
maxIndex = Math.Max(maxIndex, indexTimeFrame);
|
|
}
|
|
}
|
|
|
|
if (maxIndex >= retVal.StartingIndex)
|
|
{
|
|
retVal.TimeFrames = new DateTime[maxIndex - retVal.StartingIndex + 1, 2];
|
|
|
|
for (int i = retVal.StartingIndex; i <= maxIndex; i++)
|
|
{
|
|
if (TimeFrames.TryGetValue(i, out var _tf))
|
|
{
|
|
retVal.TimeFrames[i - retVal.StartingIndex, 0] = _tf.Key;
|
|
retVal.TimeFrames[i - retVal.StartingIndex, 1] = _tf.Value;
|
|
}
|
|
else
|
|
{
|
|
retVal.TimeFrames[i - retVal.StartingIndex, 0] = DateTime.MinValue;
|
|
retVal.TimeFrames[i - retVal.StartingIndex, 1] = DateTime.MinValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return new List<cF4SDHealthCardRawData.cHealthCardTable>() { retVal };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> getTableRawDataStatic(DbDataReader _reader, cDataHistoryConfigTable tableConfig, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (await _reader.ReadAsync(Token))
|
|
{
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
var objValues = new object[_reader.FieldCount];
|
|
var n = _reader.GetValues(objValues);
|
|
var ColNames = new string[_reader.FieldCount];
|
|
if (ColNames.Length == _reader.FieldCount)
|
|
{
|
|
var RetVal = new cF4SDHealthCardRawData.cHealthCardTable();
|
|
for (int i = 0; i < _reader.FieldCount; i++)
|
|
{
|
|
var objVal = objValues[i] == DBNull.Value ? null : objValues[i];
|
|
var strCol = _reader.GetName(i);
|
|
RetVal.Columns.Add(strCol, new cF4SDHealthCardRawData.cHealthCardTableColumn(RetVal) { ColumnName = strCol, Values = new List<object>() { objVal } });
|
|
}
|
|
|
|
RetVal.Name = tableConfig.Name;
|
|
RetVal.InformationClass = tableConfig.ParentCluster.InformationClass;
|
|
RetVal.Origin = tableConfig.ParentCluster.Origin;
|
|
RetVal.IsStatic = tableConfig.Type == eDataHistoryTableType.Static;
|
|
RetVal.TableType = tableConfig.Type;
|
|
|
|
return new List<cF4SDHealthCardRawData.cHealthCardTable>() { RetVal };
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> getTableRawDataHistoric(DbDataReader _reader, cDataHistoryConfigTable tableConfig, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token)
|
|
{
|
|
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (tableConfig.EventTimeColumn == null)
|
|
return null;
|
|
|
|
cHistoricAggregationEntry[] arrColAgg = new cHistoricAggregationEntry[tableConfig.Columns.Count];
|
|
var i = 0;
|
|
foreach (var col in tableConfig.Columns.Values)
|
|
{
|
|
if (col is cDataHistoryConfigColumn _colInfo)
|
|
arrColAgg[i] = new cHistoricAggregationEntry(_colInfo, MaxAge + 1, null);
|
|
i++;
|
|
}
|
|
|
|
var _colInfos = tableConfig.Columns.Values.ToList();
|
|
Dictionary<string, int> _dic = new Dictionary<string, int>(tableConfig.Columns.Count);
|
|
var _idx = 0;
|
|
foreach (var _colInfo in tableConfig.Columns.Values)
|
|
{
|
|
_dic[_colInfo.SourceName] = _idx;
|
|
_idx++;
|
|
}
|
|
|
|
var _idxTimeCol = -1;
|
|
var _arrIdxAssign = Enumerable.Repeat<int>(-1, tableConfig.Columns.Count).ToArray();
|
|
for (i = 0; i < _reader.FieldCount; i++)
|
|
{
|
|
var _n = _reader.GetName(i);
|
|
if (_dic.TryGetValue(_n, out var _ix))
|
|
_arrIdxAssign[_ix] = i;
|
|
if (_n == tableConfig.EventTimeColumn.SourceName)
|
|
_idxTimeCol = i;
|
|
}
|
|
if (_idxTimeCol < 0)
|
|
return null;
|
|
|
|
|
|
while (await _reader.ReadAsync(Token))
|
|
{
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
var _eventTime = _reader.GetDateTime(_idxTimeCol);
|
|
for (i = 0; i < tableConfig.Columns.Count; i++)
|
|
{
|
|
var _n = _arrIdxAssign[i];
|
|
if (_n >= 0)
|
|
{
|
|
var obj = _reader.GetValue(_n);
|
|
var _obj2 = DataHistorySqlHelper.GetSqlDataValueFromHistoryType(obj, _colInfos[i].ValueType, _colInfos[i].Cardinal);
|
|
arrColAgg[i].addValue(_obj2[0], _eventTime, RefTime, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
var RetValHistoric = new cF4SDHealthCardRawData.cHealthCardTable()
|
|
{
|
|
Name = tableConfig.Name,
|
|
InformationClass = tableConfig.ParentCluster.InformationClass,
|
|
Origin = tableConfig.ParentCluster.Origin,
|
|
IsStatic = false,
|
|
TableType = eDataHistoryTableType.History
|
|
};
|
|
|
|
i = 0;
|
|
foreach (var Entry in tableConfig.Columns.Values)
|
|
{
|
|
var agg = arrColAgg[i];
|
|
|
|
var col = new cF4SDHealthCardRawData.cHealthCardTableColumn(RetValHistoric)
|
|
{
|
|
ColumnName = agg.Column.Name,
|
|
Values = agg.getValues()
|
|
};
|
|
RetValHistoric.Columns[agg.Column.Name] = col;
|
|
|
|
i++;
|
|
}
|
|
|
|
return new List<cF4SDHealthCardRawData.cHealthCardTable>() { RetValHistoric };
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void AddTableResultSuccessorTasks(List<cDataHistoryConfigTable> Tables, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, List<Int64> UsageInfo, Guid CacheId, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var lstTables = new List<string>();
|
|
var myTables = new List<cDataHistoryConfigTable>();
|
|
foreach (var Table in Tables)
|
|
{
|
|
if (Table.ParentCluster.Origin != enumDataHistoryOrigin.Main)
|
|
continue;
|
|
|
|
if (!Table.LateDelivery)
|
|
continue;
|
|
|
|
if (Table.Cached != eDataHistoryTableCached.Yes)
|
|
continue;
|
|
|
|
myTables.Add(Table);
|
|
lstTables.Add(Table.Name);
|
|
}
|
|
|
|
if (lstTables.Count > 0)
|
|
{
|
|
var ct = new CancellationTokenSource().Token;
|
|
var tsk = GetTableResultsMainDb(myTables, Identities, RefTime, MaxAge, false, true, ct, requestInfo, LogDeep + 1);
|
|
SuccessorCache.AddTask(CacheId, lstTables, tsk, UsageInfo, ct);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
private async Task<List<cF4SDHealthCardRawData.cHealthCardTable>> getTableRawData(cDataHistoryConfigTable tableConfig, Dictionary<enumFasdInformationClass, cF4sdConnectorIds> Identities, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
if (tableConfig.LateDelivery && !instantly && !IsSecondCall)
|
|
{
|
|
return new List<cF4SDHealthCardRawData.cHealthCardTable>() {
|
|
new cF4SDHealthCardRawData.cHealthCardTable()
|
|
{
|
|
Name = tableConfig.Name,
|
|
InformationClass = enumFasdInformationClass.Ticket,
|
|
Origin = tableConfig.ParentCluster.Origin,
|
|
IsIncomplete = true
|
|
}
|
|
};
|
|
}
|
|
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var Cols = new List<string>();
|
|
foreach (var col in tableConfig.Columns.Values)
|
|
{
|
|
Cols.Add(col.Name);
|
|
if (col.SqlTypeBin != null)
|
|
Cols.Add(col.Name + "_bin");
|
|
}
|
|
|
|
if (Identities.TryGetValue(tableConfig.ParentCluster.InformationClass, out var Identity))
|
|
if (Connectors.TryGetValue(tableConfig.ParentCluster.Origin, out var C))
|
|
{
|
|
var IdValues = await C.GetIds(Identity, tableConfig.ParentCluster.InformationClass, requestInfo, LogDeep + 1);
|
|
if (IdValues != null && tableConfig.KeyColumns.Count == IdValues.Count)
|
|
{
|
|
var Filters = new Dictionary<string, object>();
|
|
for (int i = 0; i < IdValues.Count; i++)
|
|
{
|
|
if (IdValues[i] == null)
|
|
{
|
|
LogEntry($"Empty filter value used on getting raw data for table {tableConfig.Name}.", LogLevels.Warning);
|
|
return null;
|
|
}
|
|
var Col = tableConfig.KeyColumns[i];
|
|
var ColName = Col.Name; if (Col.SqlTypeBin != null)
|
|
ColName += "_bin";
|
|
Filters.Add(ColName, IdValues[i]);
|
|
}
|
|
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
using (var _reader = await DataHistorySqlHelper.getDbReaderSelectAsync(Conn, tableConfig.SourceName, Cols, Filters, Token).ConfigureAwait(false))
|
|
{
|
|
if (_reader.HasRows)
|
|
switch (tableConfig.Type)
|
|
{
|
|
case eDataHistoryTableType.Static:
|
|
return await getTableRawDataStatic(_reader, tableConfig, Token);
|
|
case eDataHistoryTableType.History:
|
|
return await getTableRawDataHistoric(_reader, tableConfig, RefTime, MaxAge, instantly, IsSecondCall, Token);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<Dictionary<enumFasdInformationClass, cF4sdConnectorIds>> getConntectorIds(List<cF4sdIdentityEntry> Identities, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var tasks = new Task<cF4sdConnectorIds>[Identities.Count];
|
|
for (int i = 0; i < Identities.Count; i++)
|
|
{
|
|
tasks[i] = getConnectorIds(Identities[i].Class, Identities[i], Token, requestInfo, LogDeep + 1);
|
|
}
|
|
|
|
var Result = await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
|
|
var RetVal = Result.Where(v => v != null).ToDictionary<cF4sdConnectorIds, enumFasdInformationClass>(x => x.infoClass);
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<cF4sdConnectorIds>> getConnectorIdList(List<cF4sdIdentityEntry> Identities, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var tasks = new Task<cF4sdConnectorIds>[Identities.Count];
|
|
for (int i = 0; i < Identities.Count; i++)
|
|
{
|
|
tasks[i] = getConnectorIds(Identities[i].Class, Identities[i], Token, requestInfo, LogDeep + 1, WithLocalAccounts: true);
|
|
}
|
|
|
|
var Result = await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
|
|
var RetVal = Result.Where(v => v != null).ToList();
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<cF4sdConnectorIds> getConnectorIds(enumFasdInformationClass infoClass, cF4sdIdentityEntry Identity, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool WithLocalAccounts = false)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
if (infoClass == enumFasdInformationClass.Ticket)
|
|
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.Ticket };
|
|
if (infoClass == enumFasdInformationClass.VirtualSession)
|
|
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.VirtualSession };
|
|
if (infoClass == enumFasdInformationClass.MobileDevice)
|
|
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.MobileDevice };
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"GetConnectorIdsFrom{infoClass}Id", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "id", Identity.Id } };
|
|
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
cF4sdConnectorIds RetVal = null;
|
|
|
|
|
|
try
|
|
{
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(conn, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
if (await Reader.ReadAsync())
|
|
{
|
|
var Entry = new cF4sdConnectorIds()
|
|
{
|
|
infoClass = infoClass,
|
|
Id = Identity.Id
|
|
};
|
|
|
|
Entry.sid = Reader.IsDBNull(0) ? null : (byte[])Reader.GetValue(0);
|
|
Entry.agentId = Reader.IsDBNull(1) ? (int?)null : Reader.GetInt32(1);
|
|
Entry.agentId2 = Reader.IsDBNull(4) ? (int?)null : Reader.GetInt32(4);
|
|
Entry.name = Reader.GetString(2);
|
|
Entry.lastSeenByAgent = Reader.IsDBNull(3) ? (DateTime?)null : Reader.GetDateTime(3);
|
|
Entry.tenantId = Reader.IsDBNull(5) ? Guid.Empty : Reader.GetGuid(5);
|
|
Entry.intuneId = Reader.IsDBNull(6) ? Guid.Empty : Reader.GetGuid(6);
|
|
Entry.azureDeviceId = Reader.IsDBNull(7) ? Guid.Empty : Reader.GetGuid(7);
|
|
Entry.citrixUserId = Reader.IsDBNull(8) ? (int?)null : Reader.GetInt32(8);
|
|
Entry.citrixTenantId = Reader.IsDBNull(9) ? String.Empty : Reader.GetString(9);
|
|
|
|
if (Identity.agentId != null)
|
|
Entry.agentId = Identity.agentId;
|
|
|
|
Entry.accountType = Identity.AccountType;
|
|
|
|
RetVal = Entry;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
}
|
|
|
|
|
|
var _doLocalAccounts = WithLocalAccounts && RetVal != null && infoClass == enumFasdInformationClass.User && InfrastructureConfig.ClientAgent?.localAccountAssignments != null;
|
|
|
|
if (DefaultLogger.IsDebug)
|
|
{
|
|
var _msgDebug = new List<string>() {
|
|
"local account lookup infos:",
|
|
$"with local accounts: {WithLocalAccounts}",
|
|
$"RetVal agent id: {RetVal?.agentId}",
|
|
$"info class: {infoClass}",
|
|
$"Local account assignments count: {InfrastructureConfig.ClientAgent?.localAccountAssignments?.Count}",
|
|
$"do local accounts: {_doLocalAccounts}"
|
|
};
|
|
DefaultLogger.LogList(LogLevels.Debug, _msgDebug);
|
|
}
|
|
|
|
if (_doLocalAccounts)
|
|
{
|
|
var lst = new List<int>();
|
|
Params = new Dictionary<string, object>() { { "ID", Identity.Id } };
|
|
var _count = 0;
|
|
|
|
var _startTime2 = DateTime.UtcNow;
|
|
apiError = 0;
|
|
|
|
if (DataHistorySqlHelper.GetWellKnownSqlStatement("GetLocalUserFromId", out Query))
|
|
|
|
try
|
|
{
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(conn, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
while (await Reader.ReadAsync())
|
|
{
|
|
_count++;
|
|
var localAgentId = Reader.GetInt32(0);
|
|
var lastSeen = Reader.IsDBNull(1) ? (DateTime?)null : Reader.GetDateTime(1);
|
|
var localAccount = Reader.GetString(2);
|
|
if (lastSeen != null)
|
|
{
|
|
if (RetVal.localAgentIds == null)
|
|
RetVal.localAgentIds = new List<cF4sdConnectorIds.localIdEntry>();
|
|
RetVal.localAgentIds.Add(new cF4sdConnectorIds.localIdEntry() { agentId = localAgentId, lastSeenByAgent = (DateTime)lastSeen, account = localAccount });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
}
|
|
|
|
|
|
LogEntry($"local account assignement for id={Identity.Id} found: {_count}, {RetVal?.localAgentIds?.Count} of them are valid.", LogLevels.Debug);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static object getJsonValueFromString(string strValue, enumFasdValueType ValueType)
|
|
{
|
|
try
|
|
{
|
|
switch (ValueType)
|
|
{
|
|
default:
|
|
string RetVal0 = null;
|
|
try
|
|
{
|
|
RetVal0 = JsonConvert.DeserializeObject<string>(strValue);
|
|
}
|
|
catch { }
|
|
if (RetVal0 == null)
|
|
RetVal0 = strValue;
|
|
return RetVal0;
|
|
case enumFasdValueType.INT:
|
|
return JsonConvert.DeserializeObject<Int32>(strValue);
|
|
case enumFasdValueType.BIGINT:
|
|
return JsonConvert.DeserializeObject<Int64>(strValue);
|
|
case enumFasdValueType.FLOAT:
|
|
return JsonConvert.DeserializeObject<float>(strValue);
|
|
case enumFasdValueType.DATETIME:
|
|
var DT = JsonConvert.DeserializeObject<DateTime>(strValue);
|
|
return DT;
|
|
// ToDo: VERSION deserialization
|
|
//case enumFasdValueType.VERSION:
|
|
// var strVal1 = JsonConvert.DeserializeObject<string>(strValue);
|
|
// if (Version.TryParse(strVal1, out var RetVersion))
|
|
// return RetVersion;
|
|
// return null;
|
|
case enumFasdValueType.BOOLEAN:
|
|
var strVal2 = JsonConvert.DeserializeObject<string>(strValue);
|
|
return cXmlParser.GetBoolFromString(strVal2);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void ComputeEventDetailColumns(cDataHistoryConfigTable TableConfig, cF4SDHealthCardRawData.cHealthCardDetailsTable TableResult)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
if (TableResult.Columns == null || TableResult.Columns.Count == 0 || TableResult.Values == null)
|
|
return;
|
|
|
|
|
|
var lstComputations = new List<cDetailsComputationInfo>();
|
|
var index = TableResult.Columns.Count;
|
|
foreach (var Entry in TableConfig.Columns.Values)
|
|
if (Entry is cDataHistoryConfigColumnComputation comp)
|
|
{
|
|
var valueIndexes = new int[comp.Computation.Columns.Count];
|
|
for (int i = 0; i < comp.Computation.Columns.Count; i++)
|
|
{
|
|
var compVal = comp.Computation.Columns[i];
|
|
var idx = TableResult.Columns.IndexOf(compVal.Name);
|
|
if (idx < 0)
|
|
{
|
|
valueIndexes = null;
|
|
break;
|
|
}
|
|
valueIndexes[i] = idx;
|
|
}
|
|
|
|
if (valueIndexes == null)
|
|
continue;
|
|
|
|
var compInfo = new cDetailsComputationInfo() { Computation = comp.Computation, ValueIndexes = valueIndexes };
|
|
lstComputations.Add(compInfo);
|
|
TableResult.Columns.Add(comp.Name);
|
|
}
|
|
|
|
foreach (var day in TableResult.Values.Values)
|
|
foreach (var Entry in day)
|
|
{
|
|
var idx = index;
|
|
foreach (var compInfo in lstComputations)
|
|
{
|
|
var vals = new object[compInfo.ValueIndexes.Length];
|
|
for (int j = 0; j < vals.Length; j++)
|
|
vals[j] = Entry[compInfo.ValueIndexes[j]];
|
|
Entry[idx] = compInfo.Computation.Compute(vals);
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public async Task<DateTime?> GetLastScanTime(string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetLastScanTime", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Name", ScanName } };
|
|
|
|
DateTime? retVal = null;
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
retVal = await DataHistorySqlHelper.GetScalarResultAsync<DateTime?>(conn, Query, Params, requestInfo, CancellationToken.None);
|
|
}
|
|
if (retVal == null)
|
|
{
|
|
retVal = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
await SetLastScanTime(ScanName, (DateTime)retVal, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
|
|
return retVal;
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<bool> SetLastScanTime(string ScanName, DateTime LastTime, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SetLastScanTime", out var Query))
|
|
return false;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Name", ScanName }, { "LastTime", LastTime } };
|
|
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return false;
|
|
}
|
|
|
|
var retVal = await DataHistorySqlHelper.GetScalarResultAsync<int?>(conn, Query, Params, requestInfo, Token);
|
|
|
|
return (retVal != null && retVal > 0);
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<Guid> CreateScanHistoryEntry(string ScanName, DateTime TimeFrom, DateTime TimeTo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var RetVal = Guid.Empty;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateScanHistoryEntry", out var Query))
|
|
return RetVal;
|
|
|
|
var RetVal2 = Guid.NewGuid();
|
|
var Params = new Dictionary<string, object>() { { "ID", RetVal2 }, { "Name", ScanName }, { "From", TimeFrom }, { "To", TimeTo }, { "Execute", DateTime.UtcNow } };
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return RetVal;
|
|
}
|
|
|
|
var rv = await DataHistorySqlHelper.GetScalarResultAsync<int?>(conn, Query, Params, requestInfo, Token);
|
|
if (rv == 1)
|
|
return RetVal2;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return Guid.Empty;
|
|
|
|
}
|
|
|
|
public async Task ConfirmScanHistoryEntry(Guid Id, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("ConfirmScanHistoryEntry", out var Query))
|
|
return;
|
|
|
|
var Params = new Dictionary<string, object>() { { "ID", Id } };
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return;
|
|
}
|
|
|
|
var ScanName = await DataHistorySqlHelper.GetScalarResultAsync<string>(conn, Query, Params, requestInfo, Token);
|
|
if (!string.IsNullOrEmpty(ScanName))
|
|
await SetLastScanTime(ScanName, DateTime.UtcNow, requestInfo, LogDeep + 1, Token);
|
|
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task RemoveLastScanHistoryEntry(string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("RemoveLastScanHistoryEntry", out var Query))
|
|
return;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Name", ScanName } };
|
|
using (var conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
|
|
return;
|
|
}
|
|
|
|
var executionTime = await DataHistorySqlHelper.GetScalarResultAsync<DateTime?>(conn, Query, Params, requestInfo, Token);
|
|
if (executionTime == null)
|
|
await SetLastScanTime(ScanName, new DateTime(1970, 1, 1, 0, 0, 0), requestInfo, LogDeep + 1, Token);
|
|
else
|
|
await SetLastScanTime(ScanName, (DateTime)executionTime, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
|
|
public async Task<Dictionary<string, cDataHistoryConfigColumnBase>> GetTableColumnValidationAsync(cDataHistoryConfigTable TableConfig, string Instance, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cDbConnection MainConn = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var closeDbConnection = false;
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetTableColumnValidation", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Table", TableConfig.SourceName }, { "Instance", Instance } };
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
|
|
if (MainConn == null)
|
|
{
|
|
closeDbConnection = true;
|
|
MainConn = new cDbConnection(mainDbConnection);
|
|
if (!MainConn.IsOpen)
|
|
return null;
|
|
}
|
|
|
|
var RetVal = new Dictionary<string, cDataHistoryConfigColumnBase>();
|
|
DbTransaction trans = MainConn.Connection.BeginTransaction(System.Data.IsolationLevel.Snapshot);
|
|
try
|
|
{
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(MainConn, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
while (await Reader.ReadAsync() && !Token.IsCancellationRequested)
|
|
{
|
|
var strColumn = Reader.GetString(0);
|
|
if (TableConfig.Columns.TryGetValue(strColumn, out var Col))
|
|
RetVal[Col.Name] = Col;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
if (!Token.IsCancellationRequested)
|
|
{
|
|
trans.Commit();
|
|
return RetVal;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
trans.Rollback();
|
|
}
|
|
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (closeDbConnection && MainConn != null)
|
|
{
|
|
MainConn.Dispose();
|
|
}
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<bool> SetTableColumnValidationAsync(cDataHistoryConfigTable TableConfig, string Instance, HashSet<string> ValidColumns, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cDbConnection MainConn = null)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
var closeDbConnection = false;
|
|
|
|
|
|
try
|
|
{
|
|
|
|
if (MainConn == null)
|
|
{
|
|
closeDbConnection = true;
|
|
MainConn = new cDbConnection(mainDbConnection);
|
|
if (!MainConn.IsOpen)
|
|
return false;
|
|
}
|
|
|
|
var RetVal = new Dictionary<string, bool>();
|
|
using (DbTransaction trans = MainConn.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable))
|
|
{
|
|
bool doCommit = false;
|
|
|
|
try
|
|
{
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetTableColumnValidationEx", out var Query))
|
|
return false;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Table", TableConfig.SourceName }, { "Instance", Instance } };
|
|
int apiError = 0;
|
|
var _startTime2 = DateTime.UtcNow;
|
|
try
|
|
{
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(MainConn, Query, Params, Token, Transaction: trans))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
if (Reader.HasRows)
|
|
{
|
|
while (await Reader.ReadAsync() && !Token.IsCancellationRequested)
|
|
{
|
|
var strColumn = Reader.GetString(0);
|
|
var bIsValid = Reader.GetInt16(1);
|
|
RetVal[strColumn] = bIsValid == 1;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
}
|
|
|
|
|
|
|
|
if (Token.IsCancellationRequested)
|
|
return false;
|
|
|
|
var toDelete = new List<string>();
|
|
var toUpdate = new Dictionary<string, bool>();
|
|
var toInsert = new Dictionary<string, bool>();
|
|
|
|
foreach (var Column in TableConfig.Columns.Values)
|
|
{
|
|
var isValid = ValidColumns.Contains(Column.Name);
|
|
if (RetVal.TryGetValue(Column.Name, out var ColInfo))
|
|
{
|
|
if (ColInfo != isValid)
|
|
toUpdate[Column.Name] = isValid;
|
|
}
|
|
else
|
|
{
|
|
toInsert[Column.Name] = isValid;
|
|
}
|
|
}
|
|
|
|
foreach (var ColumnName in ValidColumns)
|
|
{
|
|
if (!RetVal.ContainsKey(ColumnName))
|
|
toDelete.Add(ColumnName);
|
|
}
|
|
|
|
// do the table inserts
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertTableColumnValidation", out Query))
|
|
return false;
|
|
foreach (var updEntry in toInsert)
|
|
{
|
|
Params = new Dictionary<string, object>() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry.Key }, { "isValid", updEntry.Value ? 1 : 0 } };
|
|
await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans);
|
|
}
|
|
|
|
// do the table updates
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateTableColumnValidation", out Query))
|
|
return false;
|
|
foreach (var updEntry in toUpdate)
|
|
{
|
|
Params = new Dictionary<string, object>() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry.Key }, { "isValid", updEntry.Value ? 1 : 0 } };
|
|
await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans);
|
|
}
|
|
|
|
// do the table deletions
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("DeleteTableColumnValidation", out Query))
|
|
return false;
|
|
foreach (var updEntry in toDelete)
|
|
{
|
|
Params = new Dictionary<string, object>() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry } };
|
|
await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans);
|
|
}
|
|
|
|
doCommit = true;
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (doCommit)
|
|
trans.Commit();
|
|
else
|
|
trans.Rollback();
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (closeDbConnection && MainConn != null)
|
|
{
|
|
MainConn.Dispose();
|
|
}
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<List<string>> GetQuickActionAllList()
|
|
{
|
|
var returnValue = new List<string>();
|
|
foreach (var Connector in GetConnectors())
|
|
{
|
|
var _quickActions = await Connector.GetQuickActionList();
|
|
if (_quickActions != null && _quickActions.Count > 0)
|
|
returnValue.AddRange(_quickActions);
|
|
}
|
|
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
public bool CheckCleanupTimeframes()
|
|
{
|
|
if (InfrastructureConfig.HistoryDB.CleanupTimeFrames == null)
|
|
return true;
|
|
|
|
if (InfrastructureConfig.HistoryDB.CleanupTimeFrames.Count == 0)
|
|
return true;
|
|
|
|
foreach (var TF in InfrastructureConfig.HistoryDB.CleanupTimeFrames)
|
|
{
|
|
if (TF.Check())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task<HashSet<Guid>> getCleanupScanIds(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetScanHistoryCleanup", out var Query))
|
|
return null;
|
|
|
|
var Params = new Dictionary<string, object>() { { "Age1", InfrastructureConfig.HistoryDB.DaysToCache }, { "Age2", 60 } };
|
|
int apiError = 0;
|
|
|
|
try
|
|
{
|
|
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main database '{mainDbConnection.Database}', aborting query'", LogLevels.Error);
|
|
return null;
|
|
}
|
|
|
|
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(Conn, Query, Params, Token))
|
|
{
|
|
if (Reader != null)
|
|
try
|
|
{
|
|
var RetVal = new HashSet<Guid>();
|
|
if (Reader.HasRows)
|
|
{
|
|
while (await Reader.ReadAsync() && !Token.IsCancellationRequested)
|
|
try
|
|
{
|
|
var _id = Reader.GetGuid(0);
|
|
RetVal.Add(_id);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
apiError = E.HResult;
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName);
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
public async Task<int> CheckCleanup(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
var l = await getCleanupScanIds(requestInfo, LogDeep + 1, Token);
|
|
if (l != null)
|
|
return l.Count;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public async Task<int> DoCleanup(bool DontUseScanTiming, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (!DontUseScanTiming && !CheckCleanupTimeframes())
|
|
{
|
|
DoProcessUiMessage(0, "The current time is not within the defined scan time intervals.");
|
|
|
|
return -2;
|
|
}
|
|
|
|
|
|
// get the historic scan ids to cleanup
|
|
var lstIds = await getCleanupScanIds(requestInfo, LogDeep + 1, Token);
|
|
if (lstIds == null)
|
|
return -1;
|
|
if (lstIds.Count == 0)
|
|
{
|
|
DoProcessUiMessage(0, "No outdated scans found. Cleanup is not nescessary.");
|
|
return 0;
|
|
}
|
|
|
|
DoProcessUiMessage(0, $"{lstIds.Count} outdated scans found. Starting cleanup...");
|
|
|
|
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("DeleteScanHistoryEntry", out var Query))
|
|
return -1;
|
|
|
|
Query.TimeoutFactor = 100;
|
|
using (var Conn = new cDbConnection(mainDbConnection))
|
|
{
|
|
if (!Conn.IsOpen)
|
|
{
|
|
LogEntry($"Could not open main database '{mainDbConnection.Database}', aborting query'", LogLevels.Error);
|
|
return -1;
|
|
}
|
|
var ValidRemoves = 0;
|
|
foreach (var _id in lstIds)
|
|
{
|
|
try
|
|
{
|
|
if (!DontUseScanTiming && !CheckCleanupTimeframes())
|
|
return ValidRemoves;
|
|
|
|
var Params = new Dictionary<string, object>(1) { { "ID", _id } };
|
|
var n = await DataHistorySqlHelper.ExecuteAsync(Conn, Query, Params, requestInfo, Token);
|
|
if (n != null && n > 0)
|
|
ValidRemoves += (int)n;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
|
|
DoProcessUiMessage(0, $"{ValidRemoves} history scans removed.");
|
|
|
|
return ValidRemoves;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public override async Task<bool> WritePropertyAsync(cF4SDWriteParameters PropertiesToWrite, cF4sdWebRequestInfo requestInfo, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
// check if properties are writable
|
|
if (!this.ClusterConfig.Tables.TryGetValue(PropertiesToWrite.TableName, out var tableConfig))
|
|
return false;
|
|
|
|
if (PropertiesToWrite.Values == null)
|
|
return false;
|
|
|
|
var lstIllegal = new List<string>();
|
|
foreach (var Entry in PropertiesToWrite.Values)
|
|
{
|
|
if (!tableConfig.Columns.TryGetValue(Entry.Key, out var colInfo) || !colInfo.IsWritable)
|
|
lstIllegal.Add(Entry.Key);
|
|
}
|
|
foreach (var Entry in lstIllegal)
|
|
PropertiesToWrite.Values.Remove(Entry);
|
|
|
|
if (PropertiesToWrite.Values.Count == 0)
|
|
return false;
|
|
|
|
var result = lstIllegal.Count == 0;
|
|
|
|
if (this.Connectors.TryGetValue(tableConfig.ParentCluster.Origin, out var _mod))
|
|
{
|
|
var res = await _mod.WritePropertyAsync(PropertiesToWrite, requestInfo, Token);
|
|
if (res)
|
|
{
|
|
|
|
}
|
|
return result & res;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
private Guid GetUserHashGuid(Guid userId)
|
|
{
|
|
// check, if we have a GUID
|
|
if (!Guid.TryParse(userId.ToString(), out var _guid))
|
|
return Guid.Empty;
|
|
|
|
// convert the GUID into a byte arry and 'salt' it a little bit
|
|
var _arr = _guid.ToByteArray();
|
|
if (_arr.Length != 16) return Guid.Empty;
|
|
var _arrSalt = new byte[3 * 16];
|
|
for (byte i = 0; i < 16; i++)
|
|
{
|
|
byte j = Convert.ToByte(i * 3);
|
|
_arrSalt[j] = _arr[i];
|
|
_arrSalt[j + 1] = _arr[i];
|
|
_arrSalt[j + 2] = j;
|
|
}
|
|
|
|
// get the md5 hash value (128 bit = 16 byte)
|
|
var _md5 = MD5.Create();
|
|
var _arrHash = _md5.ComputeHash(_arrSalt);
|
|
if (_arrHash == null) return Guid.Empty;
|
|
if (_arrHash.Length != 16) return Guid.Empty;
|
|
|
|
// convert the hash value into a GUID
|
|
return new Guid(_arrHash);
|
|
}
|
|
|
|
public void AddRolesByMembership(cF4sdUserInfo userInfo, List<cF4SDMembershipGroup> _membershipGroups)
|
|
{
|
|
if (userInfo.Roles == null)
|
|
userInfo.Roles = new List<string>();
|
|
AddRolesByMembership(userInfo.Roles, _membershipGroups, userInfo.Name);
|
|
}
|
|
|
|
public void AddRolesByMembership(List<string> Roles, List<cF4SDMembershipGroup> _membershipGroups, string userName)
|
|
{
|
|
if (_membershipGroups?.Count > 0)
|
|
{
|
|
var _roles = InfrastructureConfig?.Authorisation?.Roles;
|
|
if (_roles != null)
|
|
foreach (var _roleEntry in _roles.Values)
|
|
{
|
|
if (_roleEntry.MembershipGroups != null)
|
|
foreach (var _grp in _roleEntry.MembershipGroups)
|
|
{
|
|
if (_membershipGroups.Contains(_grp))
|
|
{
|
|
if (Roles?.Contains(_roleEntry.Name) != true)
|
|
{
|
|
if (Roles == null)
|
|
Roles = new List<string>();
|
|
Roles.Add(_roleEntry.Name);
|
|
Debug.WriteLine($" {userName} is member of '{_roleEntry.Name}'");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static int getDayIndex(DateTime EventTime, DateTime RefTime, int HistorySize)
|
|
{
|
|
var deltaTime = (EventTime - RefTime).TotalDays;
|
|
int indexDay;
|
|
if (deltaTime >= 0)
|
|
indexDay = (int)Math.Floor(deltaTime);
|
|
else
|
|
indexDay = -(int)Math.Ceiling(-deltaTime);
|
|
|
|
if (indexDay > 0)
|
|
indexDay = 0;
|
|
indexDay = -indexDay;
|
|
if (indexDay >= HistorySize)
|
|
indexDay = HistorySize - 1;
|
|
|
|
return indexDay;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool CheckIfNotEmpty(object _o)
|
|
{
|
|
if (_o == null) return false;
|
|
if (_o is string _s && string.IsNullOrEmpty(_s)) return false;
|
|
return true;
|
|
}
|
|
|
|
public override async Task<cScanTimeInfo> GetScanTimeInfoAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
await Task.CompletedTask;
|
|
return null;
|
|
}
|
|
|
|
public override async Task<bool> DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false)
|
|
{
|
|
await Task.CompletedTask;
|
|
return true;
|
|
}
|
|
|
|
public override async Task<List<object>> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
|
{
|
|
await Task.CompletedTask;
|
|
return new List<object>() { IdEntry.Id };
|
|
}
|
|
|
|
public static string getStingList(List<string> L)
|
|
{
|
|
if (L == null || L.Count == 0)
|
|
return null;
|
|
|
|
var RetVal = "";
|
|
foreach (var Entry in L)
|
|
{
|
|
if (string.IsNullOrEmpty(Entry))
|
|
continue;
|
|
if (RetVal != "")
|
|
RetVal += ',';
|
|
RetVal += Entry;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
public cCockpitConfiguration GetCockpitConfiguration(cF4sdWebRequestInfo requestInfo)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var retVal = new cCockpitConfiguration();
|
|
|
|
var AgentConfig = InfrastructureConfig?.ClientAgent;
|
|
if (AgentConfig != null)
|
|
{
|
|
retVal.agentApiConfiguration = F4sdAgent.GetAgentApiConfiguration(false);
|
|
}
|
|
|
|
if (InfrastructureConfig?.M42Wpm?.Server != null)
|
|
{
|
|
var _lang = requestInfo.Culture?.TwoLetterISOLanguageName?.ToUpperInvariant() ?? "";
|
|
retVal.m42ServerConfiguration = new cM42ServerConfiguration()
|
|
{
|
|
Server = InfrastructureConfig.M42Wpm.Server,
|
|
DisplayName = InfrastructureConfig.M42Wpm.DisplayNames.GetValue(_lang, null)
|
|
};
|
|
}
|
|
|
|
if (RefreshGlobalConfigurationParameters())
|
|
lock (GlobalParametersConfigLock)
|
|
retVal.GlobalConfig = GlobalParametersConfigFile.Parameters;
|
|
|
|
return retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public cCollectorStatusInfo GetCollectorStatus(cF4sdWebRequestInfo requestInfo)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var _cfgInfrastructure = new cDataHistoryConfigInfrastructure();
|
|
_cfgInfrastructure.LoadFromFile(out var PMs);
|
|
var retVal = new cCollectorStatusInfo();
|
|
|
|
retVal.HasM42Config = _cfgInfrastructure.M42Wpm != null;
|
|
retVal.HasIntuneConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true);
|
|
retVal.HasMobileDeviceConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true);
|
|
retVal.HasCitrixConfig = (InfrastructureConfig.Citrix != null);
|
|
|
|
return retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override async Task<cF4SdUserInfoChange> ValidateTokenAsync(cF4SDTokenRegistration TokenRegistration, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
if (TokenCache == null)
|
|
return null;
|
|
|
|
if (TokenRegistration.UserId != requestInfo.userInfo?.Id)
|
|
return null;
|
|
|
|
cF4SdUserInfoChange _userInfoChange = null;
|
|
switch (TokenRegistration?.TokenType)
|
|
{
|
|
case cF4SDTokenRegistration.enumTokenType.M42Bearer:
|
|
_userInfoChange = await this.M42WpmCollector.ValidateTokenAsync(TokenRegistration, requestInfo, LogDeep + 1, Token);
|
|
break;
|
|
}
|
|
|
|
if (_userInfoChange == null || _userInfoChange.ValidLogonsUntil == null || _userInfoChange.ValidLogonsUntil.Count == 0)
|
|
return null;
|
|
|
|
var validPeriod = _userInfoChange.ValidLogonsUntil.First().Value;
|
|
if (validPeriod.validUntil <= DateTime.UtcNow)
|
|
return null;
|
|
|
|
await TokenCache.SetAsync(TokenRegistration, validPeriod, Token, requestInfo, LogDeep + 1);
|
|
|
|
return _userInfoChange;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override async Task<cF4SDAdditionalUserInfo> GetAdditionalUserInfo(enumAdditionalAuthentication Type, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
|
var _startTime = DateTime.UtcNow;
|
|
|
|
try
|
|
{
|
|
switch (Type)
|
|
{
|
|
case enumAdditionalAuthentication.M42WinLogon:
|
|
return await M42WpmCollector.GetAdditionalUserInfo(Type, requestInfo, LogDeep + 1, Token);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public HashSet<enumFasdInformationClass> GetSupportedInformationClasses() => new HashSet<enumFasdInformationClass>() { enumFasdInformationClass.User, enumFasdInformationClass.Computer };
|
|
|
|
public async Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdIdentityEntry> ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default)
|
|
{
|
|
List<cF4sdApiSearchResultRelation> usageRelations = await GetUsageFromOnlyAgentData(informationClass, ids.Select(id => id.Id).ToList(), age, token, null, 1);
|
|
return new cF4sdStagedSearchResultRelations() { Relations = usageRelations };
|
|
}
|
|
}
|
|
|
|
public class cScanTimeInfo
|
|
{
|
|
public readonly DateTime LastScan;
|
|
public DateTime? NextScan = null;
|
|
|
|
public SortedList<DateTime, DateTime> Intervals = new SortedList<DateTime, DateTime>();
|
|
|
|
public cScanTimeInfo(DateTime LastScan)
|
|
{
|
|
this.LastScan = LastScan;
|
|
}
|
|
|
|
|
|
private DateTime privGetScanTimeIntervals(DateTime time, DateTime LastScan, cDataHistoryScanTiming Timing)
|
|
{
|
|
try
|
|
{
|
|
var refTime = TimeZoneInfo.ConvertTimeFromUtc(time, Timing.Timezone);
|
|
refTime = refTime.Date + Timing.Offset;
|
|
refTime = refTime.ToUniversalTime();
|
|
|
|
while (refTime > time)
|
|
refTime -= TimeSpan.FromDays(1);
|
|
|
|
var diff = time - refTime;
|
|
var nDiff = diff.TotalMilliseconds / Timing.Interval.TotalMilliseconds;
|
|
nDiff = Math.Floor(nDiff);
|
|
|
|
var retVal = refTime + TimeSpan.FromMilliseconds(nDiff * Timing.Interval.TotalMilliseconds);
|
|
|
|
DateTime intv2 = retVal;
|
|
DateTime intv1 = intv2 - Timing.Interval;
|
|
while (LastScan < intv2)
|
|
{
|
|
Intervals.Add(intv1, intv2);
|
|
intv2 -= Timing.Interval;
|
|
intv1 = intv2 - Timing.Interval;
|
|
}
|
|
;
|
|
|
|
return retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
}
|
|
|
|
return DateTime.MaxValue;
|
|
}
|
|
|
|
public DateTime GetScanTime(DateTime time, cDataHistoryScanTiming Timing)
|
|
{
|
|
return privGetScanTimeIntervals(time, LastScan, Timing);
|
|
}
|
|
|
|
public void GetFirstScanTime(cDataHistoryScanTiming Timing)
|
|
{
|
|
var _now = DateTime.UtcNow;
|
|
NextScan = privGetScanTimeIntervals(_now, _now - Timing.Interval, Timing);
|
|
}
|
|
|
|
static public int GetScanIntervalIndex(DateTime time, DateTime timeFrom, DateTime timeTo, cDataHistoryScanTiming Timing)
|
|
{
|
|
try
|
|
{
|
|
var refTime = TimeZoneInfo.ConvertTimeFromUtc(time, Timing.Timezone);
|
|
refTime = refTime.Date + Timing.Offset;
|
|
refTime = refTime.ToUniversalTime();
|
|
|
|
var Diff = (time - refTime).TotalMilliseconds / Timing.Interval.TotalMilliseconds;
|
|
Diff = Math.Round(Diff);
|
|
var nDiff = Convert.ToInt32(Diff);
|
|
refTime = refTime.AddMilliseconds(nDiff * Timing.Interval.TotalMilliseconds);
|
|
|
|
|
|
var timeCenter = timeFrom.AddTicks((timeTo - timeFrom).Ticks / 2);
|
|
Diff = (refTime - timeCenter).TotalMilliseconds / Timing.Interval.TotalMilliseconds;
|
|
Diff = Math.Ceiling(Diff);
|
|
nDiff = Convert.ToInt32(Diff);
|
|
|
|
return nDiff;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
public class cDataHistoryInfoClassListEntry
|
|
{
|
|
public string Name { get; set; }
|
|
public Guid id { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name;
|
|
}
|
|
}
|
|
|
|
public class cF4sdConnectorIds
|
|
{
|
|
public class localIdEntry
|
|
{
|
|
public int agentId;
|
|
public DateTime lastSeenByAgent;
|
|
public string account;
|
|
}
|
|
|
|
public enumFasdInformationClass infoClass { get; set; } = enumFasdInformationClass.Unknown;
|
|
public Guid Id { get; set; }
|
|
public int? agentId { get; set; } = null;
|
|
public int? agentId2 { get; set; } = null;
|
|
public List<localIdEntry> localAgentIds { get; set; } = null;
|
|
public byte[] sid { get; set; } = null;
|
|
|
|
public string name { get; set; } = null;
|
|
|
|
public DateTime? lastSeenByAgent { get; set; } = null;
|
|
|
|
public enumAccountType accountType { get; set; } = enumAccountType.unknow;
|
|
|
|
public Guid tenantId { get; set; }
|
|
public Guid intuneId { get; set; }
|
|
public Guid azureDeviceId { get; set; }
|
|
public string citrixTenantId { get; set; }
|
|
public int? citrixUserId { get; set; }
|
|
}
|
|
|
|
public class cDataHistoryUiStatusMessage
|
|
{
|
|
public int Indent = 0;
|
|
public string Message;
|
|
|
|
public static cDataHistoryUiStatusMessage Create(int Indent, string Message)
|
|
{
|
|
return new cDataHistoryUiStatusMessage()
|
|
{
|
|
Indent = Indent,
|
|
Message = Message
|
|
};
|
|
}
|
|
}
|
|
|
|
public class cCollectorStatusInfo
|
|
{
|
|
public bool HasM42Config;
|
|
public bool HasIntuneConfig;
|
|
public bool HasMobileDeviceConfig;
|
|
public bool HasCitrixConfig;
|
|
}
|
|
|
|
public class cDataHistorySHistoryScanInfo
|
|
{
|
|
public Guid ID;
|
|
public string Scan;
|
|
public DateTime TimeFrom;
|
|
public DateTime TimeTo;
|
|
}
|
|
|
|
internal class cDataHistoryUsageIdInfo
|
|
{
|
|
internal Guid Id;
|
|
internal enumAccountType AccountType = enumAccountType.unknow;
|
|
internal string account = null;
|
|
internal string domain = null;
|
|
}
|
|
|
|
public class cF4sdWebRequestInfo
|
|
{
|
|
public readonly string requestName;
|
|
public readonly string id = null;
|
|
public readonly DateTime created = DateTime.UtcNow;
|
|
public readonly cF4sdUserInfo userInfo = null;
|
|
public readonly CultureInfo Culture = null;
|
|
public cM42WebClient M42WebClient = null;
|
|
public int SqlDuration = 0;
|
|
private List<(string, int)> privSqlDurations { get; set; } = null;
|
|
public List<(string, int)> SqlDurations
|
|
{
|
|
get
|
|
{
|
|
if (privSqlDurations == null)
|
|
privSqlDurations = new List<(string, int)>();
|
|
return privSqlDurations;
|
|
}
|
|
}
|
|
|
|
public cF4sdWebRequestInfo(string requestName, string id, cF4sdUserInfo userInfo = null)
|
|
{
|
|
try
|
|
{
|
|
this.requestName = requestName;
|
|
this.id = requestName + "-" + id;
|
|
this.userInfo = userInfo;
|
|
if (!string.IsNullOrEmpty(userInfo?.Language))
|
|
{
|
|
try
|
|
{
|
|
this.Culture = CultureInfo.GetCultureInfoByIetfLanguageTag(userInfo.Language);
|
|
}
|
|
catch { }
|
|
}
|
|
if (cLogManager.DefaultLogger.IsDebug) LogEntry($"authentication user language: {userInfo?.Language}, user culture: {this.Culture?.Name}", LogLevels.Debug);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class cHistoricAggregationEntry
|
|
{
|
|
internal cDataHistoryConfigColumn Column;
|
|
internal int JsonSubValue = -1;
|
|
internal int HistorySize = 0;
|
|
|
|
internal object LatestValue = null;
|
|
internal DateTime? LastestEvent = null;
|
|
|
|
internal Int64?[] aggInt = null;
|
|
internal Double?[] aggDouble = null;
|
|
internal Double?[] weightDouble = null;
|
|
internal String[] aggString = null;
|
|
internal List<string>[] listString = null;
|
|
internal Boolean?[] aggBoolean = null;
|
|
internal DateTime?[] aggEvent = null;
|
|
internal DateTime?[] aggTime = null;
|
|
internal Version[] aggVersion = null;
|
|
internal Guid?[] aggGuid = null;
|
|
|
|
private object lockAggregation = new object();
|
|
|
|
internal cHistoricAggregationEntry(cDataHistoryConfigColumn Column, int HistorySize, Dictionary<string, string[]> JsonSettings)
|
|
{
|
|
this.Column = Column;
|
|
this.HistorySize = HistorySize;
|
|
|
|
if (Column.SourceJsonColumn >= 0)
|
|
JsonSubValue = Column.SourceJsonColumn;
|
|
else if (Column.SourceJsonField != null && JsonSettings != null)
|
|
{
|
|
if (JsonSettings.TryGetValue(Column.SourceName, out var jsonList))
|
|
{
|
|
for (int i = 0; i < jsonList.Length; i++)
|
|
if (jsonList[i] == Column.SourceJsonField)
|
|
{
|
|
JsonSubValue = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.average:
|
|
aggDouble = new Double?[HistorySize];
|
|
weightDouble = new Double?[HistorySize];
|
|
return;
|
|
case eDataHistoryAggregationType.latestTime:
|
|
aggEvent = new DateTime?[HistorySize];
|
|
return;
|
|
case eDataHistoryAggregationType.count:
|
|
case eDataHistoryAggregationType.valuecount:
|
|
aggInt = new Int64?[HistorySize];
|
|
return;
|
|
case eDataHistoryAggregationType.Unknown:
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
case eDataHistoryAggregationType.first:
|
|
aggEvent = new DateTime?[HistorySize];
|
|
break;
|
|
}
|
|
|
|
switch (Column.ValueType)
|
|
{
|
|
case enumFasdValueType.INT:
|
|
case enumFasdValueType.BIGINT:
|
|
aggInt = new Int64?[HistorySize];
|
|
return;
|
|
case enumFasdValueType.FLOAT:
|
|
aggDouble = new Double?[HistorySize];
|
|
return;
|
|
case enumFasdValueType.DATETIME:
|
|
aggTime = new DateTime?[HistorySize];
|
|
return;
|
|
case enumFasdValueType.VERSION:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.sum:
|
|
listString = new List<string>[HistorySize];
|
|
return;
|
|
}
|
|
aggVersion = new Version[HistorySize];
|
|
return;
|
|
case enumFasdValueType.GUID:
|
|
aggGuid = new Guid?[HistorySize];
|
|
return;
|
|
case enumFasdValueType.BOOLEAN:
|
|
aggBoolean = new bool?[HistorySize];
|
|
return;
|
|
case enumFasdValueType.STRING:
|
|
case enumFasdValueType.IPV4:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.sum:
|
|
listString = new List<string>[HistorySize];
|
|
return;
|
|
}
|
|
aggString = new String[HistorySize];
|
|
return;
|
|
}
|
|
}
|
|
|
|
internal void addValue(object Value, DateTime EventTime, DateTime RefTime, Int32 EventDuration)
|
|
{
|
|
try
|
|
{
|
|
var indexDay = cDataHistoryCollector.getDayIndex(EventTime, RefTime, HistorySize);
|
|
|
|
if (Value is cDataHistoryCustomJsonMeasure _cm)
|
|
{
|
|
if (_cm.Values == null)
|
|
return;
|
|
if (_cm.ErrorCode != null && _cm.ErrorCode != 0)
|
|
return;
|
|
if (!string.IsNullOrEmpty(_cm.ErrorDescription))
|
|
return;
|
|
if (_cm.ResultCode != null && _cm.ResultCode != 0)
|
|
return;
|
|
|
|
var _s = _cm.Values.GetType().ToString();
|
|
|
|
if (_cm.Values is JValue _jVal)
|
|
Value = _jVal.Value;
|
|
else if (_cm.Values is JArray _jArr)
|
|
{
|
|
var _res = new object[_jArr.Count];
|
|
var i = 0;
|
|
foreach (var _jEntry in _jArr)
|
|
{
|
|
_res[i] = null;
|
|
if (_jEntry is JValue _jVal2)
|
|
{
|
|
_res[i] = _jVal2.Value;
|
|
}
|
|
i++;
|
|
}
|
|
Value = _res;
|
|
}
|
|
}
|
|
|
|
if ((JsonSubValue >= 0) && (Value is object[] arrVals))
|
|
Value = arrVals[JsonSubValue];
|
|
|
|
lock (lockAggregation)
|
|
{
|
|
if ((LastestEvent == null || EventTime >= LastestEvent) && !(Value is object[]))
|
|
{
|
|
LatestValue = Value;
|
|
LastestEvent = EventTime;
|
|
}
|
|
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.average:
|
|
if (cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
{
|
|
switch (Column.ValueType)
|
|
{
|
|
case enumFasdValueType.INT:
|
|
case enumFasdValueType.BIGINT:
|
|
case enumFasdValueType.FLOAT:
|
|
var val01 = Convert.ToDouble(Value);
|
|
if (weightDouble[indexDay] == null)
|
|
weightDouble[indexDay] = 0;
|
|
weightDouble[indexDay] += EventDuration;
|
|
if (aggDouble[indexDay] == null)
|
|
aggDouble[indexDay] = 0;
|
|
aggDouble[indexDay] += val01 * EventDuration;
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestTime:
|
|
if (aggEvent[indexDay] == null || aggEvent[indexDay] < EventTime)
|
|
aggEvent[indexDay] = EventTime;
|
|
return;
|
|
case eDataHistoryAggregationType.count:
|
|
if (aggInt[indexDay] == null)
|
|
aggInt[indexDay] = 1;
|
|
else
|
|
aggInt[indexDay]++;
|
|
return;
|
|
case eDataHistoryAggregationType.valuecount:
|
|
if (cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
{
|
|
if (aggInt[indexDay] == null)
|
|
aggInt[indexDay] = 1;
|
|
else
|
|
aggInt[indexDay]++;
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.Unknown:
|
|
return;
|
|
}
|
|
|
|
switch (Column.ValueType)
|
|
{
|
|
case enumFasdValueType.INT:
|
|
case enumFasdValueType.BIGINT:
|
|
if (cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
{
|
|
var val02 = Convert.ToInt64(Value);
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
if (aggInt[indexDay] == null)
|
|
aggInt[indexDay] = val02;
|
|
else
|
|
aggInt[indexDay] = Math.Min((Int64)aggInt[indexDay], val02);
|
|
return;
|
|
case eDataHistoryAggregationType.max:
|
|
if (aggInt[indexDay] == null)
|
|
aggInt[indexDay] = val02;
|
|
else
|
|
aggInt[indexDay] = Math.Max((Int64)aggInt[indexDay], val02);
|
|
return;
|
|
case eDataHistoryAggregationType.sum:
|
|
if (aggInt[indexDay] == null)
|
|
aggInt[indexDay] = val02;
|
|
else
|
|
aggInt[indexDay] += val02;
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggInt[indexDay] = val02;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggInt[indexDay] = val02;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggInt[indexDay] = val02;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggInt[indexDay] = val02;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case enumFasdValueType.FLOAT:
|
|
if (cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
{
|
|
var val03 = Convert.ToDouble(Value);
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
if (aggDouble[indexDay] == null)
|
|
aggDouble[indexDay] = val03;
|
|
else
|
|
aggDouble[indexDay] = Math.Min((Double)aggDouble[indexDay], val03);
|
|
return;
|
|
case eDataHistoryAggregationType.max:
|
|
if (aggDouble[indexDay] == null)
|
|
aggDouble[indexDay] = val03;
|
|
else
|
|
aggDouble[indexDay] = Math.Max((Double)aggDouble[indexDay], val03);
|
|
return;
|
|
case eDataHistoryAggregationType.sum:
|
|
if (aggDouble[indexDay] == null)
|
|
aggDouble[indexDay] = val03;
|
|
else
|
|
aggDouble[indexDay] += val03;
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggDouble[indexDay] = val03;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggDouble[indexDay] = val03;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggDouble[indexDay] = val03;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggDouble[indexDay] = val03;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case enumFasdValueType.DATETIME:
|
|
if (cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
{
|
|
var val04 = Convert.ToDateTime(Value);
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
if (aggTime[indexDay] == null)
|
|
aggTime[indexDay] = val04;
|
|
else if (val04 < aggTime[indexDay])
|
|
aggTime[indexDay] = val04;
|
|
return;
|
|
case eDataHistoryAggregationType.max:
|
|
if (aggTime[indexDay] == null)
|
|
aggTime[indexDay] = val04;
|
|
else if (val04 > aggTime[indexDay])
|
|
aggTime[indexDay] = val04;
|
|
return;
|
|
case eDataHistoryAggregationType.sum:
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggTime[indexDay] = val04;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggTime[indexDay] = val04;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggTime[indexDay] = val04;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggTime[indexDay] = val04;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case enumFasdValueType.VERSION:
|
|
if (Value != null && Version.TryParse(Value.ToString(), out var val05))
|
|
{
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
if (aggVersion[indexDay] == null)
|
|
aggVersion[indexDay] = val05;
|
|
else if (val05 < aggVersion[indexDay])
|
|
aggVersion[indexDay] = val05;
|
|
return;
|
|
case eDataHistoryAggregationType.max:
|
|
if (aggVersion[indexDay] == null)
|
|
aggVersion[indexDay] = val05;
|
|
else if (val05 > aggVersion[indexDay])
|
|
aggVersion[indexDay] = val05;
|
|
return;
|
|
case eDataHistoryAggregationType.sum:
|
|
var strVal05 = val05.ToString();
|
|
if (listString[indexDay] == null)
|
|
listString[indexDay] = new List<string>() { strVal05 };
|
|
else if (listString[indexDay].Count < 32 && !listString[indexDay].Contains(strVal05))
|
|
listString[indexDay].Add(strVal05);
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggVersion[indexDay] = val05;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggVersion[indexDay] = val05;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggVersion[indexDay] = val05;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggVersion[indexDay] = val05;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case enumFasdValueType.GUID:
|
|
if (Value == null)
|
|
return;
|
|
Guid _guid = Guid.Empty;
|
|
if (Value is Guid _guid2)
|
|
_guid = _guid2;
|
|
else
|
|
{
|
|
if (Guid.TryParse(Value.ToString(), out var _guid3))
|
|
_guid = _guid3;
|
|
else
|
|
return;
|
|
}
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggGuid[indexDay] = _guid;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggGuid[indexDay] = _guid;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggGuid[indexDay] = _guid;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggGuid[indexDay] = _guid;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
case enumFasdValueType.BOOLEAN:
|
|
if (!cDataHistoryCollector.CheckIfNotEmpty(Value))
|
|
return;
|
|
|
|
bool val06 = false;
|
|
if (Value is bool v)
|
|
val06 = v;
|
|
else if (Value is string val06Str)
|
|
{
|
|
switch (val06Str.Trim().ToLower())
|
|
{
|
|
case "1":
|
|
case "true":
|
|
case "yes":
|
|
val06 = true;
|
|
break;
|
|
case "0":
|
|
case "false":
|
|
case "no":
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
else if (Value is sbyte
|
|
|| Value is byte
|
|
|| Value is short
|
|
|| Value is ushort
|
|
|| Value is int
|
|
|| Value is uint
|
|
|| Value is long
|
|
|| Value is ulong)
|
|
{
|
|
var val06Int = Convert.ToInt64(Value);
|
|
if (val06Int == 0) { }
|
|
else if (val06Int == 1)
|
|
val06 = true;
|
|
return;
|
|
}
|
|
else if (Value is float
|
|
|| Value is double
|
|
|| Value is decimal)
|
|
{
|
|
var val06Double = Convert.ToDouble(Value);
|
|
if (val06Double == 0) { }
|
|
else if (val06Double == 1)
|
|
val06 = true;
|
|
else
|
|
return;
|
|
}
|
|
else
|
|
return;
|
|
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
if (aggBoolean[indexDay] == null)
|
|
aggBoolean[indexDay] = val06;
|
|
else
|
|
aggBoolean[indexDay] &= val06;
|
|
return;
|
|
case eDataHistoryAggregationType.max:
|
|
if (aggBoolean[indexDay] == null)
|
|
aggBoolean[indexDay] = val06;
|
|
else
|
|
aggBoolean[indexDay] |= val06;
|
|
return;
|
|
case eDataHistoryAggregationType.sum:
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggBoolean[indexDay] = val06;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggBoolean[indexDay] = val06;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggBoolean[indexDay] = val06;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggBoolean[indexDay] = val06;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
default:
|
|
if (Value == null)
|
|
return;
|
|
var val07 = Value.ToString();
|
|
if (val07 == "")
|
|
return;
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.sum:
|
|
if (listString[indexDay] == null)
|
|
listString[indexDay] = new List<string>() { val07 };
|
|
else if (listString[indexDay].Count < 32 && !listString[indexDay].Contains(val07))
|
|
listString[indexDay].Add(val07);
|
|
return;
|
|
case eDataHistoryAggregationType.first:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggString[indexDay] = val07;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime < aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggString[indexDay] = val07;
|
|
}
|
|
}
|
|
return;
|
|
case eDataHistoryAggregationType.latestValue:
|
|
if (aggEvent[indexDay] == null)
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggString[indexDay] = val07;
|
|
}
|
|
else
|
|
{
|
|
if (EventTime > aggEvent[indexDay])
|
|
{
|
|
aggEvent[indexDay] = EventTime;
|
|
aggString[indexDay] = val07;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
LogEntry($"error while processing historical value from {Column.ParentTable.Name}/{Column.Name}: {Value}", LogLevels.Error);
|
|
}
|
|
}
|
|
|
|
internal List<object> getValues()
|
|
{
|
|
try
|
|
{
|
|
var RetVal = getValuesRaw();
|
|
if (RetVal == null || !Column.FillEmptyEntries)
|
|
return RetVal;
|
|
|
|
object LastVal = null;
|
|
for (int i = RetVal.Count - 1; i >= 0; i--)
|
|
{
|
|
if (RetVal[i] == null)
|
|
RetVal[i] = LastVal;
|
|
else
|
|
LastVal = RetVal[i];
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal List<object> getValuesRaw()
|
|
{
|
|
try
|
|
{
|
|
List<object> retVal;
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.average:
|
|
switch (Column.ValueType)
|
|
{
|
|
case enumFasdValueType.INT:
|
|
case enumFasdValueType.BIGINT:
|
|
case enumFasdValueType.FLOAT:
|
|
retVal = new List<object>(HistorySize);
|
|
for (int i = 0; i < HistorySize; i++)
|
|
{
|
|
if (weightDouble[i] == 0 || aggDouble[i] == null)
|
|
retVal.Add(null);
|
|
else
|
|
retVal.Add(aggDouble[i] / weightDouble[i]);
|
|
}
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case eDataHistoryAggregationType.latestTime:
|
|
retVal = aggEvent?.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
case eDataHistoryAggregationType.count:
|
|
case eDataHistoryAggregationType.valuecount:
|
|
retVal = aggInt.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
case eDataHistoryAggregationType.Unknown:
|
|
return null;
|
|
}
|
|
|
|
switch (Column.ValueType)
|
|
{
|
|
case enumFasdValueType.INT:
|
|
case enumFasdValueType.BIGINT:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
case eDataHistoryAggregationType.max:
|
|
case eDataHistoryAggregationType.sum:
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggInt.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case enumFasdValueType.FLOAT:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
case eDataHistoryAggregationType.max:
|
|
case eDataHistoryAggregationType.sum:
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggDouble.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case enumFasdValueType.DATETIME:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
case eDataHistoryAggregationType.max:
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggTime.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case enumFasdValueType.VERSION:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
case eDataHistoryAggregationType.max:
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggVersion.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
case eDataHistoryAggregationType.sum:
|
|
retVal = listString.Select(x => (object)cDataHistoryCollector.getStingList(x)).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case enumFasdValueType.GUID:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggGuid.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
case enumFasdValueType.BOOLEAN:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.min:
|
|
case eDataHistoryAggregationType.max:
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggBoolean.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
default:
|
|
switch (Column.AggregationType)
|
|
{
|
|
case eDataHistoryAggregationType.first:
|
|
case eDataHistoryAggregationType.latestValue:
|
|
retVal = aggString.Select(x => (object)x).ToList();
|
|
return retVal;
|
|
case eDataHistoryAggregationType.sum:
|
|
retVal = listString.Select(x => (object)cDataHistoryCollector.getStingList(x)).ToList();
|
|
return retVal;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class cDataHistoryCustomJsonMeasure
|
|
{
|
|
public int? ResultCode = null;
|
|
public int? ErrorCode = null;
|
|
public string ErrorDescription = null;
|
|
public object Values;
|
|
}
|
|
|
|
}
|