/// <summary>
        /// Returns the next <see cref="MsgOut"/> available to a subscriber,
        /// or block up to a given timeout until the next one is available.
        /// </summary>
        /// <param name="timeout">The amount of time to wait for the next message.</param>
        /// <param name="token">Propagates notification that operations should be canceled.</param>
        /// <returns>The next <see cref="MsgOut"/> available to a subscriber.</returns>
        public MsgOut NextMessage(TimeSpan timeout, CancellationToken token)
        {
            if (this._disposed != 0)
            {
                throw new ObjectDisposedException(nameof(PassiveSubscription));
            }

            MsgOut message = null;

            try
            {
                while (
                    this._disposed == 0 &&
                    this.TryDequeueSinglePendingMessage(out message) == false &&
                    this._mainSem.Wait(timeout, token)
                    )
                {
                    //do nothing
                }
                ;
            }
            finally
            {
                //check for disposal in progress
                if (this._disposed != 0)
                {
                    throw new NATSBadSubscriptionException();
                }
            }


            return(message);
        }
        /// <summary>
        /// Tells this instance the request-reply process has been completed with success,
        /// and feeds the <see cref="MsgOut"/> received.
        /// </summary>
        /// <param name="message"></param>
        internal void Resolve(MsgOut message)
        {
            int sts = Interlocked.Exchange(ref this._status, StateComplete);

            if (sts != StateComplete)
            {
                this._resolveValue = message;
                this._evt.Release(1);
            }
        }
        /// <summary>
        /// Processes a valid message just parsed
        /// </summary>
        /// <param name="message"></param>
        private void NotifyMessageHandler(
            MsgOut message
            )
        {
            //update stats
            this.AddIncomingStats(1, message.PayloadLength);

            //yield the subscription pool to go up
            this._owner.SubPool.ProcessMessage(message);
        }
        /// <summary>
        /// Handler of the received <see cref="MsgOut"/> message from the subscription.
        /// The message is quicky dispatched to the proper <see cref="InFlightRequest"/>.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="reqId"></param>
        void IRequestReplayFeedback.ProcessMessage(MsgOut message, long reqId)
        {
            InFlightRequest request;

            lock (this._reqlocker)
            {
                this._requestRegister.TryGetValue(reqId, out request);
            }
            if (request != null)
            {
                request.Resolve(message);
            }
        }
        /// <summary>
        /// Processes the <see cref="MsgOut"/> as they are given from the <see cref="Parser"/>
        /// </summary>
        /// <param name="message"></param>
        internal void ProcessMessage(
            MsgOut message
            )
        {
            SubscriptionBase sub;

            lock (this._sublocker)
            {
                //retrieves the subscription proxy to dispatch the message to
                this._subRegister.TryGetValue(message.SubId, out sub);
            }

            if (sub != null)
            {
                //dispatches the message to the proxy
                message.ArrivalSubcription = sub;
                sub.ProcessMessage(message);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Parser for a message header
        /// </summary>
        /// <remarks>
        /// see: https://nats.io/documentation/internals/nats-protocol/
        /// </remarks>
        private void ParseHeader()
        {
            //initial byte-array to UTF-8 char-array conversion
            int charCount = Encoding.UTF8.GetChars(this._xbuffer, 0, this._xbuflen, this._cbuffer, 0);

            //the idea is to avoid splitting a string into other strings,
            //so simply mark the useful points of a character array
            int numseps = 0;

            for (int i = 0; i < charCount; i++)
            {
                if (this._cbuffer[i] == ' ')
                {
                    this._sepPos[numseps++] = i;
                }
            }

            string replyTo = null;

            if (numseps == 3)
            {
                //read the 'reply' argument
                replyTo = new string(
                    this._cbuffer,
                    this._sepPos[1] + 1,
                    this._sepPos[2] - this._sepPos[1] - 1
                    );
            }

            this._message = new MsgOut(
                subject: new string(this._cbuffer, 0, this._sepPos[0]),
                replyTo: replyTo,
                subId: Converters.StringToInt64(this._cbuffer, this._sepPos[0] + 1, this._sepPos[1] - this._sepPos[0] - 1)
                )
            {
                PayloadLength = (int)Converters.StringToInt64(this._cbuffer, this._sepPos[numseps - 1] + 1, this._xbuflen - this._sepPos[numseps - 1] - 1),
            };
        }
Esempio n. 7
0
 /// <summary>
 /// Processe the dispatched message
 /// </summary>
 /// <param name="message"></param>
 protected override void ProcessOutgoingMessage(MsgOut message)
 {
     this.Owner.ReactiveSubscriptionSignal(this);
 }
Esempio n. 8
0
        /// <summary>
        /// Entry-point to feed the parser with data incoming from the NATS server
        /// </summary>
        /// <param name="segment"></param>
        internal void Parse(
            ArraySegment <byte> segment
            )
        {
            byte[] buffer = segment.Array;
            int    bstart = 0;
            int    bcount = 0;

#if DEBUG
            //Print(buffer, 0, segment.Count);
#endif
            for (int i = 0, len = segment.Count; i < len; i++)
            {
                char b = (char)buffer[i];

                switch (_state)
                {
                case OP_START:
                    switch (b)
                    {
                    case 'M':
                    case 'm':
                        _state = OP_M;
                        break;

                    case 'C':
                    case 'c':
                        _state = OP_C;
                        break;

                    case 'P':
                    case 'p':
                        _state = OP_P;
                        break;

                    case '+':
                        _state = OP_PLUS;
                        break;

                    case '-':
                        _state = OP_MINUS;
                        break;

                    case 'i':
                    case 'I':
                        _state = OP_I;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_M:
                    switch (b)
                    {
                    case 'S':
                    case 's':
                        _state = OP_MS;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MS:
                    switch (b)
                    {
                    case 'G':
                    case 'g':
                        _state = OP_MSG;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MSG:
                    switch (b)
                    {
                    case ' ':
                    case '\t':
                        _state = OP_MSG_SPC;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MSG_SPC:
                    switch (b)
                    {
                    case ' ':
                        break;

                    case '\t':
                        break;

                    default:
                        this._xbuflen = 0;
                        bcount        = 0;
                        bstart        = i;
                        _state        = MSG_ARG;
                        i--;
                        break;
                    }
                    break;

                case MSG_ARG:
                    switch (b)
                    {
                    case '\r':
                        break;

                    case '\n':
                        if (bcount != 0)
                        {
                            AddSegment();
                            bcount = 0;
                        }
                        this.ParseHeader();
                        this._xbuflen = 0;
                        _state        = MSG_PAYLOAD;
                        break;

                    default:
                        bcount++;
                        break;
                    }
                    break;

                case MSG_PAYLOAD:
                    int msgSize = this._message.PayloadLength;
                    if (msgSize == 0)
                    {
                        this.NotifyMessage(this._message);
                        this._message = null;
                        _state        = MSG_END;
                    }
                    else
                    {
                        bcount = len - i;
                        if ((this._xbuflen + bcount) > msgSize)
                        {
                            bcount = msgSize - this._xbuflen;
                        }
                        if (bcount != 0)
                        {
                            bstart = i;
                            AddSegment();

                            i     += bcount - 1;
                            bcount = 0;
                        }
                        if (this._xbuflen >= msgSize)
                        {
                            this._message.SetPayload(this._xbuffer);
                            this.NotifyMessage(this._message);
                            this._message = null;

                            this._xbuflen = 0;
                            _state        = MSG_END;
                        }
                    }
                    break;

                case MSG_END:
                    switch (b)
                    {
                    case '\n':
                        _state = OP_START;
                        break;

                    default:
                        continue;
                    }
                    break;

                case OP_PLUS:
                    switch (b)
                    {
                    case 'O':
                    case 'o':
                        _state = OP_PLUS_O;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PLUS_O:
                    switch (b)
                    {
                    case 'K':
                    case 'k':
                        _state = OP_PLUS_OK;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PLUS_OK:
                    switch (b)
                    {
                    case '\n':
                        this.NotifyOperation(
                            default(ArraySegment <byte>),
                            this._state
                            );

                        _state = OP_START;
                        break;
                    }
                    break;

                case OP_MINUS:
                    switch (b)
                    {
                    case 'E':
                    case 'e':
                        _state = OP_MINUS_E;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MINUS_E:
                    switch (b)
                    {
                    case 'R':
                    case 'r':
                        _state = OP_MINUS_ER;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MINUS_ER:
                    switch (b)
                    {
                    case 'R':
                    case 'r':
                        _state = OP_MINUS_ERR;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MINUS_ERR:
                    switch (b)
                    {
                    case ' ':
                    case '\t':
                        _state = OP_MINUS_ERR_SPC;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_MINUS_ERR_SPC:
                    switch (b)
                    {
                    case ' ':
                    case '\t':
                        _state = OP_MINUS_ERR_SPC;
                        break;

                    default:
                        this._xbuflen = 0;
                        bcount        = 0;
                        bstart        = i;
                        _state        = MINUS_ERR_ARG;
                        i--;
                        break;
                    }
                    break;

                case MINUS_ERR_ARG:
                    switch (b)
                    {
                    case '\r':
                        break;

                    case '\n':
                        if (bcount != 0)
                        {
                            AddSegment();
                            bcount = 0;
                        }
                        this.NotifyError(
                            new ArraySegment <byte>(this._xbuffer, 0, this._xbuflen)
                            );

                        this._xbuflen = 0;
                        _state        = OP_START;
                        break;

                    default:
                        bcount++;
                        break;
                    }
                    break;

                case OP_P:
                    switch (b)
                    {
                    case 'I':
                    case 'i':
                        _state = OP_PI;
                        break;

                    case 'O':
                    case 'o':
                        _state = OP_PO;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PO:
                    switch (b)
                    {
                    case 'N':
                    case 'n':
                        _state = OP_PON;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PON:
                    switch (b)
                    {
                    case 'G':
                    case 'g':
                        _state = OP_PONG;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PONG:
                    switch (b)
                    {
                    case '\r':
                        break;

                    case '\n':
                        this.NotifyOperation(
                            default(ArraySegment <byte>),
                            this._state
                            );

                        _state = OP_START;
                        break;
                    }
                    break;

                case OP_PI:
                    switch (b)
                    {
                    case 'N':
                    case 'n':
                        _state = OP_PIN;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PIN:
                    switch (b)
                    {
                    case 'G':
                    case 'g':
                        _state = OP_PING;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_PING:
                    switch (b)
                    {
                    case '\r':
                        break;

                    case '\n':
                        this.NotifyOperation(
                            default(ArraySegment <byte>),
                            this._state
                            );

                        _state = OP_START;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_I:
                    switch (b)
                    {
                    case 'N':
                    case 'n':
                        _state = OP_IN;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_IN:
                    switch (b)
                    {
                    case 'F':
                    case 'f':
                        _state = OP_INF;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_INF:
                    switch (b)
                    {
                    case 'O':
                    case 'o':
                        _state = OP_INFO;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_INFO:
                    switch (b)
                    {
                    case ' ':
                    case '\t':
                        _state = OP_INFO_SPC;
                        break;

                    default:
                        this.ParseError(buffer, i, len);
                        break;
                    }
                    break;

                case OP_INFO_SPC:
                    switch (b)
                    {
                    case ' ':
                    case '\t':
                        break;

                    default:
                        this._xbuflen = 0;
                        bcount        = 0;
                        bstart        = i;
                        this._state   = INFO_ARG;
                        i--;
                        break;
                    }
                    break;

                case INFO_ARG:
                    switch (b)
                    {
                    case '\r':
                        break;

                    case '\n':
                        if (bcount != 0)
                        {
                            AddSegment();
                            bcount = 0;
                        }
                        this.NotifyOperation(
                            new ArraySegment <byte>(this._xbuffer, 0, this._xbuflen),
                            this._state
                            );

                        this._xbuflen = 0;
                        this._state   = OP_START;
                        break;

                    default:
                        bcount++;
                        break;
                    }
                    break;

                default:
                    throw new NATSException("Unable to parse.");
                } // switch(state)
            }     // for

            if (bcount != 0)
            {
                AddSegment();
            }

            //inner data accumulator
            //appends a block of fresh bytes to the local cache
            void AddSegment()
            {
                int newlen = this._xbuflen + bcount;

                if (this._xbuffer.Length < newlen)
                {
                    Array.Resize(
                        ref this._xbuffer,
                        this._xbuffer.Length + Defaults.defaultBufSize
                        );
                }

                VectorizedCopyExtension.VectorizedCopy(
                    buffer,
                    bstart,
                    this._xbuffer,
                    this._xbuflen,
                    bcount
                    );

                this._xbuflen = newlen;
            }
        }
 /// <summary>
 /// Processes the dispatched message
 /// </summary>
 /// <param name="message"></param>
 protected override void ProcessOutgoingMessage(MsgOut message)
 {
     //release the semaphore
     this._mainSem.Release();
 }