Ejemplo n.º 1
0
        public void cant_abort_without_transaction_identifier()
        {
            var frame  = new BasicFrame("ABORT");
            var client = Substitute.For <IStompClient>();

            var    sut    = new AbortHandler();
            Action actual = () => sut.Process(client, frame);

            actual.ShouldThrow <BadRequestException>();
        }
        private async void WebSocketOnClosed()
        {
            connection.Trace(TraceLevels.Events, "WS: OnClose()");

            if (disconnectToken.IsCancellationRequested || AbortHandler.TryCompleteAbort())
            {
                return;
            }

            await DoReconnect().ConfigureAwait(false);
        }
Ejemplo n.º 3
0
        // virtual for testing
        internal virtual void OnClose()
        {
            _connection.Trace(TraceLevels.Events, "WS: OnClose()");

            // Make sure to try to fail start even if an abort has started.
            var startFailed = TryFailStart(new IOException(Resources.Error_TransportDisconnectedBeforeConnectionFullyInitialized));

            if (!AbortHandler.TryCompleteAbort() && !_disconnectToken.IsCancellationRequested && !startFailed)
            {
                DoReconnect();
            }
        }
Ejemplo n.º 4
0
        public void abort_if_transaction_was_specified()
        {
            var frame = new BasicFrame("ABORT");

            frame.Headers["transaction"] = "aa";
            var client = Substitute.For <IStompClient>();

            var sut = new AbortHandler();

            sut.Process(client, frame);

            client.Received().RollbackTransaction("aa");
        }
        private void WebsocketClosed(IWebSocket webSocket, WebSocketClosedEventArgs eventArgs)
        {
            _connection.Trace(TraceLevels.Events, "WS: WebsocketClosed - Code: {0}, Reason {1}", eventArgs.Code, eventArgs.Reason);

            DisposeSocket();

            if (AbortHandler.TryCompleteAbort() || _disconnectToken.IsCancellationRequested)
            {
                return;
            }

            Task.Run(() => Reconnect(_connection, _connectionData));
        }
        // virtual for testing
        internal virtual void OnClose()
        {
            _connection.Trace(TraceLevels.Events, "WS: OnClose()");

            if (_disconnectToken.IsCancellationRequested)
            {
                return;
            }

            if (AbortHandler.TryCompleteAbort())
            {
                return;
            }

            DoReconnect();
        }
        private Task OnAfterPoll(Exception exception)
        {
            if (AbortHandler.TryCompleteAbort())
            {
                // Abort() was called, so don't reconnect
                StopPolling();
            }
            else
            {
                _reconnectInvoker = new ThreadSafeInvoker();

                if (exception != null)
                {
                    // Delay polling by the error delay
                    return(TaskAsyncHelper.Delay(ErrorDelay));
                }
            }

            return(TaskAsyncHelper.Empty);
        }
        /// <summary>
        /// Fully stops the polling loop.
        /// </summary>
        private void StopPolling()
        {
            lock (_stopLock)
            {
                if (Interlocked.Exchange(ref _running, 0) == 1)
                {
                    _disconnectRegistration.Dispose();

                    // Complete any ongoing calls to Abort()
                    // If someone calls Abort() later, have it no-op
                    AbortHandler.CompleteAbort();

                    if (_currentRequest != null)
                    {
                        // This will no-op if the request is already finished
                        _currentRequest.Abort();
                    }
                }
            }
        }
