WebApiService
using Polly;
using Relativity.Transfer.Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Relativity.Transfer.WebApi
{
[Obsolete("WebAPI support will be removed in upcoming releases. In order to communicate with Relativity use Kepler Services. For more information, see KeplerServiceBase class.")]
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");
if (!configuration.UseLegacyWebApi)
throw new ArgumentException(CoreStrings.InvalidCommunicationModeExceptionMessage, "UseLegacyWebApi");
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)
return connectionInfo.WebApiServiceUrl;
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;
}
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();
return RetrySyntaxAsync.WaitAndRetryAsync(Policy.Handle<Exception>(), MaxRetryAttempts, (Func<int, TimeSpan>)((int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt))), (Action<Exception, TimeSpan>)delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
}).ExecuteAsync<string>((Func<CancellationToken, Task<string>>)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();
<>c__DisplayClass32_0 <>4__this;
return RetrySyntaxAsync.WaitAndRetryAsync(Policy.Handle<Exception>(), MaxRetryAttempts, (Func<int, TimeSpan>)((int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt))), (Action<Exception, TimeSpan>)delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
}).ExecuteAsync<BcpStorageReport>((Func<CancellationToken, Task<BcpStorageReport>>)delegate {
<>c__DisplayClass32_0.<<GetBcpShareStorageReportAsync>b__2>d stateMachine = default(<>c__DisplayClass32_0.<<GetBcpShareStorageReportAsync>b__2>d);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<BcpStorageReport>.Create();
stateMachine.<>4__this = <>4__this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}, token);
}
public Task<bool> (int workspaceId, CancellationToken token)
{
if (workspaceId < 1 && workspaceId != -1)
throw new ArgumentOutOfRangeException("workspaceId");
Initialize();
<>c__DisplayClass33_0 <>4__this;
return RetrySyntaxAsync.WaitAndRetryAsync(Policy.Handle<Exception>(), MaxRetryAttempts, (Func<int, TimeSpan>)((int retryAttempt) => TimeSpan.FromSeconds(Math.Pow(2, (double)retryAttempt))), (Action<Exception, TimeSpan>)delegate(Exception exception, TimeSpan span) {
Log.LogError(exception, $"""{span}", Array.Empty<object>());
CheckLogin(exception);
}).ExecuteAsync<bool>((Func<CancellationToken, Task<bool>>)delegate {
<>c__DisplayClass33_0.<<ValidateBcpShareAsync>b__2>d stateMachine = default(<>c__DisplayClass33_0.<<ValidateBcpShareAsync>b__2>d);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
stateMachine.<>4__this = <>4__this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}, 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 {
return Convert.ToInt64(ByteSize.FromMegaBytes(Convert.ToDouble(value.Replace(" MB", string.Empty), CultureInfo.InvariantCulture)).Bytes);
} catch (Exception exception) {
Log.LogError(exception, "Failed to convert the {BcpValue} BCP storage report value to a long data type.", value);
return 0;
}
}
}
}