Browse Source

Added .Net Core RC2 Support

pull/73/merge
Voltana 9 years ago
parent
commit
cd3d90ea80
26 changed files with 1056 additions and 1077 deletions
  1. +3
    -3
      global.json
  2. +3
    -3
      src/Discord.Net.Audio/Discord.Net.Audio.xproj
  3. +6
    -7
      src/Discord.Net.Audio/Net/VoiceSocket.cs
  4. +21
    -11
      src/Discord.Net.Audio/project.json
  5. +3
    -3
      src/Discord.Net.Commands/Discord.Net.Commands.xproj
  6. +20
    -10
      src/Discord.Net.Commands/project.json
  7. +3
    -3
      src/Discord.Net.Modules/Discord.Net.Modules.xproj
  8. +20
    -10
      src/Discord.Net.Modules/project.json
  9. +0
    -3
      src/Discord.Net.Net45/Discord.Net.csproj
  10. +3
    -3
      src/Discord.Net/Discord.Net.xproj
  11. +9
    -6
      src/Discord.Net/DiscordClient.cs
  12. +466
    -466
      src/Discord.Net/ETF/ETFReader.cs
  13. +447
    -447
      src/Discord.Net/ETF/ETFWriter.cs
  14. +6
    -6
      src/Discord.Net/Logging/ILogger.cs
  15. +2
    -2
      src/Discord.Net/Logging/LogManager.cs
  16. +1
    -1
      src/Discord.Net/Logging/Logger.cs
  17. +1
    -1
      src/Discord.Net/Net/Rest/BuiltInEngine.cs
  18. +0
    -27
      src/Discord.Net/Net/Rest/ETFRestClient.cs
  19. +1
    -2
      src/Discord.Net/Net/Rest/RestClient.cs
  20. +1
    -1
      src/Discord.Net/Net/Rest/SharpRestEngine.cs
  21. +2
    -2
      src/Discord.Net/Net/WebSockets/BuiltInEngine.cs
  22. +1
    -1
      src/Discord.Net/Net/WebSockets/WS4NetEngine.cs
  23. +1
    -1
      src/Discord.Net/Net/WebSockets/WebSocket.cs
  24. +32
    -54
      src/Discord.Net/project.json
  25. +3
    -3
      test/Discord.Net.Tests/Discord.Net.Tests.csproj
  26. +1
    -1
      test/Discord.Net.Tests/Tests.cs

+ 3
- 3
global.json View File

@@ -1,6 +1,6 @@
{
"projects": [ "src" ],
"sdk": {
"version": "1.0.0-rc1-update1"
}
"sdk": {
"version": "1.0.0-preview1-002702"
}
}

+ 3
- 3
src/Discord.Net.Audio/Discord.Net.Audio.xproj View File

@@ -4,12 +4,12 @@
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>dff7afe3-ca77-4109-bade-b4b49a4f6648</ProjectGuid>
<RootNamespace>Discord.Audio</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
@@ -17,5 +17,5 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

+ 6
- 7
src/Discord.Net.Audio/Net/VoiceSocket.cs View File

@@ -120,7 +120,7 @@ namespace Discord.Net.WebSockets

SendIdentify(_userId.Value, _sessionId);

#if !DOTNET5_4
#if !NETSTANDARD1_3
tasks.Add(WatcherAsync());
#endif
tasks.AddRange(_engine.GetTasks(CancelToken));
@@ -178,7 +178,7 @@ namespace Discord.Net.WebSockets
await Task.Delay(1).ConfigureAwait(false);
if (_udp.Available > 0)
{
#if !DOTNET5_4
#if !NETSTANDARD1_3
packet = _udp.Receive(ref endpoint);
#else
//TODO: Is this really the only way to end a Receive call in DOTNET5_4?
@@ -346,7 +346,7 @@ namespace Discord.Net.WebSockets
{
try
{
_udp.Send(voicePacket, rtpPacketLength);
await _udp.SendAsync(voicePacket, rtpPacketLength, _endpoint).ConfigureAwait(false);
}
catch (SocketException ex)
{
@@ -371,7 +371,7 @@ namespace Discord.Net.WebSockets
break;
}
}
await _udp.SendAsync(pingPacket, pingPacket.Length).ConfigureAwait(false);
await _udp.SendAsync(pingPacket, pingPacket.Length, _endpoint).ConfigureAwait(false);
nextPingTicks = currentTicks + 5 * ticksPerSeconds;
}
}
@@ -391,7 +391,7 @@ namespace Discord.Net.WebSockets
catch (OperationCanceledException) { }
catch (InvalidOperationException) { } //Includes ObjectDisposedException
}
#if !DOTNET5_4
#if !NETSTANDARD1_3
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken
private async Task WatcherAsync()
{
@@ -437,7 +437,6 @@ namespace Discord.Net.WebSockets
_encryptionMode = UnencryptedMode;
_isEncrypted = false;
}
_udp.Connect(_endpoint);

_sequence = 0;// (ushort)_rand.Next(0, ushort.MaxValue);
//No thread issue here because SendAsync doesn't start until _isReady is true
@@ -446,7 +445,7 @@ namespace Discord.Net.WebSockets
packet[1] = (byte)(_ssrc >> 16);
packet[2] = (byte)(_ssrc >> 8);
packet[3] = (byte)(_ssrc >> 0);
await _udp.SendAsync(packet, 70).ConfigureAwait(false);
await _udp.SendAsync(packet, 70, _endpoint).ConfigureAwait(false);
}
}
break;


+ 21
- 11
src/Discord.Net.Audio/project.json View File

@@ -2,26 +2,36 @@
"version": "0.9.1",
"description": "A Discord.Net extension adding voice support.",
"authors": [ "RogueException" ],
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
"packOptions": {
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
},
"contentFiles": [ "libsodium.dll", "opus.dll" ]
},
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],
"contentFiles": [ "libsodium.dll", "opus.dll" ],

"compilationOptions": {
"buildOptions": {
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],
"preserveCompilationContext": true,
"allowUnsafe": true,
"warningsAsErrors": true
},

"dependencies": {
"NETStandard.Library": "1.5.0-rc2-24027",
"Discord.Net": "0.9.1"
},
"frameworks": {
"net45": { },
"dotnet5.4": { }
"netstandard1.3": {
"imports": [
"dotnet5.4",
"dnxcore50",
"portable-net45+win8"
]
}
}
}

+ 3
- 3
src/Discord.Net.Commands/Discord.Net.Commands.xproj View File

@@ -4,12 +4,12 @@
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>19793545-ef89-48f4-8100-3ebaad0a9141</ProjectGuid>
<RootNamespace>Discord.Commands</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
@@ -17,5 +17,5 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

+ 20
- 10
src/Discord.Net.Commands/project.json View File

@@ -2,24 +2,34 @@
"version": "0.9.1",
"description": "A Discord.Net extension adding basic command support.",
"authors": [ "RogueException" ],
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"

"packOptions": {
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
}
},
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],

"compilationOptions": {
"buildOptions": {
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],
"preserveCompilationContext": true,
"warningsAsErrors": true
},

"dependencies": {
"NETStandard.Library": "1.5.0-rc2-24027",
"Discord.Net": "0.9.1"
},
"frameworks": {
"net45": { },
"dotnet5.4": { }
"netstandard1.3": {
"imports": [
"dotnet5.4",
"dnxcore50",
"portable-net45+win8"
]
}
}
}

+ 3
- 3
src/Discord.Net.Modules/Discord.Net.Modules.xproj View File

@@ -4,12 +4,12 @@
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>01584e8a-78da-486f-9ef9-a894e435841b</ProjectGuid>
<RootNamespace>Discord.Modules</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
@@ -17,5 +17,5 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

+ 20
- 10
src/Discord.Net.Modules/project.json View File

@@ -2,25 +2,35 @@
"version": "0.9.1",
"description": "A Discord.Net extension adding basic plugin support.",
"authors": [ "RogueException" ],
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"

"packOptions": {
"tags": [ "discord", "discordapp" ],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
}
},
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],

"compilationOptions": {
"buildOptions": {
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],
"preserveCompilationContext": true,
"warningsAsErrors": true
},

"dependencies": {
"NETStandard.Library": "1.5.0-rc2-24027",
"Discord.Net": "0.9.1",
"Discord.Net.Commands": "0.9.1"
},
"frameworks": {
"net45": { },
"dotnet5.4": { }
"netstandard1.3": {
"imports": [
"dotnet5.4",
"dnxcore50",
"portable-net45+win8"
]
}
}
}

+ 0
- 3
src/Discord.Net.Net45/Discord.Net.csproj View File

@@ -550,9 +550,6 @@
<Compile Include="..\Discord.Net\Net\Rest\CompletedRequestEventArgs.cs">
<Link>Net\Rest\CompletedRequestEventArgs.cs</Link>
</Compile>
<Compile Include="..\Discord.Net\Net\Rest\ETFRestClient.cs">
<Link>Net\Rest\ETFRestClient.cs</Link>
</Compile>
<Compile Include="..\Discord.Net\Net\Rest\IRestEngine.cs">
<Link>Net\Rest\IRestEngine.cs</Link>
</Compile>


+ 3
- 3
src/Discord.Net/Discord.Net.xproj View File

@@ -4,12 +4,12 @@
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>acfb060b-ec8a-4926-b293-04c01e17ee23</ProjectGuid>
<RootNamespace>Discord</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
@@ -17,5 +17,5 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

+ 9
- 6
src/Discord.Net/DiscordClient.cs View File

@@ -243,12 +243,15 @@ namespace Discord
}

ClientAPI.Token = token;
var request = new LoginRequest() { Email = email, Password = password };
var response = await ClientAPI.Send(request).ConfigureAwait(false);
token = response.Token;
if (Config.CacheDir != null && token != oldToken && tokenPath != null)
SaveToken(tokenPath, cacheKey, token);
ClientAPI.Token = token;
if (email != null && password != null)
{
var request = new LoginRequest() { Email = email, Password = password };
var response = await ClientAPI.Send(request).ConfigureAwait(false);
token = response.Token;
if (Config.CacheDir != null && token != oldToken && tokenPath != null)
SaveToken(tokenPath, cacheKey, token);
ClientAPI.Token = token;
}

//Cache other stuff
var regionsResponse = (await ClientAPI.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false));


+ 466
- 466
src/Discord.Net/ETF/ETFReader.cs View File

@@ -1,491 +1,491 @@
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
//using Newtonsoft.Json;
//using System;
//using System.Collections.Concurrent;
//using System.Collections.Generic;
//using System.IO;
//using System.Linq;
//using System.Reflection;
//using System.Reflection.Emit;
//using System.Text;

namespace Discord.ETF
{
public class ETFReader : IDisposable
{
private static readonly ConcurrentDictionary<Type, Delegate> _deserializers = new ConcurrentDictionary<Type, Delegate>();
private static readonly Dictionary<Type, MethodInfo> _readMethods = GetPrimitiveReadMethods();
//namespace Discord.ETF
//{
// public class ETFReader : IDisposable
// {
// private static readonly ConcurrentDictionary<Type, Delegate> _deserializers = new ConcurrentDictionary<Type, Delegate>();
// private static readonly Dictionary<Type, MethodInfo> _readMethods = GetPrimitiveReadMethods();

private readonly Stream _stream;
private readonly byte[] _buffer;
private readonly bool _leaveOpen;
private readonly Encoding _encoding;
// private readonly Stream _stream;
// private readonly byte[] _buffer;
// private readonly bool _leaveOpen;
// private readonly Encoding _encoding;
public ETFReader(Stream stream, bool leaveOpen = false)
{
if (stream == null) throw new ArgumentNullException(nameof(stream));
// public ETFReader(Stream stream, bool leaveOpen = false)
// {
// if (stream == null) throw new ArgumentNullException(nameof(stream));

_stream = stream;
_leaveOpen = leaveOpen;
_buffer = new byte[11];
_encoding = Encoding.UTF8;
}
// _stream = stream;
// _leaveOpen = leaveOpen;
// _buffer = new byte[11];
// _encoding = Encoding.UTF8;
// }
public bool ReadBool()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT)
{
_stream.Read(_buffer, 0, 1);
switch (_buffer[0]) //Length
{
case 4:
ReadTrue();
return true;
case 5:
ReadFalse();
return false;
}
}
throw new InvalidDataException();
}
private void ReadTrue()
{
_stream.Read(_buffer, 0, 4);
if (_buffer[0] != 't' || _buffer[1] != 'r' || _buffer[2] != 'u' || _buffer[3] != 'e')
throw new InvalidDataException();
}
private void ReadFalse()
{
_stream.Read(_buffer, 0, 5);
if (_buffer[0] != 'f' || _buffer[1] != 'a' || _buffer[2] != 'l' || _buffer[3] != 's' || _buffer[4] != 'e')
throw new InvalidDataException();
}
// public bool ReadBool()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT)
// {
// _stream.Read(_buffer, 0, 1);
// switch (_buffer[0]) //Length
// {
// case 4:
// ReadTrue();
// return true;
// case 5:
// ReadFalse();
// return false;
// }
// }
// throw new InvalidDataException();
// }
// private void ReadTrue()
// {
// _stream.Read(_buffer, 0, 4);
// if (_buffer[0] != 't' || _buffer[1] != 'r' || _buffer[2] != 'u' || _buffer[3] != 'e')
// throw new InvalidDataException();
// }
// private void ReadFalse()
// {
// _stream.Read(_buffer, 0, 5);
// if (_buffer[0] != 'f' || _buffer[1] != 'a' || _buffer[2] != 'l' || _buffer[3] != 's' || _buffer[4] != 'e')
// throw new InvalidDataException();
// }

public int ReadSByte()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (sbyte)ReadLongInternal(type);
}
public uint ReadByte()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (byte)ReadLongInternal(type);
}
public int ReadShort()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (short)ReadLongInternal(type);
}
public uint ReadUShort()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (ushort)ReadLongInternal(type);
}
public int ReadInt()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (int)ReadLongInternal(type);
}
public uint ReadUInt()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (uint)ReadLongInternal(type);
}
public long ReadLong()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return ReadLongInternal(type);
}
public ulong ReadULong()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (ulong)ReadLongInternal(type);
}
public long ReadLongInternal(ETFType type)
{
switch (type)
{
case ETFType.SMALL_INTEGER_EXT:
_stream.Read(_buffer, 0, 1);
return _buffer[0];
case ETFType.INTEGER_EXT:
_stream.Read(_buffer, 0, 4);
return (_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | (_buffer[3]);
case ETFType.SMALL_BIG_EXT:
_stream.Read(_buffer, 0, 2);
bool isPositive = _buffer[0] == 0;
byte count = _buffer[1];
// public int ReadSByte()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (sbyte)ReadLongInternal(type);
// }
// public uint ReadByte()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (byte)ReadLongInternal(type);
// }
// public int ReadShort()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (short)ReadLongInternal(type);
// }
// public uint ReadUShort()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (ushort)ReadLongInternal(type);
// }
// public int ReadInt()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (int)ReadLongInternal(type);
// }
// public uint ReadUInt()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (uint)ReadLongInternal(type);
// }
// public long ReadLong()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return ReadLongInternal(type);
// }
// public ulong ReadULong()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (ulong)ReadLongInternal(type);
// }
// public long ReadLongInternal(ETFType type)
// {
// switch (type)
// {
// case ETFType.SMALL_INTEGER_EXT:
// _stream.Read(_buffer, 0, 1);
// return _buffer[0];
// case ETFType.INTEGER_EXT:
// _stream.Read(_buffer, 0, 4);
// return (_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | (_buffer[3]);
// case ETFType.SMALL_BIG_EXT:
// _stream.Read(_buffer, 0, 2);
// bool isPositive = _buffer[0] == 0;
// byte count = _buffer[1];

int shiftValue = (count - 1) * 8;
ulong value = 0;
_stream.Read(_buffer, 0, count);
for (int i = 0; i < count; i++, shiftValue -= 8)
value = value + _buffer[i] << shiftValue;
if (!isPositive)
return -(long)value;
else
return (long)value;
}
throw new InvalidDataException();
}
// int shiftValue = (count - 1) * 8;
// ulong value = 0;
// _stream.Read(_buffer, 0, count);
// for (int i = 0; i < count; i++, shiftValue -= 8)
// value = value + _buffer[i] << shiftValue;
// if (!isPositive)
// return -(long)value;
// else
// return (long)value;
// }
// throw new InvalidDataException();
// }

public float ReadSingle()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return (float)ReadDoubleInternal(type);
}
public double ReadDouble()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
return ReadDoubleInternal(type);
}
public double ReadDoubleInternal(ETFType type)
{
throw new NotImplementedException();
}
// public float ReadSingle()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return (float)ReadDoubleInternal(type);
// }
// public double ReadDouble()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// return ReadDoubleInternal(type);
// }
// public double ReadDoubleInternal(ETFType type)
// {
// throw new NotImplementedException();
// }

