WebApiService
using Polly;
using Polly.Retry;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace Relativity.Transfer
{
internal class WebApiService : IDisposable
{
private bool initialized;
private bool disposed;
public RelativityConnectionInfo ConnectionInfo { get; }
public int MaxRetryAttempts { get; set; }
public double TimeoutSeconds { get; set; }
protected ClientConfiguration Configuration { get; }
protected ITransferLog Log { get; }
protected FileIO ServiceInstance { get; set; }
protected IUserManagerService UserManagerService { get; }
public WebApiService(RelativityConnectionInfo connectionInfo, ClientConfiguration configuration, IUserManagerService userManagerService, ITransferLog log)
: this(connectionInfo, configuration, userManagerService, log, configuration.MaxHttpRetryAttempts, configuration.HttpTimeoutSeconds)
{
}
public WebApiService(RelativityConnectionInfo connectionInfo, ClientConfiguration configuration, IUserManagerService userManagerService, ITransferLog log, int maxRetryAttempts, double timeoutSeconds)
{
if (connectionInfo == null)
throw new ArgumentNullException("connectionInfo");
if (configuration == null)
throw new ArgumentNullException("configuration");
if (userManagerService == null)
throw new ArgumentNullException("userManagerService");
if (log == null)
throw new ArgumentNullException("log");
Configuration = configuration;
ConnectionInfo = connectionInfo;
UserManagerService = userManagerService;
ServiceInstance = null;
Log = log;
initialized = false;
MaxRetryAttempts = maxRetryAttempts;
TimeoutSeconds = timeoutSeconds;
}
~WebApiService()
{
Dispose(false);
}
public static Uri GetWebApiServiceUrl(RelativityConnectionInfo connectionInfo, ITransferLog log)
{
if (connectionInfo == null)
throw new ArgumentNullException("connectionInfo");
if (!(connectionInfo.WebApiServiceUrl != (Uri)null)) {
connectionInfo.WebApiServiceUrl = UrlHelper.Combine(connectionInfo.Host, "RelativityWebAPI");
log.LogWarning("The WebApiServiceUrl wasn't assigned. Manually creating the {Url} URL to prevent failure.", connectionInfo.WebApiServiceUrl);
return connectionInfo.WebApiServiceUrl;
}
return connectionInfo.WebApiServiceUrl;
}
public static IHttpCredential GetWebApiHttpCredential(RelativityConnectionInfo connectionInfo)
{
if (connectionInfo == null)
throw new ArgumentNullException("connectionInfo");
return connectionInfo.WebApiServiceCredential ?? connectionInfo.Credential;
}
public Task<string> (int workspaceId, CancellationToken token)
{
if (workspaceId < 1 && workspaceId != -1)
throw new ArgumentOutOfRangeException("workspaceId");
Initialize();
RetryPolicy retryPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(MaxRetryAttempts, (int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt)), delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
});
return retryPolicy.ExecuteAsync(delegate {
Task<string> task = Task.Factory.FromAsync((Func<AsyncCallback, object, IAsyncResult>)((AsyncCallback callback, object stateObject) => ServiceInstance.BeginGetBcpSharePath(workspaceId, callback, stateObject)), (Func<IAsyncResult, string>)ServiceInstance.EndGetBcpSharePath, (object)null);
task.Wait(token);
return task;
}, token);
}
public Task<BcpStorageReport> (int workspaceId, CancellationToken token)
{
if (workspaceId < 1 && workspaceId != -1)
throw new ArgumentOutOfRangeException("workspaceId");
Initialize();
RetryPolicy retryPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(MaxRetryAttempts, (int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt)), delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
});
return retryPolicy.ExecuteAsync(async delegate {
Dictionary<string, string> reportDict = (await Task.Factory.FromAsync((Func<AsyncCallback, object, IAsyncResult>)((AsyncCallback callback, object stateObject) => ServiceInstance.BeginGetBcpShareSpaceReport(workspaceId, callback, stateObject)), (Func<IAsyncResult, string[][]>)ServiceInstance.EndGetBcpShareSpaceReport, (object)null).ConfigureAwait(false)).ToDictionary((string[] line) => line[0], (string[] line) => line[1]);
BcpStorageReport report = new BcpStorageReport();
if (reportDict.ContainsKey("Drive Name"))
report.DriveName = reportDict["Drive Name"];
if (reportDict.ContainsKey("Free Space"))
report.TotalAvailableBytes = TryGetStorageReportBytes(reportDict["Free Space"]);
if (reportDict.ContainsKey("Used Space"))
report.TotalUsedBytes = TryGetStorageReportBytes(reportDict["Used Space"]);
if (reportDict.ContainsKey("Total Space"))
report.TotalBytes = TryGetStorageReportBytes(reportDict["Total Space"]);
return report;
}, token);
}
public Task<bool> (int workspaceId, CancellationToken token)
{
if (workspaceId < 1 && workspaceId != -1)
throw new ArgumentOutOfRangeException("workspaceId");
Initialize();
RetryPolicy retryPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(MaxRetryAttempts, (int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt)), delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
});
return retryPolicy.ExecuteAsync(async (CancellationToken ct) => await Task.Factory.FromAsync((Func<AsyncCallback, object, IAsyncResult>)((AsyncCallback callback, object stateObject) => ServiceInstance.BeginValidateBcpShare(workspaceId, callback, stateObject)), (Func<IAsyncResult, bool>)ServiceInstance.EndValidateBcpShare, (object)null).ConfigureAwait(false), token);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void CheckLogin(Exception exception)
{
List<string> source = new List<string> {
exception.ToString(),
exception.InnerException?.ToString() ?? string.Empty
};
bool flag = source.Any((string x) => x.IndexOf("kcuraaccessdeniedmarker", StringComparison.OrdinalIgnoreCase) != -1);
bool flag2 = source.Any((string x) => x.IndexOf("NeedToReLoginException", StringComparison.OrdinalIgnoreCase) != -1);
if (flag) {
Log.LogInformation("An access denied exception occurred and requesting a new distributed login token.", Array.Empty<object>());
UserManagerService.Login();
} else if (flag2) {
Log.LogInformation(string.IsNullOrWhiteSpace(UserManagerService.DistributedToken) ? "The distributed login token is null or empty and requesting a distributed login token." : "The distributed login token has expired and requesting a new distributed login token.", Array.Empty<object>());
UserManagerService.Login();
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposed) {
if (disposing && ServiceInstance != null)
((Component)ServiceInstance).Dispose();
disposed = true;
}
}
protected virtual void Initialize()
{
if (!initialized) {
FileIO fileIO = new FileIO();
fileIO.set_Credentials(GetWebApiHttpCredential(ConnectionInfo).CreateCredentials());
fileIO.set_CookieContainer(Configuration.CookieContainer);
fileIO.set_Timeout((int)TimeSpan.FromSeconds(TimeoutSeconds).TotalMilliseconds);
fileIO.set_Url(UrlHelper.Combine(GetWebApiServiceUrl(ConnectionInfo, Log), "FileIO.asmx").ToString());
ServiceInstance = fileIO;
ServicePointManager.SecurityProtocol = (SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12);
initialized = true;
}
}
private long TryGetStorageReportBytes(string value)
{
try {
string value2 = value.Replace(" MB", string.Empty);
double bytes = ByteSize.FromMegaBytes(Convert.ToDouble(value2)).Bytes;
return Convert.ToInt64(bytes);
} catch (Exception exception) {
Log.LogError(exception, "Failed to convert the {BcpValue} BCP storage report value to a long data type.", value);
return 0;
}
}
}
}