- modularize Citrix and agent integrations and add remote desktop endpoints - extend ticket overview, ticket links, token validation, and staged relation handling - update configuration, licensing, project, signing, and publish artifacts
1022 lines
37 KiB
C#
1022 lines
37 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.Design;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using C4IT.HTTP;
|
|
using C4IT.Logging;
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
using static C4IT.Logging.cLogManager;
|
|
|
|
namespace C4IT.FASD.Communication.Citrix
|
|
{
|
|
public class cCitrixApiResultList : List<cCitrixApiResultBase>
|
|
{
|
|
public string NextResultUrl { get; private set; } = null;
|
|
public bool retryForbidden { get; private set; } = false;
|
|
|
|
public cCitrixApiResultList(bool retryForbidden)
|
|
{
|
|
this.retryForbidden = retryForbidden;
|
|
}
|
|
|
|
public bool hasRemaining
|
|
{
|
|
get
|
|
{
|
|
return !string.IsNullOrEmpty(NextResultUrl);
|
|
}
|
|
}
|
|
|
|
public void AddResult(dynamic Result)
|
|
{
|
|
try
|
|
{
|
|
NextResultUrl = null;
|
|
|
|
if (Result.TryGetValue("@odata.nextLink", out JToken JT))
|
|
{
|
|
var JO = (JValue)JT;
|
|
|
|
NextResultUrl = Result["@odata.nextLink"];
|
|
}
|
|
|
|
if (Result.TryGetValue("value", out JToken JT2))
|
|
{
|
|
foreach (dynamic Entry in Result.value)
|
|
try
|
|
{
|
|
var val = new cCitrixApiResultBase(Entry);
|
|
this.Add(val);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public class cCitrixApiResultBase
|
|
{
|
|
public string ID { get; private set; } = null;
|
|
public string ODataId { get; private set; } = null;
|
|
public string DisplayName { get; private set; } = null;
|
|
|
|
public string Context { get; private set; } = null;
|
|
|
|
public dynamic Result { get; private set; } = null;
|
|
|
|
public cCitrixApiResultBase(dynamic Result, string namePropery = null)
|
|
{
|
|
this.Result = Result;
|
|
|
|
try { ID = Result.Id; } catch { }
|
|
;
|
|
try
|
|
{
|
|
if (namePropery == null)
|
|
namePropery = "displayName";
|
|
if (Result.TryGetValue(namePropery, out JToken JT1))
|
|
{
|
|
var _ty = JT1.GetType().ToString();
|
|
if (JT1 is JValue _jVal)
|
|
DisplayName = _jVal.Value?.ToString();
|
|
}
|
|
else if (Result.TryGetValue("name", out JToken JT2))
|
|
DisplayName = Result.name;
|
|
}
|
|
catch { }
|
|
try { Context = Result["@odata.context"]; } catch { }
|
|
ODataId = GetStringFromDynamic(Result, "@odata.id");
|
|
if (string.IsNullOrEmpty(ODataId))
|
|
ODataId = @"https://api.cloud.com/" + ID;
|
|
}
|
|
|
|
public cCitrixApiResultBase(cCitrixApiResultBase Result)
|
|
{
|
|
if (Result == null)
|
|
return;
|
|
|
|
this.Result = Result.Result;
|
|
ID = Result.ID;
|
|
ODataId = Result.ODataId;
|
|
DisplayName = Result.DisplayName;
|
|
Context = Result.Context;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static string GetStringFromDynamic(dynamic O, string ProperyName)
|
|
{
|
|
try
|
|
{
|
|
return (string)O[ProperyName];
|
|
}
|
|
catch { }
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class cCitrixCustomerInfo
|
|
{
|
|
public string Id { get; set; }
|
|
public string Name { get; set; } = string.Empty;
|
|
|
|
public cCitrixSiteInfo PrimarySite { get; set; }
|
|
|
|
public Dictionary<Guid, cCitrixSiteInfo> Sites { get; private set; } = new Dictionary<Guid, cCitrixSiteInfo>();
|
|
}
|
|
|
|
public class cCitrixSiteInfo
|
|
{
|
|
public Guid Id { get; set; }
|
|
public string Name { get; set; } = string.Empty;
|
|
|
|
public bool? IsValid { get; set; } = null;
|
|
public bool IsPrimarySite { get; set; } = false;
|
|
}
|
|
|
|
public class cCitrixCommunicationSystem
|
|
{
|
|
public const string constCitrixCloudMonitorUrl = "monitorodata/";
|
|
|
|
public const string constCitrixOnPremMonitorUrl = "Citrix/Monitor/OData/v4/Data/";
|
|
|
|
public cCitrixCommunicationMonitor Monitor { get; private set; }
|
|
public cCitrixCommunicationCvad CVAD { get; private set; }
|
|
|
|
public bool IsCloud { get; private set; }
|
|
|
|
public string Name { get; private set; } = string.Empty;
|
|
|
|
public cCitrixCommunicationSystem(cCitrixCommunicationCloudBase CitrixCloud, string Name)
|
|
{
|
|
IsCloud = true;
|
|
this.Name = Name;
|
|
this.Monitor = new cCitrixCommunicationMonitor(CitrixCloud);
|
|
this.CVAD = new cCitrixCommunicationCvad(CitrixCloud);
|
|
}
|
|
|
|
public cCitrixCommunicationSystem(cCitrixCommunicationOnPremCvad Cvad, cCitrixCommunicationOnPremMonitor Monitor, string Name)
|
|
{
|
|
IsCloud = false;
|
|
this.Name = Name;
|
|
this.Monitor = new cCitrixCommunicationMonitor(Monitor);
|
|
this.CVAD = new cCitrixCommunicationCvad(Cvad);
|
|
}
|
|
|
|
public async Task<cCitrixCustomerInfo> ScanCustomerInfosAsync(CancellationToken token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var _retVal = new cCitrixCustomerInfo();
|
|
var CustomerInfo = await CVAD.GetCustomerInfoAsync(token);
|
|
if (token.IsCancellationRequested)
|
|
return null;
|
|
|
|
if (CustomerInfo == null)
|
|
return _retVal;
|
|
|
|
_retVal.Id = CustomerInfo.Id;
|
|
_retVal.Name = CustomerInfo.Name;
|
|
|
|
cCitrixSiteInfo PrimarySite = null;
|
|
int maxConsitency = 0;
|
|
int countC0 = 0;
|
|
int countC1 = 0;
|
|
int countC2 = 0;
|
|
foreach (var site in CustomerInfo.Sites.Values)
|
|
{
|
|
var _newSite = new cCitrixSiteInfo()
|
|
{
|
|
Name = site.Name,
|
|
Id = site.Id,
|
|
IsValid = false
|
|
};
|
|
|
|
// validate the site consitency
|
|
var _resultConsitency = await CheckSiteConsitencyAsync(site.Id.ToString("D"), token);
|
|
if (token.IsCancellationRequested)
|
|
return null;
|
|
switch (_resultConsitency)
|
|
{
|
|
case 0: _newSite.IsValid = null; countC0++; break;
|
|
case 1: _newSite.IsValid = true; countC1++; break;
|
|
case 2: _newSite.IsValid = true; countC2++; break;
|
|
}
|
|
|
|
if (maxConsitency < _resultConsitency)
|
|
PrimarySite = _newSite;
|
|
|
|
maxConsitency = Math.Max(maxConsitency, _resultConsitency);
|
|
|
|
_retVal.Sites.Add(_newSite.Id, _newSite);
|
|
}
|
|
|
|
if (PrimarySite != null)
|
|
{
|
|
if (countC2 == 1)
|
|
PrimarySite.IsPrimarySite = true;
|
|
else if (countC1 == 1 && countC2 == 0)
|
|
PrimarySite.IsPrimarySite = true;
|
|
}
|
|
|
|
if (PrimarySite?.IsPrimarySite == true)
|
|
_retVal.PrimarySite = PrimarySite;
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<int> CheckSiteConsitencyAsync(string SiteId, CancellationToken token)
|
|
{
|
|
// check if the machines queried from the monitor component could be found in the cvad component
|
|
// return values:
|
|
// 2: all machines could be found
|
|
// 1: al least one machine could be found
|
|
// 0: no machines in monitor component
|
|
// -1: none of the machines could be found
|
|
// -2: internal error occured
|
|
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
var _lastSiteId = CVAD.CitrixInfo.SiteId;
|
|
try
|
|
{
|
|
CVAD.CitrixInfo.SiteId = SiteId;
|
|
|
|
// get the machine list from cvad
|
|
var _machinesCvad = await CVAD.GetMachineNamesAsync(token);
|
|
if (token.IsCancellationRequested)
|
|
return -2;
|
|
|
|
// get the machine list from monitor
|
|
var _machinesMonitor = await Monitor.GetMachineNamesAsync(token);
|
|
if (token.IsCancellationRequested)
|
|
return -2;
|
|
|
|
if (_machinesMonitor == null || _machinesMonitor.Count == 0)
|
|
return 0;
|
|
|
|
var atLeastOne = false;
|
|
var all = true;
|
|
foreach ( var machineName in _machinesMonitor )
|
|
{
|
|
if (_machinesCvad.Contains(machineName))
|
|
atLeastOne = true;
|
|
else
|
|
all = false;
|
|
}
|
|
|
|
if (atLeastOne && all)
|
|
return 2;
|
|
if (atLeastOne)
|
|
return 1;
|
|
|
|
return -1;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
CVAD.CitrixInfo.SiteId = _lastSiteId;
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
public interface iCitrixCvadInfo
|
|
{
|
|
string CustomerId { get; }
|
|
|
|
string SiteId { get; set; }
|
|
|
|
}
|
|
|
|
public class cCitrixCommunicationCloudBase : cHttpApiBase, iCitrixCvadInfo
|
|
{
|
|
public const int constMaxPageSize = 1000;
|
|
|
|
private string InstanceId = null;
|
|
|
|
public cCitrixCommunicationCloudBase(string baseUrlCloud) : base("Citrix customer tenant", $"{baseUrlCloud}/cctrustoauth2/{{Tenant}}/tokens/clients", "Citrix API", baseUrlCloud)
|
|
{
|
|
MaxConcurrentRequests = 1;
|
|
KnownAutoRetryErrors.Add((HttpStatusCode)429);
|
|
autoRetryCount = 50;
|
|
autoRetryDelay = 200;
|
|
autoRetryOnKnownErrors = true;
|
|
}
|
|
|
|
private protected override List<KeyValuePair<string, string>> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
|
|
{
|
|
|
|
return new List<KeyValuePair<string, string>>()
|
|
{
|
|
new KeyValuePair<string, string>("Authorization", $"CwsAuth Bearer={AccessToken}"),
|
|
new KeyValuePair<string, string>("Citrix-CustomerId", privLogonInfo.Tenant),
|
|
new KeyValuePair<string, string>("Citrix-InstanceId", InstanceId)
|
|
};
|
|
}
|
|
|
|
public string CustomerId { get {
|
|
return this.privLogonInfo?.Tenant;
|
|
} }
|
|
|
|
public string SiteId
|
|
{
|
|
get { return InstanceId; }
|
|
set { InstanceId = value; }
|
|
}
|
|
}
|
|
|
|
public class cCitrixCommunicationOnPremCvad : cHttpApiBase, iCitrixCvadInfo
|
|
{
|
|
private const string constLogonUrl = "manage/Tokens";
|
|
private string privCustomerId = null;
|
|
private string InstanceId = null;
|
|
|
|
public cCitrixCommunicationOnPremCvad(string baseUrl) : base("Citrix on-prem system", baseUrl, "Citrix API", baseUrl + "/cvad/")
|
|
{
|
|
// MaxConcurrentRequests = 1;
|
|
//KnownAutoRetryErrors.Add((HttpStatusCode)429);
|
|
//autoRetryCount = 50;
|
|
//autoRetryDelay = 200;
|
|
//autoRetryOnKnownErrors = true;
|
|
}
|
|
|
|
public string CustomerId { get { return privCustomerId; } }
|
|
|
|
public string SiteId
|
|
{
|
|
get { return InstanceId; }
|
|
set { InstanceId = value; }
|
|
}
|
|
|
|
private protected override async Task<cCredentialLoginInfo> privLogonWithCredentialsAsync(NetworkCredential credentials)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var _usr = credentials.UserName;
|
|
if (!string.IsNullOrEmpty(credentials.Domain))
|
|
_usr = $"{credentials.Domain}\\{_usr}";
|
|
var _auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_usr}:{credentials.Password}"));
|
|
using (var httpClient = new HttpClient())
|
|
{
|
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", _auth);
|
|
httpClient.BaseAddress = new Uri(RequestBaseUrl);
|
|
var _result = await httpClient.PostAsync(constLogonUrl, null);
|
|
if (_result != null)
|
|
{
|
|
var content = await _result.Content.ReadAsStringAsync();
|
|
if (_result.IsSuccessStatusCode)
|
|
{
|
|
var JO = JObject.Parse(content);
|
|
var token = JO["Token"]?.ToString();
|
|
var CustomerId = JO["CustomerId"]?.ToString();
|
|
var strExpires = JO["ExpiresAt"]?.ToString();
|
|
if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(CustomerId) || string.IsNullOrEmpty(strExpires))
|
|
{
|
|
LastErrorMessage = $"CVAD Logon failed because no valid token information could be found in the logon result.";
|
|
return new cCredentialLoginInfo();
|
|
}
|
|
|
|
|
|
if (!DateTime.TryParse(strExpires, out var expires))
|
|
{
|
|
LastErrorMessage = $"CVAD Logon failed because no valid expiration information could be found in the logon result.";
|
|
return new cCredentialLoginInfo();
|
|
}
|
|
|
|
expires = DateTime.SpecifyKind(expires, DateTimeKind.Utc);
|
|
var _now = DateTime.UtcNow;
|
|
|
|
var _expieresInteral = expires - _now;
|
|
var _delta = _expieresInteral.TotalSeconds * RelogonFactor;
|
|
var expires2 = _now + TimeSpan.FromSeconds(_delta);
|
|
|
|
this.privCustomerId = CustomerId;
|
|
|
|
return new cCredentialLoginInfo() { IsValid = true, Token = token, TokenExpiresIn = expires2 };
|
|
}
|
|
else
|
|
{
|
|
LastErrorMessage = $"CVAD Logon failed with status code {(int)_result.StatusCode}: {_result.ReasonPhrase}";
|
|
}
|
|
}
|
|
else
|
|
LastErrorMessage = $"CVAD Logon failed due to unknown reason.";
|
|
}
|
|
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LastErrorMessage = $"CVAD Logon failed with exception: {E.Message}";
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
return new cCredentialLoginInfo();
|
|
}
|
|
|
|
private protected override List<KeyValuePair<string, string>> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
|
|
{
|
|
var _retVal = new List<KeyValuePair<string, string>>()
|
|
{
|
|
new KeyValuePair<string, string>("Authorization", $"CwsAuth Bearer={AccessToken}")
|
|
};
|
|
|
|
if (privCustomerId != null)
|
|
_retVal.Add(new KeyValuePair<string, string>("Citrix-CustomerId", privCustomerId));
|
|
|
|
if (InstanceId != null)
|
|
_retVal.Add(new KeyValuePair<string, string>("Citrix-InstanceId", InstanceId));
|
|
|
|
return _retVal;
|
|
}
|
|
|
|
}
|
|
|
|
public class cCitrixCommunicationOnPremMonitor : cHttpApiBase
|
|
{
|
|
private const string constLogonUrl = "Users?$top=1&$select=Id";
|
|
|
|
public cCitrixCommunicationOnPremMonitor(string baseUrl) : base("Citrix on-prem system", baseUrl, "Citrix API", baseUrl + string.Format("/Citrix/Monitor/OData/v4/Data/"))
|
|
{
|
|
}
|
|
|
|
private protected override async Task<cCredentialLoginInfo> privLogonWithCredentialsAsync(NetworkCredential credentials)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var _auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{credentials.Domain}\\{credentials.UserName}:{credentials.Password}"));
|
|
|
|
using (var _handler = new HttpClientHandler())
|
|
{
|
|
_handler.Credentials = credentials;
|
|
_handler.PreAuthenticate = true;
|
|
using (var httpClient = new HttpClient(_handler))
|
|
{
|
|
httpClient.BaseAddress = new Uri(RequestBaseUrl);
|
|
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
|
var _result = await httpClient.GetAsync(constLogonUrl);
|
|
if (_result != null)
|
|
{
|
|
var content = await _result.Content.ReadAsStringAsync();
|
|
if (_result.IsSuccessStatusCode)
|
|
return new cCredentialLoginInfo() { IsValid = true, Token = null, TokenExpiresIn = DateTime.MaxValue, useAlwaysCredentials = true };
|
|
else
|
|
LastErrorMessage = $"Monitor Logon failed with status code {(int)_result.StatusCode}: {_result.ReasonPhrase}";
|
|
}
|
|
else
|
|
LastErrorMessage = $"Monitor Logon failed due to unknown reason.";
|
|
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LastErrorMessage = $"Monitor Logon failed with exception: {E.Message}";
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
|
|
return new cCredentialLoginInfo();
|
|
}
|
|
|
|
private protected override List<KeyValuePair<string, string>> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
|
|
{
|
|
var _retVal = new List<KeyValuePair<string, string>>();
|
|
{
|
|
new KeyValuePair<string, string>("Accept", "application/json");
|
|
}
|
|
;
|
|
|
|
return _retVal;
|
|
}
|
|
}
|
|
|
|
public class cCitrixCommunicationBase
|
|
{
|
|
private cHttpApiBase HttpApi;
|
|
|
|
public Uri baseUri { get; private set; }
|
|
|
|
public string LastErrorMessage { get { return HttpApi.LastErrorMessage; } }
|
|
|
|
public cCitrixCommunicationBase(cHttpApiBase HttpApi, string baseUrl)
|
|
{
|
|
this.HttpApi = HttpApi;
|
|
this.baseUri = new Uri(new Uri(HttpApi.RequestBaseUrl), baseUrl);
|
|
}
|
|
|
|
public async Task<cCitrixApiResultBase> RequestAsync(string Request, eHttpMethod httpMethod, object JsonData, string nameProperty = null, bool retryForbidden = false, bool noAutoRelogon = false, CancellationToken token = default)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var uriRequest = new Uri(baseUri, Request);
|
|
|
|
var data = await HttpApi.privRequestAsync(uriRequest.OriginalString, httpMethod, JsonData, retryForbidden, noAutoRelogon: noAutoRelogon, token: token);
|
|
if (data == null)
|
|
return null;
|
|
|
|
if (data is bool isValid)
|
|
{
|
|
if (isValid)
|
|
return new cCitrixApiResultBase(null);
|
|
else
|
|
return null;
|
|
}
|
|
|
|
var RetVal = new cCitrixApiResultBase(data, nameProperty);
|
|
return RetVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public async Task<cCitrixApiResultList> RequestListAsync(string Request, bool loadPaged, bool retryForbidden, CancellationToken token = default)
|
|
{
|
|
try
|
|
{
|
|
var uriRequest = new Uri(baseUri, Request);
|
|
var res = await HttpApi.privRequestAsync(uriRequest.OriginalString, autoRetry: retryForbidden, token: token);
|
|
if (res != null)
|
|
{
|
|
var RetVal = new cCitrixApiResultList(retryForbidden);
|
|
RetVal.AddResult(res);
|
|
if (!RetVal.hasRemaining || loadPaged)
|
|
return RetVal;
|
|
while (RetVal.hasRemaining)
|
|
{
|
|
if (!await RequestNextAsync(RetVal))
|
|
return RetVal;
|
|
}
|
|
return RetVal;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public async Task<bool> RequestNextAsync(cCitrixApiResultList List, CancellationToken token = default)
|
|
{
|
|
try
|
|
{
|
|
var res = await HttpApi.privRequestAsync(List.NextResultUrl, autoRetry: List.retryForbidden, token: token);
|
|
if (res != null)
|
|
{
|
|
List.AddResult(res);
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public class cCitrixCommunicationCvad
|
|
{
|
|
public const string constCitrixCvadUrl = "cvad/";
|
|
|
|
public const string constCitrixApiMe = "manage/Me";
|
|
public const string constCitrixApiMachineNames = "manage/Machines?fields=DnsName";
|
|
public const string constCitrixApiSessions = "manage/Sessions?fields=Id,Uid,State,StartTime";
|
|
|
|
public cCitrixCommunicationBase Request { get; private set; }
|
|
|
|
public iCitrixCvadInfo CitrixInfo { get; private set; }
|
|
|
|
public cCitrixCommunicationCvad(cCitrixCommunicationCloudBase CitrixCloud)
|
|
{
|
|
this.Request = new cCitrixCommunicationBase(CitrixCloud, constCitrixCvadUrl);
|
|
this.CitrixInfo = CitrixCloud as iCitrixCvadInfo;
|
|
}
|
|
|
|
public cCitrixCommunicationCvad(cCitrixCommunicationOnPremCvad OnPremCvad)
|
|
{
|
|
this.Request = new cCitrixCommunicationBase(OnPremCvad, null);
|
|
this.CitrixInfo = OnPremCvad as iCitrixCvadInfo;
|
|
}
|
|
|
|
|
|
public string GetServer()
|
|
{
|
|
return Request?.baseUri?.Host;
|
|
}
|
|
|
|
public async Task<cCitrixCustomerInfo> GetCustomerInfoAsync(CancellationToken Token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var _resultMe = await Request.RequestAsync(constCitrixApiMe, eHttpMethod.get, null);
|
|
|
|
if (Token.IsCancellationRequested)
|
|
return null;
|
|
|
|
if (_resultMe?.Result == null)
|
|
return null;
|
|
|
|
var _obj = _resultMe.Result.Customers;
|
|
var _customers = _obj as IEnumerable<dynamic>;
|
|
|
|
if (_customers == null)
|
|
return null;
|
|
|
|
cCitrixCustomerInfo _retVal = null;
|
|
|
|
foreach (var _customer in _customers) {
|
|
var id = _customer.Id;
|
|
if (id != CitrixInfo?.CustomerId)
|
|
continue;
|
|
|
|
_retVal = new cCitrixCustomerInfo()
|
|
{
|
|
Id = _customer.Id,
|
|
Name = _customer?.Name
|
|
};
|
|
|
|
_obj = _customer.Sites;
|
|
var _sites = _obj as IEnumerable<dynamic>;
|
|
if (_sites != null)
|
|
foreach (var _site in _sites)
|
|
{
|
|
try
|
|
{
|
|
if (Guid.TryParse(_site.Id.ToString(), out Guid _id))
|
|
{
|
|
var siteInfo = new cCitrixSiteInfo()
|
|
{
|
|
Id = _id,
|
|
Name = _site.Name
|
|
};
|
|
_retVal.Sites[_id] = siteInfo;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<List<string>> GetMachineNamesAsync(CancellationToken token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
var _result = await Request.RequestAsync(constCitrixApiMachineNames, eHttpMethod.get, null, token: token);
|
|
|
|
if (_result?.Result == null)
|
|
return null;
|
|
|
|
var _items = _result.Result?.Items as IEnumerable<dynamic>;
|
|
|
|
if (_items == null)
|
|
return null;
|
|
|
|
var _retVal = new List<string>();
|
|
foreach ( var item in _items )
|
|
{
|
|
try
|
|
{
|
|
var _dnsName = item.DnsName?.ToString()?.ToLowerInvariant();
|
|
if (!string.IsNullOrEmpty( _dnsName ))
|
|
_retVal.Add( _dnsName );
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public class SessionInfo
|
|
{
|
|
public string Id { get; set; }
|
|
public string Uid { get; set; }
|
|
public string State { get; set; }
|
|
public DateTime? StartTime { get; set; }
|
|
}
|
|
|
|
public async Task<List<SessionInfo>> GetSessionsAsync()
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
try
|
|
{
|
|
var _result = await Request.RequestAsync(constCitrixApiSessions, eHttpMethod.get, null);
|
|
if (_result?.Result == null)
|
|
return null;
|
|
var _items = _result.Result?.Items as IEnumerable<dynamic>;
|
|
if (_items == null)
|
|
return null;
|
|
var _retVal = new List<SessionInfo>();
|
|
foreach (var item in _items)
|
|
{
|
|
try
|
|
{
|
|
var _sessionInfo = new SessionInfo()
|
|
{
|
|
Id = item.Id?.ToString(),
|
|
Uid = item.Uid?.ToString(),
|
|
State = item.State?.ToString(),
|
|
StartTime = item.StartTime != null ? (DateTime?)item.StartTime : null
|
|
};
|
|
_retVal.Add(_sessionInfo);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
return _retVal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class cCitrixCommunicationMonitor
|
|
{
|
|
public const string constCitrixCloudUrl = "monitorodata/";
|
|
|
|
public const string constCitrixMachineNames = "Machines/?$select=DnsName&$filter=DesktopGroupId+ne+null+and+Name+ne+null";
|
|
public const string constCitrixUserList = "Users?$select=Id,Sid,Upn,Domain&$filter=Domain ne ''";
|
|
public const string constCitrixMachineList = "Machines?$select=Id,Sid,DnsName&$filter=DesktopGroupId ne null and Name ne null";
|
|
public const string constCitrixSessionListDetailed = "Sessions?$select=SessionKey,StartDate,EndDate,ConnectionState, UserId, MachineId&$expand=Machine($select=Id,DnsName,Name)&$filter=EndDate eq null or EndDate gt {0}";
|
|
|
|
public int MaxPageSize { get; set; } = 100;
|
|
|
|
public cCitrixCommunicationBase Request { get; private set; }
|
|
|
|
public cCitrixCommunicationMonitor(cCitrixCommunicationCloudBase CitrixCloud)
|
|
{
|
|
this.Request = new cCitrixCommunicationBase(CitrixCloud, constCitrixCloudUrl);
|
|
}
|
|
|
|
public cCitrixCommunicationMonitor(cCitrixCommunicationOnPremMonitor OnPremMonitor)
|
|
{
|
|
this.Request = new cCitrixCommunicationBase(OnPremMonitor, null);
|
|
}
|
|
|
|
private string getFormattedDateTime(int DayOffset = 0)
|
|
{
|
|
var _dateTime = DateTime.UtcNow.AddDays(DayOffset);
|
|
var _strDateTime = _dateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
|
|
return _strDateTime;
|
|
}
|
|
|
|
private string getFormattedGuid(Guid id)
|
|
{
|
|
return id.ToString("D");
|
|
}
|
|
|
|
public async Task<List<string>> GetMachineNamesAsync(CancellationToken token)
|
|
{
|
|
var _processor = new ScanEntryStringListProcessor("DnsName", true);
|
|
var _count = await RequestListAsync(constCitrixMachineList, _processor.ProcessScannedItemAsync, token: token);
|
|
return _processor.Result;
|
|
}
|
|
|
|
public delegate Task<bool> ProcessScanEntryDelegate(dynamic ScanEntry, CancellationToken token);
|
|
|
|
public abstract class ScanEntryProcessor
|
|
{
|
|
public abstract Task<bool> ProcessScannedItemAsync(dynamic _node, CancellationToken token);
|
|
}
|
|
|
|
public class ScanEntryCountProcessor : ScanEntryProcessor
|
|
{
|
|
private string nameProperty = null;
|
|
|
|
public ScanEntryCountProcessor(string nameProperty)
|
|
{
|
|
this.nameProperty = nameProperty;
|
|
}
|
|
|
|
public async override Task<bool> ProcessScannedItemAsync(dynamic _node, CancellationToken token)
|
|
{
|
|
try
|
|
{
|
|
string _prop = cCitrixApiResultBase.GetStringFromDynamic(_node, nameProperty);
|
|
if (!string.IsNullOrEmpty(_prop))
|
|
return true;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public class ScanEntryStringListProcessor : ScanEntryProcessor
|
|
{
|
|
private string nameProperty = null;
|
|
private bool toLowercase = false;
|
|
|
|
public List<string> Result = new List<string>();
|
|
|
|
public ScanEntryStringListProcessor(string nameProperty, bool toLowercase = false)
|
|
{
|
|
this.nameProperty = nameProperty;
|
|
this.toLowercase = toLowercase;
|
|
}
|
|
|
|
public async override Task<bool> ProcessScannedItemAsync(dynamic _node, CancellationToken token)
|
|
{
|
|
try
|
|
{
|
|
string _prop = cCitrixApiResultBase.GetStringFromDynamic(_node, nameProperty);
|
|
if (!string.IsNullOrEmpty(_prop))
|
|
{
|
|
if (toLowercase)
|
|
_prop = _prop.ToLowerInvariant();
|
|
Result.Add(_prop);
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
private async Task<int> RequestListAsync(string Url, ProcessScanEntryDelegate ProcessScanEntry, CancellationToken token)
|
|
{
|
|
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
|
|
|
try
|
|
{
|
|
int countTotal = 0;
|
|
int skipping = 0;
|
|
int lastCount = 0;
|
|
do
|
|
{
|
|
lastCount = 0;
|
|
var _url = Url + $"&$top={MaxPageSize}&$skip={skipping}";
|
|
var _result = await Request.RequestAsync(_url, eHttpMethod.get, null, token: token);
|
|
if (_result == null || _result.Result == null)
|
|
return -1;
|
|
|
|
var _items = _result.Result?.value as IEnumerable<dynamic>;
|
|
|
|
if (_items == null)
|
|
return -1;
|
|
|
|
foreach (var item in _items)
|
|
{
|
|
try
|
|
{
|
|
var _item = item as dynamic;
|
|
var _ok = await ProcessScanEntry(_item, token);
|
|
if (token.IsCancellationRequested)
|
|
return 0;
|
|
if (_ok)
|
|
{
|
|
lastCount++;
|
|
countTotal++;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
}
|
|
|
|
skipping += lastCount;
|
|
} while (lastCount >= MaxPageSize);
|
|
|
|
return countTotal;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
LogException(E);
|
|
}
|
|
finally
|
|
{
|
|
if (CM != null) LogMethodEnd(CM);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public async Task<int> ScanUsersAsync(ScanEntryProcessor _processor, CancellationToken token)
|
|
{
|
|
return await RequestListAsync(constCitrixUserList, _processor.ProcessScannedItemAsync, token);
|
|
}
|
|
|
|
public async Task<int> ScanMachinesAsync(ScanEntryProcessor _processor, CancellationToken token)
|
|
{
|
|
return await RequestListAsync(constCitrixMachineList, _processor.ProcessScannedItemAsync, token);
|
|
}
|
|
|
|
public async Task<int> ScanSessionsAsync(ScanEntryProcessor _processor, int DayOffset, CancellationToken token)
|
|
{
|
|
var _url = string.Format(constCitrixSessionListDetailed, getFormattedDateTime(DayOffset));
|
|
return await RequestListAsync(_url, _processor.ProcessScannedItemAsync, token);
|
|
}
|
|
}
|
|
} |