// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; namespace Microsoft.AspNet.SignalR.Messaging { public class Message { private static readonly byte[] _zeroByteBuffer = new byte[0]; private static readonly UTF8Encoding _encoding = new UTF8Encoding(); public Message() { Encoding = _encoding; } public Message(string source, string key, string value) { if (source == null) { throw new ArgumentNullException("source"); } if (key == null) { throw new ArgumentNullException("key"); } Source = source; Key = key; Encoding = _encoding; Value = value == null ? new ArraySegment(_zeroByteBuffer) : new ArraySegment(Encoding.GetBytes(value)); } public Message(string source, string key, ArraySegment value) : this() { if (source == null) { throw new ArgumentNullException("source"); } if (key == null) { throw new ArgumentNullException("key"); } Source = source; Key = key; Value = value; } /// /// Which connection the message originated from /// public string Source { get; set; } /// /// The signal for the message (connection id, group, etc) /// public string Key { get; set; } /// /// The message payload /// public ArraySegment Value { get; set; } /// /// The command id if this message is a command /// public string CommandId { get; set; } /// /// Determines if the caller should wait for acknowledgement for this message /// public bool WaitForAck { get; set; } /// /// Determines if this message is itself an ACK /// public bool IsAck { get; set; } /// /// A list of connection ids to filter out /// public string Filter { get; set; } /// /// The encoding of the message /// public Encoding Encoding { get; private set; } /// /// The payload id. Only used in scaleout scenarios /// public ulong MappingId { get; set; } /// /// The stream index this message came from. Only used the scaleout scenarios. /// public int StreamIndex { get; set; } public bool IsCommand { get { return !String.IsNullOrEmpty(CommandId); } } [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This may be expensive")] public string GetString() { // If there's no encoding this is a raw binary payload if (Encoding == null) { throw new NotSupportedException(); } return Encoding.GetString(Value.Array, Value.Offset, Value.Count); } public void WriteTo(Stream stream) { var binaryWriter = new BinaryWriter(stream); binaryWriter.Write(Source); binaryWriter.Write(Key); binaryWriter.Write(Value.Count); binaryWriter.Write(Value.Array, Value.Offset, Value.Count); binaryWriter.Write(CommandId ?? String.Empty); binaryWriter.Write(WaitForAck); binaryWriter.Write(IsAck); binaryWriter.Write(Filter ?? String.Empty); } public static Message ReadFrom(Stream stream) { var message = new Message(); var binaryReader = new BinaryReader(stream); message.Source = binaryReader.ReadString(); message.Key = binaryReader.ReadString(); int bytes = binaryReader.ReadInt32(); message.Value = new ArraySegment(binaryReader.ReadBytes(bytes)); message.CommandId = binaryReader.ReadString(); message.WaitForAck = binaryReader.ReadBoolean(); message.IsAck = binaryReader.ReadBoolean(); message.Filter = binaryReader.ReadString(); return message; } } }