Ejemplo n.º 1
0
        private async Task ProcessRequestsAsync(PipeReader reader)
        {
            while (true)
            {
                ReadResult readResult    = default;
                bool       endConnection = false;
                _currentCommand = StompCommand.None;
                _currentHeaders.Clear();

                do
                {
                    readResult = await reader.ReadAsync();
                }while (!TryParseRequest(readResult, out endConnection));

                if (endConnection)
                {
                    return;
                }

                DoResponse();

                if (readResult.IsCompleted)
                {
                    break;
                }
            }

            reader.Complete();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Sends the specified frame, and registers a completion for the response frame by receipt ID.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="headers"></param>
        /// <param name="body"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        ValueTask <StompFrame> SendFrameAndWaitWithReceiptAsync(StompCommand command, IEnumerable <KeyValuePair <string, string> > headers, ReadOnlyMemory <byte> body, CancellationToken cancellationToken)
        {
            headers ??= Enumerable.Empty <KeyValuePair <string, string> >();

            var receiptIdText = Interlocked.Increment(ref prevReceiptId).ToString();

            headers           = headers.Prepend(new KeyValuePair <string, string>("receipt", receiptIdText));
            cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, new CancellationTokenSource(options.ReceiptTimeout).Token).Token;
            return(SendFrameAndWaitAsync(command, headers, body, f => f.GetHeaderValue("receipt-id") == receiptIdText, cancellationToken));
        }
Ejemplo n.º 3
0
        /// <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);
                        }
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Attempts to read the next line from the sequence.
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        bool TryReadCommand(ref SequenceReader <byte> sequence, out StompCommand command)
        {
            command = StompCommand.Unknown;

            // read up to line ending
            if (sequence.TryReadTo(out ReadOnlySequence <byte> itemBytes, (byte)'\n') == false)
            {
                return(false);
            }

            // if so, it should be the command name
            if (TryParseCommand(Encoding.UTF8.GetString(itemBytes).TrimEnd(), out command) == false)
            {
                throw new StompProtocolException("Cannot parse STOMP command.");
            }

            return(true);
        }
Ejemplo n.º 5
0
        public AppFunc Invoke(AppFunc next) =>
        async environment =>
        {
            var requestFrame = environment.ReadFromEnvironmentRequest();

            if (StompCommand.IsConnectRequest(requestFrame.Command))
            {
                string stompAcceptVersion;
                var    stompProtocolVersion = requestFrame.Headers.TryGetValue("accept-version", out stompAcceptVersion)
                        ? stompAcceptVersion
                        : "1.0";

                if (environment.ContainsKey("stomp.protocolVersion"))
                {
                    environment["stomp.protocolVersion"] = stompProtocolVersion;
                }
                else
                {
                    environment.Add("stomp.protocolVersion", stompProtocolVersion);
                }
            }

            await next(environment);
        };
Ejemplo n.º 6
0
 public void OnCommandLine(StompCommand command)
 {
     _connection.OnCommandLine(command);
 }
Ejemplo n.º 7
0
 public void OnCommandLine(StompCommand command)
 {
     _currentCommand = command;
 }
Ejemplo n.º 8
0
        public AppFunc Invoke(AppFunc next) =>
        async environment =>
        {
            var stompCommand = (string)environment["stomp.requestMethod"];

            if (StompCommand.IsConnectRequest(stompCommand))
            {
                string version;
                object versionObject;
                if (!environment.TryGetValue("stomp.protocolVersion", out versionObject))
                {
                    version = "1.0";
                }
                else
                {
                    version = versionObject as string;
                }

                if (Options.AcceptedVersions.Contains(version))
                {
                    var sessionId = Guid.NewGuid().ToString();
                    new StompFrame(StompCommand.CONNECTED, new Dictionary <string, string>
                    {
                        ["version"] = version,
                        ["session"] = sessionId
                    }).WriteToEnvironmentResponse(environment);

                    //Give other middleware a chance to disagree.
                    await next(environment);

                    //If there wasn't a disagreement.
                    if ((string)environment["stomp.responseMethod"] == StompCommand.CONNECTED)
                    {
                        Options.AddSession(sessionId);
                    }
                }
                else
                {
                    new StompFrame(StompCommand.ERROR, new Dictionary <string, string>
                    {
                        { "message", "No acceptable protocol version negotiated." }
                    }).WriteToEnvironmentResponse(environment);
                }
            }
            else
            {
                var headers = (ImmutableArray <KeyValuePair <string, string> >)environment["stomp.requestHeaders"];

                string sessionId;

                if (headers.TryGetValue("session", out sessionId) && !string.IsNullOrWhiteSpace(sessionId))
                {
                    if (Options.ValidateSession(sessionId))
                    {
                        await next(environment);
                    }
                    else
                    {
                        new StompFrame(StompCommand.ERROR, new Dictionary <string, string>
                        {
                            { "message", "Invalid or expired/rejected session identifier." }
                        }).WriteToEnvironmentResponse(environment);
                    }
                }
                else
                {
                    new StompFrame(StompCommand.ERROR, new Dictionary <string, string> {
                        { "message", "Session not established." }
                    }).WriteToEnvironmentResponse(environment);
                }
            }
        };
Ejemplo n.º 9
0
 /// <summary>
 /// Initializes a new instance.
 /// </summary>
 /// <param name="command"></param>
 /// <param name="headers"></param>
 /// <param name="body"></param>
 public StompFrame(StompCommand command, IEnumerable <KeyValuePair <string, string> > headers, ReadOnlyMemory <byte> body)
 {
     Command = command;
     Headers = headers ?? Enumerable.Empty <KeyValuePair <string, string> >();
     Body    = body;
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Parses the command line string.
        /// </summary>
        /// <param name="line"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        bool TryParseCommand(string line, out StompCommand command)
        {
            switch (line)
            {
            case "CONNECT":
                command = StompCommand.Connect;
                return(true);

            case "STOMP":
                command = StompCommand.Stomp;
                return(true);

            case "CONNECTED":
                command = StompCommand.Connected;
                return(true);

            case "SEND":
                command = StompCommand.Send;
                return(true);

            case "SUBSCRIBE":
                command = StompCommand.Subscribe;
                return(true);

            case "UNSUBSCRIBE":
                command = StompCommand.Unsubscribe;
                return(true);

            case "ACK":
                command = StompCommand.Ack;
                return(true);

            case "NACK":
                command = StompCommand.Nack;
                return(true);

            case "BEGIN":
                command = StompCommand.Begin;
                return(true);

            case "DISCONNECT":
                command = StompCommand.Disconnect;
                return(true);

            case "MESSAGE":
                command = StompCommand.Message;
                return(true);

            case "RECEIPT":
                command = StompCommand.Receipt;
                return(true);

            case "ERROR":
                command = StompCommand.Error;
                return(true);

            default:
                command = StompCommand.Unknown;
                return(false);
            }
            ;
        }