public virtual RetryWrapper <GitObjectTaskResult> .InvocationResult TryDownloadObjects(
            Func <IEnumerable <string> > objectIdGenerator,
            Func <int, GitEndPointResponseData, RetryWrapper <GitObjectTaskResult> .CallbackResult> onSuccess,
            Action <RetryWrapper <GitObjectTaskResult> .ErrorEventArgs> onFailure,
            bool preferBatchedLooseObjects)
        {
            // We pass the query generator in as a function because we don't want the consumer to know about JSON or network retry logic,
            // but we still want the consumer to be able to change the query on each retry if we fail during their onSuccess handler.
            long requestId = HttpRequestor.GetNewRequestId();

            return(this.TrySendProtocolRequest(
                       requestId,
                       onSuccess,
                       onFailure,
                       HttpMethod.Post,
                       new Uri(this.CacheServer.ObjectsEndpointUrl),
                       CancellationToken.None,
                       () => this.ObjectIdsJsonGenerator(requestId, objectIdGenerator),
                       preferBatchedLooseObjects ? CustomLooseObjectsHeader : null));
        }
        public virtual GitRefs QueryInfoRefs(string branch)
        {
            long requestId = HttpRequestor.GetNewRequestId();

            Uri infoRefsEndpoint;

            try
            {
                infoRefsEndpoint = new Uri(this.enlistment.RepoUrl + GSDConstants.Endpoints.InfoRefs);
            }
            catch (UriFormatException)
            {
                return(null);
            }

            RetryWrapper <GitRefs> retrier = new RetryWrapper <GitRefs>(this.RetryConfig.MaxAttempts, CancellationToken.None);

            retrier.OnFailure += RetryWrapper <GitRefs> .StandardErrorHandler(this.Tracer, requestId, "QueryInfoRefs");

            RetryWrapper <GitRefs> .InvocationResult output = retrier.Invoke(
                tryCount =>
            {
                using (GitEndPointResponseData response = this.SendRequest(
                           requestId,
                           infoRefsEndpoint,
                           HttpMethod.Get,
                           requestContent: null,
                           cancellationToken: CancellationToken.None))
                {
                    if (response.HasErrors)
                    {
                        return(new RetryWrapper <GitRefs> .CallbackResult(response.Error, response.ShouldRetry));
                    }

                    List <string> infoRefsResponse = response.RetryableReadAllLines();
                    return(new RetryWrapper <GitRefs> .CallbackResult(new GitRefs(infoRefsResponse, branch)));
                }
            });

            return(output.Result);
        }
        public bool TryQueryGSDConfig(bool logErrors, out ServerGSDConfig serverGSDConfig, out HttpStatusCode?httpStatus, out string errorMessage)
        {
            serverGSDConfig = null;
            httpStatus      = null;
            errorMessage    = null;

            Uri    gvfsConfigEndpoint;
            string gvfsConfigEndpointString = this.repoUrl + GSDConstants.Endpoints.GSDConfig;

            try
            {
                gvfsConfigEndpoint = new Uri(gvfsConfigEndpointString);
            }
            catch (UriFormatException e)
            {
                EventMetadata metadata = new EventMetadata();
                metadata.Add("Method", nameof(this.TryQueryGSDConfig));
                metadata.Add("Exception", e.ToString());
                metadata.Add("Url", gvfsConfigEndpointString);
                this.Tracer.RelatedError(metadata, "UriFormatException when constructing Uri", Keywords.Network);

                return(false);
            }

            long requestId = HttpRequestor.GetNewRequestId();
            RetryWrapper <ServerGSDConfig> retrier = new RetryWrapper <ServerGSDConfig>(this.RetryConfig.MaxAttempts, CancellationToken.None);

            if (logErrors)
            {
                retrier.OnFailure += RetryWrapper <ServerGSDConfig> .StandardErrorHandler(this.Tracer, requestId, "QueryGvfsConfig");
            }

            RetryWrapper <ServerGSDConfig> .InvocationResult output = retrier.Invoke(
                tryCount =>
            {
                using (GitEndPointResponseData response = this.SendRequest(
                           requestId,
                           gvfsConfigEndpoint,
                           HttpMethod.Get,
                           requestContent: null,
                           cancellationToken: CancellationToken.None))
                {
                    if (response.HasErrors)
                    {
                        return(new RetryWrapper <ServerGSDConfig> .CallbackResult(response.Error, response.ShouldRetry));
                    }

                    try
                    {
                        string configString    = response.RetryableReadToEnd();
                        ServerGSDConfig config = JsonConvert.DeserializeObject <ServerGSDConfig>(configString);
                        return(new RetryWrapper <ServerGSDConfig> .CallbackResult(config));
                    }
                    catch (JsonReaderException e)
                    {
                        return(new RetryWrapper <ServerGSDConfig> .CallbackResult(e, shouldRetry: false));
                    }
                }
            });

            if (output.Succeeded)
            {
                serverGSDConfig = output.Result;
                httpStatus      = HttpStatusCode.OK;
                return(true);
            }

            GitObjectsHttpException httpException = output.Error as GitObjectsHttpException;

            if (httpException != null)
            {
                httpStatus   = httpException.StatusCode;
                errorMessage = httpException.Message;
            }

            if (logErrors)
            {
                this.Tracer.RelatedError(
                    new EventMetadata
                {
                    { "Exception", output.Error.ToString() }
                },
                    $"{nameof(this.TryQueryGSDConfig)} failed");
            }

            return(false);
        }
        public virtual List <GitObjectSize> QueryForFileSizes(IEnumerable <string> objectIds, CancellationToken cancellationToken)
        {
            long requestId = HttpRequestor.GetNewRequestId();

            string objectIdsJson       = ToJsonList(objectIds);
            Uri    cacheServerEndpoint = new Uri(this.CacheServer.SizesEndpointUrl);
            Uri    originEndpoint      = new Uri(this.enlistment.RepoUrl + GSDConstants.Endpoints.GSDSizes);

            EventMetadata metadata = new EventMetadata();

            metadata.Add("RequestId", requestId);
            int objectIdCount = objectIds.Count();

            if (objectIdCount > 10)
            {
                metadata.Add("ObjectIdCount", objectIdCount);
            }
            else
            {
                metadata.Add("ObjectIdJson", objectIdsJson);
            }

            this.Tracer.RelatedEvent(EventLevel.Informational, "QueryFileSizes", metadata, Keywords.Network);

            RetryWrapper <List <GitObjectSize> > retrier = new RetryWrapper <List <GitObjectSize> >(this.RetryConfig.MaxAttempts, cancellationToken);

            retrier.OnFailure += RetryWrapper <List <GitObjectSize> > .StandardErrorHandler(this.Tracer, requestId, "QueryFileSizes");

            RetryWrapper <List <GitObjectSize> > .InvocationResult requestTask = retrier.Invoke(
                tryCount =>
            {
                Uri gvfsEndpoint;
                if (this.nextCacheServerAttemptTime < DateTime.Now)
                {
                    gvfsEndpoint = cacheServerEndpoint;
                }
                else
                {
                    gvfsEndpoint = originEndpoint;
                }

                using (GitEndPointResponseData response = this.SendRequest(requestId, gvfsEndpoint, HttpMethod.Post, objectIdsJson, cancellationToken))
                {
                    if (response.StatusCode == HttpStatusCode.NotFound)
                    {
                        this.nextCacheServerAttemptTime = DateTime.Now.AddDays(1);
                        return(new RetryWrapper <List <GitObjectSize> > .CallbackResult(response.Error, true));
                    }

                    if (response.HasErrors)
                    {
                        return(new RetryWrapper <List <GitObjectSize> > .CallbackResult(response.Error, response.ShouldRetry));
                    }

                    string objectSizesString         = response.RetryableReadToEnd();
                    List <GitObjectSize> objectSizes = JsonConvert.DeserializeObject <List <GitObjectSize> >(objectSizesString);
                    return(new RetryWrapper <List <GitObjectSize> > .CallbackResult(objectSizes));
                }
            });

            return(requestTask.Result ?? new List <GitObjectSize>(0));
        }