feat: expand cockpit integrations and support workflows

Add Phoenix remote desktop, action connector, documentation engine, and gamification support. Refactor support-case processing and search/action UI, and update installer assets and dependencies.
This commit is contained in:
Meik
2026-07-13 11:16:53 +02:00
parent bbedbf71c8
commit 0b52999b1d
303 changed files with 11235 additions and 3580 deletions

View File

@@ -56,7 +56,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -95,12 +95,15 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="F4sdCockpitCommunicationM42Web.cs" />
<Compile Include="FasdCockpitCommunicationWeb.cs" />
<Compile Include="FasdCockpitMachineConfiguration.cs" />
<Compile Include="TicketOverview\TicketOverviewCountsResponse.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Compile Include="RemoteDesktopCommunication\AgentRemoteDesktopCommunication.cs" />
<Compile Include="F4sdCockpitCommunicationM42Web.cs" />
<Compile Include="FasdCockpitCommunicationWeb.cs" />
<Compile Include="FasdCockpitMachineConfiguration.cs" />
<Compile Include="RemoteDesktopCommunication\AgentRemoteDesktopConnecitonDetails.cs" />
<Compile Include="RemoteDesktopCommunication\ApiResult.cs" />
<Compile Include="TicketOverview\TicketOverviewCountsResponse.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\F4SD-Logging\F4SD-Logging.csproj">
<Project>{7793f281-b226-4e20-b6f6-5d53d70f1dc1}</Project>

View File

