public async Task FlushBlocks()
 {
     using (await _lockSem.GetDisposable().ConfigureAwait(false))
     {
         if (Status != InMessageStatus.AllBlocksReceived)
         {
             throw new InvalidOperationException(
                       "Status != InMessageStatus.AllBlocksReceived");
         }
         int l = ReceivedData.Length;
         for (int i = 0; i < l; i++)
         {
             ReceivedData[i] = null;
         }
     }
 }
예제 #2
0
 public async Task SendBlock(uint blockId)
 {
     if (blockId >= BlockCount)
     {
         throw new ArgumentOutOfRangeException("blockId");
     }
     if (Status == OutMessageStatus.HandshakeOk)
     {
         Status = OutMessageStatus.FirstBlockSent;
     }
     using (await _blocksSentLockSem.GetDisposable().ConfigureAwait(false))
     {
         if (!BlocksSent[blockId])
         {
             BlocksSentCount++;
             BlocksSent[blockId] = true;
             if (
                 Status == OutMessageStatus.FirstBlockSent &&
                 BlocksSentCount == BlockCount
                 )
             {
                 Status = OutMessageStatus.AllBlocksSent;
             }
         }
     }
 }
예제 #3
0
 public async Task <T1> GetClientProxy()
 {
     using (_stateHelper.GetFuncWrapper())
     {
         using (await _proxyLockSem.GetDisposable().ConfigureAwait(false))
         {
             return(_proxy ?? (_proxy = (new ProxyFactory()).CreateProxy <T1>(this)));
         }
     }
 }
예제 #4
0
 public async Task <uint> GetNextOutMessageId()
 {
     using (
         await _nextOutMessageIdLockSem.GetDisposable().ConfigureAwait(false)
         )
     {
         if (_nextOutMessageId == 0)
         {
             _nextOutMessageId++;
         }
         return(_nextOutMessageId++);
     }
 }
