inital
This commit is contained in:
439
FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs
Normal file
439
FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs
Normal file
@@ -0,0 +1,439 @@
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Graphics;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using C4IT.Security;
|
||||
|
||||
using FasdCockpitBase.Models;
|
||||
|
||||
using FasdDesktopUi.Pages.SettingsPage;
|
||||
using FasdDesktopUi.Pages.SplashScreenView;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models
|
||||
{
|
||||
public class cConnectionStatusHelper
|
||||
{
|
||||
public enum enumOnlineStatus
|
||||
{
|
||||
notSpecified = 0,
|
||||
offline,
|
||||
connectionError,
|
||||
incompatibleServerVersion,
|
||||
serverNotConfigured,
|
||||
serverStarting,
|
||||
illegalConfig,
|
||||
unauthorized,
|
||||
online
|
||||
}
|
||||
|
||||
public enum enumCheckReason
|
||||
{
|
||||
firstStart = 0,
|
||||
lateInit,
|
||||
heartBeat
|
||||
}
|
||||
|
||||
public bool IsActive = true;
|
||||
|
||||
public readonly Version MinServerVersion = new Version("0.0.0.0");
|
||||
|
||||
private enum enumCheckRunning { no = 0, running, again };
|
||||
|
||||
private enumCheckReason checkReason = enumCheckReason.firstStart;
|
||||
|
||||
public delegate void ConnectionStatusDelegate(enumOnlineStatus? Status);
|
||||
public static event ConnectionStatusDelegate ApiConnectionStatusChanged;
|
||||
|
||||
public delegate cF4SdUserInfoChange M42FormBasedAuthenticationDelegate();
|
||||
public event M42FormBasedAuthenticationDelegate M42FormBasedAuthentication;
|
||||
|
||||
public static cConnectionStatusHelper Instance { get; set; }
|
||||
|
||||
public bool IsAuthorizationSupported { get; private set; } = false;
|
||||
private System.Timers.Timer timer;
|
||||
|
||||
#region Lock Elements Connecion Status
|
||||
private readonly object connectionStatusCheckLock = new object();
|
||||
private enumCheckRunning IsConnectionStatusCheckRunning = enumCheckRunning.no;
|
||||
#endregion
|
||||
|
||||
public enumOnlineStatus ApiConnectionStatus = enumOnlineStatus.notSpecified;
|
||||
|
||||
public cConnectionStatusHelper()
|
||||
{
|
||||
ApiConnectionStatus = enumOnlineStatus.offline;
|
||||
cFasdCockpitCommunicationBase.Instance.CheckConnectionStatus = RunConnectionStatusCheckAsync;
|
||||
timer = new System.Timers.Timer();
|
||||
timer.Elapsed += Timer_Elapsed;
|
||||
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
var arrMinClientVersion = assembly.GetCustomAttributes(typeof(AssemblyMinServerVersion), false);
|
||||
if (arrMinClientVersion != null && arrMinClientVersion.Length >= 1)
|
||||
{
|
||||
var attrMinClientVersion = (AssemblyMinServerVersion)(arrMinClientVersion[0]);
|
||||
MinServerVersion = new Version(attrMinClientVersion.minServerVersion);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) => await RunConnectionStatusCheckAsync();
|
||||
|
||||
public async Task RunConnectionStatusCheckAsync()
|
||||
{
|
||||
await RunConnectionStatusCheckAsync(null);
|
||||
}
|
||||
|
||||
private (int timerInterval, int shortInterval) GetTimerIntervalFromRegistry(int defaultInterval, int defaultShortInterval)
|
||||
{
|
||||
int timerInterval = defaultInterval;
|
||||
int shortInterval = defaultShortInterval;
|
||||
|
||||
if (!cLogManager.DefaultLogger.IsDebug)
|
||||
return (timerInterval, shortInterval);
|
||||
|
||||
try
|
||||
{
|
||||
var regBase = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32);
|
||||
var regKey = regBase.OpenSubKey("SOFTWARE\\Consulting4IT GmbH\\First Aid Service Desk\\Cockpit", false);
|
||||
|
||||
if (regKey is null || !int.TryParse(regKey.GetValue("DebugConnectionCheck", 0).ToString(), out var regValue))
|
||||
return (timerInterval, shortInterval);
|
||||
|
||||
if (regValue <= 0)
|
||||
return (timerInterval, shortInterval);
|
||||
|
||||
timerInterval = regValue * 1000;
|
||||
shortInterval = timerInterval / 10;
|
||||
}
|
||||
catch { }
|
||||
|
||||
return (timerInterval, shortInterval);
|
||||
}
|
||||
|
||||
private void HandleConnectionStatus(enumConnectionStatus status, ref int timerInterval, int timerInteralShort)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case enumConnectionStatus.unknown:
|
||||
case enumConnectionStatus.serverNotFound:
|
||||
if (ApiConnectionStatus != enumOnlineStatus.offline)
|
||||
ApiConnectionStatus = enumOnlineStatus.offline;
|
||||
timerInterval = timerInteralShort;
|
||||
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'serverNotFound'");
|
||||
break;
|
||||
case enumConnectionStatus.serverResponseError:
|
||||
ApiConnectionStatus = enumOnlineStatus.connectionError;
|
||||
timerInterval = timerInteralShort;
|
||||
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'serverResponseError'");
|
||||
break;
|
||||
case enumConnectionStatus.incompatibleServerVersion:
|
||||
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'incompatibleServerVersion'");
|
||||
ApiConnectionStatus = enumOnlineStatus.incompatibleServerVersion;
|
||||
break;
|
||||
case enumConnectionStatus.serverStarting:
|
||||
ApiConnectionStatus = enumOnlineStatus.serverStarting;
|
||||
break;
|
||||
case enumConnectionStatus.serverNotConfigured:
|
||||
ApiConnectionStatus = enumOnlineStatus.serverNotConfigured;
|
||||
break;
|
||||
case enumConnectionStatus.connected:
|
||||
if (cCockpitConfiguration.Instance == null || cF4SDCockpitXmlConfig.Instance == null)
|
||||
ApiConnectionStatus = enumOnlineStatus.illegalConfig;
|
||||
else if (ApiConnectionStatus != enumOnlineStatus.online)
|
||||
ApiConnectionStatus = enumOnlineStatus.online;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunConnectionStatusCheckAsync(SplashScreenView splashScreen)
|
||||
{
|
||||
if (!IsActive)
|
||||
return;
|
||||
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
(int timerInterval, int shortTimerInterval) = GetTimerIntervalFromRegistry(300000, 30000);
|
||||
enumOnlineStatus oldConnectionStatus = ApiConnectionStatus;
|
||||
|
||||
try
|
||||
{
|
||||
timer.Stop();
|
||||
lock (connectionStatusCheckLock)
|
||||
{
|
||||
switch (IsConnectionStatusCheckRunning)
|
||||
{
|
||||
case enumCheckRunning.again:
|
||||
LogEntry("RunConnectionStatusCheckAsync is already running. Status is 'again'.");
|
||||
return;
|
||||
case enumCheckRunning.running:
|
||||
LogEntry("RunConnectionStatusCheckAsync is already running. Status is 'running'.");
|
||||
IsConnectionStatusCheckRunning = enumCheckRunning.again;
|
||||
return;
|
||||
default:
|
||||
IsConnectionStatusCheckRunning = enumCheckRunning.running;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cCheckConnectionResult connectionResult = await cFasdCockpitCommunicationBase.Instance.CheckConnection(MinServerVersion);
|
||||
IsAuthorizationSupported = connectionResult?.ApiConnectionInfo?.SupportAuthorisation ?? false;
|
||||
|
||||
HandleConnectionStatus(connectionResult.ConnectionStatus, ref timerInterval, shortTimerInterval);
|
||||
if (connectionResult.ConnectionStatus != enumConnectionStatus.connected)
|
||||
return;
|
||||
|
||||
if (checkReason < enumCheckReason.heartBeat && ApiConnectionStatus == enumOnlineStatus.illegalConfig)
|
||||
{
|
||||
// download the xml config files
|
||||
Task<bool> loadConfigFilesTask = Task.Run(async () => await cFasdCockpitConfig.Instance.LoadConfigFilesAsync(cFasdCockpitCommunicationBase.Instance));
|
||||
// get the cockpit base configuration from server
|
||||
Task<bool> getCockpitConfig = Task.Run(async () => await cFasdCockpitConfig.Instance.GetCockpitConfigurationAsync());
|
||||
|
||||
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.LoadConfigs")));
|
||||
var configTasks = await Task.WhenAll(loadConfigFilesTask, getCockpitConfig);
|
||||
|
||||
if (configTasks.Any(t => t == false))
|
||||
return;
|
||||
if (cFasdCockpitConfig.Instance?.Global != null && cCockpitConfiguration.Instance?.GlobalConfig != null)
|
||||
{
|
||||
cFasdCockpitConfig.Instance.Global.Load(cCockpitConfiguration.Instance.GlobalConfig);
|
||||
cFasdCockpitConfig.Instance.Global.Save();
|
||||
}
|
||||
}
|
||||
|
||||
cF4sdUserInfo userInfo;
|
||||
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
|
||||
{
|
||||
userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo;
|
||||
}
|
||||
if (IsAuthorizationSupported)
|
||||
{
|
||||
if (userInfo is null || DateTime.UtcNow > userInfo.RenewUntil)
|
||||
{
|
||||
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.AuthenticateUser")));
|
||||
ApiConnectionStatus = enumOnlineStatus.unauthorized;
|
||||
const string cockpitUserRole = "Cockpit.User";
|
||||
#if isNewFeature
|
||||
const string cockpitTicketAgentRole = "Cockpit.TicketAgent";
|
||||
#endif
|
||||
userInfo = await cFasdCockpitCommunicationBase.Instance.WinLogon();
|
||||
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
|
||||
{
|
||||
cFasdCockpitCommunicationBase.CockpitUserInfo = userInfo;
|
||||
}
|
||||
if (userInfo?.Roles is null || !userInfo.Roles.Contains(cockpitUserRole))
|
||||
{
|
||||
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.NoAuthorization")));
|
||||
LogEntry($"Cockpit User ({userInfo?.Name} with Id {userInfo?.Id}, has not the required permissions.", LogLevels.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Run(async () => await cFasdCockpitConfig.Instance.InstantiateAnalyticsAsync(cFasdCockpitConfig.SessionId));
|
||||
ApiConnectionStatus = enumOnlineStatus.online;
|
||||
#if isNewFeature
|
||||
if (userInfo.Roles.Contains(cockpitTicketAgentRole))
|
||||
cCockpitConfiguration.Instance.ticketSupport.EditTicket = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (userInfo == null)
|
||||
{
|
||||
string cockpitUserName = Environment.UserName;
|
||||
string cockpitUserDomain = Environment.UserDomainName;
|
||||
Guid cockpitUserId = await cFasdCockpitCommunicationBase.Instance.GetUserIdByAccount(cockpitUserName, cockpitUserDomain);
|
||||
if (cockpitUserId == Guid.Empty)
|
||||
LogEntry($"Could not get UserId for cockpit user '{cockpitUserName}@{cockpitUserDomain}'.", LogLevels.Warning);
|
||||
else
|
||||
{
|
||||
userInfo = new cF4sdUserInfo()
|
||||
{
|
||||
Id = cockpitUserId,
|
||||
AccountType = cF4sdUserInfo.enumAccountType.unknown,
|
||||
};
|
||||
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
|
||||
{
|
||||
cFasdCockpitCommunicationBase.CockpitUserInfo = userInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
ApiConnectionStatus = enumOnlineStatus.online;
|
||||
}
|
||||
|
||||
if (App.M42OptionMenuItem != null)
|
||||
App.M42OptionMenuItem.Enabled = userInfo != null;
|
||||
|
||||
// check, if the are logons needed
|
||||
bool m42Valid = await CheckAndRefreshM42LogonAsync();
|
||||
await cFasdCockpitConfig.Instance.CheckAgentScriptAvailabilityAsync();
|
||||
await cFasdCockpitConfig.Instance.CheckServerQuickActionAvailabilityAsync();
|
||||
await cFasdCockpitCommunicationBase.Instance.InitializeAfterOnlineAsync();
|
||||
cFasdCockpitConfig.Instance.OnUiSettingsChanged();
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (connectionStatusCheckLock)
|
||||
{
|
||||
if (IsConnectionStatusCheckRunning == enumCheckRunning.again)
|
||||
timerInterval = 1;
|
||||
IsConnectionStatusCheckRunning = enumCheckRunning.no;
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
if (IsActive)
|
||||
{
|
||||
if (ApiConnectionStatus == enumOnlineStatus.online)
|
||||
NotifyerSupport.SetNotifyIcon("Default", null, NotifyerSupport.enumIconAlignment.BottomRight);
|
||||
else
|
||||
NotifyerSupport.SetNotifyIcon("Default", "OverlayOffline", NotifyerSupport.enumIconAlignment.BottomRight);
|
||||
if (ApiConnectionStatus != oldConnectionStatus)
|
||||
OnApiConnectionStatusChanged();
|
||||
}
|
||||
if (timer != null)
|
||||
{
|
||||
timer.Interval = timerInterval;
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> CheckAndRefreshM42LogonAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo;
|
||||
|
||||
if (userInfo == null)
|
||||
return false;
|
||||
|
||||
// do we have a valid M42 token?
|
||||
if (userInfo?.ValidLogonsUntil != null && userInfo.ValidLogonsUntil.TryGetValue(enumAdditionalAuthentication.M42WinLogon, out var logonPeriod))
|
||||
{
|
||||
if (logonPeriod.renewUntil > DateTime.UtcNow)
|
||||
return true;
|
||||
}
|
||||
|
||||
// do we need a logon?
|
||||
var isNeeded = false;
|
||||
if (cFasdCockpitConfig.Instance?.M42Config == null)
|
||||
return false;
|
||||
|
||||
cF4sdCockpitConfigM42 config = cFasdCockpitConfig.Instance.M42Config;
|
||||
if (config.Control == enumM42AuthenticationControl.always)
|
||||
isNeeded = true;
|
||||
else if (config.Control == enumM42AuthenticationControl.auto)
|
||||
{
|
||||
if (userInfo?.additionalLogons == null)
|
||||
return false;
|
||||
|
||||
if (userInfo.additionalLogons.Contains(enumAdditionalAuthentication.M42WinLogon))
|
||||
isNeeded = true;
|
||||
}
|
||||
|
||||
if (!isNeeded)
|
||||
return false;
|
||||
|
||||
// yes, we need a new logon
|
||||
cF4sdCockpitM42BearerTokenInfo tokenInfo = null;
|
||||
cF4SdUserInfoChange userChange = null;
|
||||
switch (config.Method)
|
||||
{
|
||||
case enumM42AuthenticationMethod.passthrough:
|
||||
tokenInfo = await cFasdCockpitCommunicationBase.Instance.M42.ValidateLogonPassthrough();
|
||||
break;
|
||||
case enumM42AuthenticationMethod.basic:
|
||||
var user = config.BasicUser;
|
||||
var pw = PrivateSecurePassword.Instance.Decode(config.BasicPassword);
|
||||
tokenInfo = await cFasdCockpitCommunicationBase.Instance.M42.ValidateLogonBasic(user, pw);
|
||||
break;
|
||||
case enumM42AuthenticationMethod.token:
|
||||
var token = PrivateSecurePassword.Instance.Decode(config.ApiToken);
|
||||
tokenInfo = await cFasdCockpitCommunicationBase.Instance.M42.ValidateLogonToken(token);
|
||||
break;
|
||||
case enumM42AuthenticationMethod.forms:
|
||||
var FormBasedAuth = M42FormBasedAuthentication;
|
||||
userChange = FormBasedAuth?.Invoke();
|
||||
break;
|
||||
}
|
||||
|
||||
if (tokenInfo?.Token != null && tokenInfo.ValidUntil > DateTime.UtcNow)
|
||||
{
|
||||
var tokenRegistration = new cF4SDTokenRegistration()
|
||||
{
|
||||
UserId = userInfo.Id,
|
||||
TokenType = cF4SDTokenRegistration.enumTokenType.M42Bearer,
|
||||
Secret = tokenInfo.Token
|
||||
};
|
||||
|
||||
userChange = await cFasdCockpitCommunicationBase.Instance.RegisterExternalTokenAsync(tokenRegistration);
|
||||
}
|
||||
|
||||
if (userChange != null)
|
||||
{
|
||||
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
|
||||
{
|
||||
userChange.ChangeUserInfo(cFasdCockpitCommunicationBase.CockpitUserInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnApiConnectionStatusChanged()
|
||||
{
|
||||
ConnectionStatusDelegate handler = ApiConnectionStatusChanged;
|
||||
handler?.Invoke(ApiConnectionStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user