Isolated Analyzers and Relay projects

This commit is contained in:
RogueException
2017-04-25 09:25:19 -03:00
parent be6abe1161
commit 41d9788411
9 changed files with 0 additions and 15 deletions

View File

@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Builder;
using System;
namespace Discord.Relay
{
public static class ApplicationBuilderExtensions
{
public static void UseDiscordRelay(this IApplicationBuilder app, Action<RelayServer> configAction = null)
{
var server = new RelayServer(configAction);
server.StartAsync();
app.Use(async (context, next) =>
{
if (context.WebSockets.IsWebSocketRequest)
await server.AcceptAsync(context);
await next();
});
}
}
}

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Discord.Net.Tests")]

View File

@@ -0,0 +1,18 @@
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Relay</AssemblyName>
<RootNamespace>Discord.Relay</RootNamespace>
<Description>A core Discord.Net library containing the Relay server.</Description>
<TargetFrameworks>netstandard1.3</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
<ProjectReference Include="..\Discord.Net.Rest\Discord.Net.Rest.csproj" />
<ProjectReference Include="..\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="1.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,79 @@
using Discord.API;
using Discord.API.Gateway;
using Discord.Logging;
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using WebSocketClient = System.Net.WebSockets.WebSocket;
namespace Discord.Relay
{
public class RelayConnection
{
private readonly RelayServer _server;
private readonly WebSocketClient _socket;
private readonly CancellationTokenSource _cancelToken;
private readonly byte[] _inBuffer, _outBuffer;
private readonly Logger _logger;
internal RelayConnection(RelayServer server, WebSocketClient socket, int id)
{
_server = server;
_socket = socket;
_cancelToken = new CancellationTokenSource();
_inBuffer = new byte[4000];
_outBuffer = new byte[4000];
_logger = server.LogManager.CreateLogger($"Client #{id}");
}
internal async Task RunAsync()
{
await _logger.InfoAsync($"Connected");
var token = _cancelToken.Token;
try
{
var segment = new ArraySegment<byte>(_inBuffer);
//Send HELLO
await SendAsync(GatewayOpCode.Hello, new HelloEvent { HeartbeatInterval = 15000 }).ConfigureAwait(false);
while (_socket.State == WebSocketState.Open)
{
var result = await _socket.ReceiveAsync(segment, token).ConfigureAwait(false);
if (result.MessageType == WebSocketMessageType.Close)
await _logger.WarningAsync($"Received Close {result.CloseStatus} ({result.CloseStatusDescription ?? "No Reason"})").ConfigureAwait(false);
else
await _logger.InfoAsync($"Received {result.Count} bytes");
}
}
catch (OperationCanceledException)
{
try { await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None).ConfigureAwait(false); }
catch { }
}
catch (Exception ex)
{
try { await _socket.CloseAsync(WebSocketCloseStatus.InternalServerError, ex.Message, CancellationToken.None).ConfigureAwait(false); }
catch { }
}
finally
{
await _logger.InfoAsync($"Disconnected");
}
}
internal void Stop()
{
_cancelToken.Cancel();
}
private async Task SendAsync(GatewayOpCode opCode, object payload)
{
var frame = new SocketFrame { Operation = (int)opCode, Payload = payload };
var bytes = _server.Serialize(frame, _outBuffer);
var segment = new ArraySegment<byte>(_outBuffer, 0, bytes);
await _socket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,103 @@
using Discord.API;
using Discord.Logging;
using Discord.Net.Rest;
using Discord.Net.WebSockets;
using Discord.Rest;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using WebSocketClient = System.Net.WebSockets.WebSocket;
namespace Discord.Relay
{
public class RelayServer
{
public event Func<LogMessage, Task> Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } }
internal readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>();
private readonly HashSet<RelayConnection> _connections;
private readonly SemaphoreSlim _lock;
private readonly JsonSerializer _serializer;
private readonly DiscordSocketApiClient _discord;
private int _nextId;
internal LogManager LogManager { get; }
internal RelayServer(Action<RelayServer> configAction)
{
_connections = new HashSet<RelayConnection>();
_lock = new SemaphoreSlim(1, 1);
_serializer = new JsonSerializer();
_discord = new DiscordSocketApiClient(
DefaultRestClientProvider.Instance,
DefaultWebSocketProvider.Instance,
DiscordRestConfig.UserAgent);
configAction?.Invoke(this);
LogManager = new LogManager(LogSeverity.Debug);
LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false);
}
internal async Task AcceptAsync(HttpContext context)
{
WebSocketClient socket;
try
{
socket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
}
catch { return; }
var _ = Task.Run(async () =>
{
var conn = new RelayConnection(this, socket, Interlocked.Increment(ref _nextId));
await AddConnection(conn).ConfigureAwait(false);
try
{
await conn.RunAsync().ConfigureAwait(false);
}
finally { await RemoveConnection(conn).ConfigureAwait(false); }
});
}
internal void StartAsync()
{
Task.Run(async () =>
{
await _discord.ConnectAsync().ConfigureAwait(false);
});
}
internal async Task AddConnection(RelayConnection conn)
{
await _lock.WaitAsync().ConfigureAwait(false);
try
{
_connections.Add(conn);
}
finally { _lock.Release(); }
}
internal async Task RemoveConnection(RelayConnection conn)
{
await _lock.WaitAsync().ConfigureAwait(false);
try
{
_connections.Remove(conn);
}
finally { _lock.Release(); }
}
internal int Serialize(object obj, byte[] buffer)
{
using (var stream = new MemoryStream(buffer))
using (var writer = new StreamWriter(stream))
{
_serializer.Serialize(writer, obj);
return (int)stream.Position;
}
}
}
}