com.unity.ide.visualstudio@2.0.7

## [2.0.7] - 2021-02-02

Integration:

Remove com.unity.nuget.newtonsoft-json dependency in favor of the built-in JsonUtility for the VS Test Runner.

## [2.0.6] - 2021-01-20

Project generation:

- Improved language version detection.

Integration:

- Added support for the VS Test Runner.
- Added initial support for displaying asset usage.
- Fixed remaining issues with special characters in file/path.
This commit is contained in:
Unity Technologies
2021-02-02 00:00:00 +00:00
parent 08ab0fbd80
commit 8cbbe811d0
34 changed files with 999 additions and 70 deletions

View File

@@ -11,9 +11,6 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
{
private readonly BinaryReader _reader;
// Max UDP packet size is 65507
private const int MaxStringLength = 65000;
public Deserializer(byte[] buffer)
{
_reader = new BinaryReader(new MemoryStream(buffer));
@@ -27,7 +24,7 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
public string ReadString()
{
var length = ReadInt32();
return length > 0 && length <= MaxStringLength
return length > 0
? Encoding.UTF8.GetString(_reader.ReadBytes(length))
: "";
}

View File

@@ -30,5 +30,19 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
UpdatePackage,
ProjectPath,
// This message is a technical one for big messages, not intended to be used directly
Tcp,
RunStarted,
RunFinished,
TestStarted,
TestFinished,
TestListRetrieved,
RetrieveTestList,
ExecuteTests,
ShowUsage
}
}

View File

@@ -71,7 +71,23 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
if (message != null)
{
message.Origin = (IPEndPoint)endPoint;
ReceiveMessage?.Invoke(this, new MessageEventArgs(message));
int port;
int bufferSize;
if (IsValidTcpMessage(message, out port, out bufferSize))
{
// switch to TCP mode to handle big messages
TcpClient.Queue(message.Origin.Address, port, bufferSize, buffer =>
{
var originalMessage = DeserializeMessage(buffer);
originalMessage.Origin = message.Origin;
ReceiveMessage?.Invoke(this, new MessageEventArgs(originalMessage));
});
}
else
{
ReceiveMessage?.Invoke(this, new MessageEventArgs(message));
}
}
}
catch (ObjectDisposedException)
@@ -86,6 +102,22 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
BeginReceiveMessage();
}
private static bool IsValidTcpMessage(Message message, out int port, out int bufferSize)
{
port = 0;
bufferSize = 0;
if (message.Value == null)
return false;
if (message.Type != MessageType.Tcp)
return false;
var parts = message.Value.Split(':');
if (parts.Length != 2)
return false;
if (!int.TryParse(parts[0], out port))
return false;
return int.TryParse(parts[1], out bufferSize);
}
private void RaiseMessagerException(Exception e)
{
MessagerException?.Invoke(this, new ExceptionEventArgs(e));
@@ -108,6 +140,18 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
if (_disposed)
return;
if (buffer.Length >= UdpSocket.BufferSize)
{
// switch to TCP mode to handle big messages
var port = TcpListener.Queue(buffer);
if (port > 0)
{
// success, replace original message with "switch to tcp" marker + port information + buffer length
message = MessageFor(MessageType.Tcp, string.Concat(port, ':', buffer.Length));
buffer = SerializeMessage(message);
}
}
_socket.BeginSendTo(buffer, 0, Math.Min(buffer.Length, UdpSocket.BufferSize), SocketFlags.None, target, SendMessageCallback, null);
}
}

View File

@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Microsoft.Unity.VisualStudio.Editor.Messaging
{
internal class TcpClient
{
private const int ConnectOrReadTimeoutMilliseconds = 5000;
private class State
{
public System.Net.Sockets.TcpClient TcpClient;
public NetworkStream NetworkStream;
public byte[] Buffer;
public Action<byte[]> OnBufferAvailable;
}
public static void Queue(IPAddress address, int port, int bufferSize, Action<byte[]> onBufferAvailable)
{
var client = new System.Net.Sockets.TcpClient();
var state = new State {OnBufferAvailable = onBufferAvailable, TcpClient = client, Buffer = new byte[bufferSize]};
try
{
ThreadPool.QueueUserWorkItem(_ =>
{
var handle = client.BeginConnect(address, port, OnClientConnected, state);
if (!handle.AsyncWaitHandle.WaitOne(ConnectOrReadTimeoutMilliseconds))
Cleanup(state);
});
}
catch (Exception)
{
Cleanup(state);
}
}
private static void OnClientConnected(IAsyncResult result)
{
var state = (State)result.AsyncState;
try
{
state.TcpClient.EndConnect(result);
state.NetworkStream = state.TcpClient.GetStream();
var handle = state.NetworkStream.BeginRead(state.Buffer, 0, state.Buffer.Length, OnEndRead, state);
if (!handle.AsyncWaitHandle.WaitOne(ConnectOrReadTimeoutMilliseconds))
Cleanup(state);
}
catch (Exception)
{
Cleanup(state);
}
}
private static void OnEndRead(IAsyncResult result)
{
var state = (State)result.AsyncState;
try
{
var count = state.NetworkStream.EndRead(result);
if (count == state.Buffer.Length)
state.OnBufferAvailable?.Invoke(state.Buffer);
}
catch (Exception)
{
// Ignore and cleanup
}
finally
{
Cleanup(state);
}
}
private static void Cleanup(State state)
{
state.NetworkStream?.Dispose();
state.TcpClient?.Close();
state.NetworkStream = null;
state.TcpClient = null;
state.Buffer = null;
state.OnBufferAvailable = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6674c38820d12a49ac116d416521d85
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,82 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
using System;
using System.Net;
using System.Threading;
namespace Microsoft.Unity.VisualStudio.Editor.Messaging
{
internal class TcpListener
{
private const int ListenTimeoutMilliseconds = 5000;
private class State
{
public System.Net.Sockets.TcpListener TcpListener;
public byte[] Buffer;
}
public static int Queue(byte[] buffer)
{
var tcpListener = new System.Net.Sockets.TcpListener(IPAddress.Any, 0);
var state = new State {Buffer = buffer, TcpListener = tcpListener};
try
{
tcpListener.Start();
int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
ThreadPool.QueueUserWorkItem(_ =>
{
bool listening = true;
while (listening)
{
var handle = tcpListener.BeginAcceptTcpClient(OnIncomingConnection, state);
listening = handle.AsyncWaitHandle.WaitOne(ListenTimeoutMilliseconds);
}
Cleanup(state);
});
return port;
}
catch (Exception)
{
Cleanup(state);
return -1;
}
}
private static void OnIncomingConnection(IAsyncResult result)
{
var state = (State)result.AsyncState;
try
{
using (var client = state.TcpListener.EndAcceptTcpClient(result))
{
using (var stream = client.GetStream())
{
stream.Write(state.Buffer, 0, state.Buffer.Length);
}
}
}
catch (Exception)
{
// Ignore and cleanup
}
}
private static void Cleanup(State state)
{
state.TcpListener?.Stop();
state.TcpListener = null;
state.Buffer = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ded625cf0d03fa94c9f939fd13ced18d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -10,6 +10,8 @@ namespace Microsoft.Unity.VisualStudio.Editor.Messaging
{
internal class UdpSocket : Socket
{
// Maximum UDP payload is 65507 bytes.
// TCP mode will be used when the payload is bigger than this BufferSize
public const int BufferSize = 1024 * 8;
internal UdpSocket()