/Raven.Client.Lightweight/Connection/Async/AsyncServerClient.cs
C# | 2727 lines | 2322 code | 386 blank | 19 comment | 323 complexity | 2c9f9bc948dccdd45e455eeb26ab532d MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Apache-2.0, BSD-3-Clause, CC-BY-SA-3.0
Large files files are truncated, but you can click here to view the full file
- //-----------------------------------------------------------------------
- // <copyright file="AsyncServerClient.cs" company="Hibernating Rhinos LTD">
- // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
- // </copyright>
- //-----------------------------------------------------------------------
-
- using Raven.Abstractions;
- using Raven.Abstractions.Cluster;
- using Raven.Abstractions.Commands;
- using Raven.Abstractions.Connection;
- using Raven.Abstractions.Data;
- using Raven.Abstractions.Exceptions;
- using Raven.Abstractions.Extensions;
- using Raven.Abstractions.Indexing;
- using Raven.Abstractions.Json;
- using Raven.Abstractions.Replication;
- using Raven.Abstractions.Smuggler;
- using Raven.Abstractions.Util;
- using Raven.Client.Changes;
- using Raven.Client.Connection.Implementation;
- using Raven.Client.Connection.Profiling;
- using Raven.Client.Connection.Request;
- using Raven.Client.Document;
- using Raven.Client.Exceptions;
- using Raven.Client.Extensions;
- using Raven.Client.Indexes;
- using Raven.Client.Listeners;
- using Raven.Client.Metrics;
- using Raven.Client.Util.Auth;
- using Raven.Database.Data;
- using Raven.Imports.Newtonsoft.Json;
- using Raven.Imports.Newtonsoft.Json.Linq;
- using Raven.Json.Linq;
-
- using System;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
-
- namespace Raven.Client.Connection.Async
- {
- public class AsyncServerClient : IAsyncDatabaseCommands, IAsyncInfoDatabaseCommands
- {
- private readonly ProfilingInformation profilingInformation;
-
- private readonly IDocumentConflictListener[] conflictListeners;
-
- private readonly Guid? sessionId;
-
- private readonly Func<AsyncServerClient, string, bool, IRequestExecuter> requestExecuterGetter;
-
- private readonly Func<string, RequestTimeMetric> requestTimeMetricGetter;
-
- private readonly string databaseName;
-
- private readonly string primaryUrl;
-
- private readonly OperationCredentials credentialsThatShouldBeUsedOnlyInOperationsWithoutReplication;
-
- private readonly RequestExecuterSelector requestExecuterSelector;
-
- internal readonly DocumentConvention convention;
-
- internal readonly HttpJsonRequestFactory jsonRequestFactory;
-
- private int requestCount;
-
- private NameValueCollection operationsHeaders = new NameValueCollection();
-
- public string Url
- {
- get { return primaryUrl; }
- }
-
- public IRequestExecuter RequestExecuter
- {
- get { return requestExecuterSelector.Select(); }
- }
-
- public OperationCredentials PrimaryCredentials
- {
- get
- {
- return credentialsThatShouldBeUsedOnlyInOperationsWithoutReplication;
- }
- }
-
- public AsyncServerClient(
- string url,
- DocumentConvention convention,
- OperationCredentials credentials,
- HttpJsonRequestFactory jsonRequestFactory,
- Guid? sessionId,
- Func<AsyncServerClient, string, bool, IRequestExecuter> requestExecuterGetter,
- Func<string, RequestTimeMetric> requestTimeMetricGetter,
- string databaseName,
- IDocumentConflictListener[] conflictListeners,
- bool incrementReadStripe)
- {
- profilingInformation = ProfilingInformation.CreateProfilingInformation(sessionId);
- primaryUrl = url;
- if (primaryUrl.EndsWith("/"))
- primaryUrl = primaryUrl.Substring(0, primaryUrl.Length - 1);
- this.jsonRequestFactory = jsonRequestFactory;
- this.sessionId = sessionId;
- this.convention = convention;
- credentialsThatShouldBeUsedOnlyInOperationsWithoutReplication = credentials;
- this.databaseName = databaseName;
- this.conflictListeners = conflictListeners;
-
- this.requestExecuterGetter = requestExecuterGetter;
- this.requestTimeMetricGetter = requestTimeMetricGetter;
- requestExecuterSelector = new RequestExecuterSelector(() =>
- requestExecuterGetter(this, databaseName, incrementReadStripe), convention);
- requestExecuterSelector.Select().UpdateReplicationInformationIfNeededAsync(this);
- }
-
- public void Dispose()
- {
- }
-
- public Task<string[]> GetIndexNamesAsync(int start, int pageSize, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url.IndexNames(start, pageSize), HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)).AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- var json = (RavenJArray)await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- return json.Select(x => x.Value<string>()).ToArray();
- }
- }, token);
- }
-
- public Task<IndexDefinition[]> GetIndexesAsync(int start, int pageSize, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- var operationUrl = operationMetadata.Url + "/indexes/?start=" + start + "&pageSize=" + pageSize;
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationUrl, HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- var json = (RavenJArray)await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- //NOTE: To review, I'm not confidence this is the correct way to deserialize the index definition
- return json.Select(x =>
- {
- var value = ((RavenJObject)x)["definition"].ToString();
- return JsonConvert.DeserializeObject<IndexDefinition>(value, new JsonToJsonConverter());
- }).ToArray();
- }
- }, token);
- }
-
- public Task<TransformerDefinition[]> GetTransformersAsync(int start, int pageSize, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- var operationUrl = operationMetadata.Url + "/transformers?start=" + start + "&pageSize=" + pageSize;
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationUrl, HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- var json = (RavenJArray)await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
-
- //NOTE: To review, I'm not confidence this is the correct way to deserialize the transformer definition
- return json.Select(x => JsonConvert.DeserializeObject<TransformerDefinition>(((RavenJObject)x)["definition"].ToString(), new JsonToJsonConverter())).ToArray();
- }
- }, token);
- }
-
- public Task SetTransformerLockAsync(string name, TransformerLockMode lockMode, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Post, async (operationMetadata, requestTimeMetric) =>
- {
- var operationUrl = operationMetadata.Url + "/transformers/" + name + "?op=" + "lockModeChange" + "&mode=" + lockMode;
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationUrl, HttpMethod.Post, operationMetadata.Credentials, convention)))
- {
- request.AddOperationHeaders(OperationsHeaders);
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- return await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
-
- internal Task ReplicateIndexAsync(string name, CancellationToken token = default(CancellationToken))
- {
- var url = String.Format("/replication/replicate-indexes?indexName={0}", Uri.EscapeDataString(name));
-
- using (var request = CreateRequest(url, HttpMethods.Post))
- return request.ExecuteRawResponseAsync();
- }
-
- public Task ResetIndexAsync(string name, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethods.Reset, async (operationMetadata, requestTimeMetric) =>
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url + "/indexes/" + name, HttpMethods.Reset, operationMetadata.Credentials, convention, requestTimeMetric)))
- {
- request.AddOperationHeaders(OperationsHeaders);
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- return await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
-
- public Task SetIndexLockAsync(string name, IndexLockMode unLockMode, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Post, async (operationMetadata, requestTimeMetric) =>
- {
- var operationUrl = operationMetadata.Url + "/indexes/" + name + "?op=" + "lockModeChange" + "&mode=" + unLockMode;
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationUrl, HttpMethod.Post, operationMetadata.Credentials, convention, requestTimeMetric)))
- {
- request.AddOperationHeaders(OperationsHeaders);
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- return await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
- public Task SetIndexPriorityAsync(string name, IndexingPriority priority, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Post, async (operationMetadata, requestTimeMetric) =>
- {
- var operationUrl = operationMetadata.Url + "/indexes/set-priority/" + name + "?priority=" + priority;
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationUrl, HttpMethod.Post, operationMetadata.Credentials, convention, requestTimeMetric)))
- {
- request.AddOperationHeaders(OperationsHeaders);
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- return await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
- public Task<string> PutIndexAsync<TDocument, TReduceResult>(string name, IndexDefinitionBuilder<TDocument, TReduceResult> indexDef, CancellationToken token = default(CancellationToken))
- {
- return PutIndexAsync(name, indexDef, false, token);
- }
-
- public Task<string> PutIndexAsync<TDocument, TReduceResult>(string name,
- IndexDefinitionBuilder<TDocument, TReduceResult> indexDef, bool overwrite = false, CancellationToken token = default(CancellationToken))
- {
- return PutIndexAsync(name, indexDef.ToIndexDefinition(convention), overwrite, token);
- }
-
- public Task<bool> IndexHasChangedAsync(string name, IndexDefinition indexDef, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Post, (operationMetadata, requestTimeMetric) => DirectIndexHasChangedAsync(name, indexDef, operationMetadata, requestTimeMetric, token), token);
- }
-
- private async Task<bool> DirectIndexHasChangedAsync(string name, IndexDefinition indexDef, OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, CancellationToken token)
- {
- var requestUri = operationMetadata.Url.Indexes(name) + "?op=hasChanged";
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUri, HttpMethod.Post, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- var serializeObject = JsonConvert.SerializeObject(indexDef, Default.Converters);
-
- await request.WriteAsync(serializeObject).WithCancellation(token).ConfigureAwait(false);
- var result = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- return result.Value<bool>("Changed");
- }
- }
-
- public Task<string> PutIndexAsync(string name, IndexDefinition indexDef, CancellationToken token = default(CancellationToken))
- {
- return PutIndexAsync(name, indexDef, false, token);
- }
-
- public Task<string> PutIndexAsync(string name, IndexDefinition indexDef, bool overwrite, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Put, (operationMetadata, requestTimeMetric) => DirectPutIndexAsync(name, indexDef, overwrite, operationMetadata, requestTimeMetric, token), token);
- }
-
- public Task<string[]> PutIndexesAsync(IndexToAdd[] indexesToAdd, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Put, (operationMetadata, requestTimeMetric) => DirectPutIndexesAsync(indexesToAdd, operationMetadata, token), token);
- }
-
- public Task<string[]> PutSideBySideIndexesAsync(IndexToAdd[] indexesToAdd, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Put, (operationMetadata, requestTimeMetric) => DirectPutSideBySideIndexesAsync(indexesToAdd, operationMetadata, minimumEtagBeforeReplace, replaceTimeUtc, token), token);
- }
-
- public Task<string> PutTransformerAsync(string name, TransformerDefinition transformerDefinition, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Put, (operationMetadata, requestTimeMetric) => DirectPutTransformerAsync(name, transformerDefinition, operationMetadata, requestTimeMetric, token), token);
- }
-
- public async Task<string> DirectPutIndexAsync(string name, IndexDefinition indexDef, bool overwrite, OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, CancellationToken token = default(CancellationToken))
- {
- var requestUri = operationMetadata.Url + "/indexes/" + Uri.EscapeUriString(name) + "?definition=yes";
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUri, HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
-
- try
- {
- await request.ExecuteRequestAsync().WithCancellation(token).ConfigureAwait(false);
- if (overwrite == false)
- throw new InvalidOperationException("Cannot put index: " + name + ", index already exists");
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode != HttpStatusCode.NotFound)
- throw;
- }
- }
-
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUri, HttpMethod.Put, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- var serializeObject = JsonConvert.SerializeObject(indexDef, Default.Converters);
-
- ErrorResponseException responseException;
- try
- {
- await request.WriteAsync(serializeObject).ConfigureAwait(false);
- var result = await request.ReadResponseJsonAsync().ConfigureAwait(false);
- return result.Value<string>("Index");
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode != HttpStatusCode.BadRequest) throw;
- responseException = e;
- }
- var error = await responseException.TryReadErrorResponseObject(new { Error = "", Message = "", IndexDefinitionProperty = "", ProblematicText = "" }).ConfigureAwait(false);
- if (error == null) throw responseException;
-
- throw new IndexCompilationException(error.Message) { IndexDefinitionProperty = error.IndexDefinitionProperty, ProblematicText = error.ProblematicText };
- }
- }
-
- public async Task<string[]> DirectPutIndexesAsync(IndexToAdd[] indexesToAdd, OperationMetadata operationMetadata, CancellationToken token = default(CancellationToken))
- {
- var requestUri = operationMetadata.Url + "/indexes";
- return await PutIndexes(operationMetadata, token, requestUri, indexesToAdd).ConfigureAwait(false);
- }
-
- public async Task<string[]> DirectPutSideBySideIndexesAsync(IndexToAdd[] indexesToAdd, OperationMetadata operationMetadata, Etag minimumEtagBeforeReplace, DateTime? replaceTimeUtc, CancellationToken token = default(CancellationToken))
- {
- var sideBySideIndexes = new SideBySideIndexes
- {
- IndexesToAdd = indexesToAdd,
- MinimumEtagBeforeReplace = minimumEtagBeforeReplace,
- ReplaceTimeUtc = replaceTimeUtc
- };
-
- var requestUri = operationMetadata.Url + "/side-by-side-indexes";
- return await PutIndexes(operationMetadata, token, requestUri, sideBySideIndexes).ConfigureAwait(false);
- }
-
- private async Task<string[]> PutIndexes(OperationMetadata operationMetadata, CancellationToken token, string requestUri, object obj)
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUri, HttpMethod.Put, operationMetadata.Credentials, convention).AddOperationHeaders(OperationsHeaders)))
- {
- var serializeObject = JsonConvert.SerializeObject(obj, Default.Converters);
-
- ErrorResponseException responseException;
- try
- {
- await request.WriteAsync(serializeObject).WithCancellation(token).ConfigureAwait(false);
- var result = await request.ReadResponseJsonAsync().ConfigureAwait(false);
- return result
- .Value<RavenJArray>("Indexes")
- .Select(x => x.Value<string>())
- .ToArray();
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode != HttpStatusCode.BadRequest)
- throw;
- responseException = e;
- }
- var error = await responseException.TryReadErrorResponseObject(new { Error = "", Message = "", IndexDefinitionProperty = "", ProblematicText = "" }).ConfigureAwait(false);
- if (error == null)
- throw responseException;
-
- throw new IndexCompilationException(error.Message) { IndexDefinitionProperty = error.IndexDefinitionProperty, ProblematicText = error.ProblematicText };
- }
- }
-
- public async Task<string> DirectPutTransformerAsync(string name, TransformerDefinition transformerDefinition, OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, CancellationToken token = default(CancellationToken))
- {
- var requestUri = operationMetadata.Url + "/transformers/" + name;
-
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUri, HttpMethod.Put, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- var serializeObject = JsonConvert.SerializeObject(transformerDefinition, Default.Converters);
-
- ErrorResponseException responseException;
- try
- {
- await request.WriteAsync(serializeObject).ConfigureAwait(false);
- var result = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- return result.Value<string>("Transformer");
- }
- catch (BadRequestException e)
- {
- throw new TransformCompilationException(e.Message);
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode != HttpStatusCode.BadRequest)
- throw;
- responseException = e;
- }
- var error = await responseException.TryReadErrorResponseObject(new { Error = "", Message = "" }).ConfigureAwait(false);
- if (error == null)
- throw responseException;
-
- throw new TransformCompilationException(error.Message);
- }
- }
-
- public Task DeleteIndexAsync(string name, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Delete, async (operationMetadata, requestTimeMetric) =>
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url.Indexes(name), HttpMethod.Delete, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(operationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
- await request.ExecuteRequestAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
-
- public Task<Operation> DeleteByIndexAsync(string indexName, IndexQuery queryToDelete, BulkOperationOptions options = null, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Delete, async (operationMetadata, requestTimeMetric) =>
- {
- var notNullOptions = options ?? new BulkOperationOptions();
- string path = queryToDelete.GetIndexQueryUrl(operationMetadata.Url, indexName, "bulk_docs") + "&allowStale=" + notNullOptions.AllowStale
- + "&details=" + notNullOptions.RetrieveDetails;
- if (notNullOptions.MaxOpsPerSec != null)
- path += "&maxOpsPerSec=" + notNullOptions.MaxOpsPerSec;
- if (notNullOptions.StaleTimeout != null)
- path += "&staleTimeout=" + notNullOptions.StaleTimeout;
-
- token.ThrowCancellationIfNotDefault(); //maybe the operation is canceled and we can spare the request..
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, path, HttpMethod.Delete, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader);
- RavenJToken jsonResponse;
- try
- {
- jsonResponse = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode == HttpStatusCode.NotFound) throw new InvalidOperationException("There is no index named: " + indexName, e);
- throw;
- }
-
- // Be compatible with the response from v2.0 server
- var opId = ((RavenJObject)jsonResponse)["OperationId"];
-
- if (opId == null || opId.Type != JTokenType.Integer) return null;
-
- return new Operation(this, opId.Value<long>());
- }
- }, token);
- }
-
- public Task DeleteTransformerAsync(string name, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Delete, async (operationMetadata, requestTimeMetric) =>
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url.Transformer(name), HttpMethod.Delete, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(operationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader );
- await request.ExecuteRequestAsync().WithCancellation(token).ConfigureAwait(false);
- }
- }, token);
- }
-
- public Task<RavenJObject> PatchAsync(string key, PatchRequest[] patches, CancellationToken token = default(CancellationToken))
- {
- return PatchAsync(key, patches, null, token);
- }
-
- public async Task<RavenJObject> PatchAsync(string key, PatchRequest[] patches, bool ignoreMissing, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new PatchCommandData
- {
- Key = key,
- Patches = patches,
- }
- }, null, token).ConfigureAwait(false);
- if (!ignoreMissing && batchResults[0].PatchResult != null &&
- batchResults[0].PatchResult == PatchResult.DocumentDoesNotExists)
- throw new DocumentDoesNotExistsException("Document with key " + key + " does not exist.");
- return batchResults[0].AdditionalData;
- }
-
- public Task<RavenJObject> PatchAsync(string key, ScriptedPatchRequest patch, CancellationToken token = default(CancellationToken))
- {
- return PatchAsync(key, patch, null, token);
- }
-
- public async Task<RavenJObject> PatchAsync(string key, PatchRequest[] patches, Etag etag, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new PatchCommandData
- {
- Key = key,
- Patches = patches,
- Etag = etag,
- }
- }, null, token).ConfigureAwait(false);
- return batchResults[0].AdditionalData;
- }
-
- public async Task<RavenJObject> PatchAsync(string key, PatchRequest[] patchesToExisting,
- PatchRequest[] patchesToDefault, RavenJObject defaultMetadata, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new PatchCommandData
- {
- Key = key,
- Patches = patchesToExisting,
- PatchesIfMissing = patchesToDefault,
- Metadata = defaultMetadata
- }
- }, null, token).ConfigureAwait(false);
- return batchResults[0].AdditionalData;
- }
-
- public async Task<RavenJObject> PatchAsync(string key, ScriptedPatchRequest patch, bool ignoreMissing, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new ScriptedPatchCommandData
- {
- Key = key,
- Patch = patch,
- }
- }, null, token).ConfigureAwait(false);
- if (!ignoreMissing && batchResults[0].PatchResult != null &&
- batchResults[0].PatchResult == PatchResult.DocumentDoesNotExists)
- throw new DocumentDoesNotExistsException("Document with key " + key + " does not exist.");
- return batchResults[0].AdditionalData;
- }
-
- public async Task<RavenJObject> PatchAsync(string key, ScriptedPatchRequest patch, Etag etag, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new ScriptedPatchCommandData
- {
- Key = key,
- Patch = patch,
- Etag = etag
- }
- }, null, token).ConfigureAwait(false);
- return batchResults[0].AdditionalData;
- }
-
- public async Task<RavenJObject> PatchAsync(string key, ScriptedPatchRequest patchExisting,
- ScriptedPatchRequest patchDefault, RavenJObject defaultMetadata, CancellationToken token = default(CancellationToken))
- {
- var batchResults = await BatchAsync(new ICommandData[]
- {
- new ScriptedPatchCommandData
- {
- Key = key,
- Patch = patchExisting,
- PatchIfMissing = patchDefault,
- Metadata = defaultMetadata
- }
- }, null, token).ConfigureAwait(false);
- return batchResults[0].AdditionalData;
- }
-
- public Task<PutResult> PutAsync(string key, Etag etag, RavenJObject document, RavenJObject metadata, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Put, (operationMetadata, requestTimeMetric) => DirectPutAsync(operationMetadata, requestTimeMetric, key, etag, document, metadata, token), token);
- }
-
- private async Task<PutResult> DirectPutAsync(OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, string key, Etag etag, RavenJObject document, RavenJObject metadata, CancellationToken token = default(CancellationToken))
- {
- if (metadata == null)
- metadata = new RavenJObject();
- var method = String.IsNullOrEmpty(key) ? HttpMethod.Post : HttpMethod.Put;
- if (etag != null)
- metadata[Constants.MetadataEtagField] = new RavenJValue((string)etag);
- else
- metadata.Remove(Constants.MetadataEtagField);
-
- if (key != null)
- key = Uri.EscapeDataString(key);
-
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url + "/docs/" + key, method, metadata, operationMetadata.Credentials, convention, requestTimeMetric).AddOperationHeaders(OperationsHeaders)))
- {
- request.AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader );
-
- ErrorResponseException responseException;
- try
- {
- await request.WriteAsync(document).WithCancellation(token).ConfigureAwait(false);
- var result = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- if (result == null)
- {
- throw new InvalidOperationException("Got null response from the server after doing a put on " + key + ", something is very wrong. Probably a garbled response.");
- }
- return convention.CreateSerializer().Deserialize<PutResult>(new RavenJTokenReader(result));
- }
- catch (ErrorResponseException e)
- {
- if (e.StatusCode != HttpStatusCode.Conflict) throw;
- responseException = e;
- }
- throw FetchConcurrencyException(responseException);
- }
- }
-
- public IAsyncDatabaseCommands ForDatabase(string database)
- {
- return ForDatabaseInternal(database);
- }
-
- public IAsyncDatabaseCommands ForSystemDatabase()
- {
- return ForSystemDatabaseInternal();
- }
-
- internal AsyncServerClient ForDatabaseInternal(string database)
- {
- if (database == Constants.SystemDatabase)
- return ForSystemDatabaseInternal();
-
- var databaseUrl = MultiDatabase.GetRootDatabaseUrl(Url).ForDatabase(database);
- if (databaseUrl == Url)
- return this;
-
- return new AsyncServerClient(databaseUrl, convention,
- credentialsThatShouldBeUsedOnlyInOperationsWithoutReplication,
- jsonRequestFactory, sessionId,
- requestExecuterGetter, requestTimeMetricGetter, database, conflictListeners, false)
- {
- operationsHeaders = operationsHeaders
- };
- }
-
- internal AsyncServerClient ForSystemDatabaseInternal()
- {
- var databaseUrl = MultiDatabase.GetRootDatabaseUrl(Url);
- if (databaseUrl == Url)
- return this;
-
- return new AsyncServerClient(databaseUrl, convention, credentialsThatShouldBeUsedOnlyInOperationsWithoutReplication, jsonRequestFactory, sessionId, requestExecuterGetter, requestTimeMetricGetter, null, conflictListeners, false) { operationsHeaders = operationsHeaders };
- }
-
- public NameValueCollection OperationsHeaders
- {
- get { return operationsHeaders; }
- set { operationsHeaders = value; }
- }
-
- public IAsyncGlobalAdminDatabaseCommands GlobalAdmin { get { return new AsyncAdminServerClient(this); } }
-
- public IAsyncAdminDatabaseCommands Admin { get { return new AsyncAdminServerClient(this); } }
-
- public Task<JsonDocument> GetAsync(string key, CancellationToken token = default(CancellationToken))
- {
- EnsureIsNotNullOrEmpty(key, "key");
-
- return ExecuteWithReplication(HttpMethod.Get, (operationMetadata, requestTimeMetric) => DirectGetAsync(operationMetadata, requestTimeMetric, key, token), token);
- }
-
- public Task<TransformerDefinition> GetTransformerAsync(string name, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- try
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url.Transformer(name), HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)).AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- var transformerDefinitionJson = (RavenJObject)await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- var value = transformerDefinitionJson.Value<RavenJObject>("Transformer");
- return convention.CreateSerializer().Deserialize<TransformerDefinition>(new RavenJTokenReader(value));
- }
- }
- catch (ErrorResponseException we)
- {
- if (we.StatusCode == HttpStatusCode.NotFound)
- return null;
-
- throw;
- }
- }, token);
- }
-
- public Task<IndexDefinition> GetIndexAsync(string name, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- try
- {
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, operationMetadata.Url.IndexDefinition(name), HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)).AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- var indexDefinitionJson = (RavenJObject)await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- var value = indexDefinitionJson.Value<RavenJObject>("Index");
- return convention.CreateSerializer().Deserialize<IndexDefinition>(new RavenJTokenReader(value));
- }
- }
- catch (ErrorResponseException we)
- {
- if (we.StatusCode == HttpStatusCode.NotFound)
- return null;
-
- throw;
- }
-
- }, token);
- }
-
- public Task<IndexingPerformanceStatistics[]> GetIndexingPerformanceStatisticsAsync()
- {
- return ExecuteWithReplication(HttpMethod.Get, async (operationMetadata, requestTimeMetric) =>
- {
- var url = operationMetadata.Url.IndexingPerformanceStatistics();
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, url, HttpMethod.Get, operationMetadata.Credentials, convention, requestTimeMetric)).AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- var indexingPerformanceStatisticsJson = (RavenJArray)await request.ReadResponseJsonAsync().ConfigureAwait(false);
- var results = new IndexingPerformanceStatistics[indexingPerformanceStatisticsJson.Length];
- for (var i = 0; i < indexingPerformanceStatisticsJson.Length; i++)
- {
- var stats = (RavenJObject)indexingPerformanceStatisticsJson[i];
- results[i] = stats.Deserialize<IndexingPerformanceStatistics>(convention);
- }
-
- return results;
- }
- });
- }
-
- private async Task<JsonDocument> DirectGetAsync(OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, string key, CancellationToken token)
- {
- if (key.Length > 127)
- {
- // avoid hitting UrlSegmentMaxLength limits in Http.sys
- var multiLoadResult = await DirectGetAsync(operationMetadata, requestTimeMetric, new[] { key }, new string[0], null, new Dictionary<string, RavenJToken>(), false, token).WithCancellation(token).ConfigureAwait(false);
- var result = multiLoadResult.Results.FirstOrDefault();
- if (result == null)
- return null;
- return SerializationHelper.RavenJObjectToJsonDocument(result);
- }
-
- var metadata = new RavenJObject();
- AddTransactionInformation(metadata);
- var createHttpJsonRequestParams = new CreateHttpJsonRequestParams(this,
- (operationMetadata.Url + "/docs?id=" + Uri.EscapeDataString(key)),
- HttpMethod.Get,
- metadata,
- operationMetadata.Credentials,
- convention,
- requestTimeMetric);
-
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(
- createHttpJsonRequestParams.AddOperationHeaders(OperationsHeaders))
- .AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- Task<JsonDocument> resolveConflictTask;
- try
- {
- var requestJson = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- var docKey = request.ResponseHeaders.Get(Constants.DocumentIdFieldName) ?? key;
- docKey = Uri.UnescapeDataString(docKey);
- request.ResponseHeaders.Remove(Constants.DocumentIdFieldName);
- var deserializeJsonDocument = SerializationHelper.DeserializeJsonDocument(docKey, requestJson, request.ResponseHeaders, request.ResponseStatusCode);
- return deserializeJsonDocument;
- }
- catch (ErrorResponseException e)
- {
- switch (e.StatusCode)
- {
- case HttpStatusCode.NotFound:
- return null;
- case HttpStatusCode.Conflict:
- resolveConflictTask = ResolveConflict(e.ResponseString, e.Etag, operationMetadata, requestTimeMetric, key, token);
- break;
- default:
- throw;
- }
- }
- return await resolveConflictTask.WithCancellation(token).ConfigureAwait(false);
- }
- }
-
- private async Task<JsonDocument> ResolveConflict(string httpResponse, Etag etag, OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, string key, CancellationToken token)
- {
- var conflicts = new StringReader(httpResponse);
- var conflictsDoc = RavenJObject.Load(new RavenJsonTextReader(conflicts));
- var result =
- await TryResolveConflictOrCreateConcurrencyException(operationMetadata, requestTimeMetric, key, conflictsDoc, etag, token).ConfigureAwait(false);
- if (result != null)
- throw result;
- return await DirectGetAsync(operationMetadata, requestTimeMetric, key, token).ConfigureAwait(false);
- }
-
- public Task<MultiLoadResult> GetAsync(string[] keys, string[] includes, string transformer = null,
- Dictionary<string, RavenJToken> transformerParameters = null, bool metadataOnly = false, CancellationToken token = default(CancellationToken))
- {
- return ExecuteWithReplication(HttpMethod.Get, (operationMetadata, requestTimeMetric) => DirectGetAsync(operationMetadata, requestTimeMetric, keys, includes, transformer, transformerParameters, metadataOnly, token), token);
- }
-
- private async Task<MultiLoadResult> DirectGetAsync(OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, string[] keys, string[] includes, string transformer,
- Dictionary<string, RavenJToken> transformerParameters, bool metadataOnly, CancellationToken token = default(CancellationToken))
- {
- var path = operationMetadata.Url + "/queries/?";
- if (metadataOnly)
- path += "&metadata-only=true";
- if (includes != null && includes.Length > 0)
- {
- path += string.Join("&", includes.Select(x => "include=" + x).ToArray());
- }
- if (string.IsNullOrEmpty(transformer) == false)
- path += "&transformer=" + transformer;
-
- if (transformerParameters != null)
- {
- path = transformerParameters.Aggregate(path,
- (current, transformerParam) =>
- current + ("&" + string.Format("tp-{0}={1}", transformerParam.Key, transformerParam.Value)));
- }
-
- var metadata = new RavenJObject();
- AddTransactionInformation(metadata);
-
- var uniqueIds = new HashSet<string>(keys);
- // if it is too big, we drop to POST (note that means that we can't use the HTTP cache any longer)
- // we are fine with that, requests to load > 128 items are going to be rare
- var isGet = uniqueIds.Sum(x => x.Length) < 1024;
- var method = isGet ? HttpMethod.Get : HttpMethod.Post;
- if (isGet)
- {
- path += "&" + string.Join("&", uniqueIds.Select(x => "id=" + Uri.EscapeDataString(x)).ToArray());
- }
- var createHttpJsonRequestParams = new CreateHttpJsonRequestParams(this, path, method, metadata, operationMetadata.Credentials, convention)
- .AddOperationHeaders(OperationsHeaders);
- using (var request = jsonRequestFactory.CreateHttpJsonRequest(createHttpJsonRequestParams)
- .AddRequestExecuterAndReplicationHeaders(this, operationMetadata.Url, operationMetadata.ClusterInformation.WithClusterFailoverHeader))
- {
- if (isGet == false)
- {
- await request.WriteAsync(new RavenJArray(uniqueIds)).WithCancellation(token).ConfigureAwait(false);
- }
-
- var result = await request.ReadResponseJsonAsync().WithCancellation(token).ConfigureAwait(false);
- return await CompleteMultiGetAsync(operationMetadata, requestTimeMetric, keys, includes, transformer, transformerParameters, result, token).ConfigureAwait(false);
- }
- }
-
- private async Task<MultiLoadResult> CompleteMultiGetAsync(OperationMetadata operationMetadata, IRequestTimeMetric requestTimeMetric, string[] keys, string[] includes, string transformer,
- Dictionary<string, RavenJToken> transformerParameters, RavenJToken result, CancellationToken token = default(CancellationToken))
- {
- ErrorResponseException responseException;
- try
- {
- var uniqueKeys = new HashSet<string>(keys);
-
- var results = result
- .Value<RavenJArray>("Results")
- .Select(x => x as RavenJObject)
- .ToList();
-
- var documents = results
- .Where(x => x != null && x.ContainsKey("@metadata") && x["@metadata"].Value<string>("@id") != null)
- .ToDictionary(x => x["@metadata"].Value<string>("@id"), x => x, StringComparer.OrdinalIgnoreCase);
-
- if (results.Count >= uniqueKeys.Count)
- {
- for (var i = 0; i < uniqueKeys.Count; i++)
- {
- va…
Large files files are truncated, but you can click here to view the full file