public bool? ReadNullableBool()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT)
{
_stream.Read(_buffer, 0, 1);
switch (_buffer[0]) //Length
{
case 3:
if (ReadNil())
return null;
break;
case 4:
ReadTrue();
return true;
case 5:
ReadFalse();
return false;
}
}
throw new InvalidDataException();
}
public int? ReadNullableSByte()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (sbyte)ReadLongInternal(type);
}
public uint? ReadNullableByte()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (byte)ReadLongInternal(type);
}
public int? ReadNullableShort()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (short)ReadLongInternal(type);
}
public uint? ReadNullableUShort()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (ushort)ReadLongInternal(type);
}
public int? ReadNullableInt()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (int)ReadLongInternal(type);
}
public uint? ReadNullableUInt()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (uint)ReadLongInternal(type);
}
public long? ReadNullableLong()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return ReadLongInternal(type);
}
public ulong? ReadNullableULong()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (ulong)ReadLongInternal(type);
}
public float? ReadNullableSingle()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return (float)ReadDoubleInternal(type);
}
public double? ReadNullableDouble()
{
_stream.Read(_buffer, 0, 1);
ETFType type = (ETFType)_buffer[0];
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
return ReadDoubleInternal(type);
}
// public bool? ReadNullableBool()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT)
// {
// _stream.Read(_buffer, 0, 1);
// switch (_buffer[0]) //Length
// {
// case 3:
// if (ReadNil())
// return null;
// break;
// case 4:
// ReadTrue();
// return true;
// case 5:
// ReadFalse();
// return false;
// }
// }
// throw new InvalidDataException();
// }
// public int? ReadNullableSByte()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (sbyte)ReadLongInternal(type);
// }
// public uint? ReadNullableByte()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (byte)ReadLongInternal(type);
// }
// public int? ReadNullableShort()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (short)ReadLongInternal(type);
// }
// public uint? ReadNullableUShort()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (ushort)ReadLongInternal(type);
// }
// public int? ReadNullableInt()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (int)ReadLongInternal(type);
// }
// public uint? ReadNullableUInt()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (uint)ReadLongInternal(type);
// }
// public long? ReadNullableLong()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return ReadLongInternal(type);
// }
// public ulong? ReadNullableULong()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (ulong)ReadLongInternal(type);
// }
// public float? ReadNullableSingle()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return (float)ReadDoubleInternal(type);
// }
// public double? ReadNullableDouble()
// {
// _stream.Read(_buffer, 0, 1);
// ETFType type = (ETFType)_buffer[0];
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null;
// return ReadDoubleInternal(type);
// }

public string ReadString()
{
throw new NotImplementedException();
}
public byte[] ReadByteArray()
{
throw new NotImplementedException();
}
// public string ReadString()
// {
// throw new NotImplementedException();
// }
// public byte[] ReadByteArray()
// {
// throw new NotImplementedException();
// }

public T Read<T>()
where T : new()
{
var type = typeof(T);
var typeInfo = type.GetTypeInfo();
var action = _deserializers.GetOrAdd(type, _ => CreateDeserializer<T>(type, typeInfo)) as Func<ETFReader, T>;
return action(this);
}
/*public void Read<T, U>()
where T : Nullable<T>
where U : struct, new()
{
}*/
public T[] ReadArray<T>()
{
throw new NotImplementedException();
}
public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>()
{
throw new NotImplementedException();
}
/*public object Read(object obj)
{
throw new NotImplementedException();
}*/
// public T Read<T>()
// where T : new()
// {
// var type = typeof(T);
// var typeInfo = type.GetTypeInfo();
// var action = _deserializers.GetOrAdd(type, _ => CreateDeserializer<T>(type, typeInfo)) as Func<ETFReader, T>;
// return action(this);
// }
// /*public void Read<T, U>()
// where T : Nullable<T>
// where U : struct, new()
// {
// }*/
// public T[] ReadArray<T>()
// {
// throw new NotImplementedException();
// }
// public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>()
// {
// throw new NotImplementedException();
// }
// /*public object Read(object obj)
// {
// throw new NotImplementedException();
// }*/

private bool ReadNil(bool ignoreLength = false)
{
if (!ignoreLength)
{
_stream.Read(_buffer, 0, 1);
byte length = _buffer[0];
if (length != 3) return false;
}
// private bool ReadNil(bool ignoreLength = false)
// {
// if (!ignoreLength)
// {
// _stream.Read(_buffer, 0, 1);
// byte length = _buffer[0];
// if (length != 3) return false;
// }

_stream.Read(_buffer, 0, 3);
if (_buffer[0] == 'n' && _buffer[1] == 'i' && _buffer[2] == 'l')
return true;
// _stream.Read(_buffer, 0, 3);
// if (_buffer[0] == 'n' && _buffer[1] == 'i' && _buffer[2] == 'l')
// return true;

return false;
}
// return false;
// }

#region Emit
private static Func<ETFReader, T> CreateDeserializer<T>(Type type, TypeInfo typeInfo)
where T : new()
{
var method = new DynamicMethod("DeserializeETF", type, new[] { typeof(ETFReader) }, true);
var generator = method.GetILGenerator();
// #region Emit
// private static Func<ETFReader, T> CreateDeserializer<T>(Type type, TypeInfo typeInfo)
// where T : new()
// {
// var method = new DynamicMethod("DeserializeETF", type, new[] { typeof(ETFReader) }, true);
// var generator = method.GetILGenerator();

generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
EmitReadValue(generator, type, typeInfo, true);
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
// EmitReadValue(generator, type, typeInfo, true);

generator.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Func<ETFReader, T>)) as Func<ETFReader, T>;
}
private static void EmitReadValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop)
{
//Convert enum types to their base type
if (typeInfo.IsEnum)
{
type = Enum.GetUnderlyingType(type);
typeInfo = type.GetTypeInfo();
}
//Primitives/Enums
if (!typeInfo.IsEnum && IsType(type, typeof(sbyte), typeof(byte), typeof(short),
typeof(ushort), typeof(int), typeof(uint), typeof(long),
typeof(ulong), typeof(double), typeof(bool), typeof(string),
typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?),
typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?),
typeof(bool?), typeof(float?), typeof(double?)
/*typeof(object), typeof(DateTime)*/))
{
//No conversion needed
generator.EmitCall(OpCodes.Call, GetReadMethod(type), null);
}
//Dictionaries
/*else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{
generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Enumerable
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Nullable Structs
else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) &&
typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType)
{
generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Structs/Classes
else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive))
{
if (isTop)
{
typeInfo.ForEachField(f =>
{
string name;
if (!f.IsPublic || !IsETFProperty(f, out name)) return;
// generator.Emit(OpCodes.Ret);
// return method.CreateDelegate(typeof(Func<ETFReader, T>)) as Func<ETFReader, T>;
// }
// private static void EmitReadValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop)
// {
// //Convert enum types to their base type
// if (typeInfo.IsEnum)
// {
// type = Enum.GetUnderlyingType(type);
// typeInfo = type.GetTypeInfo();
// }
// //Primitives/Enums
// if (!typeInfo.IsEnum && IsType(type, typeof(sbyte), typeof(byte), typeof(short),
// typeof(ushort), typeof(int), typeof(uint), typeof(long),
// typeof(ulong), typeof(double), typeof(bool), typeof(string),
// typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?),
// typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?),
// typeof(bool?), typeof(float?), typeof(double?)
// /*typeof(object), typeof(DateTime)*/))
// {
// //No conversion needed
// generator.EmitCall(OpCodes.Call, GetReadMethod(type), null);
// }
// //Dictionaries
// /*else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
// {
// generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Enumerable
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
// {
// generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Nullable Structs
// else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) &&
// typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType)
// {
// generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Structs/Classes
// else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive))
// {
// if (isTop)
// {
// typeInfo.ForEachField(f =>
// {
// string name;
// if (!f.IsPublic || !IsETFProperty(f, out name)) return;

generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj
generator.Emit(OpCodes.Ldfld, f); //ETFReader(this), obj.fieldValue
EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false);
});
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
// generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
// generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj
// generator.Emit(OpCodes.Ldfld, f); //ETFReader(this), obj.fieldValue
// EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false);
// });

typeInfo.ForEachProperty(p =>
{
string name;
if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return;
// typeInfo.ForEachProperty(p =>
// {
// string name;
// if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return;

generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj
generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFReader(this), obj.propValue
EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false);
});
}
else
{
//While we could drill deeper and make a large serializer that also serializes all subclasses,
//it's more efficient to serialize on a per-type basis via another Write<T> call.
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
}*/
//Unsupported (decimal, char)
else
throw new InvalidOperationException($"Deserializing {type.Name} is not supported.");
}
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
// generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this)
// generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj
// generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFReader(this), obj.propValue
// EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false);
// });
// }
// else
// {
// //While we could drill deeper and make a large serializer that also serializes all subclasses,
// //it's more efficient to serialize on a per-type basis via another Write<T> call.
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// }*/
// //Unsupported (decimal, char)
// else
// throw new InvalidOperationException($"Deserializing {type.Name} is not supported.");
// }

private static bool IsType(Type type, params Type[] types)
{
for (int i = 0; i < types.Length; i++)
{
if (type == types[i])
return true;
}
return false;
}
private static bool IsETFProperty(FieldInfo f, out string name)
{
var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
if (attrib != null)
{
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name;
return true;
}
name = null;
return false;
}
private static bool IsETFProperty(PropertyInfo p, out string name)
{
var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
if (attrib != null)
{
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name;
return true;
}
name = null;
return false;
}
// private static bool IsType(Type type, params Type[] types)
// {
// for (int i = 0; i < types.Length; i++)
// {
// if (type == types[i])
// return true;
// }
// return false;
// }
// private static bool IsETFProperty(FieldInfo f, out string name)
// {
// var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
// if (attrib != null)
// {
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name;
// return true;
// }
// name = null;
// return false;
// }
// private static bool IsETFProperty(PropertyInfo p, out string name)
// {
// var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
// if (attrib != null)
// {
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name;
// return true;
// }
// name = null;
// return false;
// }

private static MethodInfo GetReadMethod(string name)
=> typeof(ETFReader).GetTypeInfo().GetDeclaredMethods(name).Single();
private static MethodInfo GetReadMethod(Type type)
{
MethodInfo method;
if (_readMethods.TryGetValue(type, out method))
return method;
return null;
}
private static Dictionary<Type, MethodInfo> GetPrimitiveReadMethods()
{
return new Dictionary<Type, MethodInfo>
{
{ typeof(bool), GetReadMethod(nameof(ReadBool)) },
{ typeof(bool?), GetReadMethod(nameof(ReadNullableBool)) },
{ typeof(byte), GetReadMethod(nameof(ReadByte)) },
{ typeof(byte?), GetReadMethod(nameof(ReadNullableByte)) },
{ typeof(sbyte), GetReadMethod(nameof(ReadSByte)) },
{ typeof(sbyte?), GetReadMethod(nameof(ReadNullableSByte)) },
{ typeof(short), GetReadMethod(nameof(ReadShort)) },
{ typeof(short?), GetReadMethod(nameof(ReadNullableShort)) },
{ typeof(ushort), GetReadMethod(nameof(ReadUShort)) },
{ typeof(ushort?), GetReadMethod(nameof(ReadNullableUShort)) },
{ typeof(int), GetReadMethod(nameof(ReadInt)) },
{ typeof(int?), GetReadMethod(nameof(ReadNullableInt)) },
{ typeof(uint), GetReadMethod(nameof(ReadUInt)) },
{ typeof(uint?), GetReadMethod(nameof(ReadNullableUInt)) },
{ typeof(long), GetReadMethod(nameof(ReadLong)) },
{ typeof(long?), GetReadMethod(nameof(ReadNullableLong)) },
{ typeof(ulong), GetReadMethod(nameof(ReadULong)) },
{ typeof(ulong?), GetReadMethod(nameof(ReadNullableULong)) },
{ typeof(float), GetReadMethod(nameof(ReadSingle)) },
{ typeof(float?), GetReadMethod(nameof(ReadNullableSingle)) },
{ typeof(double), GetReadMethod(nameof(ReadDouble)) },
{ typeof(double?), GetReadMethod(nameof(ReadNullableDouble)) },
};
}
#endregion
// private static MethodInfo GetReadMethod(string name)
// => typeof(ETFReader).GetTypeInfo().GetDeclaredMethods(name).Single();
// private static MethodInfo GetReadMethod(Type type)
// {
// MethodInfo method;
// if (_readMethods.TryGetValue(type, out method))
// return method;
// return null;
// }
// private static Dictionary<Type, MethodInfo> GetPrimitiveReadMethods()
// {
// return new Dictionary<Type, MethodInfo>
// {
// { typeof(bool), GetReadMethod(nameof(ReadBool)) },
// { typeof(bool?), GetReadMethod(nameof(ReadNullableBool)) },
// { typeof(byte), GetReadMethod(nameof(ReadByte)) },
// { typeof(byte?), GetReadMethod(nameof(ReadNullableByte)) },
// { typeof(sbyte), GetReadMethod(nameof(ReadSByte)) },
// { typeof(sbyte?), GetReadMethod(nameof(ReadNullableSByte)) },
// { typeof(short), GetReadMethod(nameof(ReadShort)) },
// { typeof(short?), GetReadMethod(nameof(ReadNullableShort)) },
// { typeof(ushort), GetReadMethod(nameof(ReadUShort)) },
// { typeof(ushort?), GetReadMethod(nameof(ReadNullableUShort)) },
// { typeof(int), GetReadMethod(nameof(ReadInt)) },
// { typeof(int?), GetReadMethod(nameof(ReadNullableInt)) },
// { typeof(uint), GetReadMethod(nameof(ReadUInt)) },
// { typeof(uint?), GetReadMethod(nameof(ReadNullableUInt)) },
// { typeof(long), GetReadMethod(nameof(ReadLong)) },
// { typeof(long?), GetReadMethod(nameof(ReadNullableLong)) },
// { typeof(ulong), GetReadMethod(nameof(ReadULong)) },
// { typeof(ulong?), GetReadMethod(nameof(ReadNullableULong)) },
// { typeof(float), GetReadMethod(nameof(ReadSingle)) },
// { typeof(float?), GetReadMethod(nameof(ReadNullableSingle)) },
// { typeof(double), GetReadMethod(nameof(ReadDouble)) },
// { typeof(double?), GetReadMethod(nameof(ReadNullableDouble)) },
// };
// }
// #endregion

#region IDisposable
private bool _isDisposed = false;
// #region IDisposable
// private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if (_leaveOpen)
_stream.Flush();
else
_stream.Dispose();
}
_isDisposed = true;
}
}
// protected virtual void Dispose(bool disposing)
// {
// if (!_isDisposed)
// {
// if (disposing)
// {
// if (_leaveOpen)
// _stream.Flush();
// else
// _stream.Dispose();
// }
// _isDisposed = true;
// }
// }

public void Dispose() => Dispose(true);
#endregion
}
}
// public void Dispose() => Dispose(true);
// #endregion
// }
//}

+ 447
- 447
src/Discord.Net/ETF/ETFWriter.cs View File

@@ -1,482 +1,482 @@
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
//using Newtonsoft.Json;
//using System;
//using System.Collections.Concurrent;
//using System.Collections.Generic;
//using System.IO;
//using System.Linq;
//using System.Reflection;
//using System.Reflection.Emit;
//using System.Text;

