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); }
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) { 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); }
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); }