public ApiDataSentEventArgs(
     Guid[] trackingIds,
     ApiData[] apiData,
     ISentApiData sentApiData)
 {
     TrackingIds = trackingIds;
     ApiData     = apiData;
     SentApiData = sentApiData;
 }
예제 #2
0
 public string[] Test(Guid trackingId, ApiData sourceData, ISentApiData sentApiData)
 {
     using (var stream = new MemoryStream(sentApiData.PayloadByteArray)) {
         return(Serializer.DeserializeItems <KancolleApiSendModel>(stream, PrefixStyle.Base128, 0).SelectMany(sendModel => {
             var targetData = this.ToApiData(sendModel);
             if (sourceData.RequestBody == targetData.RequestBody && sourceData.ResponseBody == targetData.ResponseBody)
             {
                 double originalRequestByteCount = Encoding.UTF8.GetByteCount(sourceData.RequestBody);
                 this.sumOriginalRequestByteCount += originalRequestByteCount;
                 double originalResponseByteCount = Encoding.UTF8.GetByteCount(sourceData.ResponseBody);
                 this.sumOriginalResponseByteCount += originalResponseByteCount;
                 var originalByteCount = originalRequestByteCount + originalResponseByteCount;
                 var sumOriginalByteCount = this.sumOriginalRequestByteCount + this.sumOriginalResponseByteCount;
                 double modifiedRequestByteCount;
                 using (var modifiedRequestStream = new MemoryStream()) {
                     Serializer.Serialize(modifiedRequestStream, sendModel.RequestValuePatches);
                     modifiedRequestByteCount = modifiedRequestStream.Length;
                 }
                 this.sumModifiedRequestByteCount += modifiedRequestByteCount;
                 double modifiedResponseByteCount;
                 using (var modifiedResponseStream = new MemoryStream()) {
                     Serializer.Serialize(modifiedResponseStream, sendModel.ResponseValuePatches);
                     modifiedResponseByteCount = modifiedResponseStream.Length;
                 }
                 this.sumModifiedResponseByteCount += modifiedResponseByteCount;
                 var modifiedByteCount = modifiedRequestByteCount + modifiedResponseByteCount;
                 var sumModifiedByteCount = this.sumModifiedRequestByteCount + this.sumModifiedResponseByteCount;
                 return new[] {
                     string.Format(
                         "Req:  {0,7} -> {1,7}, {2,7:0.00%}: {3,9} -> {4,9}, {5,7:0.00%}",
                         originalRequestByteCount,
                         modifiedRequestByteCount,
                         modifiedRequestByteCount / originalRequestByteCount,
                         this.sumOriginalRequestByteCount,
                         this.sumModifiedRequestByteCount,
                         this.sumModifiedRequestByteCount / this.sumOriginalRequestByteCount),
                     string.Format(
                         "Res:  {0,7} -> {1,7}, {2,7:0.00%}: {3,9} -> {4,9}, {5,7:0.00%}",
                         originalResponseByteCount,
                         modifiedResponseByteCount,
                         modifiedResponseByteCount / originalResponseByteCount,
                         this.sumOriginalResponseByteCount,
                         this.sumModifiedResponseByteCount,
                         this.sumModifiedResponseByteCount / this.sumOriginalResponseByteCount),
                     string.Format(
                         "Both: {0,7} -> {1,7}, {2,7:0.00%}: {3,9} -> {4,9}, {5,7:0.00%}",
                         originalByteCount,
                         modifiedByteCount,
                         modifiedByteCount / originalByteCount,
                         sumOriginalByteCount,
                         sumModifiedByteCount,
                         sumModifiedByteCount / sumOriginalByteCount)
                 };
             }
             else
             {
                 return new[] { "APIの復元に失敗しました。" };
             }
         }).ToArray());
     }
 }
        public async Task SendingThread(CancellationToken cancellationToken)
        {
            try {
                var lastResult  = TransferResult.Succeeded;
                var timeToDelay = TimeSpan.Zero;
                var rand        = new Random();
                while (!cancellationToken.IsCancellationRequested)
                {
                    bool shouldWait = false;

                    if (timeToDelay != TimeSpan.Zero)
                    {
                        try {
                            await Task.Delay(timeToDelay, cancellationToken);
                        }
                        catch (OperationCanceledException) {
                            break;
                        }
                    }

                    lock (QueueLock) {
                        shouldWait = Queue.Count == 0;
                    }

                    if (shouldWait)
                    {
                        try {
                            SendEvent.WaitOne();
                        }
                        catch (Exception ex) {
                            this.FatalError(this, new FatalErrorEventArgs("Failed to wait event for sending data. Stopping sending.", ex));
                            break;
                        }
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    lock (QueueLock) {
                        if (Queue.Count == 0)
                        {
                            continue;
                        }
                    }

                    var itemsToSend = new List <QueueItem>();
                    lock (QueueLock) {
                        if (DataSender.SupportsMultiPost)
                        {
                            itemsToSend.AddRange(Queue.Take(MaxChunkSize));
                        }
                        else
                        {
                            itemsToSend.Add(Queue.Peek());
                        }
                    }

                    if (!itemsToSend.Any())
                    {
                        continue;
                    }

                    var dataArray   = itemsToSend.Select(x => x.ApiData).ToArray();
                    var trackingIds = itemsToSend.Select(x => x.TrackingId).ToArray();
                    try {
                        this.ApiDataSending?.Invoke(this, new ApiDataSendingEventArgs(trackingIds, dataArray));

                        ISentApiData sentApiData = null;
                        if (DataSender.SupportsMultiPost)
                        {
                            sentApiData = await DataSender.SendData(dataArray);
                        }
                        else
                        {
                            sentApiData = await DataSender.SendData(dataArray[0]);
                        }

                        lastResult  = TransferResult.Succeeded;
                        timeToDelay = TimeSpan.Zero;

                        this.ApiDataSent?.Invoke(this, new ApiDataSentEventArgs(trackingIds, dataArray, sentApiData));
                    }
                    catch (DataSendingException ex) {
                        this.SendingError?.Invoke(this, new SendingErrorEventArgs(trackingIds, "Failed sending API data.", dataArray, ex));
                        switch (ex.Reason)
                        {
                        case SendingErrorReason.ServerError:
                            if (lastResult == TransferResult.ServerError)
                            {
                                timeToDelay += ServerErrorDelayIncrement;
                                if (timeToDelay > MaxDelayAfterServerkError)
                                {
                                    timeToDelay = MaxDelayAfterServerkError;
                                }
                            }
                            else
                            {
                                timeToDelay = MinDelayAfterServerkError;
                            }
                            lastResult = TransferResult.ServerError;
                            break;

                        case SendingErrorReason.HttpProtocolError:
                        case SendingErrorReason.NetworkError:
                        case SendingErrorReason.Unknown:
                            if (lastResult == TransferResult.NetworkError)
                            {
                                timeToDelay += NetworkErrorDelayIncrement;
                                if (timeToDelay > MaxDelayAfterNetworkError)
                                {
                                    timeToDelay = MaxDelayAfterNetworkError;
                                }
                            }
                            else
                            {
                                timeToDelay = MinDelayAfterNetworkError;
                            }
                            lastResult = TransferResult.NetworkError;
                            break;
                        }
                        continue;
                    }
                    catch (OperationCanceledException) {
                        break;
                    }
                    catch (Exception ex) {
                        this.InternalError?.Invoke(this, new InternalErrorEventArgs(trackingIds, "Failed to something before sending API data.", ex, dataArray));
                        continue;
                    }

                    lock (QueueLock) {
                        for (int i = 0; i < itemsToSend.Count && Queue.Count > 0; i++)
                        {
                            Queue.Dequeue();
                        }
                    }
                }
            }
            catch (Exception ex) {
                FatalError?.Invoke(this, new FatalErrorEventArgs("Sending thread aborted. API data will no longer be sent from now.", ex));
            }
        }