namespace Discord.ETF
{
public unsafe class ETFWriter : IDisposable
{
private static readonly ConcurrentDictionary<Type, Delegate> _serializers = new ConcurrentDictionary<Type, Delegate>();
private static readonly ConcurrentDictionary<Type, Delegate> _indirectSerializers = new ConcurrentDictionary<Type, Delegate>();
//namespace Discord.ETF
//{
// public unsafe class ETFWriter : IDisposable
// {
// private static readonly ConcurrentDictionary<Type, Delegate> _serializers = new ConcurrentDictionary<Type, Delegate>();
// private static readonly ConcurrentDictionary<Type, Delegate> _indirectSerializers = new ConcurrentDictionary<Type, Delegate>();

private static readonly byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' };
private static readonly byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' };
private static readonly byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' };
// private static readonly byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' };
// private static readonly byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' };
// private static readonly byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' };

private static readonly MethodInfo _writeTMethod = GetGenericWriteMethod(null);
private static readonly MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>));
private static readonly MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>));
private static readonly MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>));
private static readonly DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
// private static readonly MethodInfo _writeTMethod = GetGenericWriteMethod(null);
// private static readonly MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>));
// private static readonly MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>));
// private static readonly MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>));
// private static readonly DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

private readonly Stream _stream;
private readonly byte[] _buffer;
private readonly bool _leaveOpen;
private readonly Encoding _encoding;
// private readonly Stream _stream;
// private readonly byte[] _buffer;
// private readonly bool _leaveOpen;
// private readonly Encoding _encoding;

public virtual Stream BaseStream
{
get
{
Flush();
return _stream;
}
}
// public virtual Stream BaseStream
// {
// get
// {
// Flush();
// return _stream;
// }
// }
public ETFWriter(Stream stream, bool leaveOpen = false)
{
if (stream == null) throw new ArgumentNullException(nameof(stream));
// public ETFWriter(Stream stream, bool leaveOpen = false)
// {
// if (stream == null) throw new ArgumentNullException(nameof(stream));

_stream = stream;
_leaveOpen = leaveOpen;
_buffer = new byte[11];
_encoding = Encoding.UTF8;
}
// _stream = stream;
// _leaveOpen = leaveOpen;
// _buffer = new byte[11];
// _encoding = Encoding.UTF8;
// }
public void Write(bool value)
{
if (value)
_stream.Write(_trueBytes, 0, _trueBytes.Length);
else
_stream.Write(_falseBytes, 0, _falseBytes.Length);
}
public void Write(sbyte value) => Write((long)value);
public void Write(byte value) => Write((ulong)value);
public void Write(short value) => Write((long)value);
public void Write(ushort value) => Write((ulong)value);
public void Write(int value) => Write((long)value);
public void Write(uint value) => Write((ulong)value);
public void Write(long value)
{
if (value >= byte.MinValue && value <= byte.MaxValue)
{
_buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT;
_buffer[1] = (byte)value;
_stream.Write(_buffer, 0, 2);
}
else if (value >= int.MinValue && value <= int.MaxValue)
{
//TODO: Does this encode negatives correctly?
_buffer[0] = (byte)ETFType.INTEGER_EXT;
_buffer[1] = (byte)(value >> 24);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 8);
_buffer[4] = (byte)value;
_stream.Write(_buffer, 0, 5);
}
else
{
_buffer[0] = (byte)ETFType.SMALL_BIG_EXT;
if (value < 0)
{
_buffer[2] = 1; //Is negative
value = -value;
}
// public void Write(bool value)
// {
// if (value)
// _stream.Write(_trueBytes, 0, _trueBytes.Length);
// else
// _stream.Write(_falseBytes, 0, _falseBytes.Length);
// }
// public void Write(sbyte value) => Write((long)value);
// public void Write(byte value) => Write((ulong)value);
// public void Write(short value) => Write((long)value);
// public void Write(ushort value) => Write((ulong)value);
// public void Write(int value) => Write((long)value);
// public void Write(uint value) => Write((ulong)value);
// public void Write(long value)
// {
// if (value >= byte.MinValue && value <= byte.MaxValue)
// {
// _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT;
// _buffer[1] = (byte)value;
// _stream.Write(_buffer, 0, 2);
// }
// else if (value >= int.MinValue && value <= int.MaxValue)
// {
// //TODO: Does this encode negatives correctly?
// _buffer[0] = (byte)ETFType.INTEGER_EXT;
// _buffer[1] = (byte)(value >> 24);
// _buffer[2] = (byte)(value >> 16);
// _buffer[3] = (byte)(value >> 8);
// _buffer[4] = (byte)value;
// _stream.Write(_buffer, 0, 5);
// }
// else
// {
// _buffer[0] = (byte)ETFType.SMALL_BIG_EXT;
// if (value < 0)
// {
// _buffer[2] = 1; //Is negative
// value = -value;
// }

byte bytes = 0;
while (value > 0)
_buffer[3 + bytes++] = (byte)(value >>= 8);
_buffer[1] = bytes; //Encoded bytes
// byte bytes = 0;
// while (value > 0)
// _buffer[3 + bytes++] = (byte)(value >>= 8);
// _buffer[1] = bytes; //Encoded bytes

_stream.Write(_buffer, 0, 3 + bytes);
}
}
public void Write(ulong value)
{
if (value <= byte.MaxValue)
{
_buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT;
_buffer[1] = (byte)value;
_stream.Write(_buffer, 0, 2);
}
else if (value <= int.MaxValue)
{
_buffer[0] = (byte)ETFType.INTEGER_EXT;
_buffer[1] = (byte)(value >> 24);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 8);
_buffer[4] = (byte)value;
_stream.Write(_buffer, 0, 5);
}
else
{
_buffer[0] = (byte)ETFType.SMALL_BIG_EXT;
_buffer[2] = 0; //Always positive
// _stream.Write(_buffer, 0, 3 + bytes);
// }
// }
// public void Write(ulong value)
// {
// if (value <= byte.MaxValue)
// {
// _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT;
// _buffer[1] = (byte)value;
// _stream.Write(_buffer, 0, 2);
// }
// else if (value <= int.MaxValue)
// {
// _buffer[0] = (byte)ETFType.INTEGER_EXT;
// _buffer[1] = (byte)(value >> 24);
// _buffer[2] = (byte)(value >> 16);
// _buffer[3] = (byte)(value >> 8);
// _buffer[4] = (byte)value;
// _stream.Write(_buffer, 0, 5);
// }
// else
// {
// _buffer[0] = (byte)ETFType.SMALL_BIG_EXT;
// _buffer[2] = 0; //Always positive

byte bytes = 0;
while (value > 0)
_buffer[3 + bytes++] = (byte)(value >>= 8);
_buffer[1] = bytes; //Encoded bytes
// byte bytes = 0;
// while (value > 0)
// _buffer[3 + bytes++] = (byte)(value >>= 8);
// _buffer[1] = bytes; //Encoded bytes

_stream.Write(_buffer, 0, 3 + bytes);
}
}
// _stream.Write(_buffer, 0, 3 + bytes);
// }
// }

public void Write(float value) => Write((double)value);
public void Write(double value)
{
ulong value2 = *(ulong*)&value;
_buffer[0] = (byte)ETFType.NEW_FLOAT_EXT;
_buffer[1] = (byte)(value2 >> 56);
_buffer[2] = (byte)(value2 >> 48);
_buffer[3] = (byte)(value2 >> 40);
_buffer[4] = (byte)(value2 >> 32);
_buffer[5] = (byte)(value2 >> 24);
_buffer[6] = (byte)(value2 >> 16);
_buffer[7] = (byte)(value2 >> 8);
_buffer[8] = (byte)value2;
_stream.Write(_buffer, 0, 9);
}
// public void Write(float value) => Write((double)value);
// public void Write(double value)
// {
// ulong value2 = *(ulong*)&value;
// _buffer[0] = (byte)ETFType.NEW_FLOAT_EXT;
// _buffer[1] = (byte)(value2 >> 56);
// _buffer[2] = (byte)(value2 >> 48);
// _buffer[3] = (byte)(value2 >> 40);
// _buffer[4] = (byte)(value2 >> 32);
// _buffer[5] = (byte)(value2 >> 24);
// _buffer[6] = (byte)(value2 >> 16);
// _buffer[7] = (byte)(value2 >> 8);
// _buffer[8] = (byte)value2;
// _stream.Write(_buffer, 0, 9);
// }

public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond));
// public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond));

