Class representing a STOMP FRAME. No validation is done here except a command string is required. All validations must be done in inheritors. This object is not immutable, BUT should be used as if it were.
示例#1
0
        private async Task WriteFrameAsyncImpl(Frame frame, CancellationToken cancellationToken)
        {
#if TRACE
            Console.WriteLine(frame);
#endif
            if (frame.Command == StompCommands.Connect)
            {
                if (frame.Headers.Any(kvp => kvp.Key.Any(ch => ch == '\n' || ch == ':') || kvp.Value.Any(ch => ch == '\n')))
                    throw new InvalidDataException("Connect header names MUST not contain LF or ':' characters; Connected header values MUST not contain any LF.");

                await _writer.WriteAsync(frame.Command, cancellationToken);
                await _writer.WriteAsync(StompOctets.LineFeedByte, cancellationToken);

                await WriteConnectHeadersAsync(frame, cancellationToken);

                await _writer.WriteAsync(frame.BodyArray, cancellationToken);
                await _writer.WriteAsync(StompOctets.EndOfFrameByte, cancellationToken);
            }
            else
            {
                await _writer.WriteAsync(frame.Command, cancellationToken);
                await _writer.WriteAsync(StompOctets.LineFeedByte, cancellationToken);

                await WriteHeadersAsync(frame, cancellationToken);

                await _writer.WriteAsync(frame.BodyArray, cancellationToken);
                await _writer.WriteAsync(StompOctets.EndOfFrameByte, cancellationToken);
            }

            await _writer.FlushAsync(cancellationToken);
        }
示例#2
0
        /// <summary>
        /// Transform a frame into a 'subclass' matching its command.
        /// These subclasses are: ReceiptFrame, MessageFrame, ErrorFrame, ConnectedFrame.
        /// </summary>
        /// <param name="frame">Frame to be interpreted.</param>
        /// <returns>A new frame which class matches its command type.</returns>
        public static Frame Interpret(Frame frame)
        {
            if (frame == null)
                throw new ArgumentNullException("frame");

            switch (frame.Command)
            {
                case StompCommands.Heartbeat:
                    return frame;
                case StompCommands.Receipt:
                    if (frame.BodyArray != Frame.EmptyBody)
                        throw new InvalidDataException("Receipt frame MUST NOT have a body.");
                    return new ReceiptFrame(frame.Headers);
                case StompCommands.Message:
                    return new MessageFrame(frame.Headers, frame.BodyArray);
                case StompCommands.Error:
                    return new ErrorFrame(frame.Headers, frame.BodyArray);
                case StompCommands.Connected:
                    if (frame.BodyArray != Frame.EmptyBody)
                        throw new InvalidDataException("Connected frame MUST NOT have a body.");
                    return new ConnectedFrame(frame.Headers);
                default:
                    throw new InvalidDataException(string.Format("'{0}' is not a valid STOMP server command.", frame.Command));
            }
        }
示例#3
0
 public static Task WriteAsync(this IStompFrameWriter writer, Frame frame)
 {
     return writer.WriteAsync(frame, CancellationToken.None);
 }
        static bool AssertExpectedCommandFrame(Frame frame, string expectedFrameCommand)
        {
            // If error
            if (frame.Command == StompCommands.Error)
            {
                // Using the incoming frame, Interpret will create a new instance of a sub-class 
                // of Frame depending on the Command. If the frame is a HEARTBEAT, the same frame 
                // will be returned. Possible sub-classes: ConnectedFrame, ErrorFrame, MessageFrame,
                // ReceiptFrame.
                // Interpret throws exception if the incoming frame is malformed (not standard).
                ErrorFrame errFrame = StompInterpreter.Interpret(frame) as ErrorFrame;

                Console.WriteLine("ERROR RESPONSE");
                Console.WriteLine("Message : " + errFrame.Message);
                
                return false;
            }

            if (frame.Command != expectedFrameCommand)
            {
                Console.WriteLine("UNEXPECTED FRAME.");
                Console.WriteLine(frame.ToString());
                
                return false;
            }

            return true;
        }
示例#5
0
 public Task WriteAsync(Frame frame, CancellationToken cancellationToken)
 {
     return _frameWriter.WriteAsync(frame, cancellationToken);
 }
 public Task WriteAsync(Frame frame, CancellationToken cancellationToken)
 {
     return _serialTaskExecuter.Execute(() => _writer.WriteAsync(frame, cancellationToken), cancellationToken);
 }
示例#7
0
 public async Task WriteAsync(Frame frame, CancellationToken cancellationToken)
 {
     //Make sure IO operations do not get executed on UI thread.
     await WriteFrameAsyncImpl(frame, cancellationToken).ConfigureAwait(false);
 }
示例#8
0
 private async Task WriteHeadersAsync(Frame frame, CancellationToken cancellationToken)
 {
     foreach (var header in frame.Headers.Where(header => header.Value != null))
     {
         await WriteEscapedString(header.Key, cancellationToken);
         await _writer.WriteAsync(StompOctets.ColonByte, cancellationToken);
         await WriteEscapedString(header.Value, cancellationToken);
         await _writer.WriteAsync(StompOctets.LineFeedByte, cancellationToken);
     }
     await _writer.WriteAsync(StompOctets.LineFeedByte, cancellationToken);
 }
        /// <summary>
        /// Write a frame and wait for its receipt frame before returning.
        /// 
        /// This method does not add a receipt header if it is not included already.
        /// If the receipt header is not in the frame headers then it returns after sending the message.
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task WriteAsync(Frame frame, CancellationToken cancellationToken)
        {
            string receipt = frame.Command == StompCommands.Connect ? _connectReceiptHeader : frame.GetHeader(StompHeaders.Receipt);

            if (receipt == null)
            {
                await _writer.WriteAsync(frame, cancellationToken);
            }
            else
            {
                TaskCompletionSource<object> receiptWaiter = new TaskCompletionSource<object>();
                Task task = receiptWaiter.Task;
                _receiptWaiters[receipt] = receiptWaiter;

                do
                {
                    await _writer.WriteAsync(frame, cancellationToken);
                } while (await Task.WhenAny(task, Task.Delay(_retryInterval, cancellationToken)) != task 
                         && !task.IsFaulted && !task.IsCanceled);

                if (task.IsFaulted) throw task.Exception;
                if (task.IsCanceled) throw new OperationCanceledException(cancellationToken);
            }
        }
        private void OnNext(Frame frame)
        {
            string receiptId = 
                  frame.Command == StompCommands.Receipt ? frame.GetHeader(StompHeaders.ReceiptId)
                : frame.Command == StompCommands.Connected ? _connectReceiptHeader
                : null;

            if(receiptId != null)
            {
                TaskCompletionSource<object> tcs;
                if (_receiptWaiters.TryGetValue(receiptId, out tcs))
                {
                    tcs.TrySetResult(null);
                    _receiptWaiters.TryRemove(receiptId, out tcs);
                }
            }
        }