@@ -17,15 +17,14 @@ using C4IT.Security;
using C4IT.FASD.Communication.Agent;
using FasdCockpitBase.Models;
using FasdCockpitCommunication;
using FasdCockpitCommunication.TicketOverview;
using FasdCockpitCommunication;
using FasdCockpitCommunication.TicketOverview;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static C4IT.Logging.cLogManager;
using C4IT.Configuration;
using System.Runtime.InteropServices.WindowsRuntime;
using FasdCockpitCommunication.RemoteDesktopCommunication;
namespace C4IT.FASD.Cockpit.Communication
{
@@ -38,6 +37,7 @@ namespace C4IT.FASD.Cockpit.Communication
public cFasdCockpitCommunicationWeb()
{
M42 = new cF4sdCockpitCommunicationM42Web();
RemoteDesktopManager = new AgentRemoteDesktopCommunication();
}
public override bool IsDemo() => false;
@@ -73,7 +73,8 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(false);
var result = await http.GetHttpJson($"api/CheckConnection", 15000, CancellationToken.None);
var _url = $"api/CheckConnection";
var result = await http.GetHttpJson(_url, 15000, CancellationToken.None);
if (!result.IsOk)
{
@@ -81,7 +82,7 @@ namespace C4IT.FASD.Cockpit.Communication
return output;
}
SaveApiResultValueJson("CheckConnection", result.Result);
if (Debug_apiValues) SaveApiResultValueJson("CheckConnection", result.Result, _url);
var connectionResult = JsonConvert.DeserializeObject<cFasdApiConnectionInfo>(result.Result);
output.ApiConnectionInfo = connectionResult;
var assembly = Assembly.GetExecutingAssembly();
@@ -139,7 +140,7 @@ namespace C4IT.FASD.Cockpit.Communication
public static cOneTimePW GetOneTimePw() => new cOneTimePW("OneTimePw", cSecurePassword.Instance);
public cHttpHelper GetHttpHelper(bool useToken)
public static cHttpHelper GetHttpHelper(bool useToken)
{
try
{
@@ -171,7 +172,7 @@ namespace C4IT.FASD.Cockpit.Communication
if (result.IsOk)
{
SaveApiResultValue("Logon-GetUserIdByAccount", result.Result, "json");
if (Debug_apiValues) SaveApiResultValue("Logon-GetUserIdByAccount", result.Result, "json");
output = JsonConvert.DeserializeObject<Guid>(result.Result);
}
}
@@ -200,7 +201,7 @@ namespace C4IT.FASD.Cockpit.Communication
if (result.IsOk)
{
if (Debug_apiValues) SaveApiResultValueJson("Logon-Logon", result.Result);
if (Debug_apiValues) SaveApiResultValueJson("Logon-Logon", result.Result, _url);
var _retVal = JsonConvert.DeserializeObject<cF4sdUserInfo>(result.Result);
return _retVal;
}
@@ -234,11 +235,12 @@ namespace C4IT.FASD.Cockpit.Communication
{
var _payLoad = JsonConvert.SerializeObject(Token);
var http = GetHttpHelper(true);
var apiAccessInfo = await http.PostJsonAsync($"api/Logon/RegisterExternalToken", _payLoad, 14000, System.Threading.CancellationToken.None);
var _url = $"api/Logon/RegisterExternalToken";
var apiAccessInfo = await http.PostJsonAsync(_url, _payLoad, 14000, System.Threading.CancellationToken.None);
if (apiAccessInfo.IsOk)
{
var _str = apiAccessInfo.Result;
if (Debug_apiValues) SaveApiResultValueJson("Logon-RegisterExternalToken", _str);
if (Debug_apiValues) SaveApiResultValueJson("Logon-RegisterExternalToken", _str, _url);
var RetVal = JsonConvert.DeserializeObject<cF4SdUserInfoChange>(_str);
return RetVal;
}
@@ -271,9 +273,11 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(true);
var result = await http.GetHttpJson($"api/Logon/GetAdditionalUserInfo?AccountType={Type}", 5000, CancellationToken.None);
var _url = $"api/Logon/GetAdditionalUserInfo?AccountType={Type}";
var result = await http.GetHttpJson(_url, 5000, CancellationToken.None);
if (result.IsOk)
{
if (Debug_apiValues) SaveApiResultValueJson("Logon-GetAdditionalUserInfo", result.Result, _url);
var _retVal = JsonConvert.DeserializeObject<cF4SDAdditionalUserInfo>(result.Result);
return _retVal;
}
@@ -307,17 +311,17 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(false);
var result = await http.GetHttpJson("api/F4SDAnalytics/GetF4SDAnalyticsState", 2000, CancellationToken.None);
var _url = "api/F4SDAnalytics/GetF4SDAnalyticsState";
var result = await http.GetHttpJson(_url, 2000, CancellationToken.None);
if (result.IsOk)
{
if (Debug_apiValues) SaveApiResultValueJson("F4SDAnalytics-GetF4SDAnalyticsState", result.Result);
if (Debug_apiValues) SaveApiResultValueJson("F4SDAnalytics-GetF4SDAnalyticsState", result.Result, _url);
output = JsonConvert.DeserializeObject<bool>(result.Result);
}
else
{
apiError = (int)result.Status;
await CheckConnectionStatus?.Invoke();
}
}
@@ -353,7 +357,6 @@ namespace C4IT.FASD.Cockpit.Communication
if (!result.IsOk)
{
apiError = (int)result.Status;
await CheckConnectionStatus?.Invoke();
}
return result.IsOk;
@@ -391,7 +394,6 @@ namespace C4IT.FASD.Cockpit.Communication
if (!result.IsOk)
{
apiError = (int)result.Status;
await CheckConnectionStatus?.Invoke();
}
}
catch (Exception E)
@@ -576,7 +578,7 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(false);
var result = await http.GetHttpJson("api/CheckCollectorStatus", 15000, CancellationToken.None);
if (!result.IsOk)
@@ -617,7 +619,6 @@ namespace C4IT.FASD.Cockpit.Communication
if (!result.IsOk)
{
apiError = (int)result.Status;
await CheckConnectionStatus?.Invoke();
return null;
}
@@ -629,7 +630,6 @@ namespace C4IT.FASD.Cockpit.Communication
catch (Exception E)
{
apiError = E.HResult;
await CheckConnectionStatus?.Invoke();
LogException(E);
}
finally
@@ -875,6 +875,8 @@ namespace C4IT.FASD.Cockpit.Communication
public override async Task<cFasdApiSearchResultCollection> GetUserSearchResults(string Name, List<string> SIDs)
{
const string ApiName = "SearchUserByNameAndSids";
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
@@ -895,7 +897,7 @@ namespace C4IT.FASD.Cockpit.Communication
strSids = HttpUtility.UrlEncode(strSids);
var strUrl = $"api/SearchUserByNameAndSids?Name={_Name}&SIDs={strSids}";
var strUrl = $"api/{ApiName}?Name={_Name}&SIDs={strSids}";
var http = GetHttpHelper(true);
var result = await http.GetHttpJson(strUrl, 10000, System.Threading.CancellationToken.None);
@@ -907,7 +909,7 @@ namespace C4IT.FASD.Cockpit.Communication
return null;
}
if (Debug_apiValues) SaveApiResultValueJson("SearchUserByNameAndSids", result.Result, strUrl);
if (Debug_apiValues) SaveApiResultValueJson(ApiName, result.Result, strUrl);
var deserializedObject = JsonConvert.DeserializeObject<cFasdApiSearchResultCollection>(result.Result);
return deserializedObject;
@@ -919,7 +921,7 @@ namespace C4IT.FASD.Cockpit.Communication
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("SearchUserByNameAndSids", timeStart, apiError);
if (Debug_apiTiming) SaveApiTimingEntry(ApiName, timeStart, apiError);
LogMethodEnd(CM);
}
@@ -959,6 +961,9 @@ namespace C4IT.FASD.Cockpit.Communication
public override async Task<cF4sdStagedSearchResultRelationTaskId> StartGatheringRelations(IEnumerable<cFasdApiSearchResultEntry> relatedTo, CancellationToken token)
{
const string ApiName = "StagedSearchRelations";
const string LogName = ApiName + "_Start";
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
@@ -967,7 +972,7 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
string url = $"api/StagedSearchRelations?age={cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge}";
string url = $"api/{ApiName}?age={cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge}";
string json = JsonConvert.SerializeObject(relatedTo);
var http = GetHttpHelper(true);
var result = await http.PostJsonAsync(url, json, 5_000, token);
@@ -979,6 +984,7 @@ namespace C4IT.FASD.Cockpit.Communication
return null;
}
if (Debug_apiValues) SaveApiResultValueJson(LogName, result.Result, url);
return JsonConvert.DeserializeObject<cF4sdStagedSearchResultRelationTaskId>(result.Result);
}
catch (Exception ex)
@@ -989,7 +995,7 @@ namespace C4IT.FASD.Cockpit.Communication
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("StagedSearchRelationsStart", timeStart, apiError);
if (Debug_apiTiming) SaveApiTimingEntry(LogName, timeStart, apiError);
LogMethodEnd(CM);
}
return null;
@@ -997,6 +1003,9 @@ namespace C4IT.FASD.Cockpit.Communication
public override async Task<cF4sdStagedSearchResultRelations> GetStagedRelations(Guid id, CancellationToken token)
{
const string ApiName = "StagedSearchRelations";
const string LogName = ApiName + "_Get";
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
@@ -1005,7 +1014,7 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
string url = $"api/StagedSearchRelations/{id}";
string url = $"api/{ApiName}/{id}";
var http = GetHttpHelper(true);
var result = await http.GetHttpJson(url, 25_000, token, true);
@@ -1016,6 +1025,7 @@ namespace C4IT.FASD.Cockpit.Communication
return null;
}
if (Debug_apiValues) SaveApiResultValueJson(LogName, result.Result, url);
return JsonConvert.DeserializeObject<cF4sdStagedSearchResultRelations>(result.Result);
}
catch (Exception ex)
@@ -1026,14 +1036,17 @@ namespace C4IT.FASD.Cockpit.Communication
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("StagedSearchRelationsStart", timeStart, apiError);
if (Debug_apiTiming) SaveApiTimingEntry(LogName, timeStart, apiError);
LogMethodEnd(CM);
}
return null;
}
private async Task<cF4sdStagedSearchResultRelations> GetRelationResults(Guid relationTaskId, CancellationToken token)
public override async Task StopGatheringRelations(Guid id, CancellationToken token)
{
const string ApiName = "StagedSearchRelations";
const string LogName = ApiName + "_Stop";
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
@@ -1042,18 +1055,21 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
string url = $"api/StagedSearchRelations/{relationTaskId}";
string url = $"api/{ApiName}/{id}/stop";
var http = GetHttpHelper(true);
var result = await http.GetHttpJson(url, 5_000, token, true);
var result = await http.GetHttpJson(url, 5_000, token);
if (!result.IsOk)
{
apiError = (int)result.Status;
await CheckConnectionStatus?.Invoke();
return null;
if (!token.IsCancellationRequested)
await CheckConnectionStatus?.Invoke();
}
return JsonConvert.DeserializeObject<cF4sdStagedSearchResultRelations>(result.Result);
}
catch (TaskCanceledException E) when (token.IsCancellationRequested)
{
apiError = E.HResult;
LogEntry($"{LogName} was cancelled by token.", LogLevels.Debug);
}
catch (Exception ex)
{
@@ -1063,10 +1079,9 @@ namespace C4IT.FASD.Cockpit.Communication
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("StagedSearchRelations", timeStart, apiError);
if (Debug_apiTiming) SaveApiTimingEntry(LogName, timeStart, apiError);
LogMethodEnd(CM);
}
return null;
}
public override async Task<List<cF4sdApiSearchResultRelation>> GetSearchResultRelations(enumF4sdSearchResultClass resultType, List<cFasdApiSearchResultEntry> searchResults)
@@ -1101,7 +1116,7 @@ namespace C4IT.FASD.Cockpit.Communication
TimeSpan getRelationsDelay = TimeSpan.FromMilliseconds(500);
for (int i = 0; i < maxRetryCount; i++)
{
var relations = await GetRelationResults(relationTaskId.Id, CancellationToken.None).ConfigureAwait(false);
var relations = await GetStagedRelations(relationTaskId.Id, CancellationToken.None).ConfigureAwait(false);
output.AddRange(relations?.Relations);
if (relations.IsComplete)
@@ -1127,131 +1142,131 @@ namespace C4IT.FASD.Cockpit.Communication
LogMethodEnd(CM);
}
return output;
}
#region Ticketübersicht
public override async Task<Dictionary<string, int>> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
var apiError = 0;
var timeStart = DateTime.UtcNow;
try
{
var normalizedKeys = (keys ?? Enumerable.Empty<string>())
.Where(k => !string.IsNullOrWhiteSpace(k))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
var http = GetHttpHelper(true);
var scope = useRoleScope ? "role" : "personal";
var urlBuilder = new StringBuilder($"api/TicketOverview/GetCounts?scope={scope}");
if (normalizedKeys.Count > 0)
{
var joinedKeys = HttpUtility.UrlEncode(string.Join(",", normalizedKeys));
urlBuilder.Append($"&keys={joinedKeys}");
}
var url = urlBuilder.ToString();
var result = await http.GetHttpJson(url, 15000, CancellationToken.None);
if (!result.IsOk)
{
apiError = (int)result.Status;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogEntry($"Error on requesting ticket overview counts ({scope}). Status: {result.Status}", LogLevels.Warning);
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetCounts", result.Result, url);
var response = JsonConvert.DeserializeObject<TicketOverviewCountsResponse>(result.Result);
return response?.ToDictionary(normalizedKeys) ?? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
catch (Exception E)
{
apiError = E.HResult;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogException(E);
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetCounts", timeStart, apiError);
LogMethodEnd(CM);
}
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
public override async Task<List<cF4sdApiSearchResultRelation>> GetTicketOverviewRelations(string key, bool useRoleScope, int count)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
var apiError = 0;
var timeStart = DateTime.UtcNow;
var output = new List<cF4sdApiSearchResultRelation>();
try
{
if (string.IsNullOrWhiteSpace(key))
return output;
var http = GetHttpHelper(true);
var scope = useRoleScope ? "role" : "personal";
var safeKey = HttpUtility.UrlEncode(key);
var url = $"api/TicketOverview/GetRelations?key={safeKey}&scope={scope}&count={Math.Max(0, count)}";
var result = await http.GetHttpJson(url, 20000, CancellationToken.None);
if (!result.IsOk)
{
apiError = (int)result.Status;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogEntry($"Error on requesting ticket overview relations for '{key}' ({scope}). Status: {result.Status}", LogLevels.Warning);
return output;
}
if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetRelations", result.Result, url);
var relations = JsonConvert.DeserializeObject<List<cF4sdApiSearchResultRelation>>(result.Result);
if (relations != null)
output = relations;
}
catch (Exception E)
{
apiError = E.HResult;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogException(E);
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetRelations", timeStart, apiError);
LogMethodEnd(CM);
}
return output;
}
#endregion
public override async Task<cF4SDHealthCardRawData> GetHealthCardData(cF4sdHealthCardRawDataRequest requestData)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
return output;
}
#region Ticketübersicht
public override async Task<Dictionary<string, int>> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
var apiError = 0;
var timeStart = DateTime.UtcNow;
try
{
var normalizedKeys = (keys ?? Enumerable.Empty<string>())
.Where(k => !string.IsNullOrWhiteSpace(k))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
var http = GetHttpHelper(true);
var scope = useRoleScope ? "role" : "personal";
var urlBuilder = new StringBuilder($"api/TicketOverview/GetCounts?scope={scope}");
if (normalizedKeys.Count > 0)
{
var joinedKeys = HttpUtility.UrlEncode(string.Join(",", normalizedKeys));
urlBuilder.Append($"&keys={joinedKeys}");
}
var url = urlBuilder.ToString();
var result = await http.GetHttpJson(url, 15000, CancellationToken.None);
if (!result.IsOk)
{
apiError = (int)result.Status;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogEntry($"Error on requesting ticket overview counts ({scope}). Status: {result.Status}", LogLevels.Warning);
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetCounts", result.Result, url);
var response = JsonConvert.DeserializeObject<TicketOverviewCountsResponse>(result.Result);
return response?.ToDictionary(normalizedKeys) ?? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
catch (Exception E)
{
apiError = E.HResult;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogException(E);
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetCounts", timeStart, apiError);
LogMethodEnd(CM);
}
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
}
public override async Task<List<cF4sdApiSearchResultRelation>> GetTicketOverviewRelations(string key, bool useRoleScope, int count)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
var apiError = 0;
var timeStart = DateTime.UtcNow;
var output = new List<cF4sdApiSearchResultRelation>();
try
{
if (string.IsNullOrWhiteSpace(key))
return output;
var http = GetHttpHelper(true);
var scope = useRoleScope ? "role" : "personal";
var safeKey = HttpUtility.UrlEncode(key);
var url = $"api/TicketOverview/GetRelations?key={safeKey}&scope={scope}&count={Math.Max(0, count)}";
var result = await http.GetHttpJson(url, 20000, CancellationToken.None);
if (!result.IsOk)
{
apiError = (int)result.Status;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogEntry($"Error on requesting ticket overview relations for '{key}' ({scope}). Status: {result.Status}", LogLevels.Warning);
return output;
}
if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetRelations", result.Result, url);
var relations = JsonConvert.DeserializeObject<List<cF4sdApiSearchResultRelation>>(result.Result);
if (relations != null)
output = relations;
}
catch (Exception E)
{
apiError = E.HResult;
if (CheckConnectionStatus != null)
await CheckConnectionStatus.Invoke();
LogException(E);
}
finally
{
if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetRelations", timeStart, apiError);
LogMethodEnd(CM);
}
return output;
}
#endregion
public override async Task<cF4SDHealthCardRawData> GetHealthCardData(cF4sdHealthCardRawDataRequest requestData)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
var apiError = 0;
var timeStart = DateTime.UtcNow;
@@ -1546,7 +1561,8 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(false);
var apiAccessInfo = await http.GetHttpJson($"api/GetAgentApiConfiguration", 10000, System.Threading.CancellationToken.None);
var _url = $"api/GetAgentApiConfiguration";
var apiAccessInfo = await http.GetHttpJson(_url, 10000, System.Threading.CancellationToken.None);
if (!apiAccessInfo.IsOk)
{
@@ -1554,7 +1570,7 @@ namespace C4IT.FASD.Cockpit.Communication
return false;
}
if (Debug_apiValues) SaveApiResultValueJson("GetAgentApiConfiguration", apiAccessInfo.Result);
if (Debug_apiValues) SaveApiResultValueJson("GetAgentApiConfiguration", apiAccessInfo.Result, _url);
var apiConfiguration = JsonConvert.DeserializeObject<cAgentApiConfiguration>(apiAccessInfo.Result);
if (apiConfiguration != null)
apiConfiguration.ClientSecret = cSecurePassword.Instance.Decode(apiConfiguration.ClientSecret);
@@ -1570,7 +1586,6 @@ namespace C4IT.FASD.Cockpit.Communication
catch (Exception E)
{
apiError = E.HResult;
await CheckConnectionStatus?.Invoke();
LogException(E);
}
finally
@@ -1593,7 +1608,8 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(true);
var cockpitconfigResult = await http.GetHttpJson($"api/GetCockpitConfiguration", 10000, System.Threading.CancellationToken.None);
var _url = $"api/GetCockpitConfiguration";
var cockpitconfigResult = await http.GetHttpJson(_url, 10000, System.Threading.CancellationToken.None);
if (!cockpitconfigResult.IsOk)
{
@@ -1601,7 +1617,7 @@ namespace C4IT.FASD.Cockpit.Communication
return false;
}
if (Debug_apiValues) SaveApiResultValueJson("GetCockpitConfiguration", cockpitconfigResult.Result);
if (Debug_apiValues) SaveApiResultValueJson("GetCockpitConfiguration", cockpitconfigResult.Result, _url);
var Configuration = JsonConvert.DeserializeObject<cCockpitConfiguration>(cockpitconfigResult.Result);
if (Configuration?.agentApiConfiguration?.ClientSecret != null)
Configuration.agentApiConfiguration.ClientSecret = cSecurePassword.Instance.Decode(Configuration.agentApiConfiguration.ClientSecret);
@@ -1616,7 +1632,6 @@ namespace C4IT.FASD.Cockpit.Communication
catch (Exception E)
{
apiError = E.HResult;
await CheckConnectionStatus?.Invoke();
LogException(E);
}
finally
@@ -1639,7 +1654,8 @@ namespace C4IT.FASD.Cockpit.Communication
try
{
var http = GetHttpHelper(false);
var result = await http.GetHttpJson("api/QuickAction/GetQuickActionList", 15000, CancellationToken.None);
var _url = "api/QuickAction/GetQuickActionList";
var result = await http.GetHttpJson(_url, 15000, CancellationToken.None);
if (!result.IsOk)
{
@@ -1652,6 +1668,7 @@ namespace C4IT.FASD.Cockpit.Communication
}
if (result.Result is string jsonString && !string.IsNullOrWhiteSpace(jsonString))
{
if (Debug_apiValues) SaveApiResultValueJson("GetQuickActionsOfServer", result.Result, _url);
return JsonConvert.DeserializeObject<List<string>>(result.Result);
}
}
@@ -2041,10 +2058,17 @@ namespace C4IT.FASD.Cockpit.Communication
private void SaveApiResultValueJson(string ApiName, string json, string comment = null)
{
List<string> comments = null;
if (comment != null)
comments = new List<string>() { comment };
SaveApiResultValueJson(ApiName, json, comments);
try
{
List<string> comments = null;
if (comment != null)
comments = new List<string>() { comment };
SaveApiResultValueJson(ApiName, json, comments);
}
catch (Exception E)
{
LogException(E);
}
}
private void SaveApiResultValueJson(string ApiName, string json, List<string> comment)
@@ -2157,6 +2181,6 @@ namespace C4IT.FASD.Cockpit.Communication
return null;
}
}
}

