Exemplo n.º 1
0
 public async Task SendAsync(DicomClientCancellation cancellation)
 {
     if (Interlocked.CompareExchange(ref _sendCalled, 1, 0) != 0)
     {
         _dicomClient.Logger.Warn($"[{this}] Called SendAsync more than once, ignoring subsequent calls");
         return;
     }
     await _dicomClient.TransitionToConnectState(cancellation).ConfigureAwait(false);
 }
        private async Task <IDicomClientState> OnCancel(DicomClientCancellation cancellation)
        {
            switch (cancellation.Mode)
            {
            case DicomClientCancellationMode.ImmediatelyAbortAssociation:
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested, immediately aborting association");
                return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));

            case DicomClientCancellationMode.ImmediatelyReleaseAssociation:
            default:
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested, immediately releasing association");
                return(await _dicomClient.TransitionToReleaseAssociationState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }
        }
Exemplo n.º 3
0
        public async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            if (cancellation.Token.IsCancellationRequested)
            {
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested, won't connect");
                return(await _dicomClient.TransitionToIdleState(cancellation).ConfigureAwait(false));
            }

            _disposables.Add(cancellation.Token.Register(() => _cancellationRequestedTaskCompletionSource.SetResult(true)));

            var connect = Connect(cancellation);
            var cancel  = _cancellationRequestedTaskCompletionSource.Task;

            var winner = await Task.WhenAny(connect, cancel).ConfigureAwait(false);

            if (winner == connect)
            {
                IDicomClientConnection connection = null;
                try
                {
                    connection = await connect.ConfigureAwait(false);

                    return(await _dicomClient.TransitionToRequestAssociationState(connection, cancellation).ConfigureAwait(false));
                }
                catch (Exception e)
                {
                    return(await _dicomClient.TransitionToCompletedWithErrorState(connection, e, cancellation).ConfigureAwait(false));
                }
            }

            if (winner != cancel)
            {
                throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
            }

            // Cancellation or abort was triggered but wait for the connection anyway, because we need to dispose of it properly
            try
            {
                var connection = await connect.ConfigureAwait(false);

                return(await _dicomClient.TransitionToCompletedState(connection, cancellation).ConfigureAwait(false));
            }
            catch (Exception e)
            {
                return(await _dicomClient.TransitionToCompletedWithErrorState((IDicomClientConnection)null, e, cancellation).ConfigureAwait(false));
            }
        }
Exemplo n.º 4
0
        public async Task SendAsync(DicomClientCancellation cancellation)
        {
            if (!(_initialisationParameters is DicomClientCompletedWithErrorInitialisationParameters))
            {
                _dicomClient.Logger.Warn($"[{this}] Called SendAsync during COMPLETED (without errors) state but this is unnecessary, the DicomClient will automatically" +
                                         "transition back to IDLE in a moment");
                return;
            }

            if (Interlocked.CompareExchange(ref _sendCalled, 1, 0) != 0)
            {
                _dicomClient.Logger.Warn($"[{this}] Called SendAsync more than once, ignoring subsequent calls");
                return;
            }

            await _dicomClient.TransitionToIdleState(cancellation).ConfigureAwait(false);
        }
Exemplo n.º 5
0
        public async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            if (!cancellation.Token.IsCancellationRequested &&
                _dicomClient.QueuedRequests.TryPeek(out StrongBox <DicomRequest> _) &&
                Interlocked.CompareExchange(ref _sendCalled, 1, 0) == 0)
            {
                _dicomClient.Logger.Debug($"[{this}] More requests to send (and no cancellation requested yet), automatically opening new association");
                return(await _dicomClient.TransitionToConnectState(cancellation).ConfigureAwait(false));
            }

            if (cancellation.Token.IsCancellationRequested)
            {
                _dicomClient.Logger.Debug($"[{this}] Cancellation requested, staying idle");
                return(this);
            }

            _dicomClient.Logger.Debug($"[{this}] No requests to send, staying idle");
            return(this);
        }
