using Google.Protobuf; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using Tango.PMR.Common; using Tango.PMR.DataStore; using Tango.PMR.Integration; namespace Tango.PMR { /// /// Contains helper class for encoding and decoding PMR messages. /// public static class MessageFactory { private static Dictionary _pmrTypes; private static Dictionary _pmrDataStoreTypes; private static MethodInfo _parseTangoMessageMethod; static MessageFactory() { _parseTangoMessageMethod = typeof(MessageFactory).GetMethod("ParseTangoMessage", BindingFlags.Public | BindingFlags.Static); _pmrTypes = new Dictionary(); var types = typeof(MessageFactory).Assembly.GetTypes().ToList(); foreach (var value in Enum.GetValues(typeof(MessageType)).OfType()) { var type = types.SingleOrDefault(x => x.Name == value.ToOriginalName()); if (type != null) { _pmrTypes.Add(value, type); } } _pmrDataStoreTypes = new Dictionary(); foreach (var value in Enum.GetValues(typeof(DataStoreMessageType)).OfType()) { var type = types.SingleOrDefault(x => x.Name == value.ToOriginalName()); if (type != null) { _pmrDataStoreTypes.Add(value, type); } } } /// /// Returns the matching PMR type from the PMR message type. /// /// Type of the message. /// public static Type GetPMRTypeFromMessageType(MessageType messageType) { return _pmrTypes[messageType]; } /// /// Returns the matching PMR type from the PMR message type. /// /// Type of the message. /// public static Type GetDataStorePMRTypeFromDataStoreMessageType(DataStoreMessageType messageType) { return _pmrDataStoreTypes[messageType]; } /// /// Creates a new . /// /// /// public static TangoMessage CreateTangoMessage() where T : IMessage { TangoMessage tango = new TangoMessage(Activator.CreateInstance(), ParseMessageType(typeof(T).Name)); return tango; } /// /// Creates a new . /// /// /// public static TangoMessage CreateTangoMessage(T message) where T : IMessage { TangoMessage tango = CreateTangoMessage(); tango.Message = message; return tango; } /// /// Creates a new . /// /// /// public static TangoMessage CreateTangoMessage(String token) where T : IMessage { TangoMessage tango = CreateTangoMessage(); tango.Container.Token = token; return tango; } /// /// Creates a new . /// /// /// public static TangoMessage CreateTangoMessage(T message, String token) where T : IMessage { TangoMessage tango = CreateTangoMessage(token); tango.Message = message; return tango; } /// /// Parses the specified tango message type from the specified byte array. /// /// /// The data. /// public static TangoMessage ParseTangoMessage(byte[] data) where T : IMessage { MessageContainer container = MessageContainer.Parser.ParseFrom(data); MessageParser parser = new MessageParser(() => Activator.CreateInstance()); TangoMessage tango = new TangoMessage(container, parser.ParseFrom(container.Data)); return tango; } /// /// Parses the specified tango message type from the specified message container. /// /// /// The data. /// public static TangoMessage ParseTangoMessageFromContainer(MessageContainer container) where T : IMessage { MessageParser parser = new MessageParser(() => Activator.CreateInstance()); TangoMessage tango = new TangoMessage(container, parser.ParseFrom(container.Data)); return tango; } /// /// Parses an unknown tango message from the specified byte array. /// /// The data. /// public static ITangoMessage ParseTangoMessageAgnostic(byte[] data) { MessageContainer container = MessageContainer.Parser.ParseFrom(data); IMessage message = ExtractMessageFromContainer(container); return (ITangoMessage)_parseTangoMessageMethod.MakeGenericMethod(message.GetType()).Invoke(null, new[] { data }); } /// /// Parses the message from the specified container. /// /// /// The container. /// public static T ExtractMessageFromContainer(MessageContainer container) where T : IMessage { MessageParser parser = new MessageParser(() => Activator.CreateInstance()); return parser.ParseFrom(container.Data); } /// /// Parses the message from the specified container. /// /// /// The container. /// public static IMessage ExtractMessageFromContainer(MessageContainer container) { var type = _pmrTypes[container.Type]; MessageParser parser = type.GetProperty("Parser").GetValue(container) as MessageParser; return parser.ParseFrom(container.Data); } /// /// Parses a message container from the specified byte array. /// /// The data. /// public static MessageContainer ParseContainer(byte[] data) { MessageContainer container = MessageContainer.Parser.ParseFrom(data); return container; } /// /// Parses a message container from the specified byte array containing JSON data. /// /// The data. /// public static MessageContainer ParseContainerJson(byte[] data) { MessageContainer container = MessageContainer.Parser.ParseJson(Encoding.UTF8.GetString(data)); return container; } /// /// Parses the specified text to a PMR . /// /// The text. /// /// Could not parse message type " + text public static MessageType ParseMessageType(String text) { MessageType t; if (Enum.TryParse(text, true, out t)) { return t; } else { throw new InvalidCastException("Message type " + text + " was not found on PMR MessageType enumeration!"); } } /// /// Parses the specified text to a PMR . /// /// The text. /// /// Could not parse message type " + text public static DataStoreMessageType ParseDataStoreMessageType(String text) { DataStoreMessageType t; if (Enum.TryParse(text, true, out t)) { return t; } else { throw new InvalidCastException("Data Store Message type " + text + " was not found on PMR DataStoreMessageType enumeration!"); } } /// /// Gets the available request stubs. /// /// public static List GetAvailableRequestStubs() { return typeof(MessageFactory).Assembly.GetTypes().Where(x => x.Namespace != null && x.Namespace.Contains("Stubs") && x.Name.Contains("Request") && !x.Name.Contains("Reflection")).ToList(); } /// /// Gets the available request & response stubs. /// /// public static List GetAvailableRequestResponseStubs() { return typeof(MessageFactory).Assembly.GetTypes().Where(x => x.Namespace != null && x.Namespace.Contains("Stubs") && !x.Name.Contains("Reflection")).ToList(); } /// /// Parses the proto message from the specified bytes. Requires the message type. /// /// The data. /// The type. /// public static IMessage ParseProtoMessage(byte[] data, Type type) { using (MemoryStream ms = new MemoryStream(data)) { ms.Position = 0; using (BinaryReader reader = new BinaryReader(ms)) { IMessage message = Activator.CreateInstance(type) as IMessage; MessageParser parser = type.GetProperty("Parser").GetValue(message) as MessageParser; return parser.ParseFrom(data); } } } } }