/// <summary> /// Called when mod is loaded /// </summary> public override void OnModLoad() { GlobalLogger = string.IsNullOrEmpty(TestVersion) ? new Logger(DiscordLogLevel.Warning) : new Logger(DiscordLogLevel.Debug); GlobalLogger.Info($"Using Discord Extension Version: {GetExtensionVersion}"); AppDomain.CurrentDomain.UnhandledException += (sender, exception) => { GlobalLogger.Exception("An exception was thrown!", exception.ExceptionObject as Exception); }; string configPath = Path.Combine(Interface.Oxide.InstanceDirectory, "discord.config.json"); if (!File.Exists(configPath)) { DiscordConfig = new DiscordConfig(configPath); DiscordConfig.Save(); } DiscordConfig = ConfigFile.Load <DiscordConfig>(configPath); DiscordConfig.Save(); DiscordLink = new DiscordLink(GlobalLogger); DiscordCommand = new DiscordCommand(DiscordConfig.Commands.CommandPrefixes); DiscordSubscriptions = new DiscordSubscriptions(GlobalLogger); Manager.RegisterLibrary(nameof(DiscordLink), DiscordLink); Manager.RegisterLibrary(nameof(DiscordCommand), DiscordCommand); Manager.RegisterLibrary(nameof(DiscordSubscriptions), DiscordSubscriptions); Interface.Oxide.RootPluginManager.OnPluginAdded += DiscordClient.OnPluginAdded; Interface.Oxide.RootPluginManager.OnPluginRemoved += DiscordClient.OnPluginRemoved; }
public static Task Main(string[] args) { var services = new ServiceCollection(); services.AddLogging((builder) => { builder.AddSimpleConsole(console => { console.SingleLine = true; }); }); services.AddSingleton(_credentials); services.AddSingleton <ArmDeployment>(); services.AddHttpClient <DiscordClient>(); services.AddSingleton <ILookupClient, LookupClient>(); services.AddSingleton <AcmeCertificateGenerator>(); services.AddSingleton((sp) => { var options = new JsonSerializerOptions(); options.Converters.Add(new JsonStringEnumConverter()); return(JsonSerializer.Deserialize <Dictionary <string, ApplicationCommand> >( File.ReadAllText("commands.json"), options) !); }); var serviceProvider = services.BuildServiceProvider(); var root = new RootCommand("Deployment utilities for AzureBot") { InfraCommand.GetCommand(serviceProvider), DiscordCommand.GetCommand(serviceProvider), }; return(root.InvokeAsync(args)); }
private static async Task ProcessMessage(DiscordMessage message, DiscordUser author, DiscordChannel channel) { DateTimeOffset startTime = DateTimeOffset.Now; if (!string.IsNullOrWhiteSpace(message?.Content) && !author.IsBot && !author.IsCurrent && !ProcessedMessageIds.Contains(message.Id)) { if (message.Content.ToLower().StartsWith(Config.Prefix.ToLower())) { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Found command prefix, parsing..."); IEnumerable <string> commandSegments = Strings.SplitCommandLine(message.Content.Substring(Config.Prefix.Length)); foreach (IParseExtension extenstion in ParseExtensions) { commandSegments = extenstion.Parse(commandSegments, channel); } if (commandSegments.Any()) { string commandAlias = commandSegments.First().ToLower(); IEnumerable <DiscordCommand> foundCommands = Commands.Where(c => c.Aliases.Any(a => a.ToLower() == commandAlias)); DiscordCommand commandToRun = foundCommands.FirstOrDefault(); if (foundCommands.Count() == 1) { await ExecuteCommandAsync(message, author, channel, commandSegments.Skip(1), commandAlias, commandToRun, startTime); } else if (commandSegments.Count() >= 2) { foundCommands = AssemblyCommands.FirstOrDefault(c => c.Key.Name.ToLowerInvariant() == commandAlias) .Value?.Where(c => c.Aliases.Contains(commandSegments.ElementAt(1).ToLower())); if (foundCommands != null && foundCommands.Count() == 1) { await ExecuteCommandAsync(message, author, channel, commandSegments.Skip(2), commandAlias, foundCommands.First(), startTime); } else { if (commandToRun != null) { await ExecuteCommandAsync(message, author, channel, commandSegments.Skip(1), commandAlias, foundCommands.First(), startTime); } else { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Unable to find command with alias \"{commandAlias}\"."); await SendTemporaryMessage(message, author, channel, $"```\r\n{commandAlias}: command not found!\r\n```"); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, null, startTime, "404", false)); } } } else if (commandToRun != null) { await ExecuteCommandAsync(message, author, channel, commandSegments.Skip(1), commandAlias, foundCommands.First(), startTime); } } } } }
public InvalidParameterEventArgs(DiscordCommand command, ParameterAttribute param, string input) : base(command, param) { InputtedParameter = input; }
private static void ManageException(DiscordMessage message, DiscordUser author, DiscordChannel channel, Exception ex, DiscordCommand command) { _appLogArea.WriteLine($"\n --- Something's f****d up! --- \n{ex.ToString()}\n"); TelemetryClient?.TrackException(ex, new Dictionary <string, string> { { "command", command.GetType().Name } }); if (!(ex is TaskCanceledException) && !(ex is OperationCanceledException)) { if (_ownerDm != null) { try { _ownerDm.SendMessageAsync($"An {ex.GetType().Name} has occured processing command \"{command.Name}\" in {channel.Mention}{(channel.Guild != null ? $" ({channel.Guild.Name})" : "")}"); _ownerDm.SendMessageAsync($"```\r\n" + $"{ex.ToString()}" + $"```"); _ownerDm.SendMessageAsync($"Message content: `{message.Content}`"); _ownerDm.SendMessageAsync($"Message author: {author.Mention}"); } catch { } } new Task(async() => { try { DiscordMessage msg = await channel.SendMessageAsync( $"Something's gone very wrong executing that command, and an {ex.GetType().Name} occured." + $"{(_ownerDm != null ? "\r\nThis error has been reported, and should be fixed soon:tm:!" : "")}" + $"\r\nThis message will be deleted in 10 seconds."); await Task.Delay(10_000); await msg.DeleteAsync(); } catch { } }).Start(); } }
private static async Task RunCommandAsync(DiscordMessage message, DiscordUser author, DiscordChannel channel, IEnumerable <string> commandSegments, string commandAlias, DiscordCommand command, DateTimeOffset start) { bool success = true; try { using (WamBotContext dbContext = new WamBotContext()) { await channel.TriggerTypingAsync(); command = InstantateDiscordCommand(command.GetType()); HappinessData.TryGetValue(author.Id, out sbyte h); CommandContext context = new CommandContext(commandSegments.ToArray(), message, Client) { Happiness = h, _logger = _loggerFactory.CreateLogger("Commands"), UserData = await dbContext.Users.FindOrCreateAsync(author.Id, () => new UserData(author)) }; CommandResult result = await command.RunCommand(commandSegments.ToArray(), context); _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] \"{command.Name}\" returned ReturnType.{result.ReturnType}."); if (result.ReturnType != ReturnType.None) { if (result.ReturnType == ReturnType.Text && result.ResultText.Length > 2000) { for (int i = 0; i < result.ResultText.Length; i += 1993) { string str = result.ResultText.Substring(i, Math.Min(1993, result.ResultText.Length - i)); if (result.ResultText.StartsWith("```") && !str.StartsWith("```")) { str = "```" + str; } if (result.ResultText.EndsWith("```") && !str.EndsWith("```")) { str = str + "```"; } _appLogArea.WriteLine($"Chunking message to {str.Length} chars"); await channel.SendMessageAsync(str); await Task.Delay(2000); } } else { if (!string.IsNullOrWhiteSpace(result.Attachment)) { await channel.SendFileAsync(result.Attachment, result.ResultText, embed : result.ResultEmbed); } else if (result.Stream != null || result.ReturnType == ReturnType.File) { if (result.Stream.Length <= 8 * 1024 * 1024) { await channel.SendFileAsync(result.Stream, result.FileName, result.ResultText, false, result.ResultEmbed); } else { await channel.SendMessageAsync("This command has resulted in an attachment that is over 8MB in size and cannot be sent."); } } else { await channel.SendMessageAsync(result.ResultText, embed : result.ResultEmbed); } } } RequestTelemetry request = GetRequestTelemetry(author, channel, command, start, success ? "200" : "500", success); foreach (var pair in result.InsightsData) { request.Properties.Add(pair); } TelemetryClient?.TrackRequest(request); HappinessData[author.Id] = (sbyte)((int)(context.Happiness).Clamp(sbyte.MinValue, sbyte.MaxValue)); } } catch (BadArgumentsException) { await HandleBadRequest(message, author, channel, commandSegments, commandAlias, command, start); } catch (CommandException ex) { await channel.SendMessageAsync(ex.Message); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, command, start, "400", false)); } catch (ArgumentOutOfRangeException) { await channel.SendMessageAsync("Hey there! That's gonna cause some issues, no thanks!!"); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, command, start, "400", false)); } catch (Exception ex) { success = false; ManageException(message, author, channel, ex, command); sbyte h = 0; HappinessData?.TryGetValue(author.Id, out h); HappinessData[author.Id] = (sbyte)((int)h - 1).Clamp(sbyte.MinValue, sbyte.MaxValue); } finally { if (command is IDisposable disp) { disp.Dispose(); } } }
private static async Task HandleBadRequest(DiscordMessage message, DiscordUser author, DiscordChannel channel, IEnumerable <string> commandSegments, string commandAlias, DiscordCommand command, DateTimeOffset start) { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] {command.Name} does not take {commandSegments.Count()} arguments."); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, command, start, "400", false)); if (command.Usage != null) { await SendTemporaryMessage(message, author, channel, $"```\r\n{commandAlias} usage: {Config.Prefix}{commandAlias} [{command.Usage}]\r\n```"); } }
private static async Task ExecuteCommandAsync(DiscordMessage message, DiscordUser author, DiscordChannel channel, IEnumerable <string> commandSegments, string commandAlias, DiscordCommand command, DateTimeOffset start) { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Found {command.Name} command!"); ProcessedMessageIds.Add(message.Id); if (command.ArgumentCountPrecidate(commandSegments.Count())) { if (CheckPermissions(channel.Guild?.CurrentMember ?? Client.CurrentUser, channel, command)) { if (CheckPermissions(author, channel, command)) { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Running command \"{command.Name}\" asynchronously."); new Task(async() => await RunCommandAsync(message, author, channel, commandSegments, commandAlias, command, start)).Start(); } else { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Attempt to run command without correct user permissions."); await SendTemporaryMessage(message, author, channel, $"Oi! You're not alowed to run that command! F**k off!"); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, command, start, "401", false)); } } else { _appLogArea.WriteLine($"[{message.Channel.Guild.Name ?? message.Channel.Name}] Attempt to run command without correct bot permissions."); await SendTemporaryMessage(message, author, channel, $"Sorry! I don't have permission to run that command in this server! Contact an admin/mod for more info."); TelemetryClient?.TrackRequest(GetRequestTelemetry(author, channel, command, start, "403", false)); } } else { await HandleBadRequest(message, author, channel, commandSegments, commandAlias, command, start); } }
internal static async Task LoadPluginsAsync() { _appLogArea.WriteLine(""); List <string> dlls = Directory.EnumerateFiles("Plugins").Where(f => Path.GetExtension(f) == ".dll").ToList(); dlls.Insert(0, Assembly.GetExecutingAssembly().Location); foreach (string str in Config.AdditionalPluginDirectories) { dlls.AddRange(Directory.EnumerateFiles(str).Where(f => Path.GetExtension(f) == ".dll")); } _appLogArea.WriteLine($"{(Commands.Any() ? "Reloading" : "Loading")} {dlls.Count()} plugins..."); Commands.Clear(); AssemblyCommands.Clear(); ParseExtensions.Clear(); foreach (string dllPath in dlls) { try { Assembly assembly = Assembly.LoadFrom(dllPath); if (assembly != null && assembly.DefinedTypes.Any(t => t.GetInterfaces()?.Contains(typeof(ICommandsAssembly)) == true)) { Debug.WriteLine(dllPath); _appLogArea.WriteLine($"Searching {Path.GetFileName(dllPath)} for commands."); ICommandsAssembly asm = null; List <DiscordCommand> asmCommands = new List <DiscordCommand>(); foreach (Type type in assembly.GetTypes()) { if (type.GetInterfaces().Contains(typeof(ICommandsAssembly))) { asm = (ICommandsAssembly)Activator.CreateInstance(type); } if (type.GetInterfaces().Contains(typeof(IParseExtension))) { ParseExtensions.Add((IParseExtension)Activator.CreateInstance(type)); } if (type.GetInterfaces().Contains(typeof(IParamConverter))) { Tools.RegisterPatameterParseExtension((IParamConverter)Activator.CreateInstance(type)); } if (type.IsSubclassOf(typeof(DiscordCommand)) && !type.IsAbstract) { DiscordCommand command = InstantateDiscordCommand(type); if (command != null) { asmCommands.Add(command); } } } if (asm == null) { _appLogArea.WriteLine($"Loaded {asmCommands.Count()} commands from {Path.GetFileName(dllPath)} without command assembly manifest. Categorised help will be unavailable for these commands."); _appLogArea.WriteLine("Consider adding an \"ICommandAssembly\" class as soon as possible."); } else { if (asm is IBotStartup s) { await s.Startup(Client); } _appLogArea.WriteLine($"Loaded {asmCommands.Count()} plugins from {Path.GetFileName(dllPath)}!"); } Commands.AddRange(asmCommands); if (asm != null) { AssemblyCommands.Add(asm, asmCommands); } } } catch (Exception ex) { _appLogArea.WriteLine($"An {ex.GetType().Name} occured while loading from {Path.GetFileName(dllPath)}\n{ex.Message}"); } } _appLogArea.WriteLine(""); _appLogArea.WriteLine($"Plugins loaded!"); _appLogArea.WriteLine($"{Commands.Count} commands available: {string.Join(", ", Commands.Select(c => c.Name))}"); _appLogArea.WriteLine($"{ParseExtensions.Count} parse extensions available: {string.Join(", ", ParseExtensions.Select(c => c.Name))}"); _appLogArea.WriteLine(""); }
static void Main(string[] args) { DiscordClient client = new DiscordClient("token", true, true); client.EnableVerboseLogging = true; client.GetTextClientLogger.EnableLogging = true; client.GetTextClientLogger.LogMessageReceived += (sender, e) => Console.WriteLine($"{e.message.TimeStamp} -- {e.message.Message}"); Console.WriteLine("Attempting to connect!"); client.CommandPrefixes.Add("testbot."); client.AddCommand(DiscordCommand.Create("create") .AddParameter("name") .Do(e => { Hook.Webhook hook = e.Channel.CreateWebhook(e.args[0]); SlackMessage message = new SlackMessage(); message.Add(new SlackText("text", "List of Webhooks")); SlackContainer attachment = new SlackContainer(); attachment.Add(new SlackText("color", "#36a64f")); attachment.Add(new SlackText("pretext", hook.Token)); attachment.Add(new SlackText("author_name", $"{hook.Name} [{hook.ID}]")); attachment.Add(new SlackText("author_icon", hook.User.GetAvatarURL().ToString())); attachment.Add(new SlackText("title", hook.Name)); attachment.Add(new SlackText("text", hook.Token)); attachment.Add(new SlackText("image_url", hook.Avatar)); message.Add(new SlackContainerList("attachments", new List <SlackContainer>() { attachment })); hook.SendSlack(message.ToJObject()); } )); client.AddCommand(DiscordCommand.Create("list") .Do(e => { Hook.Webhook fHook = null; SlackMessage message = new SlackMessage(); message.Add(new SlackText("text", $"New {Formatter.Bold(Formatter.Bold("webhook"))} {Formatter.InlineCode("created")}")); List <SlackContainer> attachments = new List <SlackContainer>(); foreach (Hook.Webhook hook in e.Channel.GetWebhooks()) { if (fHook == null) { fHook = hook; } SlackContainer attachment = new SlackContainer(); attachment.Add(new SlackText("color", "#36a64f")); attachment.Add(new SlackText("pretext", hook.Token)); attachment.Add(new SlackText("author_name", $"{hook.Name} [{hook.ID}]")); attachment.Add(new SlackText("author_icon", hook.User.GetAvatarURL().ToString())); attachment.Add(new SlackText("title", hook.Name)); attachment.Add(new SlackText("text", hook.Token)); attachment.Add(new SlackText("image_url", hook.Avatar)); attachments.Add(attachment); } message.Add(new SlackContainerList("attachments", attachments)); fHook.SendSlack(message.ToJObject(), false); } )); client.AddCommand(DiscordCommand.Create("removeall") .Do(e => { foreach (Hook.Webhook hook in e.Channel.GetWebhooks()) { hook.Delete(); } } )); try { client.SendLoginRequest(); client.Connect(); } catch (Exception e) { Console.WriteLine(e.Message); } client.Connected += (sender, e) => { Console.WriteLine("CLIENT CONNECTED"); }; client.MessageReceived += (sender, e) => // Channel message has been received { if (e.MessageText == "tiaqoy0 is the most awesome person in the world") // fixed* -> love you afro <3 { e.Channel.SendMessage(e.MessageText); } }; Console.ReadLine(); Environment.Exit(0); }