Exemplo n.º 6
0
        public override async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            var sendAbort      = _initialisationParameters.Connection.SendAbortAsync(DicomAbortSource.ServiceUser, DicomAbortReason.NotSpecified);
            var onReceiveAbort = _onAbortReceivedTaskCompletionSource.Task;
            var onDisconnect   = _onConnectionClosedTaskCompletionSource.Task;
            var onTimeout      = Task.Delay(100, _associationAbortTimeoutCancellationTokenSource.Token);

            var winner = await Task.WhenAny(sendAbort, onReceiveAbort, onDisconnect, onTimeout).ConfigureAwait(false);

            if (winner == sendAbort)
            {
                _dicomClient.Logger.Debug($"[{this}] Abort notification sent to server. Disconnecting...");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }
            if (winner == onReceiveAbort)
            {
                _dicomClient.Logger.Debug($"[{this}] Received abort while aborting. Neat.");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onDisconnect)
            {
                _dicomClient.Logger.Debug($"[{this}] Disconnected while aborting. Perfect.");
                var connectionClosedEvent = await onDisconnect.ConfigureAwait(false);

                if (connectionClosedEvent.Exception == null)
                {
                    return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }
                else
                {
                    return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, connectionClosedEvent.Exception, cancellation));
                }
            }

            if (winner == onTimeout)
            {
                _dicomClient.Logger.Debug($"[{this}] Abort notification timed out. Disconnecting...");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
        }
Exemplo n.º 7
0
        public async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            switch (_initialisationParameters)
            {
            case DicomClientCompletedWithoutErrorInitialisationParameters parameters:
            {
                _dicomClient.Logger.Debug($"[{this}] DICOM client completed without errors");

                if (parameters.Connection != null)
                {
                    _dicomClient.Logger.Debug($"[{this}] Cleaning up");
                    await Cleanup(parameters.Connection).ConfigureAwait(false);
                }

                return(await _dicomClient.TransitionToIdleState(cancellation).ConfigureAwait(false));
            }

            case DicomClientCompletedWithErrorInitialisationParameters parameters:
            {
                _dicomClient.Logger.Debug($"[{this}] DICOM client completed with an error");

                if (parameters.Connection != null)
                {
                    _dicomClient.Logger.Debug($"[{this}] An error occurred while we had an active connection, cleaning that up first");
                    await Cleanup(parameters.Connection).ConfigureAwait(false);
                }
                else
                {
                    _dicomClient.Logger.Warn($"[{this}] An error occurred and no active connection was detected, so no cleanup will happen!");
                }

                throw parameters.ExceptionToThrow;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(_initialisationParameters), "Unknown initialisation parameters");
            }
        }
 public abstract Task SendAsync(DicomClientCancellation cancellation);
 public abstract Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation);
 public override Task SendAsync(DicomClientCancellation cancellation)
 {
     // Ignore, we're already sending
     return(CompletedTaskProvider.CompletedTask);
 }
        public override async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            if (cancellation.Token.IsCancellationRequested)
            {
                switch (cancellation.Mode)
                {
                case DicomClientCancellationMode.ImmediatelyReleaseAssociation:
                    _dicomClient.Logger.Warn($"[{this}] Cancellation is requested before requests could be sent, releasing association ...");
                    return(await _dicomClient.TransitionToReleaseAssociationState(_initialisationParameters, cancellation).ConfigureAwait(false));

                case DicomClientCancellationMode.ImmediatelyAbortAssociation:
                    _dicomClient.Logger.Warn($"[{this}] Cancellation is requested before requests could be sent, aborting association ...");
                    return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));

                default:
                    throw new ArgumentOutOfRangeException(nameof(cancellation.Mode), cancellation.Mode, "Unknown cancellation mode");
                }
            }

            _disposables.Add(cancellation.Token.Register(() => _sendRequestsCancellationTokenSource.Cancel()));
            _disposables.Add(cancellation.Token.Register(() => _onCancellationTaskCompletionSource.TrySetResultAsynchronously(true)));

            _dicomClient.Logger.Debug($"[{this}] Sending DICOM requests");

            await SendInitialRequests().ConfigureAwait(false);

            var allRequestsHaveCompleted = KeepSendingUntilAllRequestsHaveCompletedAsync();
            var onReceiveAbort           = _onAbortReceivedTaskCompletionSource.Task;
            var onDisconnect             = _onConnectionClosedTaskCompletionSource.Task;
            var onCancellation           = _onCancellationTaskCompletionSource.Task;

            var winner = await Task.WhenAny(
                allRequestsHaveCompleted,
                onReceiveAbort,
                onDisconnect,
                onCancellation
                )
                         .ConfigureAwait(false);

            if (winner == allRequestsHaveCompleted)
            {
                if (_numberOfSentRequests < _maximumNumberOfRequestsPerAssociation)
                {
                    _dicomClient.Logger.Debug($"[{this}] All requests are done, going to linger association now...");
                    return(await _dicomClient.TransitionToLingerState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }

                _dicomClient.Logger.Debug($"[{this}] The maximum number of requests per association ({_maximumNumberOfRequestsPerAssociation}) have been sent, immediately releasing association now...");
                return(await _dicomClient.TransitionToReleaseAssociationState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onCancellation)
            {
                switch (cancellation.Mode)
                {
                case DicomClientCancellationMode.ImmediatelyReleaseAssociation:
                    _dicomClient.Logger.Warn($"[{this}] Cancellation requested, releasing association...");
                    return(await _dicomClient.TransitionToReleaseAssociationState(_initialisationParameters, cancellation).ConfigureAwait(false));

                case DicomClientCancellationMode.ImmediatelyAbortAssociation:
                    _dicomClient.Logger.Warn($"[{this}] Cancellation requested, aborting association...");
                    return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));

                default:
                    throw new ArgumentOutOfRangeException(nameof(cancellation.Mode), cancellation.Mode, "Unknown cancellation mode");
                }
            }

            if (winner == onReceiveAbort)
            {
                _dicomClient.Logger.Warn($"[{this}] Association is aborted while sending requests, cleaning up...");
                var abortReceivedResult = onReceiveAbort.Result;
                var exception           = new DicomAssociationAbortedException(abortReceivedResult.Source, abortReceivedResult.Reason);
                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, exception, cancellation).ConfigureAwait(false));
            }

            if (winner == onDisconnect)
            {
                _dicomClient.Logger.Debug($"[{this}] Disconnected while sending requests, cleaning up...");
                var connectionClosedEvent = await onDisconnect.ConfigureAwait(false);

                if (connectionClosedEvent.Exception == null)
                {
                    return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }
                else
                {
                    return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, connectionClosedEvent.Exception, cancellation).ConfigureAwait(false));
                }
            }

            throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
        }
 // Ignore, we're already sending
 public override Task SendAsync(DicomClientCancellation cancellation) => Task.CompletedTask;
