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/ | |||
# Codealike UID | |||
codealike.json | |||
codealike.json | |||
*.ignore |
@@ -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 |
@@ -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> | |||
<Folder Include="Entities\" /> | |||
<Folder Include="..\..\..\..\..\%2540discord\%2540next\Discord.Net\src\Discord.Net\Rest\Requests\" /> | |||
<Folder Include="Rest\Requests\" /> | |||
</ItemGroup> | |||
</Project> |
@@ -16,5 +16,11 @@ namespace Discord | |||
Rest = restApi; | |||
Gateway = gatewayApi; | |||
} | |||
public void Dispose() | |||
{ | |||
Rest.Dispose(); | |||
Gateway.Dispose(); | |||
} | |||
} | |||
} |
@@ -20,9 +20,13 @@ namespace Discord | |||
/// </summary> | |||
public static readonly Uri DefaultGatewayUri = new Uri("wss://gateway.discord.gg"); | |||
/// <summary> | |||
/// The base URL for the Rest API. | |||
/// The default REST URI. | |||
/// </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> | |||
/// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. | |||
/// </summary> | |||
@@ -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(); | |||
@@ -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<IDiscordRestApi>(config.RestApiUrl, refitSettings); | |||
_api = RestService.For<IDiscordRestApi>(_http, refitSettings); | |||
} | |||
public Task<GatewayInfo> GetGatewayInfoAsync() | |||
{ | |||
return _api.GetGatewayInfoAsync(); | |||
} | |||
public void Dispose() | |||
{ | |||
_http.Dispose(); | |||
} | |||
} | |||
} |
@@ -1,3 +1,4 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
using Refit; | |||
using Discord.Rest.Models; | |||
@@ -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(); | |||
} | |||
} | |||
} |