basic enough to test some stuff with fixed some bugs with disposables in the processpull/1435/head
| @@ -206,4 +206,6 @@ docs/api/\.manifest | |||||
| \.idea/ | \.idea/ | ||||
| # Codealike UID | # Codealike UID | ||||
| codealike.json | |||||
| codealike.json | |||||
| *.ignore | |||||
| @@ -7,6 +7,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5DAC796B-0B7 | |||||
| EndProject | EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net\Discord.Net.csproj", "{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net\Discord.Net.csproj", "{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}" | ||||
| EndProject | 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 | Global | ||||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| Debug|Any CPU = Debug|Any CPU | 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|x64.Build.0 = Release|Any CPU | ||||
| {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x86.ActiveCfg = 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 | {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 | EndGlobalSection | ||||
| GlobalSection(NestedProjects) = preSolution | GlobalSection(NestedProjects) = preSolution | ||||
| {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370} = {5DAC796B-0B77-4F84-B790-83DB78C6DFFE} | {3194F5DC-C0AF-4459-AAA3-91CB8FB8C370} = {5DAC796B-0B77-4F84-B790-83DB78C6DFFE} | ||||
| {5BE5DE89-53B7-4243-AEA8-FD8A6420908A} = {4795640A-030C-4A9A-A9B0-20C56AF4DA3F} | |||||
| EndGlobalSection | EndGlobalSection | ||||
| EndGlobal | EndGlobal | ||||
| @@ -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<object>().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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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<Assembly> 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; } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| <Project Sdk="Microsoft.NET.Sdk"> | |||||
| <PropertyGroup> | |||||
| <OutputType>Exe</OutputType> | |||||
| <TargetFramework>netcoreapp3.1</TargetFramework> | |||||
| </PropertyGroup> | |||||
| <ItemGroup> | |||||
| <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.5.0-beta1-final" /> | |||||
| </ItemGroup> | |||||
| <ItemGroup> | |||||
| <ProjectReference Include="..\..\src\Discord.Net\Discord.Net.csproj" /> | |||||
| </ItemGroup> | |||||
| </Project> | |||||
| @@ -15,6 +15,7 @@ | |||||
| <ItemGroup> | <ItemGroup> | ||||
| <Folder Include="Entities\" /> | <Folder Include="Entities\" /> | ||||
| <Folder Include="..\..\..\..\..\%2540discord\%2540next\Discord.Net\src\Discord.Net\Rest\Requests\" /> | <Folder Include="..\..\..\..\..\%2540discord\%2540next\Discord.Net\src\Discord.Net\Rest\Requests\" /> | ||||
| <Folder Include="Rest\Requests\" /> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| </Project> | </Project> | ||||
| @@ -16,5 +16,11 @@ namespace Discord | |||||
| Rest = restApi; | Rest = restApi; | ||||
| Gateway = gatewayApi; | Gateway = gatewayApi; | ||||
| } | } | ||||
| public void Dispose() | |||||
| { | |||||
| Rest.Dispose(); | |||||
| Gateway.Dispose(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -20,9 +20,13 @@ namespace Discord | |||||
| /// </summary> | /// </summary> | ||||
| public static readonly Uri DefaultGatewayUri = new Uri("wss://gateway.discord.gg"); | public static readonly Uri DefaultGatewayUri = new Uri("wss://gateway.discord.gg"); | ||||
| /// <summary> | /// <summary> | ||||
| /// The base URL for the Rest API. | |||||
| /// The default REST URI. | |||||
| /// </summary> | /// </summary> | ||||
| public string RestApiUrl { get; set; } = "https://discordapp.com/api/v6/"; | |||||
| public static readonly Uri DefaultRestUri = new Uri("https://discordapp.com/api/v6/"); | |||||
| /// <summary> | |||||
| /// The URI to use when making HTTP requests. If specified, this will override the default. | |||||
| /// </summary> | |||||
| public Uri? RestUri = null; | |||||
| /// <summary> | /// <summary> | ||||
| /// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. | /// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -1,12 +1,13 @@ | |||||
| using System; | |||||
| using System.Net.Http.Headers; | using System.Net.Http.Headers; | ||||
| using Discord.Rest; | using Discord.Rest; | ||||
| using Discord.Socket; | using Discord.Socket; | ||||
| namespace Discord | 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(); | config = config ?? new DiscordConfig(); | ||||
| @@ -3,6 +3,8 @@ using System.Threading.Tasks; | |||||
| using Refit; | using Refit; | ||||
| using Discord.Rest.Models; | using Discord.Rest.Models; | ||||
| using System.Net.Http.Headers; | using System.Net.Http.Headers; | ||||
| using System; | |||||
| using System.Net.Http; | |||||
| // This is essentially a reimplementation of Wumpus.Net.Rest | // This is essentially a reimplementation of Wumpus.Net.Rest | ||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| @@ -10,20 +12,31 @@ namespace Discord.Rest | |||||
| public class DiscordRestApi : IDiscordRestApi | public class DiscordRestApi : IDiscordRestApi | ||||
| { | { | ||||
| private readonly IDiscordRestApi _api; | private readonly IDiscordRestApi _api; | ||||
| private readonly HttpClient _http; | |||||
| public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) | public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) | ||||
| { | { | ||||
| _http = new HttpClient(new DiscordHttpClientHandler(token), true) | |||||
| { | |||||
| BaseAddress = config.RestUri ?? DiscordConfig.DefaultRestUri, | |||||
| }; | |||||
| var jsonOptions = new JsonSerializerOptions(); | var jsonOptions = new JsonSerializerOptions(); | ||||
| var refitSettings = new RefitSettings | var refitSettings = new RefitSettings | ||||
| { | { | ||||
| ContentSerializer = new JsonContentSerializer(jsonOptions), | ContentSerializer = new JsonContentSerializer(jsonOptions), | ||||
| }; | }; | ||||
| _api = RestService.For<IDiscordRestApi>(config.RestApiUrl, refitSettings); | |||||
| _api = RestService.For<IDiscordRestApi>(_http, refitSettings); | |||||
| } | } | ||||
| public Task<GatewayInfo> GetGatewayInfoAsync() | public Task<GatewayInfo> GetGatewayInfoAsync() | ||||
| { | { | ||||
| return _api.GetGatewayInfoAsync(); | return _api.GetGatewayInfoAsync(); | ||||
| } | } | ||||
| public void Dispose() | |||||
| { | |||||
| _http.Dispose(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,3 +1,4 @@ | |||||
| using System; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Refit; | using Refit; | ||||
| using Discord.Rest.Models; | using Discord.Rest.Models; | ||||
| @@ -4,7 +4,7 @@ using System.Threading.Tasks; | |||||
| namespace Discord.Socket | namespace Discord.Socket | ||||
| { | { | ||||
| public class DiscordGatewayApi | |||||
| public class DiscordGatewayApi : IDisposable | |||||
| { | { | ||||
| private readonly DiscordConfig _config; | private readonly DiscordConfig _config; | ||||
| private readonly string _token; | private readonly string _token; | ||||
| @@ -33,5 +33,10 @@ namespace Discord.Socket | |||||
| { | { | ||||
| await Task.CompletedTask; | await Task.CompletedTask; | ||||
| } | } | ||||
| public void Dispose() | |||||
| { | |||||
| Socket.Dispose(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||