Exemplo n.º 13
0
        public override async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            if (cancellation.Token.IsCancellationRequested)
            {
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested before association request was made, going to disconnect now");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            await SendAssociationRequest().ConfigureAwait(false);

            _disposables.Add(cancellation.Token.Register(() => _onCancellationRequestedTaskCompletionSource.TrySetResultAsynchronously(true)));

            var associationIsAccepted      = _onAssociationAcceptedTaskCompletionSource.Task;
            var associationIsRejected      = _onAssociationRejectedTaskCompletionSource.Task;
            var abortReceived              = _onAbortReceivedTaskCompletionSource.Task;
            var onDisconnect               = _onConnectionClosedTaskCompletionSource.Task;
            var associationRequestTimesOut = Task.Delay(_dicomClient.AssociationRequestTimeoutInMs, _associationRequestTimeoutCancellationTokenSource.Token);
            var onCancellationRequested    = _onCancellationRequestedTaskCompletionSource.Task;

            var winner = await Task.WhenAny(
                associationIsAccepted,
                associationIsRejected,
                abortReceived,
                onDisconnect,
                associationRequestTimesOut,
                onCancellationRequested
                ).ConfigureAwait(false);

            if (winner == associationIsAccepted)
            {
                _dicomClient.Logger.Debug($"[{this}] Association is accepted");
                var association = associationIsAccepted.Result.Association;
                _dicomClient.NotifyAssociationAccepted(new EventArguments.AssociationAcceptedEventArgs(association));
                return(await _dicomClient.TransitionToSendingRequestsState(_initialisationParameters, association, cancellation).ConfigureAwait(false));
            }

            if (winner == associationIsRejected)
            {
                var associationRejectedResult = associationIsRejected.Result;

                _dicomClient.Logger.Warn($"[{this}] Association is rejected");
                var result = associationRejectedResult.Result;
                var source = associationRejectedResult.Source;
                var reason = associationRejectedResult.Reason;
                _dicomClient.NotifyAssociationRejected(new EventArguments.AssociationRejectedEventArgs(result, source, reason));
                var exception = new DicomAssociationRejectedException(result, source, reason);
                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, exception, cancellation).ConfigureAwait(false));
            }

            if (winner == abortReceived)
            {
                _dicomClient.Logger.Warn($"[{this}] Association is aborted");
                var abortReceivedResult = abortReceived.Result;
                var exception           = new DicomAssociationAbortedException(abortReceivedResult.Source, abortReceivedResult.Reason);
                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, exception, cancellation).ConfigureAwait(false));
            }

            if (winner == onDisconnect)
            {
                _dicomClient.Logger.Warn($"[{this}] Disconnected");
                var connectionClosedEvent = await onDisconnect.ConfigureAwait(false);

                if (connectionClosedEvent.Exception == null)
                {
                    return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }
                else
                {
                    return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, connectionClosedEvent.Exception, cancellation));
                }
            }

            if (winner == associationRequestTimesOut)
            {
                _dicomClient.Logger.Warn($"[{this}] Association request timeout");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onCancellationRequested)
            {
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested while requesting association, aborting now...");
                return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
        }
Exemplo n.º 14
0
 public override Task SendAsync(DicomClientCancellation cancellation)
 {
     // Ignore, we will automatically send again if there are requests
     return(CompletedTaskProvider.CompletedTask);
 }