View File

@@ -0,0 +1,116 @@
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.FASD.Communication.Agent;
using C4IT.HTTP;
using FasdCockpitBase;
using FasdCockpitBase.Models.RemoteDesktopConnection;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace FasdCockpitCommunication.RemoteDesktopCommunication
{
internal class AgentRemoteDesktopCommunication : RemoteDesktopCommunicationBase
{
private readonly HttpClient _httpClient = new HttpClient();
public AgentRemoteDesktopCommunication()
{
_httpClient.BaseAddress = new Uri(cFasdCockpitMachineConfiguration.Instance.ServerUrl);
}
public override async Task<T> InitiateConnection<T>(IRemoteDesktopClientInfo clientInfo, bool isElevated, CancellationToken token)
{
cHttpHelper httpHelper = cFasdCockpitCommunicationWeb.GetHttpHelper(false);
string json = JsonConvert.SerializeObject(clientInfo);
string path = "api/RemoteDesktop/Initiate";
if (isElevated)
path += "?isElevated=true";
cHttpResult result = await httpHelper.PostJsonAsync(path, json, 30_000, token);
return JsonConvert.DeserializeObject<T>(result.Result);
}
public override async Task<RemoteDesktopConnectionStatusResult> GetConnectionStatus(Guid connectionId, CancellationToken token)
{
cHttpHelper http = cFasdCockpitCommunicationWeb.GetHttpHelper(false);
string path = $"api/RemoteDesktop/{connectionId}/Status";
cHttpResult result = await http.GetHttpJson(path, 15_000, token, true);
if (!result.IsOk)
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Unknown);
AgentRemoteConnectionStatusDto connectionStatus = JsonConvert.DeserializeObject<AgentRemoteConnectionStatusDto>(result.Result);
return GetGeneralConnectionStatus(connectionStatus);
}
private RemoteDesktopConnectionStatusResult GetGeneralConnectionStatus(AgentRemoteConnectionStatusDto connectionStatus)
{
switch (connectionStatus.Status)
{
case AgentRemoteConnectionStatus.New:
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Initiated);
case AgentRemoteConnectionStatus.Accepted:
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Accepted);
case AgentRemoteConnectionStatus.DisconnectedByHelpdesk:
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Finished);
case AgentRemoteConnectionStatus.DisconnectedByClient:
case AgentRemoteConnectionStatus.Failed:
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Canceled);
case AgentRemoteConnectionStatus.Unknown:
default:
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Unknown);
}
}
public override async Task StopConnection(Guid connectionId, CancellationToken token)
{
cHttpHelper http = cFasdCockpitCommunicationWeb.GetHttpHelper(false);
string path = $"api/RemoteDesktop/{connectionId}/Stop";
await http.DeleteAsync(path, 15_000, token, true);
}
public override async Task<HealthInformation> GetHealth(CancellationToken token)
{
cHttpHelper http = cFasdCockpitCommunicationWeb.GetHttpHelper(false);
string path = $"api/RemoteDesktop/health";
cHttpResult result = await http.GetHttpJson(path, 10_000, token, true);
if (!result.IsOk)
return new HealthInformation(HealthStatus.unhealthy);
return JsonConvert.DeserializeObject<HealthInformation>(result.Result);
}
public override async Task<bool> IsRemoteDesktopCommunicationAvailable()
{
cHttpHelper http = cFasdCockpitCommunicationWeb.GetHttpHelper(false);
string path = $"api/RemoteDesktop/IsActive";
cHttpResult result = await http.GetHttpJson(path, 5_000, CancellationToken.None, false);
if (!result.IsOk)
return false;
bool isRemoteViewerActive = JsonConvert.DeserializeObject<bool>(result.Result); ;
if (!isRemoteViewerActive)
return false;
return await base.IsRemoteDesktopCommunicationAvailable();
}
}
public class AgentRemoteClientInfo : IRemoteDesktopClientInfo
{
[JsonProperty("orgCode")]
public int OrganisationCode { get; set; }
[JsonProperty("deviceCode")]
public int DeviceCode { get; set; }
[JsonProperty("accountCode")]
public int AccountCode { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using FasdCockpitBase.Models.RemoteDesktopConnection;
using Newtonsoft.Json;
using System;
namespace FasdCockpitCommunication.RemoteDesktopCommunication
{
public class AgentRemoteDesktopConnecitonDetails : ApiResult, IRemoteDesktopConnectionDetails
{
[JsonProperty("connectionId")]
public Guid ConnectionId { get; set; }
[JsonProperty("phoenixServiceUrl")]
public Uri PhoenixServiceUrl { get; set; }
[JsonProperty("secret")]
public string Secret { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace FasdCockpitCommunication.RemoteDesktopCommunication
{
public class ApiResult
{
[JsonProperty("errors")]
public IList<ApiError> Errors { get; set; }
}
public class ApiError
{
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
}

View File

@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.2" newVersion="10.0.0.2" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.3" newVersion="10.0.0.3" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
</packages>