aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Transport
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-05 01:22:04 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-05 01:22:04 +0200
commit574f075256fbadd2dadb769c5aff5ebfd6dedd56 (patch)
treeff3a10d9163899a730182cbba020810bc85e5259 /Software/Visual_Studio/Tango.Transport
parente03ca60e3efeb8466f47c30920f6ab36306b3f74 (diff)
downloadTango-574f075256fbadd2dadb769c5aff5ebfd6dedd56.tar.gz
Tango-574f075256fbadd2dadb769c5aff5ebfd6dedd56.zip
Switched generic messages to Protobuf-net.
Diffstat (limited to 'Software/Visual_Studio/Tango.Transport')
-rw-r--r--Software/Visual_Studio/Tango.Transport/AutoProtobuf.cs138
-rw-r--r--Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs76
-rw-r--r--Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj7
-rw-r--r--Software/Visual_Studio/Tango.Transport/TransporterBase.cs18
4 files changed, 231 insertions, 8 deletions
diff --git a/Software/Visual_Studio/Tango.Transport/AutoProtobuf.cs b/Software/Visual_Studio/Tango.Transport/AutoProtobuf.cs
new file mode 100644
index 000000000..d028860b8
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Transport/AutoProtobuf.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using ProtoBuf.Meta;
+
+namespace Tango.Transport
+{
+ public static class AutoProtobuf
+ {
+ private const BindingFlags Flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ private static readonly Dictionary<Type, HashSet<Type>> SubTypes = new Dictionary<Type, HashSet<Type>>();
+ private static readonly ConcurrentBag<Type> BuiltTypes = new ConcurrentBag<Type>();
+ private static readonly Type ObjectType = typeof(object);
+
+ /// <summary>
+ /// Build the ProtoBuf serializer from the generic <see cref="Type">type</see>.
+ /// </summary>
+ /// <typeparam name="T">The type of build the serializer for.</typeparam>
+ public static void Build<T>()
+ {
+ var type = typeof(T);
+ Build(type);
+ }
+
+ /// <summary>
+ /// Build the ProtoBuf serializer from the data's <see cref="Type">type</see>.
+ /// </summary>
+ /// <typeparam name="T">The type of build the serializer for.</typeparam>
+ /// <param name="data">The data who's type a serializer will be made.</param>
+ // ReSharper disable once UnusedParameter.Global
+ public static void Build<T>(T data)
+ {
+ Build<T>();
+ }
+
+ /// <summary>
+ /// Build the ProtoBuf serializer for the <see cref="Type">type</see>.
+ /// </summary>
+ /// <param name="type">The type of build the serializer for.</param>
+ public static void Build(Type type)
+ {
+ if (BuiltTypes.Contains(type))
+ {
+ return;
+ }
+
+ lock (type)
+ {
+ if (RuntimeTypeModel.Default.CanSerialize(type))
+ {
+ if (type.IsGenericType)
+ {
+ BuildGenerics(type);
+ }
+
+ return;
+ }
+
+ var meta = RuntimeTypeModel.Default.Add(type, false);
+ var fields = GetFields(type);
+
+ meta.Add(fields.Select(m => m.Name).ToArray());
+ meta.UseConstructor = false;
+
+ BuildBaseClasses(type);
+ BuildGenerics(type);
+
+ foreach (var memberType in fields.Select(f => f.FieldType).Where(t => !t.IsPrimitive))
+ {
+ Build(memberType);
+ }
+
+ BuiltTypes.Add(type);
+ }
+ }
+
+ /// <summary>
+ /// Gets the fields for a type.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns></returns>
+ private static FieldInfo[] GetFields(Type type)
+ {
+ return type.GetFields(Flags);
+ }
+
+ /// <summary>
+ /// Builds the base class serializers for a type.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ private static void BuildBaseClasses(Type type)
+ {
+ var baseType = type.BaseType;
+ var inheritingType = type;
+
+
+ while (baseType != null && baseType != ObjectType)
+ {
+ HashSet<Type> baseTypeEntry;
+
+ if (!SubTypes.TryGetValue(baseType, out baseTypeEntry))
+ {
+ baseTypeEntry = new HashSet<Type>();
+ SubTypes.Add(baseType, baseTypeEntry);
+ }
+
+ if (!baseTypeEntry.Contains(inheritingType))
+ {
+ Build(baseType);
+ RuntimeTypeModel.Default[baseType].AddSubType(baseTypeEntry.Count + 500, inheritingType);
+ baseTypeEntry.Add(inheritingType);
+ }
+
+ inheritingType = baseType;
+ baseType = baseType.BaseType;
+ }
+ }
+
+ /// <summary>
+ /// Builds the serializers for the generic parameters for a given type.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ private static void BuildGenerics(Type type)
+ {
+ if (type.IsGenericType || (type.BaseType != null && type.BaseType.IsGenericType))
+ {
+ var generics = type.IsGenericType ? type.GetGenericArguments() : type.BaseType.GetGenericArguments();
+
+ foreach (var generic in generics)
+ {
+ Build(generic);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs b/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs
new file mode 100644
index 000000000..927300224
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs
@@ -0,0 +1,76 @@
+using Google.Protobuf;
+using ProtoBuf;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Transport
+{
+ public static class ProtoSerializer
+ {
+ static ProtoSerializer()
+ {
+ ProtoBuf.Meta.RuntimeTypeModel.Default.AutoAddMissingTypes = true;
+ ProtoBuf.Meta.RuntimeTypeModel.Default.AutoAddProtoContractTypesOnly = false;
+ ProtoBuf.Meta.RuntimeTypeModel.Default.InferTagFromNameDefault = true;
+ ProtoBuf.Meta.RuntimeTypeModel.Default.UseImplicitZeroDefaults = true;
+ }
+
+ public static object Deserialize(Type type, byte[] array)
+ {
+ AutoProtobuf.Build(type);
+
+ using (MemoryStream ms = new MemoryStream(array))
+ {
+ return Serializer.Deserialize(type, ms);
+ }
+ }
+
+ public static object DeserializeFromByteString(Type type, ByteString byteString)
+ {
+ AutoProtobuf.Build(type);
+
+ return Deserialize(type, byteString.ToByteArray());
+ }
+
+ //---------------------------------------------------------------------
+
+ public static byte[] Serialize<T>(T message)
+ {
+ AutoProtobuf.Build<T>();
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ Serializer.Serialize<T>(ms, message);
+ return ms.ToArray();
+ }
+ }
+
+ public static T Deserialize<T>(byte[] array)
+ {
+ AutoProtobuf.Build<T>();
+
+ using (MemoryStream ms = new MemoryStream(array))
+ {
+ return Serializer.Deserialize<T>(ms);
+ }
+ }
+
+ public static ByteString SerializeToByteString<T>(T message)
+ {
+ AutoProtobuf.Build<T>();
+
+ return ByteString.CopyFrom(Serialize<T>(message));
+ }
+
+ public static T DeserializeFromByteString<T>(ByteString byteString)
+ {
+ AutoProtobuf.Build<T>();
+
+ return Deserialize<T>(byteString.ToByteArray());
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj b/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj
index 260a1e4f7..8c71f80e7 100644
--- a/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj
+++ b/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj
@@ -41,6 +41,9 @@
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
+ <Reference Include="protobuf-net">
+ <HintPath>..\Referenced Assemblies\Protobuf-net\protobuf-net.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
@@ -83,6 +86,7 @@
<Compile Include="Adapters\TcpTransportAdapterWriteMode.cs" />
<Compile Include="Adapters\UsbSerialBaudRates.cs" />
<Compile Include="Adapters\UsbTransportAdapter.cs" />
+ <Compile Include="AutoProtobuf.cs" />
<Compile Include="Components\ComPortEnumerator.cs" />
<Compile Include="Compression\Common\CommandLineParser.cs" />
<Compile Include="Compression\Common\CRC.cs" />
@@ -121,6 +125,7 @@
<Compile Include="PendingResponse.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ITransporter.cs" />
+ <Compile Include="ProtoSerializer.cs" />
<Compile Include="RequestFailedEventArgs.cs" />
<Compile Include="ResponseErrorException.cs" />
<Compile Include="Routing\SimpleTransportRouter.cs" />
@@ -181,7 +186,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
+ <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
</VisualStudio>
</ProjectExtensions>
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
index 45b89f9ff..339473929 100644
--- a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
+++ b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
@@ -866,10 +866,11 @@ namespace Tango.Transport
public async Task<Response> SendGenericRequest<Request, Response>(Request request, TransportRequestConfig config = null) where Request : class where Response : class
{
GenericRequest genericRequest = new GenericRequest();
- genericRequest.Type = request.GetType().Name;
- genericRequest.Data = ByteString.CopyFromUtf8(JsonConvert.SerializeObject(request, _genericMessageSettings));
+ genericRequest.Type = request.GetType().AssemblyQualifiedName;
+ genericRequest.Data = ProtoSerializer.SerializeToByteString<Request>(request);
+
var response = await SendRequest<GenericRequest, GenericResponse>(genericRequest, config);
- var responseObject = JsonConvert.DeserializeObject<Response>(response.Message.Data.ToStringUtf8());
+ var responseObject = ProtoSerializer.DeserializeFromByteString<Response>(response.Message.Data);
return responseObject;
}
@@ -884,7 +885,9 @@ namespace Tango.Transport
public async Task SendGenericResponse<Response>(Response response, String token, TransportResponseConfig config = null) where Response : class
{
GenericResponse genericResponse = new GenericResponse();
- genericResponse.Data = ByteString.CopyFromUtf8(JsonConvert.SerializeObject(response, _genericMessageSettings));
+
+ genericResponse.Data = ProtoSerializer.SerializeToByteString<Response>(response);
+
await SendResponse<GenericResponse>(genericResponse, token, config);
}
@@ -898,8 +901,9 @@ namespace Tango.Transport
public IObservable<Response> SendGenericContinuousRequest<Request, Response>(Request request, TransportContinuousRequestConfig config = null) where Request : class where Response : class
{
GenericRequest genericRequest = new GenericRequest();
- genericRequest.Type = request.GetType().Name;
- genericRequest.Data = ByteString.CopyFromUtf8(JsonConvert.SerializeObject(request, _genericMessageSettings));
+ genericRequest.Type = request.GetType().AssemblyQualifiedName;
+
+ genericRequest.Data = ProtoSerializer.SerializeToByteString<Request>(request);
Subject<Response> subject = new Subject<Response>();
@@ -908,7 +912,7 @@ namespace Tango.Transport
try
{
- var responseObject = JsonConvert.DeserializeObject<Response>(response.Message.Data.ToStringUtf8());
+ var responseObject = ProtoSerializer.DeserializeFromByteString<Response>(response.Message.Data);
subject.OnNext(responseObject);
}
catch (Exception ex)