/// <summary> /// Sets the payload as a segment of a byte-array /// </summary> /// <param name="buffer">The byte array where to read the data from.</param> /// <param name="offset">The index where to start to read from.</param> /// <param name="count">The number of bytes to read.</param> /// <returns>The <see cref="MsgIn"/> instance itself, useful for fluent patterns.</returns> public MsgIn SetPayload(byte[] buffer, int offset, int count) { this.PayloadInternal = new byte[count]; VectorizedCopyExtension.VectorizedCopy( buffer, offset, this.PayloadInternal, 0, count ); return(this); }
/// <summary> /// Sets the payload of the message as a byte-array. /// </summary> /// <remarks> /// The access of this method is allowed only to the NATS client infrastructure. /// </remarks> /// <param name="buffer">The byte array with the data as payload</param> internal void SetPayload(byte[] buffer) { this._payloadInternal = new byte[this.PayloadLength]; //since the local payload byte-array is exposed to the host, //here it makes a copy of the given data VectorizedCopyExtension.VectorizedCopy( buffer, 0, this._payloadInternal, 0, this.PayloadLength ); }
/// <summary> /// Copies the payload to a host-provided byte-array. /// </summary> /// <param name="buffer">The target byte-array, which should be large enough to hold the data.</param> /// <param name="offset">The starting position to copy the bytes from.</param> /// <returns>The number of bytes copied.</returns> public int GetPayloadAsByteArray(byte[] buffer, int offset) { int count = this._payloadInternal.Length; //since the local payload byte-array is exposed to the host, //here it makes a copy of the given data VectorizedCopyExtension.VectorizedCopy( this._payloadInternal, 0, buffer, offset, count ); return(count); }
/// <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; } }