Last active
December 19, 2018 17:32
-
-
Save nathan130200/7b0ad842d408726544227d96d9679138 to your computer and use it in GitHub Desktop.
C# Eval event based.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using DSharpPlus; | |
using DSharpPlus.CommandsNext; | |
using DSharpPlus.CommandsNext.Attributes; | |
using DSharpPlus.Entities; | |
using DSharpPlus.Interactivity; | |
using GameStage.Core.Entities.Eval; | |
using Humanizer; | |
using Microsoft.CodeAnalysis; | |
using Microsoft.CodeAnalysis.CSharp.Scripting; | |
using Microsoft.CodeAnalysis.Scripting; | |
using Microsoft.CodeAnalysis.Scripting.Hosting; | |
using Microsoft.Extensions.DependencyInjection; | |
using System; | |
using System.Collections.Generic; | |
using System.Collections.Immutable; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace GameStage.Core.Modules | |
{ | |
[RequireOwner] | |
public class BotOwnerModule : BaseCommandModule | |
{ | |
[Command("shutdown"), Description("Finaliza e desliga o bot."), Aliases("desligar")] | |
public async Task Shutdown(CommandContext ctx, | |
[RemainingText, Description("Código de finalização do bot.")] | |
int codigo = 0) | |
{ | |
await ctx.RespondAsync($"{ctx.User.Mention} :white_check_mark: Finalizando o bot com código `{codigo}`."); | |
await Task.Delay(2500); | |
Program.Exit(codigo); | |
} | |
[Command("gc"), Description("Chama o GC e tentar limpar conteúdo não utilizado da memória.")] | |
public async Task Gc(CommandContext ctx, | |
[RemainingText, Description("Quantidade de bytes que o GC deverá limpar.")] | |
int? quantidade = null) | |
{ | |
await ctx.TriggerTypingAsync(); | |
if (quantidade != null) | |
GC.Collect(quantidade.Value, GCCollectionMode.Forced); | |
else | |
GC.Collect(); | |
var text = $"{ctx.User.Mention} Sucesso! O GC foi acionado para limpar a memporia"; | |
if (quantidade != null) | |
text += $"em {quantidade.Value.Bytes().ToString("#.##")}"; | |
text += "!"; | |
await ctx.RespondAsync(text); | |
} | |
[Command("eval"), Description("Interpreta, Compila e Executa o trecho de código em C#")] | |
public async Task Eval(CommandContext ctx, | |
[RemainingText, Description("Código que será utilizado pela .NET Core Roslyn")] | |
string code) | |
{ | |
await ctx.TriggerTypingAsync(); | |
var start_index = code.IndexOf("```") + 3; | |
start_index = code.IndexOf('\n', start_index) + 1; | |
var end_index = code.LastIndexOf("```"); | |
if (start_index != -1 && end_index != -1) | |
code = code.Substring(start_index, end_index - start_index); | |
using (var script = new GameStageBotEvulationScript(code, ctx)) | |
{ | |
script.OnSuccess += async state => | |
{ | |
await ctx.RespondAsync(ctx.User.Mention, embed: new DiscordEmbedBuilder() | |
.AsInformation() | |
.WithRequestedBy(ctx.User) | |
.WithAuthor("GST3: Eval", iconUrl: "https://i.imgur.com/zmGTgPr.png") | |
.AddField("Status", "Sucesso") | |
.AddField("Valor Retornado", state.ReturnValue != null ? state.ReturnValue.ToString().Truncate(1500) : "Nenhum valor retornado") | |
); | |
}; | |
script.OnError += async exception => | |
{ | |
if(exception is CompilationErrorException ce) | |
{ | |
var pages = new List<Page>(); | |
var fmt = string.Empty; | |
var i = 1; | |
foreach (var error in ce.Diagnostics) | |
{ | |
var ls = error.Location.GetLineSpan(); | |
if (fmt.Length < 1500) | |
{ | |
fmt += $"{ls.StartLinePosition.Line.ToString("#,##0")};" + | |
$"{ls.StartLinePosition.Character.ToString("#,##0")}: " + | |
$"{Formatter.InlineCode(error.GetMessage())}\n"; | |
} | |
else | |
{ | |
pages.Add(new Page | |
{ | |
Content = ctx.User.Mention, | |
Embed = new DiscordEmbedBuilder() | |
.AsError() | |
.WithRequestedBy(ctx.User) | |
.WithAuthor("GST3: Eval", iconUrl: "https://i.imgur.com/zmGTgPr.png") | |
.WithDescription($"Página {i}/{ce.Diagnostics.Length}") | |
.AddField("Status", "Falha") | |
.AddField("Ocorreu Em", "Compilação") | |
.WithDescription(fmt) | |
}); | |
i++; | |
fmt = string.Empty; | |
} | |
} | |
if (!string.IsNullOrEmpty(fmt)) | |
{ | |
i++; | |
pages.Add(new Page | |
{ | |
Content = ctx.User.Mention, | |
Embed = new DiscordEmbedBuilder() | |
.AsError() | |
.WithRequestedBy(ctx.User) | |
.WithAuthor("GST3: Eval", iconUrl: "https://i.imgur.com/zmGTgPr.png") | |
.WithDescription($"Página {i}/{ce.Diagnostics.Length}") | |
.AddField("Status", "Falha") | |
.AddField("Ocorreu Em", "Compilação") | |
.WithDescription(fmt) | |
}); | |
} | |
await ctx.Client.GetInteractivity() | |
.SendPaginatedMessage(ctx.Channel, ctx.User, pages); | |
} | |
}; | |
await script.RunAsync(); | |
} | |
} | |
} | |
} | |
namespace GameStage.Core.Entities.Eval | |
{ | |
public class GameStageBotEvulationEnvironment | |
{ | |
public GameStageBotEvulationEnvironment(CommandContext context, string code) | |
{ | |
this.Context = context; | |
this.Code = code; | |
} | |
public string Code { | |
get; | |
private set; | |
} | |
public GameStageBot Bot { | |
get { | |
return GameStageBot.Instance; | |
} | |
} | |
public CommandContext Context { | |
get; | |
private set; | |
} | |
public T GetService<T>() | |
{ | |
return Context.CommandsNext.Services.GetRequiredService<T>(); | |
} | |
public object GetService(Type serviceType) | |
{ | |
return Context.CommandsNext.Services.GetRequiredService(serviceType); | |
} | |
} | |
public delegate Task GameStageBotEvulationScript_OnSuccess(ScriptState<object> state); | |
public delegate Task GameStageBotEvulationScript_OnError(Exception exception); | |
public class GameStageBotEvulationScript : IDisposable | |
{ | |
private volatile bool _disposed; | |
private volatile int _code = 0; | |
private event GameStageBotEvulationScript_OnSuccess _onSuccess; | |
private event GameStageBotEvulationScript_OnError _onError; | |
private InteractiveAssemblyLoader _loader; | |
private GameStageBotEvulationEnvironment _env; | |
private Script<object> _script; | |
public event GameStageBotEvulationScript_OnSuccess OnSuccess { | |
add { | |
_onSuccess += value; | |
} | |
remove { | |
_onSuccess -= value; | |
} | |
} | |
public event GameStageBotEvulationScript_OnError OnError { | |
add { | |
_onError += value; | |
} | |
remove { | |
_onError -= value; | |
} | |
} | |
public GameStageBotEvulationScript(string code, CommandContext context) | |
{ | |
_loader = new InteractiveAssemblyLoader(); | |
_env = new GameStageBotEvulationEnvironment(context, code); | |
_script = CSharpScript.Create(code, BuildScriptOptions(), typeof(GameStageBotEvulationEnvironment), _loader); | |
} | |
public void Dispose() | |
{ | |
if (!_disposed) | |
{ | |
_env = null; | |
_script = null; | |
_loader.Dispose(); | |
_loader = null; | |
_disposed = true; | |
} | |
} | |
public async Task RunAsync() | |
{ | |
await Task.Yield(); | |
var compilation = _script.Compile(); | |
if (compilation.Any(xd => xd.Severity == DiagnosticSeverity.Error)) | |
{ | |
await _onError?.Invoke(new CompilationErrorException("Falha ao compilar o script!", compilation)); | |
return; | |
} | |
else | |
{ | |
try | |
{ | |
await _onSuccess?.Invoke(await _script.RunAsync(_env)); | |
} | |
catch (Exception ex) | |
{ | |
await _onError?.Invoke(ex); | |
} | |
} | |
} | |
static ScriptOptions _options; | |
public static ScriptOptions BuildScriptOptions() | |
{ | |
if (_options != null) | |
return _options; | |
var options = ScriptOptions.Default; | |
options.WithFileEncoding(Encoding.UTF8) | |
.WithEmitDebugInformation(false) | |
.WithReferences(AppDomain.CurrentDomain.GetAssemblies() | |
.Where(xa => !xa.IsDynamic && !string.IsNullOrEmpty(xa.Location))) | |
.WithImports("System", "System.Text", "System.Linq", "System.Threading", "System.Threading.Tasks", | |
"DSharpPlus", "DSharpPlus.CommandsNext", "DSharpPlus.Interactivity", "DSharpPlus.Lavalink", | |
"DSharpPlus.CommandsNext.Entities", "DSharpPlus.Entities", "DSharpPlus.Lavalink.Entities", | |
"GameStage", "GameStage.Core"); | |
return _options = options; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment