示例#1
0
        private void OnCtrlEvent(CtrlType type)
        {
            BotHelper.LogDebugToConsole("[CORE] ProcessExit triggered.");

            _ctrlEventHandler.Invoke(type);
            _mre.Set();
        }
示例#2
0
        private void LoadConfig()
        {
            BotHelper.LogDebugToConsole($"[GUILDBOT] _configPath: {_configPath}");
            BotHelper.LogDebugToConsole($"[GUILDBOT] Exists(_configPath): {File.Exists(_configPath)}");
            if (File.Exists(_configPath))
            {
                BotHelper.LogDebugToConsole($"[GUILDBOT] Full Path: {Path.GetFullPath(_configPath)}");
            }
            using (var stream = File.Open(_configPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                _config = XDocument.Load(stream);

            if (_config.Root == null || _config.Root.Name != "guildbotconfig")
            {
                throw new ApplicationException("Configuration file not found.");
            }

            XElement prefixEl = _config.Root.Element("coreprefix");

            if (prefixEl == null || String.IsNullOrEmpty(prefixEl.Value))
            {
                throw new ApplicationException("Configuration file is missing prefix data.");
            }

            _prefix = prefixEl.Value;
        }
示例#3
0
        // Private methods section

        private async Task MainAsync()
        {
            try
            {
                BotHelper.LogDebugToConsole(String.Join(Environment.NewLine,
                                                        $"[CORE] Current working dir :{Directory.GetCurrentDirectory()}",
                                                        $"Current AppDomain BaseDirectory :{AppDomain.CurrentDomain.BaseDirectory}"));
                _guildBotsDict = new Dictionary <ulong, GuildBot>();

                _client      = new DiscordSocketClient();
                _client.Log += Log;

                await LoadCoreConfig().ConfigureAwait(false);

                await _client.LoginAsync(TokenType.Bot, _token).ConfigureAwait(false);

                await _client.StartAsync().ConfigureAwait(false);

                _client.Ready += () => Task.Run(ConfigGuilds);

                AppDomain.CurrentDomain.ProcessExit += (o, e) => OnCtrlEvent(CtrlType.CTRL_C_EVENT);

                _client.MessageReceived += MessageReceived;

                _mre.WaitOne();
            }
            catch (Exception ex)
            {
                ex.LogToConsole("[FATAL][CORE] Unrecoverable error occurred.");
                throw;
            }
        }
示例#4
0
        private async Task ConfigGuilds()
        {
            // move this to the config later
            const ulong serviceGuildId = 910122574527234058UL;

            var guilds       = _client.Guilds.Where(g => g.Id != serviceGuildId);
            var serviceGuild = _client.Guilds.First(g => g.Id == serviceGuildId);

            foreach (var guild in guilds)
            {
                ulong  guildID         = guild.Id;
                string guildPath       = Path.Combine(_appBaseDirectory, guildID.ToString());
                string guildConfigPath = Path.Combine(guildPath, "config.xml");
                await Task.Run(() =>
                {
                    BotHelper.LogDebugToConsole($"[CORE] guildPath:{guildPath}");

                    if (!Directory.Exists(guildPath))
                    {
                        BotHelper.LogDebugToConsole($"[CORE] Creating guildPath:{guildPath}");

                        Directory.CreateDirectory(guildPath);
                    }
                    if (!File.Exists(guildConfigPath))
                    {
                        BotHelper.LogDebugToConsole($"[CORE] Creating guild config:{guildConfigPath}");

                        GetDefaultGuildConfig().Save(guildConfigPath);
                    }
                }).ConfigureAwait(false);

                GuildBot newBot = new GuildBot(guild, serviceGuild, guildPath, _client.CurrentUser.Id);

                _ctrlEventHandler += newBot.OnCtrlEvent;

                _guildBotsDict.TryAdd(guildID, newBot);
            }
        }
示例#5
0
        private async Task LoadConfig()
        {
            await Task.Run(() =>
            {
                BotHelper.LogDebugToConsole($"[CORE] Load Config Path :{Path.Combine(_appBaseDirectory, _configFileName)}");

                if (File.Exists(Path.Combine(_appBaseDirectory, _configFileName)))
                {
                    using (var stream = File.Open(Path.Combine(_appBaseDirectory, _configFileName), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                        _config = XDocument.Load(stream);
                }
                else
                {
                    throw new ApplicationException("Configuration file not found!");
                }
            }).ConfigureAwait(false);

            if (_config.Root.Name != "botconfig")
            {
                throw new ApplicationException("Configuration file not found.");
            }

            XElement tokenEl = _config.Root.Element("token");

            if (tokenEl == null || String.IsNullOrEmpty(tokenEl.Value))
            {
                throw new ApplicationException("Configuration file is missing token data.");
            }
            _token = tokenEl.Value;

            XElement prefixEl = _config.Root.Element("coreprefix");

            if (prefixEl == null || String.IsNullOrEmpty(prefixEl.Value))
            {
                throw new ApplicationException("Configuration file is missing prefix data.");
            }
            _prefix = prefixEl.Value;
        }
示例#6
0
        private async Task EmojiStatsCmd(SocketMessage msg)
        {
            string logPrefix = "[GUILDBOT][EMOJISTATS]";

            try
            {
                var sw = new System.Diagnostics.Stopwatch();
                sw.Start();

                var emotes       = _guild.Emotes;
                var emojiStrings = emotes.Select(e => $"{e}");
                var channels     = _guild.TextChannels;

                var timestamp    = DateTime.UtcNow;
                var timeDiff     = TimeSpan.FromDays(60.0d);
                var timeBoundary = timestamp - timeDiff;

                var emoteTextDict     = new Dictionary <string, int>();
                var emoteReacDict     = new Dictionary <IEmote, int>();
                var emoteTextDictLock = new object();
                var emoteReacDictLock = new object();

                foreach (var e in emojiStrings)
                {
                    emoteTextDict.TryAdd(e, 0);
                }
                foreach (var e in emotes)
                {
                    emoteReacDict.TryAdd(e, 0);
                }

                foreach (var textChannel in channels)
                {
                    IMessage lastSeenMsg = null;

                    int q = 0;

                    BotHelper.LogDebugToConsole($"{logPrefix} Started processing of #{textChannel.Name}.");

                    var asyncMessages = textChannel.GetMessagesAsync();
                    var msgList       = new List <IMessage>();
                    try
                    {
                        await foreach (var messages in asyncMessages)
                        {
                            foreach (var message in messages)
                            {
                                lastSeenMsg = message;
                                if (message.Timestamp < timeBoundary)
                                {
                                    break;
                                }
                                msgList.Add(message);
                            }
                            if (lastSeenMsg == null || lastSeenMsg.Timestamp < timeBoundary)
                            {
                                break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.LogToConsole($"{logPrefix} Fetch Messages failed : #{textChannel.Name}");
                        continue;
                    }

                    BotHelper.LogDebugToConsole($"{logPrefix} Downloaded {msgList.Count} messages from #{textChannel.Name}.");

                    while (lastSeenMsg.Timestamp > timeBoundary)
                    {
                        int listCount;
                        try
                        {
                            listCount = msgList.Count;
                            await foreach (var messages in textChannel.GetMessagesAsync(lastSeenMsg, Direction.Before))
                            {
                                foreach (var message in messages)
                                {
                                    lastSeenMsg = message;
                                    if (message.Timestamp < timeBoundary)
                                    {
                                        break;
                                    }
                                    msgList.Add(message);
                                }
                                if (lastSeenMsg.Timestamp < timeBoundary)
                                {
                                    break;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            ex.LogToConsole($"{logPrefix} Fetch Messages failed : #{textChannel.Name}");
                            continue;
                        }

                        BotHelper.LogDebugToConsole($"{logPrefix} Downloaded {msgList.Count} messages from #{textChannel.Name}.");

                        if (msgList.Count == listCount)
                        {
                            break; // boundary is earlier than channel creation
                        }
                    }

                    int threads = Environment.ProcessorCount < 3 ? 1 : Environment.ProcessorCount - 1;

                    int count     = msgList.Count / threads;
                    int remainder = msgList.Count % threads;
                    List <List <IMessage> > splitList = new List <List <IMessage> >();
                    int j = 0;
                    for (int i = 0; i < threads; i++)
                    {
                        int curCount = (i < remainder) ? count + 1 : count;
                        splitList.Add(msgList.GetRange(j, curCount));
                        j += curCount;
                    }

                    List <Task> tasklist = new List <Task>();

                    foreach (var messagesPerCore in splitList)
                    {
                        tasklist.Add(Task.Run(() =>
                        {
                            try
                            {
                                foreach (var message in messagesPerCore)
                                {
                                    if (message.Author.IsBot || message.Author.IsWebhook)
                                    {
                                        continue;
                                    }
                                    if (message is IUserMessage um)
                                    {
                                        foreach (var reaction in um.Reactions)
                                        {
                                            if (emoteReacDict.ContainsKey(reaction.Key))
                                            {
                                                lock (emoteReacDictLock)
                                                    emoteReacDict[reaction.Key] += reaction.Value.ReactionCount;
                                            }
                                        }
                                    }
                                    if (String.IsNullOrEmpty(message.Content))
                                    {
                                        continue; // skip empty messages
                                    }
                                    foreach (var emote in emoteTextDict.Keys.ToList())
                                    {
                                        int n = (message.Content.Length - message.Content.Replace(emote, String.Empty, StringComparison.InvariantCulture).Length) / emote.Length;
                                        lock (emoteTextDictLock)
                                            emoteTextDict[emote] += n;
                                    }
                                    Interlocked.Increment(ref q);
                                }
                            }
                            catch (Exception ex)
                            {
                                ex.LogToConsole($"{logPrefix} Processing Messages failed : #{textChannel.Name}");
                            }
                        }));
                    }

                    await Task.WhenAll(tasklist).ConfigureAwait(false);

                    BotHelper.LogDebugToConsole($"{logPrefix} Processed messages from #{textChannel.Name}.");
                }

                var emoteTotalDict = new Dictionary <Discord.IEmote, int>(emoteReacDict);
                foreach (var e in emoteTotalDict.Keys.ToList())
                {
                    emoteTotalDict[e] += emoteTextDict[$"{e}"];
                }
                var outputs = new List <string>();
                var str     = $"**=== Emoji Usage Stats ===**\n\n`{"Emoji",4} \u2502 {"Total",10} \u2502 {"Reactions",10} \u2502 {"Text",10}`\n";

                foreach (var e in emoteTotalDict.OrderByDescending(kvp => kvp.Value))
                {
                    str += $"{e.Key,4}`   \u2502 {e.Value,10} \u2502 {emoteReacDict[e.Key],10} \u2502 {emoteTextDict[$"{e.Key}"],10}`{Environment.NewLine}";
                    if (str.Length > 1900)
                    {
                        outputs.Add(str);
                        str = String.Empty;
                    }
                }
                outputs.Add(str);

                sw.Stop();
                foreach (var output in outputs)
                {
                    await msg.Channel.SendMessageAsyncSafe(output).ConfigureAwait(false);

                    await Task.Delay(500).ConfigureAwait(false);
                }
                await msg.Channel.SendMessageAsyncSafe($"Total time spent: {sw.Elapsed}").ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                ex.LogToConsole($"{logPrefix}. Command failed:");
                throw;
            }
        }
示例#7
0
        protected override async Task SearchCommand(SocketMessage msg)
        {
            string cmdPrefix = $"[{LogPref}][SEARCH-FILES]";

            BotHelper.LogDebugToConsole($"{cmdPrefix} Entering.");
            var regexStr = msg.Content.Replace($"{_prefix}search", String.Empty, StringComparison.InvariantCulture).TrimStart();

            try
            {
                if (regexStr.Length == 0)
                {
                    return;
                }
                if (regexStr.Length > 200) // unreasonably long regex
                {
                    await msg.Channel.SendMessageAsyncSafe($"Занадто довгий запит: `{regexStr}` {EmojiCodes.WaitWhat}").ConfigureAwait(false);

                    return;
                }

                // init regex before starting waiter, as regex can be malformed
                Regex regex;
                try
                {
                    regex = new Regex(regexStr, RegexOptions.CultureInvariant | RegexOptions.Multiline | RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    ex.LogToConsole($"[WARNING]{cmdPrefix} Malformed regex \"{regexStr}\".");
                    await msg.Channel.SendMessageAsyncSafe($"Що це за хуйня?? {EmojiCodes.Tomas} `{regexStr}`").ConfigureAwait(false);

                    return;
                }

                using ManualResetEventSlim mres = new ManualResetEventSlim(false);

                var waitTask = Task.Run(async() =>
                {
                    BotHelper.LogDebugToConsole($"{cmdPrefix} Entering waiter.");
                    var waitMsg = await msg.Channel.SendMessageAsyncSafe($"Шукаю `{regexStr}` в цитатах {EmojiCodes.Bumagi}").ConfigureAwait(false);
                    if (waitMsg == null)
                    {
                        return;
                    }
                    string content = String.Empty;
                    while (mres != null && !mres.IsSet)
                    {
                        await Task.Delay(5000).ConfigureAwait(false);
                        content = (await msg.Channel.GetMessageAsync(waitMsg.Id).ConfigureAwait(false)).Content;
                        await waitMsg.ModifyAsync(p => { p.Content = $"{content}{EmojiCodes.Bumagi}"; }).ConfigureAwait(false);
                    }
                    content = (await msg.Channel.GetMessageAsync(waitMsg.Id).ConfigureAwait(false)).Content;
                    await waitMsg.ModifyAsync(p => { p.Content = $"{content}{Environment.NewLine}Пошук закінчено. {EmojiCodes.Picardia}"; }).ConfigureAwait(false);
                });

                var itemsDict   = new Dictionary <string, XElement>();
                var matchesDict = new Dictionary <string, string>();
                RPItemDictGenerator(GetRootByKey(String.Empty), String.Empty, itemsDict);
                BotHelper.LogDebugToConsole($"{cmdPrefix} {itemsDict.Count} entries in dictionary.");

                foreach (var kvp in itemsDict)
                {
                    string citation;
                    string citationFileName = kvp.Value.Value;

                    try
                    {
                        citation = await File.ReadAllTextAsync(Path.Combine(_guildPath, ModuleFolder, citationFileName)).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        ex.LogToConsole($"[WARNING]{cmdPrefix} Citation loading failed: {kvp.Key} - {kvp.Value.Value}");
                        continue;
                    }

                    if (citation.Length > _msgLengthLimit || !regex.IsMatch(citation))
                    {
                        continue;
                    }
                    matchesDict.Add(kvp.Key, citation);
                }

                BotHelper.LogDebugToConsole($"{cmdPrefix} {matchesDict.Count} matches.");

                mres.Set();
                await Task.WhenAll(waitTask).ConfigureAwait(false);

                if (matchesDict.Count == 0)
                {
                    await msg.Channel.SendMessageAsyncSafe($"Не знайдено **цитат** за запитом `{regexStr}` {EmojiCodes.Pepe}").ConfigureAwait(false);

                    return;
                }
                await msg.Channel.SendMessageAsyncSafe($"Знайдено {matchesDict.Count} **цитат** за запитом `{regexStr}` {EmojiCodes.DankPepe}").ConfigureAwait(false);

                string output = $"Результати пошуку **цитат** за запитом: `{regexStr}`:{Environment.NewLine}";

                var dm = await msg.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false);

                await dm.GenerateAndSendOutputMessages(output,
                                                       matchesDict,
                                                       kvp => $"`{kvp.Key}`{Environment.NewLine}{kvp.Value}{Environment.NewLine}",
                                                       s => s,
                                                       s => s).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                ex.LogToConsole($"[WARNING]{cmdPrefix} Search failed for regex \"{regexStr}\".");
                throw;
            }
            finally
            {
                BotHelper.LogDebugToConsole($"{cmdPrefix} Passing control to keys search.");
                await base.SearchCommand(msg).ConfigureAwait(false);
            }
        }
示例#8
0
        protected virtual async Task SearchCommand(SocketMessage msg)
        {
            string cmdPrefix = $"[{LogPref}][SEARCH]";

            BotHelper.LogDebugToConsole($"{cmdPrefix} Entered search.");
            var regexStr = msg.Content.Replace($"{_prefix}search", String.Empty, StringComparison.InvariantCulture).TrimStart();

            try
            {
                if (regexStr.Length == 0)
                {
                    return;
                }
                if (regexStr.Length > 200) // unreasonably long regex
                {
                    await msg.Channel.SendMessageAsyncSafe($"Занадто довгий запит: `{regexStr}` {EmojiCodes.WaitWhat}").ConfigureAwait(false);

                    return;
                }

                Regex regex;
                try
                {
                    regex = new Regex(regexStr, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    ex.LogToConsole($"[WARNING]{cmdPrefix} Malformed regex \"{regexStr}\".");
                    await msg.Channel.SendMessageAsyncSafe($"Що це за хуйня?? {EmojiCodes.Tomas} `{regexStr}`").ConfigureAwait(false);

                    return;
                }

                var matchedKeysList = RPKeyListGenerator(GetRootByKey(String.Empty), String.Empty, true).Where(key => regex.IsMatch(key)).ToList();

                BotHelper.LogDebugToConsole($"{cmdPrefix} Number of matches: {matchedKeysList.Count} for regex \"{regexStr}\".");

                if (!matchedKeysList.Any())
                {
                    await msg.Channel.SendMessageAsyncSafe($"Не знайдено **ключів** за запитом `{regexStr}` {EmojiCodes.Pepe}").ConfigureAwait(false);

                    return;
                }
                await msg.Channel.SendMessageAsyncSafe($"Знайдено {matchedKeysList.Count} **ключів** за запитом `{regexStr}` {EmojiCodes.DankPepe}").ConfigureAwait(false);

                string output = $"Результати пошуку **ключів** за запитом `{regexStr}`:{Environment.NewLine}```{Environment.NewLine}";

                var dm = await msg.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false);

                await dm.GenerateAndSendOutputMessages(output,
                                                       matchedKeysList,
                                                       s => $"{s}{Environment.NewLine}",
                                                       s => $"```{Environment.NewLine}{s}",
                                                       s => $"{s}```").ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                ex.LogToConsole($"[WARNING]{cmdPrefix} Command failed. Query=\"{regexStr}\"");
                throw;
            }
        }