public void Write(bool? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
public void Write(sbyte? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); }
public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
public void Write(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); }
public void Write(ushort? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
public void Write(int? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
public void Write(uint? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
public void Write(long? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
public void Write(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
public void Write(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
public void Write(float? value) { if (value.HasValue) Write((double)value.Value); else WriteNil(); }
public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(bool? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(sbyte? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); }
// public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
// public void Write(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); }
// public void Write(ushort? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
// public void Write(int? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(uint? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
// public void Write(long? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
// public void Write(float? value) { if (value.HasValue) Write((double)value.Value); else WriteNil(); }
// public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }

public void Write(string value)
{
if (value != null)
{
var bytes = _encoding.GetBytes(value);
int count = bytes.Length;
_buffer[0] = (byte)ETFType.BINARY_EXT;
_buffer[1] = (byte)(count >> 24);
_buffer[2] = (byte)(count >> 16);
_buffer[3] = (byte)(count >> 8);
_buffer[4] = (byte)count;
_stream.Write(_buffer, 0, 5);
_stream.Write(bytes, 0, bytes.Length);
}
else
WriteNil();
}
public void Write(byte[] value)
{
if (value != null)
{
int count = value.Length;
_buffer[0] = (byte)ETFType.BINARY_EXT;
_buffer[1] = (byte)(count >> 24);
_buffer[2] = (byte)(count >> 16);
_buffer[3] = (byte)(count >> 8);
_buffer[4] = (byte)count;
_stream.Write(_buffer, 0, 5);
_stream.Write(value, 0, value.Length);
}
else
WriteNil();
}
// public void Write(string value)
// {
// if (value != null)
// {
// var bytes = _encoding.GetBytes(value);
// int count = bytes.Length;
// _buffer[0] = (byte)ETFType.BINARY_EXT;
// _buffer[1] = (byte)(count >> 24);
// _buffer[2] = (byte)(count >> 16);
// _buffer[3] = (byte)(count >> 8);
// _buffer[4] = (byte)count;
// _stream.Write(_buffer, 0, 5);
// _stream.Write(bytes, 0, bytes.Length);
// }
// else
// WriteNil();
// }
// public void Write(byte[] value)
// {
// if (value != null)
// {
// int count = value.Length;
// _buffer[0] = (byte)ETFType.BINARY_EXT;
// _buffer[1] = (byte)(count >> 24);
// _buffer[2] = (byte)(count >> 16);
// _buffer[3] = (byte)(count >> 8);
// _buffer[4] = (byte)count;
// _stream.Write(_buffer, 0, 5);
// _stream.Write(value, 0, value.Length);
// }
// else
// WriteNil();
// }

public void Write<T>(T obj)
{
var type = typeof(T);
var typeInfo = type.GetTypeInfo();
var action = _serializers.GetOrAdd(type, _ => CreateSerializer<T>(type, typeInfo, false)) as Action<ETFWriter, T>;
action(this, obj);
}
public void Write<T>(T? obj)
where T : struct
{
if (obj != null)
Write(obj.Value);
else
WriteNil();
}
public void Write<T>(IEnumerable<T> obj)
{
if (obj != null)
{
var array = obj.ToArray();
int length = array.Length;
_buffer[0] = (byte)ETFType.LIST_EXT;
_buffer[1] = (byte)(length >> 24);
_buffer[2] = (byte)(length >> 16);
_buffer[3] = (byte)(length >> 8);
_buffer[4] = (byte)length;
_stream.Write(_buffer, 0, 5);
// public void Write<T>(T obj)
// {
// var type = typeof(T);
// var typeInfo = type.GetTypeInfo();
// var action = _serializers.GetOrAdd(type, _ => CreateSerializer<T>(type, typeInfo, false)) as Action<ETFWriter, T>;
// action(this, obj);
// }
// public void Write<T>(T? obj)
// where T : struct
// {
// if (obj != null)
// Write(obj.Value);
// else
// WriteNil();
// }
// public void Write<T>(IEnumerable<T> obj)
// {
// if (obj != null)
// {
// var array = obj.ToArray();
// int length = array.Length;
// _buffer[0] = (byte)ETFType.LIST_EXT;
// _buffer[1] = (byte)(length >> 24);
// _buffer[2] = (byte)(length >> 16);
// _buffer[3] = (byte)(length >> 8);
// _buffer[4] = (byte)length;
// _stream.Write(_buffer, 0, 5);

for (int i = 0; i < array.Length; i++)
Write(array[i]);
// for (int i = 0; i < array.Length; i++)
// Write(array[i]);

_buffer[0] = (byte)ETFType.NIL_EXT;
_stream.Write(_buffer, 0, 1);
}
else
WriteNil();
}
public void Write<TKey, TValue>(IDictionary<TKey, TValue> obj)
{
if (obj != null)
{
int length = obj.Count;
_buffer[0] = (byte)ETFType.MAP_EXT;
_buffer[1] = (byte)(length >> 24);
_buffer[2] = (byte)(length >> 16);
_buffer[3] = (byte)(length >> 8);
_buffer[4] = (byte)length;
_stream.Write(_buffer, 0, 5);
// _buffer[0] = (byte)ETFType.NIL_EXT;
// _stream.Write(_buffer, 0, 1);
// }
// else
// WriteNil();
// }
// public void Write<TKey, TValue>(IDictionary<TKey, TValue> obj)
// {
// if (obj != null)
// {
// int length = obj.Count;
// _buffer[0] = (byte)ETFType.MAP_EXT;
// _buffer[1] = (byte)(length >> 24);
// _buffer[2] = (byte)(length >> 16);
// _buffer[3] = (byte)(length >> 8);
// _buffer[4] = (byte)length;
// _stream.Write(_buffer, 0, 5);

foreach (var pair in obj)
{
Write(pair.Key);
Write(pair.Value);
}
}
else
WriteNil();
}
public void Write(object obj)
{
if (obj != null)
{
var type = obj.GetType();
var typeInfo = type.GetTypeInfo();
var action = _indirectSerializers.GetOrAdd(type, _ => CreateSerializer<object>(type, typeInfo, true)) as Action<ETFWriter, object>;
action(this, obj);
}
else
WriteNil();
}
// foreach (var pair in obj)
// {
// Write(pair.Key);
// Write(pair.Value);
// }
// }
// else
// WriteNil();
// }
// public void Write(object obj)
// {
// if (obj != null)
// {
// var type = obj.GetType();
// var typeInfo = type.GetTypeInfo();
// var action = _indirectSerializers.GetOrAdd(type, _ => CreateSerializer<object>(type, typeInfo, true)) as Action<ETFWriter, object>;
// action(this, obj);
// }
// else
// WriteNil();
// }

private void WriteNil() => _stream.Write(_nilBytes, 0, _nilBytes.Length);
// private void WriteNil() => _stream.Write(_nilBytes, 0, _nilBytes.Length);

public virtual void Flush() => _stream.Flush();
public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin);
// public virtual void Flush() => _stream.Flush();
// public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin);

#region Emit
private static Action<ETFWriter, T> CreateSerializer<T>(Type type, TypeInfo typeInfo, bool isDirect)
{
var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF",
null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true);
var generator = method.GetILGenerator();
// #region Emit
// private static Action<ETFWriter, T> CreateSerializer<T>(Type type, TypeInfo typeInfo, bool isDirect)
// {
// var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF",
// null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true);
// var generator = method.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), value
if (!isDirect)
{
if (typeInfo.IsValueType) //Unbox value types
generator.Emit(OpCodes.Unbox_Any, type); //ETFWriter(this), real_value
else //Cast reference types
generator.Emit(OpCodes.Castclass, type); //ETFWriter(this), real_value
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(type), null); //Call generic version
}
else
EmitWriteValue(generator, type, typeInfo, true);
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), value
// if (!isDirect)
// {
// if (typeInfo.IsValueType) //Unbox value types
// generator.Emit(OpCodes.Unbox_Any, type); //ETFWriter(this), real_value
// else //Cast reference types
// generator.Emit(OpCodes.Castclass, type); //ETFWriter(this), real_value
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(type), null); //Call generic version
// }
// else
// EmitWriteValue(generator, type, typeInfo, true);

generator.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Action<ETFWriter, T>)) as Action<ETFWriter, T>;
}
private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop)
{
//Convert enum types to their base type
if (typeInfo.IsEnum)
{
type = Enum.GetUnderlyingType(type);
typeInfo = type.GetTypeInfo();
}
// generator.Emit(OpCodes.Ret);
// return method.CreateDelegate(typeof(Action<ETFWriter, T>)) as Action<ETFWriter, T>;
// }
// private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop)
// {
// //Convert enum types to their base type
// if (typeInfo.IsEnum)
// {
// type = Enum.GetUnderlyingType(type);
// typeInfo = type.GetTypeInfo();
// }
//Primitives/Enums
Type targetType = null;
if (!typeInfo.IsEnum && IsType(type, typeof(long), typeof(ulong), typeof(double), typeof(bool), typeof(string),
typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?),
typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?),
typeof(bool?), typeof(float?), typeof(double?),
typeof(object), typeof(DateTime)))
{
//No conversion needed
targetType = type;
}
else if (IsType(type, typeof(sbyte), typeof(short), typeof(int)))
{
//Convert to long
generator.Emit(OpCodes.Conv_I8);
targetType = typeof(long);
}
else if (IsType(type, typeof(byte), typeof(ushort), typeof(uint)))
{
//Convert to ulong
generator.Emit(OpCodes.Conv_U8);
targetType = typeof(ulong);
}
else if (IsType(type, typeof(float)))
{
//Convert to double
generator.Emit(OpCodes.Conv_R8);
targetType = typeof(double);
}
if (targetType != null)
generator.EmitCall(OpCodes.Call, GetWriteMethod(targetType), null);
// //Primitives/Enums
// Type targetType = null;
// if (!typeInfo.IsEnum && IsType(type, typeof(long), typeof(ulong), typeof(double), typeof(bool), typeof(string),
// typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?),
// typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?),
// typeof(bool?), typeof(float?), typeof(double?),
// typeof(object), typeof(DateTime)))
// {
// //No conversion needed
// targetType = type;
// }
// else if (IsType(type, typeof(sbyte), typeof(short), typeof(int)))
// {
// //Convert to long
// generator.Emit(OpCodes.Conv_I8);
// targetType = typeof(long);
// }
// else if (IsType(type, typeof(byte), typeof(ushort), typeof(uint)))
// {
// //Convert to ulong
// generator.Emit(OpCodes.Conv_U8);
// targetType = typeof(ulong);
// }
// else if (IsType(type, typeof(float)))
// {
// //Convert to double
// generator.Emit(OpCodes.Conv_R8);
// targetType = typeof(double);
// }
// if (targetType != null)
// generator.EmitCall(OpCodes.Call, GetWriteMethod(targetType), null);

