dotnet-installer/src/dotnet/commands/dotnet-test/ReportingChannel.cs

149 lines
4.3 KiB
C#
Raw Normal View History

2015-11-30 17:33:16 -08:00
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
2015-11-30 17:33:16 -08:00
using Microsoft.Extensions.Testing.Abstractions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.DotNet.Tools.Test
{
public class ReportingChannel : IReportingChannel
2015-11-30 17:33:16 -08:00
{
public static ReportingChannel ListenOn(int port)
{
// This fixes the mono incompatibility but ties it to ipv4 connections
var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
2015-11-30 17:33:16 -08:00
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, port));
listenSocket.Listen(10);
2015-11-30 17:33:16 -08:00
return new ReportingChannel(listenSocket);
2015-11-30 17:33:16 -08:00
}
private BinaryWriter _writer;
private BinaryReader _reader;
private Socket _listenSocket;
2015-11-30 17:33:16 -08:00
private ReportingChannel(Socket listenSocket)
2015-11-30 17:33:16 -08:00
{
_listenSocket = listenSocket;
Port = ((IPEndPoint)listenSocket.LocalEndPoint).Port;
2015-11-30 17:33:16 -08:00
}
public event EventHandler<Message> MessageReceived;
2015-11-30 17:33:16 -08:00
public Socket Socket { get; private set; }
public int Port { get; }
public void Accept()
{
new Thread(() =>
{
using (_listenSocket)
{
Socket = _listenSocket.Accept();
var stream = new NetworkStream(Socket);
_writer = new BinaryWriter(stream);
_reader = new BinaryReader(stream);
// Read incoming messages on the background thread
new Thread(ReadMessages) { IsBackground = true }.Start();
}
}) { IsBackground = true }.Start();
}
2015-11-30 17:33:16 -08:00
public void Send(Message message)
{
lock (_writer)
{
try
{
TestHostTracing.Source.TraceEvent(
TraceEventType.Verbose,
0,
"[ReportingChannel]: Send({0})",
2015-11-30 17:33:16 -08:00
message);
_writer.Write(JsonConvert.SerializeObject(message));
}
catch (Exception ex)
{
TestHostTracing.Source.TraceEvent(
TraceEventType.Error,
0,
"[ReportingChannel]: Error sending {0}",
ex);
throw;
}
}
}
public void SendError(string error)
{
Send(new Message()
{
MessageType = "Error",
Payload = JToken.FromObject(new ErrorMessage()
{
Message = error,
}),
});
}
public void SendError(Exception ex)
{
SendError(ex.ToString());
}
private void ReadMessages()
{
while (true)
{
try
{
var rawMessage = _reader.ReadString();
var message = JsonConvert.DeserializeObject<Message>(rawMessage);
MessageReceived?.Invoke(this, message);
if (ShouldStopListening(message))
{
break;
}
2015-11-30 17:33:16 -08:00
}
catch (Exception ex)
{
TestHostTracing.Source.TraceEvent(
TraceEventType.Error,
0,
"[ReportingChannel]: Waiting for message failed {0}",
ex);
throw;
}
}
}
private static bool ShouldStopListening(Message message)
{
return message.MessageType == TestMessageTypes.TestRunnerTestCompleted ||
message.MessageType == TestMessageTypes.TestSessionTerminate;
}
2015-11-30 17:33:16 -08:00
public void Dispose()
{
if (Socket != null)
{
Socket.Dispose();
}
2015-11-30 17:33:16 -08:00
}
}
}