Ejemplo n.º 9
0
        private void PollingSetup(IConnection connection,
                                  string data,
                                  CancellationToken disconnectToken,
                                  PollingRequestHandler requestHandler,
                                  Action onInitialized)
        {
            // reconnectInvoker is created new on each poll
            var reconnectInvoker = new ThreadSafeInvoker();

            var disconnectRegistration = disconnectToken.SafeRegister(state =>
            {
                reconnectInvoker.Invoke();
                requestHandler.Stop();
            }, null);

            requestHandler.ResolveUrl = () =>
            {
                var url = connection.Url;

                if (connection.MessageId == null)
                {
                    url += "connect";
                    connection.Trace(TraceLevels.Events, "LP Connect: {0}", url);
                }
                else if (IsReconnecting(connection))
                {
                    url += "reconnect";
                    connection.Trace(TraceLevels.Events, "LP Reconnect: {0}", url);
                }
                else
                {
                    url += "poll";
                    connection.Trace(TraceLevels.Events, "LP Poll: {0}", url);
                }

                url += GetReceiveQueryString(connection, data);

                return(url);
            };

            requestHandler.PrepareRequest += req =>
            {
                connection.PrepareRequest(req);
            };

            requestHandler.OnMessage += message =>
            {
                var shouldReconnect      = false;
                var disconnectedReceived = false;

                connection.Trace(TraceLevels.Messages, "LP: OnMessage({0})", message);

                TransportHelper.ProcessResponse(connection,
                                                message,
                                                out shouldReconnect,
                                                out disconnectedReceived,
                                                onInitialized);

                if (IsReconnecting(connection))
                {
                    // If the timeout for the reconnect hasn't fired as yet just fire the
                    // event here before any incoming messages are processed
                    TryReconnect(connection, reconnectInvoker);
                }

                if (shouldReconnect)
                {
                    // Transition into reconnecting state
                    connection.EnsureReconnecting();
                }

                if (disconnectedReceived)
                {
                    connection.Trace(TraceLevels.Messages, "Disconnect command received from server.");
                    connection.Disconnect();
                }
            };

            requestHandler.OnError += exception =>
            {
                reconnectInvoker.Invoke();

                if (!TransportHelper.VerifyLastActive(connection))
                {
                    return;
                }

                // Transition into reconnecting state
                connection.EnsureReconnecting();

                // Sometimes a connection might have been closed by the server before we get to write anything
                // so just try again and raise OnError.
                if (!ExceptionHelper.IsRequestAborted(exception) && !(exception is IOException))
                {
                    connection.OnError(exception);
                }
                else
                {
                    requestHandler.Stop();
                }
            };

            requestHandler.OnPolling += () =>
            {
                // Capture the cleanup within a closure so it can persist through multiple requests
                TryDelayedReconnect(connection, reconnectInvoker);
            };

            requestHandler.OnAfterPoll = exception =>
            {
                if (AbortHandler.TryCompleteAbort())
                {
                    // Abort() was called, so don't reconnect
                    requestHandler.Stop();
                }
                else
                {
                    reconnectInvoker = new ThreadSafeInvoker();

                    if (exception != null)
                    {
                        // Delay polling by the error delay
                        return(TaskAsyncHelper.Delay(ErrorDelay));
                    }
                }

                return(TaskAsyncHelper.Empty);
            };

            requestHandler.OnAbort += _ =>
            {
                disconnectRegistration.Dispose();

                // Complete any ongoing calls to Abort()
                // If someone calls Abort() later, have it no-op
                AbortHandler.CompleteAbort();
            };
        }
Ejemplo n.º 10
0
 public virtual void Abort(IConnection connection, TimeSpan timeout, string connectionData)
 {
     _finished = true;
     AbortHandler.Abort(connection, timeout, connectionData);
 }
