Beispiel #1
0
        protected virtual SendResult SaveRequestResults(Stream responseStream, TransportSendStats sendStats, SendIterationContext context)
        {
            bool needRetry       = false;
            bool serverDbChanged = false;
            TransportResponseStats responseStats;

            using (var streamReader = new StreamReader(responseStream))
                using (var jsonReader = new JsonTextReader(streamReader))
                {
                    var jsonSerializer = new JsonSerializer();
                    // сохраним потоки данных конфигураций при десериализации
                    // TODO Доработать configurationsConverter
                    var configurationsConverter = new TransportResponseConfigurationsConverter(this.configurationStore);
                    jsonSerializer
                    .Converters
                    .Add(configurationsConverter);

                    var response = jsonSerializer.Deserialize <TransportResponse>(jsonReader);

                    if (response.ErrorMessage != null)
                    {
                        SendResult.Retry(context.TransportSettings.ErrorRetryTimeout);
                    }

                    // изменеилась статическая конфигурация
                    if (response.StaticConfigData != null)
                    {
                        this.agentInfoService.SetStaticConfig(new TransportStaticConfig
                        {
                            ConfigToken   = response.StaticConfigData.ConfigToken,
                            ConfigVersion = response.StaticConfigData.ConfigVersion,
                        });

                        return(SendResult.Retry(TransportConstants.DefaultUpdateStaticConfigTimeout));
                    }
                    else
                    {
                        // ConfigurationsByteArraysToFilesConverter используется при сохранении конфигураций
                        this.sendStateStore.ConfigurationsUpdated();

                        // изменилась бд системы (например сменили сервера)
                        if (response.DbTokenData != null)
                        {
                            serverDbChanged = true;

                            this.agentInfoService.SetDbToken(new TransportDbTokenData
                            {
                                DbToken = response.DbTokenData.DbToken
                            });

                            //return SendResult.Retry(TransportConstants.DefaultUpdateDbTokenTimeout);
                        }

                        responseStats = new TransportResponseStats()
                        {
                            SendedPacketsStats = sendStats.SendedPacketsStats,
                            // изменилась бд системы
                            TransferedPacketsProcessingResults = response.DbTokenData != null ? new List <TransferedPacketStats>() : sendStats.SendedPacketsStats.Select(x =>
                            {
                                var transferedPacketResponse = response.TransferedPackets.First(p => p.PacketId == x.Key.Identity.PacketId && p.ProviderKey == x.Key.ProviderKey);
                                //
                                x.Value.PreviousPartIdentity = new PacketPartIdentity(transferedPacketResponse.StorageToken, transferedPacketResponse.Id);
                                return(new TransferedPacketStats
                                {
                                    PacketInfo = x.Key,
                                    SendStats = x.Value,
                                    Result = transferedPacketResponse.Result,
                                });
                            }).ToList(),
                        };
                    }
                }

            // сохраняем данные
            var packets = responseStats.TransferedPacketsProcessingResults;

            if (serverDbChanged)
            {
                this.packetManager.RemoveAll();
            }
            else
            {
                foreach (var item in packets)
                {
                    var packet = item.PacketInfo;
                    if (item.Result == PacketProcessingResult.Saved)
                    {
                        this.packetManager.SaveSendStats(packet.ProviderKey, packet.Identity, item.SendStats);
                    }
                    else if (item.Result == PacketProcessingResult.Error)
                    {
                        needRetry = true;
                    }
                    else if (item.Result == PacketProcessingResult.Resend)
                    {
                        // сбрасываем статистику
                        this.packetManager.SaveSendStats(packet.ProviderKey, packet.Identity, new SendStats());
                    }
                    // игнорим эти результаты (если потом появится обработчик на сервере или обновиться агент до нормальной версии и в нём будет другая обработка, предполагаю что следующий набор данных будет доставлен успешно)
                    //else if (item.Result == PacketProcessingResult.Unknown)
                    //{
                    //}
                    //else if (item.Result == PacketProcessingResult.NoProcessor)
                    //{
                    //}
                    else
                    {
                        this.packetManager.SaveSendStats(packet.ProviderKey, packet.Identity, item.SendStats);
                    }
                }
            }

            return(needRetry
                ? SendResult.Retry(context.TransportSettings.ErrorRetryTimeout)
                : SendResult.Success(serverDbChanged, packets, sendStats.IgnoredPackets));
        }
