diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-03-05 01:22:04 +0200 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-03-05 01:22:04 +0200 |
| commit | 574f075256fbadd2dadb769c5aff5ebfd6dedd56 (patch) | |
| tree | ff3a10d9163899a730182cbba020810bc85e5259 /Software/Visual_Studio/Tango.Transport | |
| parent | e03ca60e3efeb8466f47c30920f6ab36306b3f74 (diff) | |
| download | Tango-574f075256fbadd2dadb769c5aff5ebfd6dedd56.tar.gz Tango-574f075256fbadd2dadb769c5aff5ebfd6dedd56.zip | |
Switched generic messages to Protobuf-net.
Diffstat (limited to 'Software/Visual_Studio/Tango.Transport')
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) |