Ejemplo n.º 11
0
        private void OpenConnection(IConnection connection,
                                    string data,
                                    CancellationToken disconnectToken,
                                    Action initializeCallback,
                                    Action <Exception> errorCallback)
        {
            // If we're reconnecting add /connect to the url
            bool   reconnecting     = initializeCallback == null;
            var    callbackInvoker  = new ThreadSafeInvoker();
            var    requestDisposer  = new Disposer();
            Action initializeInvoke = () =>
            {
                callbackInvoker.Invoke(initializeCallback);
            };
            var url = connection.Url + (reconnecting ? "reconnect" : "connect") + GetReceiveQueryString(connection, data);

            connection.Trace(TraceLevels.Events, "SSE: GET {0}", url);

            HttpClient.Get(url, req =>
            {
                _request        = req;
                _request.Accept = "text/event-stream";

                connection.PrepareRequest(_request);
            }, isLongRunning: true).ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    Exception exception;

                    if (task.IsCanceled)
                    {
                        exception = new OperationCanceledException(Resources.Error_TaskCancelledException);
                    }
                    else
                    {
                        exception = task.Exception.Unwrap();
                    }

                    if (errorCallback != null)
                    {
                        callbackInvoker.Invoke((cb, ex) => cb(ex), errorCallback, exception);
                    }
                    else if (!_stop && reconnecting)
                    {
                        // Only raise the error event if we failed to reconnect
                        connection.OnError(exception);

                        Reconnect(connection, data, disconnectToken);
                    }
                    requestDisposer.Dispose();
                }
                else
                {
                    // If the disconnect token is canceled the response to the task doesn't matter.
                    if (disconnectToken.IsCancellationRequested)
                    {
                        return;
                    }

                    var response  = task.Result;
                    Stream stream = response.GetStream();

                    var eventSource = new EventSourceStreamReader(connection, stream);

                    var esCancellationRegistration = disconnectToken.SafeRegister(state =>
                    {
                        _stop = true;

                        ((IRequest)state).Abort();
                    },
                                                                                  _request);

                    eventSource.Opened = () =>
                    {
                        // This will noop if we're not in the reconnecting state
                        if (connection.ChangeState(ConnectionState.Reconnecting, ConnectionState.Connected))
                        {
                            // Raise the reconnect event if the connection comes back up
                            connection.OnReconnected();
                        }
                    };

                    eventSource.Message = sseEvent =>
                    {
                        if (sseEvent.EventType == EventType.Data)
                        {
                            if (sseEvent.Data.Equals("initialized", StringComparison.OrdinalIgnoreCase))
                            {
                                return;
                            }

                            bool shouldReconnect;
                            bool disconnected;
                            TransportHelper.ProcessResponse(connection, sseEvent.Data, out shouldReconnect, out disconnected, initializeInvoke);

                            if (disconnected)
                            {
                                _stop = true;
                                connection.Disconnect();
                            }
                        }
                    };

                    eventSource.Closed = exception =>
                    {
                        if (exception != null)
                        {
                            // Check if the request is aborted
                            bool isRequestAborted = ExceptionHelper.IsRequestAborted(exception);

                            if (!isRequestAborted)
                            {
                                // Don't raise exceptions if the request was aborted (connection was stopped).
                                connection.OnError(exception);
                            }
                        }

                        requestDisposer.Dispose();
                        esCancellationRegistration.Dispose();
                        response.Dispose();

                        if (_stop)
                        {
                            AbortHandler.CompleteAbort();
                        }
                        else if (AbortHandler.TryCompleteAbort())
                        {
                            // Abort() was called, so don't reconnect
                        }
                        else
                        {
                            Reconnect(connection, data, disconnectToken);
                        }
                    };

                    eventSource.Start();
                }
            });

            var requestCancellationRegistration = disconnectToken.SafeRegister(state =>
            {
                if (state != null)
                {
                    // This will no-op if the request is already finished.
                    ((IRequest)state).Abort();
                }

                if (errorCallback != null)
                {
                    callbackInvoker.Invoke((cb, token) =>
                    {
#if !NET35
                        cb(new OperationCanceledException(Resources.Error_ConnectionCancelled, token));
#else
                        cb(new OperationCanceledException(Resources.Error_ConnectionCancelled));
#endif
                    }, errorCallback, disconnectToken);
                }
            }, _request);

            requestDisposer.Set(requestCancellationRegistration);
        }