Exemplo n.º 15
0
        public override async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            if (cancellation.Token.IsCancellationRequested)
            {
                return(await OnCancel(cancellation).ConfigureAwait(false));
            }

            if (_dicomClient.QueuedRequests.Any())
            {
                _dicomClient.Logger.Debug($"[{this}] DICOM client already has requests again, immediately moving back to sending requests");
                return(await _dicomClient.TransitionToSendingRequestsState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            _disposables.Add(cancellation.Token.Register(() => _onCancellationRequestedTaskCompletionSource.TrySetResultAsynchronously(true)));

            var onRequestIsAdded = _onRequestAddedTaskCompletionSource.Task;
            var onReceiveAbort   = _onAbortReceivedTaskCompletionSource.Task;
            var onDisconnect     = _onConnectionClosedTaskCompletionSource.Task;
            var onLingerTimeout  = Task.Delay(_dicomClient.AssociationLingerTimeoutInMs, _lingerTimeoutCancellationTokenSource.Token);
            var onCancel         = _onCancellationRequestedTaskCompletionSource.Task;

            var winner = await Task.WhenAny(onRequestIsAdded, onReceiveAbort, onDisconnect, onLingerTimeout, onCancel)
                         .ConfigureAwait(false);

            if (winner == onRequestIsAdded)
            {
                _dicomClient.Logger.Debug($"[{this}] A new request was added before linger timeout of {_dicomClient.AssociationLingerTimeoutInMs}ms, reusing association");
                return(await _dicomClient.TransitionToSendingRequestsState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onLingerTimeout)
            {
                _dicomClient.Logger.Debug($"[{this}] Linger timed out after {_dicomClient.AssociationLingerTimeoutInMs}ms, releasing association");
                return(await _dicomClient.TransitionToReleaseAssociationState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onReceiveAbort)
            {
                _dicomClient.Logger.Warn($"[{this}] Association was aborted while lingering the association");
                var abortReceivedResult = onReceiveAbort.Result;
                var exception           = new DicomAssociationAbortedException(abortReceivedResult.Source, abortReceivedResult.Reason);
                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, exception, cancellation).ConfigureAwait(false));
            }

            if (winner == onDisconnect)
            {
                _dicomClient.Logger.Warn($"[{this}] Disconnected while lingering the association");
                var connectionClosedEvent = await onDisconnect.ConfigureAwait(false);

                if (connectionClosedEvent.Exception == null)
                {
                    return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }

                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, connectionClosedEvent.Exception, cancellation).ConfigureAwait(false));
            }

            if (winner == onCancel)
            {
                return(await OnCancel(cancellation).ConfigureAwait(false));
            }

            throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
        }
        public override async Task <IDicomClientState> GetNextStateAsync(DicomClientCancellation cancellation)
        {
            // We can mostly ignore the cancellation token in this state, unless the cancellation mode is set to "Immediately abort"
            if (cancellation.Token.IsCancellationRequested && cancellation.Mode == DicomClientCancellationMode.ImmediatelyAbortAssociation)
            {
                return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            await _initialisationParameters.Connection.SendAssociationReleaseRequestAsync().ConfigureAwait(false);

            if (cancellation.Mode == DicomClientCancellationMode.ImmediatelyAbortAssociation)
            {
                _disposables.Add(cancellation.Token.Register(() => _onAbortRequestedTaskCompletionSource.TrySetResult(true)));
            }

            var onAssociationRelease        = _onAssociationReleasedTaskCompletionSource.Task;
            var onAssociationReleaseTimeout = Task.Delay(_dicomClient.ClientOptions.AssociationReleaseTimeoutInMs, _associationReleaseTimeoutCancellationTokenSource.Token);
            var onReceiveAbort = _onAbortReceivedTaskCompletionSource.Task;
            var onDisconnect   = _onConnectionClosedTaskCompletionSource.Task;
            var onAbort        = _onAbortRequestedTaskCompletionSource.Task;

            var winner = await Task.WhenAny(
                onAssociationRelease,
                onAssociationReleaseTimeout,
                onReceiveAbort,
                onDisconnect,
                onAbort)
                         .ConfigureAwait(false);

            if (winner == onAssociationRelease)
            {
                _dicomClient.NotifyAssociationReleased();

                _dicomClient.Logger.Debug($"[{this}] Association release response received, disconnecting...");
                return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onAssociationReleaseTimeout)
            {
                _dicomClient.Logger.Debug($"[{this}] Association release timed out, aborting...");
                return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            if (winner == onReceiveAbort)
            {
                _dicomClient.Logger.Debug($"[{this}] Association aborted, disconnecting...");
                var abortReceivedResult = onReceiveAbort.Result;
                var exception           = new DicomAssociationAbortedException(abortReceivedResult.Source, abortReceivedResult.Reason);
                return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, exception, cancellation).ConfigureAwait(false));
            }

            if (winner == onDisconnect)
            {
                _dicomClient.Logger.Debug($"[{this}] Disconnected during association release, cleaning up...");

                /*
                 * Sometimes, the server is very swift at closing the connection, before we get a chance to process the Association Release response
                 */
                _dicomClient.NotifyAssociationReleased();

                var connectionClosedEvent = await onDisconnect.ConfigureAwait(false);

                if (connectionClosedEvent.Exception == null)
                {
                    return(await _dicomClient.TransitionToCompletedState(_initialisationParameters, cancellation).ConfigureAwait(false));
                }
                else
                {
                    return(await _dicomClient.TransitionToCompletedWithErrorState(_initialisationParameters, connectionClosedEvent.Exception, cancellation).ConfigureAwait(false));
                }
            }

            if (winner == onAbort)
            {
                _dicomClient.Logger.Warn($"[{this}] Cancellation requested during association release, immediately aborting association");
                return(await _dicomClient.TransitionToAbortState(_initialisationParameters, cancellation).ConfigureAwait(false));
            }

            throw new DicomNetworkException("Unknown winner of Task.WhenAny in DICOM client, this is likely a bug: " + winner);
        }