/// <summary> /// Writes this Header to buffer starting at offset /// Keep in mind, this API assumes buffer is large enough /// for the operation. /// </summary> /// <param name="buffer">buffer to serialize this Header to</param> /// <param name="offset">offset to begin writing at.</param> /// <returns> /// the new offset. /// </returns> public int WriteToBuffer(byte[] buffer, int offset) { var newOffset = offset; buffer[newOffset++] = (byte)Name.Length; var nameBytes = Encoding.UTF8.GetBytes(Name); Buffer.BlockCopy(nameBytes, 0, buffer, newOffset, Name.Length); newOffset += Name.Length; buffer[newOffset++] = (byte)HeaderType; byte[] serializedBytes = null; int valueLength = 0; switch (HeaderType) { case EventStreamHeaderType.BoolTrue: case EventStreamHeaderType.BoolFalse: break; case EventStreamHeaderType.Byte: buffer[newOffset++] = (byte)HeaderValue; break; case EventStreamHeaderType.Int16: serializedBytes = BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder((Int16)HeaderValue)); Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, 2); newOffset += _sizeOfInt16; break; case EventStreamHeaderType.Int32: serializedBytes = BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder((Int32)HeaderValue)); Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, 4); newOffset += _sizeOfInt32; break; case EventStreamHeaderType.Int64: serializedBytes = BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder((Int64)HeaderValue)); Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, 8); newOffset += _sizeOfInt64; break; case EventStreamHeaderType.ByteBuf: serializedBytes = HeaderValue as byte[]; valueLength = serializedBytes.Length; Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder((Int16)valueLength)), 0, buffer, newOffset, 2); newOffset += _sizeOfInt16; Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, valueLength); newOffset += valueLength; break; case EventStreamHeaderType.String: serializedBytes = Encoding.UTF8.GetBytes(HeaderValue as string); valueLength = serializedBytes.Length; Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder((Int16)valueLength)), 0, buffer, newOffset, 2); newOffset += _sizeOfInt16; Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, valueLength); newOffset += valueLength; break; case EventStreamHeaderType.Timestamp: var tempValue = (Int64)((DateTime)HeaderValue).Subtract(_unixEpoch).TotalMilliseconds; serializedBytes = BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder(tempValue)); Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, 8); newOffset += _sizeOfInt64; break; case EventStreamHeaderType.UUID: serializedBytes = ((Guid)HeaderValue).ToByteArray(); Buffer.BlockCopy(serializedBytes, 0, buffer, newOffset, serializedBytes.Length); newOffset += serializedBytes.Length; break; default: throw new EventStreamParseException(string.Format(CultureInfo.InvariantCulture, "Header Type: {0} is an unknown type.", HeaderType)); } return(newOffset); }
/// <summary> /// Converts a message into a byte buffer (usually for network transmission). /// </summary> public byte[] ToByteArray() { int headersWireLength = 0; //first we need to figure out how much space the headers will take up. if (Headers != null) { foreach (var header in Headers) { headersWireLength += header.Value.GetWireSize(); } } var payloadLength = Payload?.Length ?? 0; //total message length is the framing size + the payload size + the headers wire size. var totalLength = headersWireLength + payloadLength + FramingSize; var messageBuffer = new byte[totalLength]; //now write the total length and the headers length to the message. make sure to handle endianness conversions var offset = 0; Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder(totalLength)), 0, messageBuffer, offset, SizeOfInt32); offset += SizeOfInt32; Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder(headersWireLength)), 0, messageBuffer, offset, SizeOfInt32); offset += SizeOfInt32; using (var nullStream = new NullStream()) using (var runningChecksum = new CrcCalculatorStream(nullStream)) { //write the total length and headers length to the checksum stream. runningChecksum.Write(messageBuffer, 0, offset); //take the current checksum and write it to the message. Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder(runningChecksum.Crc32)), 0, messageBuffer, offset, SizeOfInt32); //now take the current checksum and write it to the checksum stream. runningChecksum.Write(messageBuffer, offset, SizeOfInt32); offset += SizeOfInt32; //loop over the headers and write them out to the message. if (Headers != null) { foreach (var header in Headers) { offset = header.Value.WriteToBuffer(messageBuffer, offset); } //make sure to add the header bytes to the checksum stream. runningChecksum.Write(messageBuffer, PreludeLen, offset - PreludeLen); } //write the payload to the message. if (Payload != null) { Buffer.BlockCopy(Payload, 0, messageBuffer, offset, Payload.Length); //update the checksum runningChecksum.Write(messageBuffer, offset, Payload.Length); offset += Payload.Length; } //take the final checksum and add it to the end of the message. Buffer.BlockCopy(BitConverter.GetBytes(EndianConversionUtility.HostToNetworkOrder(runningChecksum.Crc32)), 0, messageBuffer, offset, SizeOfInt32); } return(messageBuffer); }