Ejemplo n.º 12
0
        internal void OpenConnection(IConnection connection, string data, CancellationToken disconnectToken, bool reconnecting)
        {
            // If we're reconnecting add /connect to the url
            var url = reconnecting
                ? UrlBuilder.BuildReconnect(connection, Name, data)
                : UrlBuilder.BuildConnect(connection, Name, data);

            connection.Trace(TraceLevels.Events, "SSE: GET {0}", url);

            var getTask = HttpClient.Get(url, req =>
            {
                _request        = req;
                _request.Accept = "text/event-stream";

                connection.PrepareRequest(_request);
            }, isLongRunning: true);

            var requestCancellationRegistration = disconnectToken.SafeRegister(state =>
            {
                _stop = true;

                // This will no-op if the request is already finished.
                ((IRequest)state).Abort();
            }, _request);

            getTask.ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    var exception = task.IsCanceled
                        ? new OperationCanceledException(Resources.Error_TaskCancelledException)
                        : task.Exception.Unwrap();

                    if (!reconnecting)
                    {
                        // It shouldn't be possible for Start to have already succeeded at this point.
                        TryFailStart(exception);
                    }
                    else if (!_stop)
                    {
                        // Only raise the error event if the error wasn't raised from Start and we're reconnecting.
                        connection.OnError(exception);

                        Reconnect(connection, data, disconnectToken);
                    }

                    requestCancellationRegistration.Dispose();
                }
                else
                {
                    // If the disconnect token is canceled the response to the task doesn't matter.
                    if (disconnectToken.IsCancellationRequested)
                    {
                        return;
                    }

                    var response  = task.Result;
                    Stream stream = response.GetStream();

                    var eventSource = new EventSourceStreamReader(connection, stream);

                    eventSource.Opened = () =>
                    {
                        // This will noop if we're not in the reconnecting state
                        if (connection.ChangeState(ConnectionState.Reconnecting, ConnectionState.Connected))
                        {
                            // Raise the reconnect event if the connection comes back up
                            connection.OnReconnected();
                        }
                    };

                    eventSource.Message = sseEvent =>
                    {
                        if (sseEvent.EventType == EventType.Data &&
                            !sseEvent.Data.Equals("initialized", StringComparison.OrdinalIgnoreCase))
                        {
                            ProcessResponse(connection, sseEvent.Data);
                        }
                    };

                    eventSource.Closed = exception =>
                    {
                        // Make sure to try to fail start even if the disconnectToken tripped and set _stop to true.
                        var startFailed = TryFailStart(exception);

                        if (exception != null && !startFailed)
                        {
                            // Check if the request is aborted
                            if (!ExceptionHelper.IsRequestAborted(exception))
                            {
                                // Don't raise exceptions if the request was aborted (connection was stopped).
                                connection.OnError(exception);
                            }
                        }

                        requestCancellationRegistration.Dispose();
                        response.Dispose();

                        if (_stop)
                        {
                            AbortHandler.CompleteAbort();
                        }
                        else if (!AbortHandler.TryCompleteAbort() && !startFailed)
                        {
                            // If Abort() was called or Start() failed, don't reconnect.
                            Reconnect(connection, data, disconnectToken);
                        }
                    };

                    eventSource.Start();
                }
            });
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Executes the module on the given graph using the provided context.
        /// </summary>
        /// <remarks>
        /// The layout will be calculated <see cref="RunInBackground">optionally</see>
        /// in a separate thread in method <see cref="RunModuleAsync"/>.
        /// </remarks>
        /// <param name="graph">The graph to execute on.</param>
        /// <param name="newContext">The context to use. This method will query a <c>ISelectionModel&lt;IModelItem></c></param>
        /// for the selected nodes and edges and the <c>GraphControl</c> to morph the layout.
        protected virtual async Task StartWithIGraph(IGraph graph, ILookup newContext)
        {
            this.graph = graph;
            if (ShouldConfigureTableLayout())
            {
                PrepareTableLayout();
            }
            ISelectionModel <IModelItem> selectionModel = newContext.Lookup <ISelectionModel <IModelItem> >();
            LayoutGraphAdapter           adapter        = new LayoutGraphAdapter(graph, selectionModel);

            this.layoutGraph = adapter.CreateCopiedLayoutGraph();
            ILookup additionalLookup = Lookups.Single(layoutGraph, typeof(LayoutGraph));
            ILookup wrappedLookup    = Lookups.Wrapped(newContext, additionalLookup);

            try {
                ICompoundEdit compoundEdit = graph.BeginEdit("Layout", "Layout");
                CheckReentrant(wrappedLookup);
                ConfigureModule();

                if (RunInBackground)
                {
                    // without the LayoutExecutor helper class on the layout graph side of things, we register the aborthandler
                    // to the layout graph with the utility method provided by AbortHandler
                    var abortHandler = AbortHandler.CreateForGraph(layoutGraph);
                    // now create the dialog that controls the abort handler
                    abortDialog = new AbortDialog {
                        AbortHandler = abortHandler, Owner = Application.Current.MainWindow
                    };
                    // start the layout in another thread.
                    var layoutThread = new Thread(async() => await RunModuleAsync(wrappedLookup, graph, compoundEdit));

                    // now if we are not doing a quick layout - and if it takes more than a few seconds, we open the dialog to
                    // enable the user to stop or cancel the execution
                    var showDialogTimer = new DispatcherTimer(DispatcherPriority.Normal, abortDialog.Dispatcher)
                    {
                        Interval = TimeSpan.FromSeconds(2)
                    };

                    showDialogTimer.Tick += delegate {
                        // it could be that the layout is already done - so check whether we still
                        // need to open the dialog
                        var dialogInstance = abortDialog;
                        if (dialogInstance != null)
                        {
                            // open the abort dialog
                            dialogInstance.Show();
                        }
                        // we only want to let it go off once - so stop the timer
                        showDialogTimer.Stop();
                    };

                    // kick-off the timer and the layout
                    showDialogTimer.Start();
                    layoutThread.Start();
                }
                else
                {
                    await RunModuleAsync(wrappedLookup, graph, compoundEdit);
                }
            } catch (Exception e) {
                FreeReentrant();
                TableLayoutConfigurator.CleanUp(graph);
                OnDone(new LayoutEventArgs(e));
                //optionally do something here...
            }
        }
        private void RunMultipageLayout()
        {
            // parse the pageWidth and pageHeight parameters
            double pageWidth;
            double pageHeight;

            if (!Double.TryParse(pageWidthTextBox.Text, out pageWidth))
            {
                pageWidth = 800;
            }
            if (!Double.TryParse(pageHeightTextBox.Text, out pageHeight))
            {
                pageHeight = 800;
            }

            // get the core layout
            string coreLayoutKey = coreLayoutComboBox.SelectedItem as string;

            if (coreLayoutKey != null && coreLayouts.ContainsKey(coreLayoutKey))
            {
                coreLayout = coreLayouts[coreLayoutKey];
            }
            else
            {
                coreLayout = coreLayouts["Hierarchic"];
            }

            // a data provider for the node, edge, and label IDs:
            // this data provider returns the node/edge/label instances themselves

            var multiPageLayoutData = new MultiPageLayoutData
            {
                NodeIds      = { Delegate = node => node },
                EdgeIds      = { Delegate = edge => edge },
                NodeLabelIds = { Delegate = label => label },
                EdgeLabelIds = { Delegate = label => label },
                AbortHandler = abortHandler = new AbortHandler()
            };

            // apply the multi page layout
            // multiPageLayout contains a list with the single page graphs
            MultiPageLayout multiPageLayout = new MultiPageLayout(coreLayout)
            {
                MaximumPageSize = new YDimension(pageWidth, pageHeight),
                LayoutCallback  = new DelegateLayoutCallback(result => BeginInvoke(new Action(() => {
                    ApplyLayoutResult(result, pageWidth, pageHeight);
                    abortHandler = null;
                    ShowLoadingIndicator(false);
                    // force to update the command state
                    CommandManager.InvalidateRequerySuggested();
                })))
            };

            // execute layout in thread to prevent ui blocking
            new Thread(() => {
                try {
                    modelGraph.ApplyLayout(multiPageLayout, multiPageLayoutData);
                } catch (AlgorithmAbortedException) {
                    // layout was aborted
                    BeginInvoke(new Action(() => {
                        // reset abortHandler and loading indicator in the view thread
                        abortHandler = null;
                        ShowLoadingIndicator(false);
                    }));
                }
            }).Start();
        }