/// <summary> /// Attempts to pass an error to the router and return whether or not it should be removed. /// </summary> /// <param name="router"></param> /// <param name="exception"></param> /// <param name="cancellationToken"></param> /// <returns></returns> async ValueTask TryAbortRouter(FrameRouter router, Exception exception, CancellationToken cancellationToken) { try { await router.AbortAsync(exception, cancellationToken); } catch (Exception e) { logger.LogError(e, "Unhandled exception occurred dispatching exception to listener."); } }
/// <summary> /// Attempts to execute the listener and return whether or not it should be removed. If the listener throws an exception, it is logged and marked for removal. /// </summary> /// <param name="router"></param> /// <param name="frame"></param> /// <param name="cancellationToken"></param> /// <returns></returns> async ValueTask <bool> TryRouteAsync(FrameRouter router, StompFrame frame, CancellationToken cancellationToken) { try { return(await router.RouteAsync(frame, cancellationToken)); } catch (Exception e) { logger.LogError(e, "Unhandled exception occurred dispatching frame to trigger."); return(false); } }
/// <summary> /// Sends the specified frame, and registers a completion for the next frame that matches the specified conditions. /// </summary> /// <param name="command"></param> /// <param name="headers"></param> /// <param name="body"></param> /// <param name="response"></param> /// <param name="cancellationToken"></param> /// <returns></returns> async ValueTask <StompFrame> SendFrameAndWaitAsync(StompCommand command, IEnumerable <KeyValuePair <string, string> > headers, ReadOnlyMemory <byte> body, Func <StompFrame, bool> response, CancellationToken cancellationToken) { headers ??= Enumerable.Empty <KeyValuePair <string, string> >(); // schedule a router for the frame filter var tcs = new TaskCompletionSource <StompFrame>(); ValueTask <bool> WriteAsync(StompFrame frame, CancellationToken cancellationToken) { tcs.SetResult(frame); return(new ValueTask <bool>(false)); } ValueTask AbortAsync(Exception exception, CancellationToken cancellationToken) { tcs.SetException(exception); return(ValueTaskHelper.CompletedTask); } var hnd = new FrameRouter(response, WriteAsync, AbortAsync); // handle cancellation through new task cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)); // subscribe to matching frames var node = await RegisterRouterAsync(hnd, cancellationToken); try { // send initial frame and wait for resumption await SendFrameAsync(new StompFrame(command, headers, body), cancellationToken); return(await tcs.Task); } finally { // ensure listener is removed upon completion if (node.List != null) { using (await routersLock.LockAsync()) if (node.List != null) { routers.Remove(node); } } } }
/// <summary> /// Registers a trigger for a frame condition. /// </summary> /// <param name="trigger"></param> /// <param name="cancellationToken"></param> /// <returns></returns> async ValueTask <LinkedListNode <FrameRouter> > RegisterRouterAsync(FrameRouter trigger, CancellationToken cancellationToken) { using (await routersLock.LockAsync(cancellationToken)) return(routers.AddLast(trigger)); }