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)); } }
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)); } }
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); }
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); }
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); }
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;
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 Task SendAsync(DicomClientCancellation cancellation) { // Ignore, we will automatically send again if there are requests return(CompletedTaskProvider.CompletedTask); }
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); }