//Dictionaries
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{
generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Enumerable
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Nullable Structs
else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) &&
typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType)
{
generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
//Structs/Classes
else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive))
{
if (isTop)
{
typeInfo.ForEachField(f =>
{
string name;
if (!f.IsPublic || !IsETFProperty(f, out name)) return;
// //Dictionaries
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
// {
// generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Enumerable
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
// {
// generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Nullable Structs
// else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) &&
// typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType)
// {
// generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// //Structs/Classes
// else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive))
// {
// if (isTop)
// {
// typeInfo.ForEachField(f =>
// {
// string name;
// if (!f.IsPublic || !IsETFProperty(f, out name)) return;

generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj
generator.Emit(OpCodes.Ldfld, f); //ETFWriter(this), obj.fieldValue
EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false);
});
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
// generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj
// generator.Emit(OpCodes.Ldfld, f); //ETFWriter(this), obj.fieldValue
// EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false);
// });

typeInfo.ForEachProperty(p =>
{
string name;
if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return;
// typeInfo.ForEachProperty(p =>
// {
// string name;
// if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return;

generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj
generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFWriter(this), obj.propValue
EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false);
});
}
else
{
//While we could drill deeper and make a large serializer that also serializes all subclasses,
//it's more efficient to serialize on a per-type basis via another Write<T> call.
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
}
}
//Unsupported (decimal, char)
else
throw new InvalidOperationException($"Serializing {type.Name} is not supported.");
}
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
// generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null);
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this)
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj
// generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFWriter(this), obj.propValue
// EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false);
// });
// }
// else
// {
// //While we could drill deeper and make a large serializer that also serializes all subclasses,
// //it's more efficient to serialize on a per-type basis via another Write<T> call.
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null);
// }
// }
// //Unsupported (decimal, char)
// else
// throw new InvalidOperationException($"Serializing {type.Name} is not supported.");
// }

private static bool IsType(Type type, params Type[] types)
{
for (int i = 0; i < types.Length; i++)
{
if (type == types[i])
return true;
}
return false;
}
private static bool IsETFProperty(FieldInfo f, out string name)
{
var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
if (attrib != null)
{
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name;
return true;
}
name = null;
return false;
}
private static bool IsETFProperty(PropertyInfo p, out string name)
{
var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
if (attrib != null)
{
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name;
return true;
}
name = null;
return false;
}
// private static bool IsType(Type type, params Type[] types)
// {
// for (int i = 0; i < types.Length; i++)
// {
// if (type == types[i])
// return true;
// }
// return false;
// }
// private static bool IsETFProperty(FieldInfo f, out string name)
// {
// var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
// if (attrib != null)
// {
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name;
// return true;
// }
// name = null;
// return false;
// }
// private static bool IsETFProperty(PropertyInfo p, out string name)
// {
// var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault();
// if (attrib != null)
// {
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name;
// return true;
// }
// name = null;
// return false;
// }

private static MethodInfo GetWriteMethod(Type paramType)
{
return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write))
.Where(x => x.GetParameters()[0].ParameterType == paramType)
.Single();
}
private static MethodInfo GetGenericWriteMethod(Type genericType)
{
if (genericType == null)
{
return typeof(ETFWriter).GetTypeInfo()
.GetDeclaredMethods(nameof(Write))
.Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0])
.Single();
}
else
{
return typeof(ETFWriter).GetTypeInfo()
.GetDeclaredMethods(nameof(Write))
.Where(x =>
{
if (!x.IsGenericMethodDefinition) return false;
var p = x.GetParameters()[0].ParameterType.GetTypeInfo();
return p.IsGenericType && p.GetGenericTypeDefinition() == genericType;
})
.Single();
}
}
#endregion
// private static MethodInfo GetWriteMethod(Type paramType)
// {
// return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write))
// .Where(x => x.GetParameters()[0].ParameterType == paramType)
// .Single();
// }
// private static MethodInfo GetGenericWriteMethod(Type genericType)
// {
// if (genericType == null)
// {
// return typeof(ETFWriter).GetTypeInfo()
// .GetDeclaredMethods(nameof(Write))
// .Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0])
// .Single();
// }
// else
// {
// return typeof(ETFWriter).GetTypeInfo()
// .GetDeclaredMethods(nameof(Write))
// .Where(x =>
// {
// if (!x.IsGenericMethodDefinition) return false;
// var p = x.GetParameters()[0].ParameterType.GetTypeInfo();
// return p.IsGenericType && p.GetGenericTypeDefinition() == genericType;
// })
// .Single();
// }
// }
// #endregion

#region IDisposable
private bool _isDisposed = false;
// #region IDisposable
// private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if (_leaveOpen)
_stream.Flush();
else
_stream.Dispose();
}
_isDisposed = true;
}
}
// protected virtual void Dispose(bool disposing)
// {
// if (!_isDisposed)
// {
// if (disposing)
// {
// if (_leaveOpen)
// _stream.Flush();
// else
// _stream.Dispose();
// }
// _isDisposed = true;
// }
// }
public void Dispose() => Dispose(true);
#endregion
}
}
// public void Dispose() => Dispose(true);
// #endregion
// }
//}

+ 6
- 6
src/Discord.Net/Logging/ILogger.cs View File

@@ -7,36 +7,36 @@ namespace Discord.Logging
LogSeverity Level { get; }