예제 #5
0
        private async void IntervalCleanupAction(long i)
        {
            var curMethodName = this.MyNameOfMethod(e => e.IntervalCleanupAction(0));

            try
            {
                using (_stateHelper.GetFuncWrapper())
                {
                    using (await _intervalCleanupActionLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        var nowTime = DateTime.UtcNow;
                        using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
                        {
                            foreach (KeyValuePair <string, DestinationInfo> destinationInfo in _destinationDb)
                            {
                                using (await destinationInfo.Value.InMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
                                {
                                    var inMessageIdsToRemove =
                                        (
                                            from inMessageInfo
                                            in destinationInfo.Value.InMessagesDb
                                            where nowTime > inMessageInfo.Value.CreatedTime
                                            + _settings.CleanInMessagesOlderThan
                                            select inMessageInfo.Key
                                        ).ToList();
                                    foreach (uint messageId in inMessageIdsToRemove)
                                    {
                                        destinationInfo.Value.InMessagesDb.Remove(messageId);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (WrongDisposableObjectStateException)
            {
            }
            catch (Exception exc)
            {
                _log.Error("{0} unexpected error '{1}'", curMethodName, exc.ToString());
            }
        }
예제 #6
0
 public async Task ConfirmBlock(uint blockId)
 {
     if (blockId >= BlockCount)
     {
         throw new ArgumentOutOfRangeException("blockId");
     }
     using (await _blockConfirmedLockSem.GetDisposable().ConfigureAwait(false))
     {
         if (!BlockConfirmed[blockId])
         {
             BlockConfirmed[blockId] = true;
             BlocksConfirmedCount++;
             if (BlocksConfirmedCount == BlockCount)
             {
                 Status = OutMessageStatus.AllBlocksConfirmed;
             }
         }
     }
 }
예제 #7
0
 private async Task WriteBuffer(byte[] writeBuffer)
 {
     using (await _writeBufferLockSem.GetDisposable().ConfigureAwait(false))
     {
         try
         {
             await _samStream.WriteAsync(
                 writeBuffer,
                 0,
                 writeBuffer.Length
                 ).ConfigureAwait(false);
         }
         catch (IOException)
         {
             IoExceptionThrown.OnNext(null);
             throw;
         }
     }
 }
예제 #8
0
            private async Task ReadAndAccumulate(
                CancellationToken cancellationToken
                )
            {
                int readBytes;

                using (await _streamReadLockSem.GetDisposable().ConfigureAwait(false))
                {
                    readBytes = await _samStream.ReadAsync(
                        _buffer,
                        0,
                        BufferSize,
                        cancellationToken
                        ).ThrowIfCancelled(cancellationToken).ConfigureAwait(false);
                }
                if (readBytes > 0)
                {
                    _accumulateBuffer.AddRange(_buffer.Take(readBytes));
                }
            }
예제 #9
0
        public async Task <uint> SendReliableMessage(
            string destination,
            byte[] data,
            IProgress <OutMessageProgressInfo> progress = null,
            uint messageId          = 0,
            uint replyToMessageId   = 0,
            byte messageKind        = 0,
            CancellationToken token = default(CancellationToken)
            )
        {
            using (_stateHelper.GetFuncWrapper())
            {
                try
                {
                    Assert.True(SamHelper.IsDestinationStringValid(destination));
                    Assert.NotNull(data);
                    Assert.InRange(data.Length, 1, _settings.MaxMesageLength);
                    if (messageId == 0)
                    {
                        messageId = await GetNextOutMessageId().ConfigureAwait(false);
                    }
                    DestinationInfo destinationInfo;
                    using (await _destinationDbLockSem.GetDisposable(token: token).ConfigureAwait(false))
                    {
                        if (!_destinationDb.ContainsKey(destination))
                        {
                            _destinationDb.Add(destination, new DestinationInfo());
                        }
                        destinationInfo = _destinationDb[destination];
                    }
                    OutMessageInfo outMessageInfo;
                    using (await destinationInfo.OutMessagesDbLockSem.GetDisposable(token: token).ConfigureAwait(false))
                    {
                        if (
                            destinationInfo.OutMessagesDb.ContainsKey(messageId)
                            )
                        {
                            throw new EnumException <SendReliableMessageExcs>(
                                      SendReliableMessageExcs.ExistMessageId
                                      );
                        }
                        outMessageInfo = new OutMessageInfo(
                            data,
                            replyToMessageId,
                            _settings.MaxBlockSize,
                            progress
                            );
                        destinationInfo.OutMessagesDb.Add(messageId, outMessageInfo);
                    }
                    try
                    {
                        uint blocksCount = outMessageInfo.BlockCount;

                        /*
                         * Handshake
                         */
                        using (
                            var compositeTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
                                _cts.Token,
                                token
                                )
                            )
                        {
                            try
                            {
                                var messageStatusTask =
                                    MessageStatusReceived
                                    .Where(
                                        x =>
                                        x.Destination == destination &&
                                        x.MessageId == messageId
                                        )
                                    .FirstAsync()
                                    .ToTask(compositeTokenSource.Token);
                                byte[] messageHash = GetMessageHash(
                                    messageId,
                                    replyToMessageId,
                                    messageKind,
                                    data
                                    );
                                for (
                                    outMessageInfo.HandshakeAttemptNo = 0;
                                    outMessageInfo.HandshakeAttemptNo
                                    <= _settings.HandshakeAttemptCount;
                                    outMessageInfo.HandshakeAttemptNo++
                                    )
                                {
                                    if (
                                        outMessageInfo.HandshakeAttemptNo
                                        == _settings.HandshakeAttemptCount
                                        )
                                    {
                                        throw new EnumException <SendReliableMessageExcs>(
                                                  SendReliableMessageExcs.HandshakeTimeout
                                                  );
                                    }
                                    await SendHandshakeStart(
                                        destination,
                                        messageId,
                                        replyToMessageId,
                                        (uint)data.Length,
                                        outMessageInfo.BlockSize,
                                        messageHash,
                                        outMessageInfo.Data[0],
                                        messageKind
                                        ).ConfigureAwait(false);

                                    var waitTasks = await Task.WhenAny(
                                        messageStatusTask,
                                        Task.Delay(
                                            TimeSpan.FromSeconds(
                                                _settings.HandshakeTimeoutSeconds
                                                ),
                                            compositeTokenSource.Token
                                            )
                                        ).ConfigureAwait(false);

                                    if (waitTasks == messageStatusTask)
                                    {
                                        var messageStatus = await messageStatusTask.ConfigureAwait(false);

                                        if (
                                            !(
                                                messageStatus.StatusCode ==
                                                MessageStatusArgs.MessageStatusCode.HandshakeOk
                                                ||
                                                (
                                                    messageStatus.StatusCode ==
                                                    MessageStatusArgs.MessageStatusCode.AllBlocksReceived &&
                                                    outMessageInfo.BlockCount == 1
                                                )
                                                )
                                            )
                                        {
                                            throw new EnumException <SendReliableMessageExcs>(
                                                      SendReliableMessageExcs.HandshakeError,
                                                      messageStatus.WriteObjectToJson()
                                                      );
                                        }
                                        break;
                                    }
                                }
                                outMessageInfo.Status            = OutMessageStatus.HandshakeOk;
                                outMessageInfo.BlockConfirmed[0] = true;
                                if (outMessageInfo.BlockCount > 1)
                                {
                                    // Handshake established, start sending blocks
                                    DateTime lastBlockConfirmationTime = DateTime.UtcNow;
                                    var      blocksInProgress          = new SortedSet <uint>();
                                    var      blocksInProgressLockSem   = new SemaphoreSlim(1);
                                    var      blockSentTimes            = new DateTime[blocksCount];
                                    using (
                                        BlockConfirmationReceived
                                        .Where(_ =>
                                               _.Destination == destination &&
                                               _.MessageId == messageId
                                               )
                                        .ObserveOn(TaskPoolScheduler.Default)
                                        .Subscribe(async x =>
                                    {
                                        if (
                                            x.BlockId < blocksCount &&
                                            !outMessageInfo.BlockConfirmed[x.BlockId]
                                            )
                                        {
                                            await outMessageInfo.ConfirmBlock(x.BlockId).ConfigureAwait(false);
                                            lastBlockConfirmationTime = DateTime.UtcNow;
                                            using (await blocksInProgressLockSem.GetDisposable().ConfigureAwait(false))
                                            {
                                                blocksInProgress.Remove(x.BlockId);
                                            }
                                        }
                                    }
                                                   )
                                        )
                                    {
                                        while (true)
                                        {
                                            compositeTokenSource.Token.ThrowIfCancellationRequested();
                                            IEnumerable <int> blocksToSend;
                                            using (
                                                await
                                                blocksInProgressLockSem.GetDisposable(token: compositeTokenSource.Token)
                                                .ConfigureAwait(false))
                                            {
                                                if (
                                                    blocksInProgress.Count == 0 &&
                                                    outMessageInfo.BlockConfirmed.All(x => x)
                                                    )
                                                {
                                                    break;
                                                }
                                                blocksInProgress.RemoveWhere(
                                                    i =>
                                                    DateTime.UtcNow >
                                                    (
                                                        blockSentTimes[i]
                                                        + TimeSpan.FromSeconds(
                                                            _settings
                                                            .ConfirmationOneBlockTimeoutSeconds
                                                            )
                                                    )
                                                    );
                                                blocksToSend = Enumerable.Range(0, (int)blocksCount)
                                                               .Where(
                                                    i =>
                                                    !blocksInProgress.Contains((uint)i) &&
                                                    !outMessageInfo.BlockConfirmed[i]
                                                    )
                                                               .Take(
                                                    Math.Max(
                                                        0,
                                                        _settings.WindowSize
                                                        - blocksInProgress.Count
                                                        )
                                                    );
                                            }
                                            foreach (int blockId in blocksToSend)
                                            {
                                                await SendBlock(
                                                    destination,
                                                    messageId,
                                                    (uint)blockId
                                                    ).ConfigureAwait(false);

                                                await outMessageInfo.SendBlock(
                                                    (uint)blockId
                                                    ).ConfigureAwait(false);

                                                using (
                                                    await
                                                    blocksInProgressLockSem.GetDisposable(token: compositeTokenSource.Token)
                                                    .ConfigureAwait(false))
                                                {
                                                    blocksInProgress.Add((uint)blockId);
                                                }
                                                blockSentTimes[blockId] = DateTime.UtcNow;
                                            }
                                            if (
                                                DateTime.UtcNow >
                                                lastBlockConfirmationTime +
                                                TimeSpan.FromSeconds(
                                                    _settings.ConfirmationTimeoutSeconds
                                                    )
                                                )
                                            {
                                                throw new EnumException <SendReliableMessageExcs>(
                                                          SendReliableMessageExcs.SendBlocksTimeout
                                                          );
                                            }
                                            await Task.Delay(50, compositeTokenSource.Token).ConfigureAwait(false);
                                        }
                                    }
                                }
                                outMessageInfo.Status = OutMessageStatus.AllBlocksSent;
                                // all blocks sent and confirmed
                                _log.Trace(
                                    "{4}, send reliable message of {0} bytes " +
                                    "to {1} id={2},rid={3},kind={5}",
                                    data.Length,
                                    destination.Substring(0, 20),
                                    messageId,
                                    replyToMessageId,
                                    _reliableSamHelperGuid.ToString().Substring(0, 5),
                                    messageKind
                                    );
                                return(messageId);
                            }
                            finally
                            {
                                compositeTokenSource.Cancel();
                            }
                        }
                    }
                    finally
                    {
                        TryRemoveOutMessageInfo(destinationInfo, messageId);
                    }
                }
                catch (EnumException <SendReliableMessageExcs> )
                {
                    throw;
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (TimeoutException)
                {
                    throw;
                }
                catch (Exception exc)
                {
                    throw new EnumException <SendReliableMessageExcs>(
                              SendReliableMessageExcs.UnexpectedError,
                              innerException: exc
                              );
                }
            }
        }
예제 #10
0
        private async void ProcessNewChangedArgs()
        {
            try
            {
                using (_stateHelper.GetFuncWrapper())
                {
                    var lockSemCalledWrapper = _lockSem.GetCalledWrapper();
                    lockSemCalledWrapper.Called = true;
                    using (await _lockSem.GetDisposable(true).ConfigureAwait(false))
                    {
                        while (!_cts.IsCancellationRequested && lockSemCalledWrapper.Called)
                        {
                            lockSemCalledWrapper.Called = false;
                            var currentChangesNumInDictToRemove =
                                _changedArgsDict.Keys.Where(_ => _ <= _prevChangesCounter).ToList();
                            foreach (long key in currentChangesNumInDictToRemove)
                            {
                                MyNotifyCollectionChangedArgs <TItem> removedArgs;
                                _changedArgsDict.TryRemove(key, out removedArgs);
                            }
                            MyNotifyCollectionChangedArgs <TItem> nextArgs;
                            if (
                                _changedArgsDict.TryRemove(
                                    _prevChangesCounter + 1,
                                    out nextArgs
                                    )
                                )
                            {
                                lockSemCalledWrapper.Called = true;
                                if (nextArgs.ChangedAction == EMyCollectionChangedAction.Reset)
                                {
                                    await ResetActionAsync().ConfigureAwait(false);
                                }
                                else if (nextArgs.ChangedAction == EMyCollectionChangedAction.NewItemsRangeInserted)
                                {
                                    var insertIndex = nextArgs.NewItemsIndices[0];
                                    var insertCount = nextArgs.NewItems.Count;
                                    if (insertCount > 0)
                                    {
                                        var insertArgs = new List <MutableTuple <int, TItem> >();
                                        for (int i = 0; i < insertCount; i++)
                                        {
                                            insertArgs.Add(
                                                MutableTuple.Create(
                                                    i + insertIndex,
                                                    nextArgs.NewItems[i]
                                                    )
                                                );
                                        }
                                        await _resultCollection.InsertRangeAtAsync(
                                            insertIndex,
                                            insertArgs
                                            ).ConfigureAwait(false);

                                        _originCollectionCopy.InsertRange(
                                            insertIndex,
                                            nextArgs.NewItems
                                            );
                                        /**/
                                        var currentResultCount = _originCollectionCopy.Count;
                                        var bulkUpdateArgs     = new List <Tuple <int, MutableTuple <int, TItem> > >();
                                        for (int i = insertIndex + insertCount; i < currentResultCount; i++)
                                        {
                                            bulkUpdateArgs.Add(
                                                Tuple.Create(
                                                    i,
                                                    MutableTuple.Create(
                                                        i,
                                                        _originCollectionCopy[i]
                                                        )
                                                    )
                                                );
                                        }
                                        if (bulkUpdateArgs.Any())
                                        {
                                            await _resultCollection.ReplaceBulkAsync(
                                                bulkUpdateArgs
                                                ).ConfigureAwait(false);
                                        }
                                    }
                                    _prevChangesCounter++;
                                }
                                else if (nextArgs.ChangedAction == EMyCollectionChangedAction.ItemsRangeRemoved)
                                {
                                    var removeIndex = nextArgs.OldItemsIndices[0];
                                    var removeCount = nextArgs.OldItems.Count;
                                    if (removeCount > 0)
                                    {
                                        await _resultCollection.RemoveRangeAsync(
                                            removeIndex,
                                            removeCount
                                            ).ConfigureAwait(false);

                                        _originCollectionCopy.RemoveRange(
                                            removeIndex,
                                            removeCount
                                            );
                                        /**/
                                        var currentResultCount = _originCollectionCopy.Count;
                                        var bulkUpdateArgs     = new List <Tuple <int, MutableTuple <int, TItem> > >();
                                        for (int i = removeIndex; i < currentResultCount; i++)
                                        {
                                            bulkUpdateArgs.Add(
                                                Tuple.Create(
                                                    i,
                                                    MutableTuple.Create(
                                                        i,
                                                        _originCollectionCopy[i]
                                                        )
                                                    )
                                                );
                                        }
                                        if (bulkUpdateArgs.Any())
                                        {
                                            await _resultCollection.ReplaceBulkAsync(
                                                bulkUpdateArgs
                                                ).ConfigureAwait(false);
                                        }
                                    }
                                    _prevChangesCounter++;
                                }
                                else if (nextArgs.ChangedAction == EMyCollectionChangedAction.ItemsChanged)
                                {
                                    var count          = nextArgs.NewItems.Count;
                                    var bulkUpdateArgs = new List <Tuple <int, MutableTuple <int, TItem> > >();
                                    for (int i = 0; i < count; i++)
                                    {
                                        _originCollectionCopy[nextArgs.NewItemsIndices[i]] = nextArgs.NewItems[i];
                                        bulkUpdateArgs.Add(
                                            Tuple.Create(
                                                nextArgs.NewItemsIndices[i],
                                                MutableTuple.Create(
                                                    nextArgs.NewItemsIndices[i],
                                                    nextArgs.NewItems[i]
                                                    )
                                                )
                                            );
                                    }
                                    if (bulkUpdateArgs.Any())
                                    {
                                        await _resultCollection.ReplaceBulkAsync(
                                            bulkUpdateArgs
                                            ).ConfigureAwait(false);
                                    }
                                    _prevChangesCounter++;
                                }
                                else
                                {
                                    throw new NotImplementedException();
                                }
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (WrongDisposableObjectStateException)
            {
            }
            catch (Exception exc)
            {
                MiscFuncs.HandleUnexpectedError(exc, _log);
            }
        }
예제 #11
0
        public async void TryToReconnect(DateTime callTime)
        {
            var curMethodName = this.MyNameOfMethod(e => e.TryToReconnect(DateTime.MinValue));

            try
            {
                using (_stateHelper.GetFuncWrapper())
                {
                    if (callTime < _lastHelperRenewedTime)
                    {
                        _log.Trace("{0} callTime < _lastHelperRenewedTime", curMethodName);
                        return;
                    }
                    using (await _tryToReconnectLockSem.GetDisposable(true).ConfigureAwait(false))
                    {
LBL_RETRY:
                        if (_cts.IsCancellationRequested)
                        {
                            return;
                        }
                        _log.Trace("{0} called", curMethodName);
                        var curImpl = _currentImplementationHelper;
                        if (curImpl != null)
                        {
                            _currentImplementationHelper = null;
                            await curImpl.MyDisposeAsync().ConfigureAwait(false);

                            foreach (var subscription in _currentImplSubscriptions)
                            {
                                subscription.Dispose();
                            }
                            _currentImplSubscriptions.Clear();
                        }
                        bool excThrown = false;
                        try
                        {
                            await InitImpl(_cts.Token).ConfigureAwait(false);
                        }
                        catch (OperationCanceledException)
                        {
                            throw;
                        }
                        catch (Exception exc)
                        {
                            _log.Error(
                                "{0} InitImpl err '{1}'",
                                curMethodName,
                                exc.Message
                                );
                            excThrown = true;
                        }
                        if (excThrown)
                        {
                            await Task.Delay(_settings.DelayOnConnectFailed, _cts.Token).ConfigureAwait(false);

                            goto LBL_RETRY;
                        }
                    }
                }
            }
            catch (WrongDisposableObjectStateException)
            {
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exc)
            {
                _log.Error(
                    "{0} unexpected error '{1}'",
                    curMethodName,
                    exc.ToString()
                    );
            }
        }