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 Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } } internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); private readonly HashSet _connections; private readonly SemaphoreSlim _lock; private readonly JsonSerializer _serializer; private readonly DiscordSocketApiClient _discord; private int _nextId; internal LogManager LogManager { get; } internal RelayServer(Action configAction) { _connections = new HashSet(); _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; } } } }