void Log(LogSeverity severity, string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Log(LogSeverity severity, FormattableString message, Exception exception = null);
#endif

void Error(string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Error(FormattableString message, Exception exception = null);
#endif
void Error(Exception exception);

void Warning(string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Warning(FormattableString message, Exception exception = null);
#endif
void Warning(Exception exception);

void Info(string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Info(FormattableString message, Exception exception = null);
#endif
void Info(Exception exception);

void Verbose(string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Verbose(FormattableString message, Exception exception = null);
#endif
void Verbose(Exception exception);

void Debug(string message, Exception exception = null);
#if DOTNET5_4
#if NETSTANDARD1_3
void Debug(FormattableString message, Exception exception = null);
#endif
void Debug(Exception exception);


+ 2
- 2
src/Discord.Net/Logging/LogManager.cs View File

@@ -25,7 +25,7 @@ namespace Discord.Logging
}
}

#if DOTNET5_4
#if NETSTANDARD1_3
public void Log(LogSeverity severity, string source, FormattableString message, Exception exception = null)
{
if (severity <= Level)
@@ -57,7 +57,7 @@ namespace Discord.Logging
public void Debug(string source, Exception ex)
=> Log(LogSeverity.Debug, source, (string)null, ex);

#if DOTNET5_4
#if NETSTANDARD1_3
public void Error(string source, FormattableString message, Exception ex = null)
=> Log(LogSeverity.Error, source, message, ex);
public void Warning(string source, FormattableString message, Exception ex = null)


+ 1
- 1
src/Discord.Net/Logging/Logger.cs View File

@@ -38,7 +38,7 @@ namespace Discord.Logging
public void Debug(Exception exception)
=> _manager.Debug(Name, exception);

#if DOTNET5_4
#if NETSTANDARD1_3
public void Log(LogSeverity severity, FormattableString message, Exception exception = null)
=> _manager.Log(severity, Name, message, exception);
public void Error(FormattableString message, Exception exception = null)


+ 1
- 1
src/Discord.Net/Net/Rest/BuiltInEngine.cs View File

@@ -1,4 +1,4 @@
#if DOTNET5_4
#if NETSTANDARD1_3
using Discord.Logging;
using System;
using System.IO;


+ 0
- 27
src/Discord.Net/Net/Rest/ETFRestClient.cs View File

@@ -1,27 +0,0 @@
using Discord.ETF;
using System.IO;
using System;
using Discord.Logging;

namespace Discord.Net.Rest
{
public class ETFRestClient : RestClient
{
private readonly ETFWriter _serializer;

public ETFRestClient(DiscordConfig config, string baseUrl, ILogger logger = null)
: base(config, baseUrl, logger)
{
_serializer = new ETFWriter(new MemoryStream());
}

protected override string Serialize<T>(T obj)
{
throw new NotImplementedException();
}
protected override T Deserialize<T>(string json)
{
throw new NotImplementedException();
}
}
}

+ 1
- 2
src/Discord.Net/Net/Rest/RestClient.cs View File

@@ -36,7 +36,6 @@ namespace Discord.Net.Rest

private readonly DiscordConfig _config;
private readonly IRestEngine _engine;
private readonly ETFWriter _serializer;
private readonly ILogger _logger;
private string _token;

@@ -57,7 +56,7 @@ namespace Discord.Net.Rest
_config = config;
_logger = logger;

#if !DOTNET5_4
#if !NETSTANDARD1_3
_engine = new RestSharpEngine(config, baseUrl, logger);
#else
_engine = new BuiltInEngine(config, baseUrl, logger);


+ 1
- 1
src/Discord.Net/Net/Rest/SharpRestEngine.cs View File

@@ -1,4 +1,4 @@
#if !DOTNET5_4
#if !NETSTANDARD1_3
using Discord.Logging;
using Nito.AsyncEx;
using RestSharp;


+ 2
- 2
src/Discord.Net/Net/WebSockets/BuiltInEngine.cs View File

@@ -1,4 +1,4 @@
#if DOTNET5_4
#if NETSTANDARD1_3
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -89,7 +89,7 @@ namespace Discord.Net.WebSockets
if (result.MessageType == WebSocketMessageType.Close)
throw new WebSocketException((int)result.CloseStatus.Value, result.CloseStatusDescription);
else
stream.Write(buffer.Array, buffer.Offset, buffer.Count);
stream.Write(buffer.Array, 0, result.Count);

}
while (result == null || !result.EndOfMessage);


+ 1
- 1
src/Discord.Net/Net/WebSockets/WS4NetEngine.cs View File

@@ -1,4 +1,4 @@
#if !DOTNET5_4
#if !NETSTANDARD1_3
using SuperSocket.ClientEngine;
using System;
using System.Collections.Concurrent;


+ 1
- 1
src/Discord.Net/Net/WebSockets/WebSocket.cs View File

@@ -49,7 +49,7 @@ namespace Discord.Net.WebSockets
CancelToken = new CancellationToken(true);
_connectedEvent = new ManualResetEventSlim(false);

#if !DOTNET5_4
#if !NETSTANDARD1_3
_engine = new WS4NetEngine(config, _taskManager);
#else
_engine = new BuiltInEngine(config);


+ 32
- 54
src/Discord.Net/project.json View File

@@ -1,29 +1,31 @@
{
"version": "0.9.1",
"description": "An unofficial .Net API wrapper for the Discord client.",
"authors": [
"RogueException"
],
"tags": [
"discord",
"discordapp"
],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
"authors": [ "RogueException" ],

"packOptions": {
"tags": [
"discord",
"discordapp"
],
"projectUrl": "https://github.com/RogueException/Discord.Net",
"licenseUrl": "http://opensource.org/licenses/MIT",
"repository": {
"type": "git",
"url": "git://github.com/RogueException/Discord.Net"
}
},
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],

"compilationOptions": {
"buildOptions": {
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ],
"preserveCompilationContext": true,
"allowUnsafe": true,
"warningsAsErrors": true
},

"configurations": {
"TestResponses": {
"compilationOptions": {
"buildOptions": {
"define": [
"DEBUG",
"TRACE",
@@ -34,48 +36,24 @@
},

"dependencies": {
"Newtonsoft.Json": "8.0.1",
"Nito.AsyncEx": "3.0.1"
"NETStandard.Library": "1.5.0-rc2-24027",
"Newtonsoft.Json": "8.0.3",
"Nito.AsyncEx": "3.0.1",
"System.Net.Requests": "4.0.11-rc2-24027",
"System.Net.Websockets.Client": "4.0.0-rc2-24027",
"System.Reflection.Emit.Lightweight": "4.0.1-rc2-24027",
"System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027",
"System.Security.Cryptography.Algorithms": "4.1.0-rc2-24027",
"System.Net.NameResolution": "4.0.0-rc2-24027"
},

"frameworks": {
"dotnet5.4": {
"dependencies": {
"System.Collections": "4.0.11-beta-23516",
"System.Collections.Concurrent": "4.0.11-beta-23516",
"System.Dynamic.Runtime": "4.0.11-beta-23516",
"System.IO.FileSystem": "4.0.1-beta-23516",
"System.IO.Compression": "4.1.0-beta-23516",
"System.Linq": "4.0.1-beta-23516",
"System.Net.Http": "4.0.1-beta-23516",
"System.Net.NameResolution": "4.0.0-beta-23516",
"System.Net.Sockets": "4.1.0-beta-23409",
"System.Net.Requests": "4.0.11-beta-23516",
"System.Net.WebSockets.Client": "4.0.0-beta-23516",
"System.Reflection": "4.1.0-beta-23516",
"System.Reflection.Emit.Lightweight": "4.0.1-beta-23516",
"System.Runtime.InteropServices": "4.0.21-beta-23516",
"System.Runtime.Serialization.Primitives": "4.1.0-beta-23516",
"System.Security.Cryptography.Algorithms": "4.0.0-beta-23516",
"System.Text.RegularExpressions": "4.0.11-beta-23516",
"System.Threading": "4.0.11-beta-23516"
}
},
"net45": {
"frameworkAssemblies": {
"System.Runtime": {
"type": "build",
"version": ""
},
"System.Threading.Tasks": {
"type": "build",
"version": ""
}
},
"dependencies": {
"WebSocket4Net": "0.14.1",
"RestSharp": "105.2.3"
}
"netstandard1.3": {
"imports": [
"dotnet5.4",
"dnxcore50",
"portable-net45+win8"
]
}
}
}

+ 3
- 3
test/Discord.Net.Tests/Discord.Net.Tests.csproj View File

@@ -59,14 +59,14 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Discord.Net.Net45\Discord.Net.csproj">
<Project>{8d71a857-879a-4a10-859e-5ff824ed6688}</Project>
<Name>Discord.Net</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>


+ 1
- 1
test/Discord.Net.Tests/Tests.cs View File

@@ -334,7 +334,7 @@ namespace Discord.Tests
async () => await SetGame(_targetBot, "test game"),
x => _observerBot.UserUpdated += x,
x => _observerBot.UserUpdated -= x,
(s, e) => _targetBot.CurrentGame == "test game");
(s, e) => _targetBot.CurrentGame.Name == "test game");

}
private async Task SetGame(DiscordClient _client, string game)


Loading…
Cancel
Save