From 0df54c6afad7251c9314d2e98a607e6be2974cff Mon Sep 17 00:00:00 2001 From: Christopher Felegy Date: Sun, 5 Jan 2020 22:39:05 -0500 Subject: [PATCH] sample: add idn repl (Interactive Discord.Net) basic enough to test some stuff with fixed some bugs with disposables in the process --- .gitignore | 4 +- Discord.Net.sln | 17 ++++++ sample/idn/Inspector.cs | 74 +++++++++++++++++++++++++ sample/idn/Program.cs | 86 +++++++++++++++++++++++++++++ sample/idn/idn.csproj | 16 ++++++ src/Discord.Net/Discord.Net.csproj | 1 + src/Discord.Net/DiscordClient.cs | 6 ++ src/Discord.Net/DiscordConfig.cs | 8 ++- src/Discord.Net/IDiscordClient.cs | 5 +- src/Discord.Net/Rest/DiscordRestApi.cs | 15 ++++- src/Discord.Net/Rest/IDiscordRestApi.cs | 1 + src/Discord.Net/Rest/Requests/Test.cs | 0 src/Discord.Net/Socket/DiscordGatewayApi.cs | 7 ++- 13 files changed, 233 insertions(+), 7 deletions(-) create mode 100644 sample/idn/Inspector.cs create mode 100644 sample/idn/Program.cs create mode 100644 sample/idn/idn.csproj delete mode 100644 src/Discord.Net/Rest/Requests/Test.cs diff --git a/.gitignore b/.gitignore index d72e0b5ea..a4e47d264 100644 --- a/.gitignore +++ b/.gitignore @@ -206,4 +206,6 @@ docs/api/\.manifest \.idea/ # Codealike UID -codealike.json \ No newline at end of file +codealike.json + +*.ignore diff --git a/Discord.Net.sln b/Discord.Net.sln index 6b31e4ec4..c52902b9b 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -7,6 +7,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5DAC796B-0B7 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net\Discord.Net.csproj", "{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{4795640A-030C-4A9A-A9B0-20C56AF4DA3F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "idn", "sample\idn\idn.csproj", "{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,8 +36,21 @@ Global {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x64.Build.0 = Release|Any CPU {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x86.ActiveCfg = Release|Any CPU {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x86.Build.0 = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x64.ActiveCfg = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x64.Build.0 = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x86.ActiveCfg = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x86.Build.0 = Debug|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|Any CPU.Build.0 = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x64.ActiveCfg = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x64.Build.0 = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x86.ActiveCfg = Release|Any CPU + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370} = {5DAC796B-0B77-4F84-B790-83DB78C6DFFE} + {5BE5DE89-53B7-4243-AEA8-FD8A6420908A} = {4795640A-030C-4A9A-A9B0-20C56AF4DA3F} EndGlobalSection EndGlobal diff --git a/sample/idn/Inspector.cs b/sample/idn/Inspector.cs new file mode 100644 index 000000000..3806e0e79 --- /dev/null +++ b/sample/idn/Inspector.cs @@ -0,0 +1,74 @@ +using System.Collections; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace idn +{ + public static class Inspector + { + public static string Inspect(object value) + { + var builder = new StringBuilder(); + if (value != null) + { + var type = value.GetType().GetTypeInfo(); + builder.AppendLine($"[{type.Namespace}.{type.Name}]"); + builder.AppendLine($"{InspectProperty(value)}"); + + if (value is IEnumerable) + { + var items = (value as IEnumerable).Cast().ToArray(); + if (items.Length > 0) + { + builder.AppendLine(); + foreach (var item in items) + builder.AppendLine($"- {InspectProperty(item)}"); + } + } + else + { + var groups = type.GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(x => x.GetIndexParameters().Length == 0) + .GroupBy(x => x.Name) + .OrderBy(x => x.Key) + .ToArray(); + if (groups.Length > 0) + { + builder.AppendLine(); + int pad = groups.Max(x => x.Key.Length) + 1; + foreach (var group in groups) + builder.AppendLine($"{group.Key.PadRight(pad, ' ')}{InspectProperty(group.First().GetValue(value))}"); + } + } + } + else + builder.AppendLine("null"); + return builder.ToString(); + } + + private static string InspectProperty(object obj) + { + if (obj == null) + return "null"; + + var type = obj.GetType(); + + var debuggerDisplay = type.GetProperty("DebuggerDisplay", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (debuggerDisplay != null) + return debuggerDisplay.GetValue(obj).ToString(); + + var toString = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Where(x => x.Name == "ToString" && x.DeclaringType != typeof(object)) + .FirstOrDefault(); + if (toString != null) + return obj.ToString(); + + var count = type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (count != null) + return $"[{count.GetValue(obj)} Items]"; + + return obj.ToString(); + } + } +} diff --git a/sample/idn/Program.cs b/sample/idn/Program.cs new file mode 100644 index 000000000..4c1c2411d --- /dev/null +++ b/sample/idn/Program.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Scripting; +using Microsoft.CodeAnalysis.Scripting; +using Discord; + +namespace idn +{ + public class Program + { + public static readonly string[] Imports = + { + "System", + "System.Collections.Generic", + "System.Linq", + "System.Threading.Tasks", + "System.Diagnostics", + "System.IO", + "Discord", + "Discord.Rest", + "Discord.Socket", + "idn" + }; + + static async Task Main(string[] args) + { + var token = File.ReadAllText("token.ignore"); + var client = IDiscordClient.Create(token); + // client.start + + var options = ScriptOptions.Default + .AddReferences(GetAssemblies().ToArray()) + .AddImports(Imports); + + var globals = new ScriptGlobals + { + Client = client, + }; + + while (true) + { + Console.Write("> "); + string input = Console.ReadLine(); + + if (input == "quit") + { + break; + } + + object eval; + try + { + eval = await CSharpScript.EvaluateAsync(input, options, globals); + } + catch (Exception e) + { + eval = e; + } + Console.WriteLine(Inspector.Inspect(eval)); + } + + // client.Stop + client.Dispose(); + } + + static IEnumerable GetAssemblies() + { + var Assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies(); + foreach (var a in Assemblies) + { + var asm = Assembly.Load(a); + yield return asm; + } + yield return Assembly.GetEntryAssembly(); + } + + public class ScriptGlobals + { + public IDiscordClient Client { get; set; } + } + } +} diff --git a/sample/idn/idn.csproj b/sample/idn/idn.csproj new file mode 100644 index 000000000..e39a15a28 --- /dev/null +++ b/sample/idn/idn.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + diff --git a/src/Discord.Net/Discord.Net.csproj b/src/Discord.Net/Discord.Net.csproj index cd23e7c45..ddb15bd0a 100644 --- a/src/Discord.Net/Discord.Net.csproj +++ b/src/Discord.Net/Discord.Net.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 130749d27..c2498985c 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -16,5 +16,11 @@ namespace Discord Rest = restApi; Gateway = gatewayApi; } + + public void Dispose() + { + Rest.Dispose(); + Gateway.Dispose(); + } } } diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index db3b45efd..e8ba2407b 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -20,9 +20,13 @@ namespace Discord /// public static readonly Uri DefaultGatewayUri = new Uri("wss://gateway.discord.gg"); /// - /// The base URL for the Rest API. + /// The default REST URI. /// - public string RestApiUrl { get; set; } = "https://discordapp.com/api/v6/"; + public static readonly Uri DefaultRestUri = new Uri("https://discordapp.com/api/v6/"); + /// + /// The URI to use when making HTTP requests. If specified, this will override the default. + /// + public Uri? RestUri = null; /// /// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. /// diff --git a/src/Discord.Net/IDiscordClient.cs b/src/Discord.Net/IDiscordClient.cs index 271db25d5..3a5c424fa 100644 --- a/src/Discord.Net/IDiscordClient.cs +++ b/src/Discord.Net/IDiscordClient.cs @@ -1,12 +1,13 @@ +using System; using System.Net.Http.Headers; using Discord.Rest; using Discord.Socket; namespace Discord { - internal interface IDiscordClient + public interface IDiscordClient : IDisposable { - static IDiscordClient Create(string token, DiscordConfig? config = default) + public static IDiscordClient Create(string token, DiscordConfig? config = default) { config = config ?? new DiscordConfig(); diff --git a/src/Discord.Net/Rest/DiscordRestApi.cs b/src/Discord.Net/Rest/DiscordRestApi.cs index 24c682478..b70c757f0 100644 --- a/src/Discord.Net/Rest/DiscordRestApi.cs +++ b/src/Discord.Net/Rest/DiscordRestApi.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Refit; using Discord.Rest.Models; using System.Net.Http.Headers; +using System; +using System.Net.Http; // This is essentially a reimplementation of Wumpus.Net.Rest namespace Discord.Rest @@ -10,20 +12,31 @@ namespace Discord.Rest public class DiscordRestApi : IDiscordRestApi { private readonly IDiscordRestApi _api; + private readonly HttpClient _http; public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) { + _http = new HttpClient(new DiscordHttpClientHandler(token), true) + { + BaseAddress = config.RestUri ?? DiscordConfig.DefaultRestUri, + }; + var jsonOptions = new JsonSerializerOptions(); var refitSettings = new RefitSettings { ContentSerializer = new JsonContentSerializer(jsonOptions), }; - _api = RestService.For(config.RestApiUrl, refitSettings); + _api = RestService.For(_http, refitSettings); } public Task GetGatewayInfoAsync() { return _api.GetGatewayInfoAsync(); } + + public void Dispose() + { + _http.Dispose(); + } } } diff --git a/src/Discord.Net/Rest/IDiscordRestApi.cs b/src/Discord.Net/Rest/IDiscordRestApi.cs index 3e58c1ce3..0f963351a 100644 --- a/src/Discord.Net/Rest/IDiscordRestApi.cs +++ b/src/Discord.Net/Rest/IDiscordRestApi.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Refit; using Discord.Rest.Models; diff --git a/src/Discord.Net/Rest/Requests/Test.cs b/src/Discord.Net/Rest/Requests/Test.cs deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Discord.Net/Socket/DiscordGatewayApi.cs b/src/Discord.Net/Socket/DiscordGatewayApi.cs index 5f4744b90..705bba536 100644 --- a/src/Discord.Net/Socket/DiscordGatewayApi.cs +++ b/src/Discord.Net/Socket/DiscordGatewayApi.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Discord.Socket { - public class DiscordGatewayApi + public class DiscordGatewayApi : IDisposable { private readonly DiscordConfig _config; private readonly string _token; @@ -33,5 +33,10 @@ namespace Discord.Socket { await Task.CompletedTask; } + + public void Dispose() + { + Socket.Dispose(); + } } }