104 lines
3.3 KiB
C#
104 lines
3.3 KiB
C#
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|