Beispiel #2
0
        protected virtual SendResult SendIteration(IList <ITransportPacketInfo> packetInfos, IList <ConfigurationRequestDataItem> configurationsToDownloadInfos, SendIterationContext context)
        {
            var url = this.GetUri(this.GetSendMessageHeaders(context));

            string formDataBoundary = string.Format("----------{0:N}", Guid.NewGuid());
            string contentType      = "multipart/form-data; boundary=" + formDataBoundary;

            // для net40
#if !NETSTANDARD2_0
            try
            {
                var req = WebRequest.Create(url) as HttpWebRequest;
                //req.KeepAlive = true;
                //req.KeepAlive = false;
                req.AllowWriteStreamBuffering = false;
                req.SendChunked = true;
                req.ServicePoint.Expect100Continue = true;
                req.Method      = "POST";
                req.ContentType = contentType;
                //req.ContinueTimeout = xxx;

                TransportSendStats sendededStats = null;
                using (Stream requestStream = req.GetRequestStream())
                {
                    sendededStats = this.WriteMessageToBody(formDataBoundary, requestStream, packetInfos, configurationsToDownloadInfos, context, () => req.HaveResponse);

                    // для тестирования...
                    //var length = 1 * 1024 * 1024 * 1024;
                    //var batch = 1 * 1024 * 1024;
                    //for (int i = 0; i < length; i += batch)
                    //{
                    //    var batchBuffer = new List<byte>();
                    //    for (int j = 0; j < batch; j++)
                    //    {
                    //        batchBuffer.Add(0);
                    //    }
                    //    if (req.HaveResponse)
                    //    {
                    //        break;
                    //    }
                    //    requestStream.Write(batchBuffer.ToArray(), 0, batchBuffer.Count);
                    //}
                }

                try
                {
                    using (var response = req.GetResponse())
                        using (var resStream = response.GetResponseStream())
                            using (var streamReader = new StreamReader(resStream))
                            {
                                // обрабатывает ответ
                                return(this.SaveRequestResults(resStream, sendededStats, context));
                            }
                }
                catch (WebException ex)
                {
                    var wRespStatusCode = ((HttpWebResponse)ex.Response).StatusCode;
                    // кастомная обработка конфигурации (для проблемы когда тело запроса с агента отправляется, хотя в этом нет смысла - лишние данные ходят по сети, это можно исправить)
                    if ((int)wRespStatusCode == 399)
                    {
                        using (var resStream = ((HttpWebResponse)ex.Response).GetResponseStream())
                            using (var streamReader = new StreamReader(resStream))
                            {
                                // обрабатывает ответ
                                return(this.SaveRequestResults(resStream, sendededStats, context));
                            }
                    }
                    if ((int)wRespStatusCode == 429)
                    {
                        var timeout = int.TryParse(ex.Response.Headers.GetValues("Retry-After").FirstOrDefault(), out var retryTm)
                            ? retryTm
                            : Convert.ToInt64(context.TransportSettings.ErrorRetryTimeout.TotalMilliseconds);

                        return(SendResult.Retry(timeout));
                    }

                    // при общих ошибках
                    return(SendResult.Retry(context.TransportSettings.ServerErrorRetryTimeout));
                }
            }
            catch (Exception)
            {
                // при общих ошибках
                return(SendResult.Retry(context.TransportSettings.ErrorRetryTimeout));
            }
#else
            try
            {
                TransportSendStats sendedStats = null;
                var reqContent = new HttpRequestMessage(HttpMethod.Post, url)
                {
                    Content = new WriteToStreamContent((requestStream, ctx) =>
                    {
                        sendedStats = this.WriteMessageToBody(formDataBoundary, requestStream, packetInfos, configurationsToDownloadInfos, context, () => false);

                        // для тестирования...
                        //var length = 1 * 1024 * 1024 * 1024;
                        //var batch = 1 * 1024 * 1024;
                        //for (int i = 0; i < length; i += batch)
                        //{
                        //    var batchBuffer = new List<byte>();
                        //    for (int j = 0; j < batch; j++)
                        //    {
                        //        batchBuffer.Add(0);
                        //    }
                        //    //if (req.HaveResponse)
                        //    //{
                        //    //    break;
                        //    //}
                        //    requestStream.Write(batchBuffer.ToArray(), 0, batchBuffer.Count);
                        //}
                    }),
                };

                // workaround net core 2.2 и тех кто использует библиотеку System.Net.Http под netstandard (с версии 4.2.1.0)
                // https://github.com/dotnet/corefx/blob/v2.1.5/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L537  (версия 2.1.5 указана для примера)
                // нужно для того чтобы в случаях "отказов" не происходило чтение всего тела запроса, а читались только основные параметры
                reqContent.Headers.ExpectContinue      = true;
                reqContent.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType);
                //reqContent.Version = new Version(1, 1);
                var result = this.httpClient.SendAsync(reqContent, HttpCompletionOption.ResponseHeadersRead).Result;

                if (result.IsSuccessStatusCode)
                {
                    using (var stream = result.Content.ReadAsStreamAsync().Result)
                    {
                        // обрабатывает ответ
                        return(this.SaveRequestResults(stream, sendedStats, context));
                    };
                }
                else
                {
                    // кастомная обработка конфигурации (для проблемы когда тело запроса с агента отправляется, хотя в этом нет смысла - лишние данные ходят по сети, это можно исправить)
                    if ((int)result.StatusCode == 399)
                    {
                        using (var stream = result.Content.ReadAsStreamAsync().Result)
                        {
                            // обрабатывает ответ
                            return(this.SaveRequestResults(stream, sendedStats, context));
                        };
                    }
                    if ((int)result.StatusCode == 429)
                    {
                        var timeout = int.TryParse(result.Headers.GetValues("Retry-After").FirstOrDefault(), out var retryTm)
                                        ? retryTm
                                        : Convert.ToInt64(context.TransportSettings.ErrorRetryTimeout.TotalMilliseconds);

                        return(SendResult.Retry(timeout));
                    }

                    return(SendResult.Retry(context.TransportSettings.ServerErrorRetryTimeout));
                }
            }
            catch (Exception)
            {
                // при общих ошибках
                return(SendResult.Retry(context.TransportSettings.ErrorRetryTimeout));
            }
#endif
        }