public async Task Execute(IJobExecutionContext context) { try { // Log that we're about to begin a check await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** Beginning check"); // Download the latest Topic Topic topic = await BcatApi.GetDataTopic(Program.TITLE_ID, Program.PASSPHRASE); // Create the target folder name string targetFolder = string.Format(Program.LOCAL_OLD_DATA_DIRECTORY, DateTime.Now.ToString(Program.FOLDER_DATE_TIME_FORMAT)); // Check if this the first run if (!Configuration.LoadedConfiguration.FirstRunCompleted) { // Log that this is the first run of BCAT await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** First run"); // Download all data Dictionary <string, byte[]> downloadedData = await BcatCheckerUtils.DownloadAllData(topic, Program.TITLE_ID, Program.PASSPHRASE, targetFolder); // Loop over all data foreach (KeyValuePair <string, byte[]> pair in downloadedData) { // Get the FileType FileType fileType = FileTypeExtensions.GetTypeFromName(pair.Key); // Check if this is a container if (fileType.IsContainer()) { // Create a Container instance Nintendo.SmashUltimate.Bcat.Container container = CreateSmashContainerInstance(fileType, pair.Value); // Add this to the container cache ContainerCache.AddFile(container, Path.GetFileName(pair.Key), pair.Value); } else { // Write this file out to the common file cache File.WriteAllBytes(Path.Combine(Program.LOCAL_COMMON_CACHE_DIRECTORY, Path.GetFileName(pair.Key)), pair.Value); } } // Save the configuration Configuration.LoadedConfiguration.FirstRunCompleted = true; Configuration.LoadedConfiguration.Write(); // Write out the topic File.WriteAllBytes(Program.LOCAL_LAST_TOPIC, MessagePackSerializer.Serialize(topic)); // Log that we're about to begin a check await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** First run complete"); return; } // Load the old Topic Topic oldTopic = MessagePackSerializer.Deserialize <Topic>(File.ReadAllBytes(Program.LOCAL_LAST_TOPIC)); #if DEBUG if (!Configuration.LoadedConfiguration.IsProduction) { /*foreach (Bcat.Directory dir in oldTopic.Directories) * { * if (dir.Name == "line_news") * { * Data dbgData = dir.Data.FirstOrDefault(); * if (dbgData == null) * { * continue; * } * dir.Data.Remove(dbgData); * //dbgData.Digest = "deadbeef"; * } * }*/ } #endif // Get the differences List <KeyValuePair <DifferenceType, string> > differences = BcatCheckerUtils.GetTopicChanges(oldTopic, topic); // Check if there aren't any if (differences.Count == 0) { // Nothing to do here goto finished; } // Download all data Dictionary <string, byte[]> data = await BcatCheckerUtils.DownloadAllData(topic, Program.TITLE_ID, Program.PASSPHRASE, targetFolder); // Loop over every difference foreach (KeyValuePair <DifferenceType, string> pair in differences) { // Log the difference await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** diff: ``" + pair.Value + "`` (" + pair.Key.ToString() + ")"); // Get the FileType FileType fileType = FileTypeExtensions.GetTypeFromName(pair.Value); // Declare a variable to hold the method parameters object[] parameters; if (pair.Key == DifferenceType.Added) { // Get the raw file byte[] rawFile = data[pair.Value]; // Check if this is a Container if (fileType.IsContainer()) { // Create a Container instance Nintendo.SmashUltimate.Bcat.Container addedContainer = CreateSmashContainerInstance(fileType, data[pair.Value]); // Add this to the container cache ContainerCache.AddFile(addedContainer, Path.GetFileName(pair.Value), rawFile); // Set the method parameters parameters = new object[] { addedContainer }; } else { // Write this file out to the common file cache File.WriteAllBytes(Path.Combine(Program.LOCAL_COMMON_CACHE_DIRECTORY, Path.GetFileName(pair.Value)), data[pair.Value]); // Set the method parameters parameters = new object[] { rawFile }; } } else if (pair.Key == DifferenceType.Changed) { // Get the raw file byte[] rawFile = data[pair.Value]; // Check if this is a Container if (fileType.IsContainer()) { // Create a Container instance Nintendo.SmashUltimate.Bcat.Container addedContainer = CreateSmashContainerInstance(fileType, data[pair.Value]); // Overwrite this to the container cache Nintendo.SmashUltimate.Bcat.Container previousContainer = ContainerCache.OverwriteFile(addedContainer, Path.GetFileName(pair.Value), rawFile); // Set the method parameters parameters = new object[] { previousContainer, addedContainer }; } else { // Construct the commoon cache path string path = Path.Combine(Program.LOCAL_COMMON_CACHE_DIRECTORY, Path.GetFileName(pair.Value)); // Load the old file byte[] previousRawFile = File.ReadAllBytes(path); // Write this file out to the common file cache File.WriteAllBytes(path, data[pair.Value]); // Set the method parameters parameters = new object[] { previousRawFile, rawFile }; } } else // Removed { // TODO: discord print continue; } // Call every difference handler await BcatCheckerUtils.CallDifferenceHandlers((int)fileType, pair.Key, parameters); } // Write out the Topic File.WriteAllBytes(Program.LOCAL_LAST_TOPIC, MessagePackSerializer.Serialize(topic)); finished: await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** Check complete"); } catch (Exception exception) { // Notify the logging channel await DiscordUtil.HandleException(exception, $"in ``BcatCheckerJob``"); } }
protected sealed override async Task UpdateInternal(DiscordLink plugin, DLEventType trigger, object data) { // Avoid hitting the rate limitation by not allowig events that can be fired often to pass straight through. if ((trigger & HighFrequencyTriggerFlags) == trigger) { if (_HighFrequencyEventTimer == null) { _HighFrequencyEventTimer = new Timer(this.TriggerTimedUpdate, null, HighFrequencyEventDelayMS, Timeout.Infinite); } return; } if (_dirty || _targetDisplays.Count <= 0) { await FindMessages(plugin); if (_dirty || _targetDisplays.Count <= 0) { return; // If something went wrong, we should just retry later } } bool createdOrDestroyedMessage = false; List <string> matchedTags = new List <string>(); List <DiscordMessage> unmatchedMessages = new List <DiscordMessage>(); foreach (TargetDisplayData channelDisplayData in _targetDisplays) { DiscordTarget target = channelDisplayData.Target; ChannelLink channelLink = target as ChannelLink; UserLink userLink = target as UserLink; if (channelLink == null && userLink == null) { continue; } DiscordChannel targetChannel = null; if (channelLink != null) { // Get the channel and verify permissions DiscordGuild discordGuild = plugin.GuildByNameOrId(channelLink.DiscordGuild); if (discordGuild == null) { continue; } targetChannel = discordGuild.ChannelByNameOrId(channelLink.DiscordChannel); if (targetChannel == null) { continue; } if (!DiscordUtil.ChannelHasPermission(targetChannel, Permissions.ReadMessageHistory)) { continue; } } else if (userLink != null) { targetChannel = await userLink.Member.CreateDmChannelAsync(); } GetDisplayContent(target, out List <Tuple <string, DiscordLinkEmbed> > tagsAndContent); foreach (ulong messageID in channelDisplayData.MessageIDs) { DiscordMessage message = await DiscordUtil.GetMessageAsync(targetChannel, messageID); if (message == null) { _dirty = true; return; // We cannot know which messages are wrong and duplicates may be created if we continue. } if (!message.Content.StartsWith(BaseTag)) { continue; // The message belongs to a different display } bool found = false; foreach (var tagAndContent in tagsAndContent) { if (message.Content.Contains(tagAndContent.Item1)) { _ = DiscordUtil.ModifyAsync(message, tagAndContent.Item1, tagAndContent.Item2); matchedTags.Add(tagAndContent.Item1); found = true; ++_opsCount; break; } } if (!found) { unmatchedMessages.Add(message); } } // Delete the messages that are no longer relevant foreach (DiscordMessage message in unmatchedMessages) { DiscordUtil.DeleteAsync(message).Wait(); createdOrDestroyedMessage = true; ++_opsCount; } unmatchedMessages.Clear(); // Send the messages that didn't already exist foreach (var tagAndContent in tagsAndContent) { if (!matchedTags.Contains(tagAndContent.Item1)) { DiscordUtil.SendAsync(targetChannel, tagAndContent.Item1, tagAndContent.Item2).Wait(); createdOrDestroyedMessage = true; ++_opsCount; } } matchedTags.Clear(); } if (createdOrDestroyedMessage) { await FindMessages(plugin); } LastUpdateTime = DateTime.Now; }
private async Task PostAccumulatedTrades() { foreach (List <CurrencyTrade> accumulatedTrades in _accumulatedTrades.Values) { if (accumulatedTrades.Count <= 0) { continue; } CurrencyTrade firstTrade = accumulatedTrades[0]; DiscordEmbedBuilder builder = new DiscordEmbedBuilder(); string leftName = firstTrade.Citizen.Name; string rightName = firstTrade.Citizen.Id == firstTrade.Buyer.Id ? firstTrade.Seller.Name : firstTrade.Buyer.Name; builder.Title = leftName + " traded with " + rightName; string boughtItemsDesc = string.Empty; float boughtTotal = 0; string soldItemsDesc = string.Empty; float soldTotal = 0; foreach (CurrencyTrade trade in accumulatedTrades) { if (trade.BoughtOrSold == Shared.Items.BoughtOrSold.Buying) { boughtItemsDesc += trade.NumberOfItems + " X " + trade.ItemUsed.DisplayName + " * " + trade.CurrencyAmount / trade.NumberOfItems + " = " + trade.CurrencyAmount + "\n"; boughtTotal += trade.CurrencyAmount; } else if (trade.BoughtOrSold == Shared.Items.BoughtOrSold.Selling) { soldItemsDesc += trade.NumberOfItems + " X " + trade.ItemUsed.DisplayName + " * " + trade.CurrencyAmount / trade.NumberOfItems + " = " + trade.CurrencyAmount + "\n"; soldTotal += trade.CurrencyAmount; } } if (!boughtItemsDesc.IsEmpty()) { boughtItemsDesc += "\nTotal = " + boughtTotal.ToString("n2"); builder.AddField("Bought", boughtItemsDesc); } if (!soldItemsDesc.IsEmpty()) { soldItemsDesc += "\nTotal = " + soldTotal.ToString("n2"); builder.AddField("Sold", soldItemsDesc); } float subTotal = soldTotal - boughtTotal; char sign = (subTotal > 0.0f ? '+' : '-'); builder.AddField("Total", sign + Math.Abs(subTotal).ToString("n2") + " " + firstTrade.Currency.Name); DiscordLink plugin = DiscordLink.Obj; if (plugin == null) { return; } foreach (ChannelLink tradeChannel in DLConfig.Data.TradeChannels) { if (!tradeChannel.IsValid()) { continue; } DiscordGuild discordGuild = plugin.GuildByNameOrId(tradeChannel.DiscordGuild); if (discordGuild == null) { continue; } DiscordChannel discordChannel = discordGuild.ChannelByNameOrId(tradeChannel.DiscordChannel); if (discordChannel == null) { continue; } _ = DiscordUtil.SendAsync(discordChannel, "", builder.Build()); } } _accumulatedTrades.Clear(); }
public async Task Execute(IJobExecutionContext context) { try { if (Configuration.LoadedConfiguration.FirstRunCompleted) { throw new Exception("Attempting to do first run more than once"); } foreach (KeyValuePair <RomType, BcatPair> bcatPairEntry in Program.BcatPairs) { // Log that we're about to begin a check await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** Beginning topic download for " + bcatPairEntry.Key.ToString()); // Download the latest Topic Topic topic = await BcatApi.GetDataTopic(bcatPairEntry.Value.TitleId, bcatPairEntry.Value.Passphrase); // Create the target folder name string targetFolder = string.Format(Program.LOCAL_OLD_DATA_DIRECTORY, DateTime.Now.ToString(Program.FOLDER_DATE_TIME_FORMAT), bcatPairEntry.Key.ToString()); // Download all data Dictionary <string, byte[]> downloadedData = await BcatCheckerUtils.DownloadAllData(topic, bcatPairEntry.Value.TitleId, bcatPairEntry.Value.Passphrase, targetFolder); // Loop over all data foreach (KeyValuePair <string, byte[]> dataPair in downloadedData) { // Get the FileType FileType fileType = FileTypeExtensions.GetTypeFromFilePath(dataPair.Key); // Populate the FileCache directories based on the FileType string path; switch (fileType) { case FileType.VersusSetting: path = string.Format(FileCache.VERSUS_SETTING_PATH, bcatPairEntry.Key.ToString()); break; case FileType.CoopSetting: // Only write the CoopSetting file once if (bcatPairEntry.Key != RomType.NorthAmerica) { continue; } path = FileCache.COOP_SETTING_PATH; break; case FileType.FestivalByaml: // Deserialize the byaml to get the ID dynamic byaml = ByamlLoader.GetByamlDynamic(dataPair.Value); // Generate the path path = string.Format(FileCache.FESTIVAL_SETTING_PATH, bcatPairEntry.Key.ToString(), byaml["FestivalId"]); break; default: continue; } // Create the directories if needed System.IO.Directory.CreateDirectory(Path.GetDirectoryName(path)); // Write the file File.WriteAllBytes(path, dataPair.Value); } // Write out the topic File.WriteAllBytes(string.Format(Program.LOCAL_LAST_TOPIC, bcatPairEntry.Key.ToString()), MessagePackSerializer.Serialize(topic)); // Set the last data download directory (Configuration.LoadedConfiguration as JelonzoBotConfiguration).LastDownloadPaths[bcatPairEntry.Key] = targetFolder; // Log that the first run is done await DiscordBot.LoggingChannel.SendMessageAsync($"**[BCAT]** First run complete for {bcatPairEntry.Key.ToString()}"); } // Save the configuration Configuration.LoadedConfiguration.FirstRunCompleted = true; Configuration.LoadedConfiguration.Write(); // Initialize the FileCache FileCache.Initialize(); } catch (Exception exception) { // Notify the logging channel await DiscordUtil.HandleException(exception, $"in ``BcatCheckerJob``"); } await QuartzScheduler.ScheduleJob <BcatCheckerJob>("Normal", Configuration.LoadedConfiguration.JobSchedules["Bcat"]); }
public override async Task <bool> HandleTextMessage(SocketMessage message) { // Get the guild SocketGuild guild = (message.Channel as SocketGuildChannel).Guild; // Parse the channel ID ulong channelId; try { channelId = MentionUtils.ParseChannel(message.Content); } catch (ArgumentException) { await DiscordUtil.SendErrorMessageByLocalizedDescription(guild, this.Channel, "discord.setup.enter_channel.bad_channel"); return(false); } // Get the channel SocketChannel foundChannel = DiscordBot.GetChannel(channelId); // Check if it exists if (foundChannel == null) { await DiscordUtil.SendErrorMessageByLocalizedDescription(guild, this.Channel, "discord.setup.enter_channel.bad_channel"); return(false); } // Check this channel's guild SocketGuildChannel socketGuildChannel = foundChannel as SocketGuildChannel; // Check that this exists and that it is in the user's guild if (socketGuildChannel == null || socketGuildChannel.Guild.Id != SetupFlow.Guild.Id) { await DiscordUtil.SendErrorMessageByLocalizedDescription(guild, this.Channel, "discord.setup.enter_channel.bad_channel"); return(false); } // Get the text channel SocketTextChannel socketTextChannel = foundChannel as SocketTextChannel; // Check if this is a text channel if (socketTextChannel == null) { await DiscordUtil.SendErrorMessageByLocalizedDescription(guild, this.Channel, "discord.setup.enter_channel.bad_channel"); return(false); } // Check if this already exists as settings if (SetupFlow.GuildSettings.ChannelSettings.Where(p => p.Key == channelId).Count() != 0) { await DiscordUtil.SendErrorMessageByLocalizedDescription(guild, this.Channel, "discord.setup.enter_channel.already_exists"); return(false); } // Get all required permissions List <ChannelPermission> requiredPermissions = new ChannelPermissions(Configuration.LoadedConfiguration.DiscordConfig.Permissions).ToList(); // Get current permissions for this channel ChannelPermissions channelPermissions = guild.CurrentUser.GetPermissions(socketTextChannel); // Get a list of permissions that the bot does not have IEnumerable <ChannelPermission> missingPermissions = requiredPermissions.Where(x => !channelPermissions.Has(x)); // Check if we are missing any if (missingPermissions.Count() > 0) { // Try to get the default language Language language = DiscordUtil.GetDefaultLanguage(guild); // Create the description string for the error message string description = Localizer.Localize("discord.setup.enter_channel.missing_permissions", language) + "\n\n"; // Append the permissions foreach (ChannelPermission permission in missingPermissions) { description += permission.ToString() + "\n"; } // Create an embed await DiscordUtil.SendErrorMessageByDescription(guild, this.Channel, description); return(false); } // Set the new message flag SetupFlow.ShouldSendNewMessage = true; if (SetupFlow.ChannelSettings == null) { // Create a DynamicSettingsData instance SetupFlow.ChannelSettings = new DynamicSettingsData(); // Set the ID SetupFlow.TargetChannelId = channelId; // Proceed to language selection await SetupFlow.SetPage((int)SetupFlowPage.SelectLanguage); } else { // Move the data SetupFlow.GuildSettings.ChannelSettings.TryRemove(SetupFlow.TargetChannelId, out DynamicSettingsData data); SetupFlow.GuildSettings.ChannelSettings.TryAdd(channelId, data); // Set a pre-prompt SetupFlow.ModeSelectPrePromptLocalizable = "discord.setup.mode_select.pre_prompt.edits_saved"; // Change to mode select await SetupFlow.SetPage((int)SetupFlowPage.ModeSelect); } return(false); }
public async Task Execute(ulong guildId = 0) { // Check if we are an admin bool isAdmin = DiscordUtil.IsAdministrator(Context.User); // Check if a guild is specified IGuild guild; if (guildId != 0) { // Check if the user does not permission if (!DiscordUtil.IsAdministrator(Context.User)) { // Return an error await DiscordUtil.SendErrorMessageByLocalizedDescription(Context.Guild, Context.Channel, "discord.error.not_admin"); return; } else { // Set the guild guild = DiscordBot.GetGuild(guildId); // Check if it exists if (guild == null) { // Return an error await DiscordUtil.SendErrorMessageByLocalizedDescription(Context.Guild, Context.Channel, "discord.setup.error.guild_not_exist"); return; } } } else { guild = Context.Guild; // Check if this is a DM if (guild == null) { // Return an error await DiscordUtil.SendErrorMessageByLocalizedDescription(Context.Guild, Context.Channel, "discord.setup.error.in_dm"); return; } } // Test if the user does not permission if (!isAdmin && !((SocketGuildUser)Context.User).GuildPermissions.Has(GuildPermission.ManageGuild)) { // Return an error await DiscordUtil.SendErrorMessageByLocalizedDescription(Context.Guild, Context.Channel, "discord.setup.error.no_permission"); return; } // Check if there are already setups running if (await DiscordBot.IsSetupFlowRunningInGuild(guild)) { // Error await DiscordUtil.SendErrorMessageByLocalizedDescription(Context.Guild, Context.Channel, "discord.setup.error.already_running"); return; } // Run the setup await DiscordBot.ActivateInteractiveFlow(new SetupFlow(Context.User, guild, Context.Channel, new Language[] { Language.EnglishUS }, guildId != 0)); }
protected override async Task UpdateInternal(DiscordLink plugin, DLEventType trigger, object data) { if (DLConfig.Data.TradeChannels.Count <= 0) { return; } if (!(data is IEnumerable <List <CurrencyTrade> > accumulatedTrades)) { return; } // Each entry is the summarized trade events for a player and a store foreach (List <CurrencyTrade> accumulatedTradeList in accumulatedTrades) { if (accumulatedTradeList.Count <= 0) { continue; } CurrencyTrade firstTrade = accumulatedTradeList[0]; DiscordLinkEmbed embed = new DiscordLinkEmbed(); string leftName = firstTrade.Citizen.Name; string rightName = (firstTrade.WorldObject as WorldObject).Name; embed.WithTitle($"{leftName} traded at {MessageUtil.StripTags(rightName)}"); // Go through all acumulated trade events and create a summary string boughtItemsDesc = string.Empty; float boughtTotal = 0; string soldItemsDesc = string.Empty; float soldTotal = 0; foreach (CurrencyTrade trade in accumulatedTradeList) { if (trade.BoughtOrSold == Shared.Items.BoughtOrSold.Buying) { boughtItemsDesc += trade.NumberOfItems + " X " + trade.ItemUsed.DisplayName + " * " + trade.CurrencyAmount / trade.NumberOfItems + " = " + trade.CurrencyAmount + "\n"; boughtTotal += trade.CurrencyAmount; } else if (trade.BoughtOrSold == Shared.Items.BoughtOrSold.Selling) { soldItemsDesc += trade.NumberOfItems + " X " + trade.ItemUsed.DisplayName + " * " + trade.CurrencyAmount / trade.NumberOfItems + " = " + trade.CurrencyAmount + "\n"; soldTotal += trade.CurrencyAmount; } } if (!boughtItemsDesc.IsEmpty()) { boughtItemsDesc += "\nTotal = " + boughtTotal.ToString("n2"); embed.AddField("Bought", boughtItemsDesc); } if (!soldItemsDesc.IsEmpty()) { soldItemsDesc += "\nTotal = " + soldTotal.ToString("n2"); embed.AddField("Sold", soldItemsDesc); } float subTotal = soldTotal - boughtTotal; char sign = (subTotal > 0.0f ? '+' : '-'); embed.AddField("Total", sign + Math.Abs(subTotal).ToString("n2") + " " + MessageUtil.StripTags(firstTrade.Currency.Name)); // Post the trade summary in all trade channels foreach (ChannelLink tradeChannel in DLConfig.Data.TradeChannels) { if (!tradeChannel.IsValid()) { continue; } DiscordGuild discordGuild = plugin.GuildByNameOrId(tradeChannel.DiscordGuild); if (discordGuild == null) { continue; } DiscordChannel discordChannel = discordGuild.ChannelByNameOrId(tradeChannel.DiscordChannel); if (discordChannel == null) { continue; } _ = DiscordUtil.SendAsync(discordChannel, string.Empty, embed); ++_opsCount; } } }
public async Task Execute(IJobExecutionContext context) { try { // Log that we're about to begin uploading data await DiscordBot.LoggingChannel.SendMessageAsync("**[RomDataUploadJob]** Beginning ROM data upload"); // Create a list of paths whose cache needs to be cleared List <string> clearPaths = new List <string>(); // Create the MSBT S3 path format string string msbtS3BasePath = "/splatoon/blitz_rom/Message/CommonMsg_{0}"; // Loop over every language foreach (Language language in BlitzUtil.SupportedLanguages) { // Log the language await DiscordBot.LoggingChannel.SendMessageAsync($"**[RomDataUploadJob]** Uploading {language.ToString()}'s MSBTs"); // Get the MsbtHolder MsbtHolder msbtHolder = BlitzLocalizer.MsbtHolders[language]; // Loop over every MSBT foreach (KeyValuePair <string, Dictionary <string, string> > pair in msbtHolder.Msbts) { // Construct the path string msbtPath = string.Format(msbtS3BasePath, language.GetSeadCode()); // Construct the file name string fileName = $"{pair.Key}.json"; // Serialize to JSON string json = JsonConvert.SerializeObject(pair.Value); // Upload to S3 S3Api.TransferFile(Encoding.UTF8.GetBytes(json), msbtPath, fileName, "application/json"); // Add to the cache list clearPaths.Add($"{msbtPath}/{fileName}"); } } // Log MSBT upload await DiscordBot.LoggingChannel.SendMessageAsync("**[RomDataUploadJob]** Uploading Mush"); // Create the Mush S3 path string string mushS3Path = "/splatoon/blitz_rom/Mush"; // Get every file in Mush foreach (string path in RomResourceLoader.GetFilesInDirectory("/Mush")) { // Get the BYAML dynamic byaml = ByamlLoader.GetByamlDynamic(path); // Construct the file name string fileName = $"{Path.GetFileNameWithoutExtension(path)}.json"; // Serialize to JSON string json = JsonConvert.SerializeObject(byaml); // Upload to S3 S3Api.TransferFile(Encoding.UTF8.GetBytes(json), mushS3Path, fileName, "application/json"); // Add to the paths to clear clearPaths.Add($"{mushS3Path}/{fileName}"); } // Log CDN cache purge starting await DiscordBot.LoggingChannel.SendMessageAsync($"**[RomDataUploadJob]** Requesting CDN cache purge ({clearPaths.Count} of {clearPaths.Count} files left)"); IEnumerable <string> pathsEnumerable = (IEnumerable <string>)clearPaths; while (pathsEnumerable.Any()) { // Tell DigitalOcean to clear the cache await DoApi.SendRequest(new DoCdnCachePurgeRequest(Configuration.LoadedConfiguration.DoConfig.EndpointId, pathsEnumerable.Take(15).ToList())); // Advance to the next set pathsEnumerable = pathsEnumerable.Skip(15); // Log files left await DiscordBot.LoggingChannel.SendMessageAsync($"**[RomDataUploadJob]** Requesting CDN cache purge ({pathsEnumerable.Count()} of {clearPaths.Count} files left)"); } // Write the app version await DiscordBot.LoggingChannel.SendMessageAsync("**[RomDataUploadJob]** Saving new ROM version to configuration"); (Configuration.LoadedConfiguration as JelonzoBotConfiguration).RomConfig.LastRomVersion = (int)context.JobDetail.JobDataMap["version"]; Configuration.LoadedConfiguration.Write(); // Log that it's complete await DiscordBot.LoggingChannel.SendMessageAsync("**[RomDataUploadJob]** ROM data upload complete"); } catch (Exception e) { await DiscordUtil.HandleException(e, "in ``RomDataUploadJob``"); } }
public async Task Execute(IJobExecutionContext context) { try { foreach (KeyValuePair <RomType, BcatPair> bcatPairEntry in Program.BcatPairs) { // Log that we're about to begin a check await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** Beginning topic download for " + bcatPairEntry.Key.ToString()); // Download the latest Topic Topic topic = await BcatApi.GetDataTopic(bcatPairEntry.Value.TitleId, bcatPairEntry.Value.Passphrase); // Create the target folder name string targetFolder = string.Format(Program.LOCAL_OLD_DATA_DIRECTORY, DateTime.Now.ToString(Program.FOLDER_DATE_TIME_FORMAT), bcatPairEntry.Key.ToString()); // Format the old Topic path string oldTopicPath = string.Format(Program.LOCAL_LAST_TOPIC, bcatPairEntry.Key.ToString()); // Load the old Topic Topic oldTopic = MessagePackSerializer.Deserialize <Topic>(File.ReadAllBytes(oldTopicPath)); #if DEBUG if (!Configuration.LoadedConfiguration.IsProduction) { /*foreach (Nintendo.Bcat.Directory dir in oldTopic.Directories) * { * if (dir.Name == "fesdata") * { * Data dbgData = dir.Data.Where(x => x.Name == "Festival.byaml").FirstOrDefault(); * dbgData.Digest = "deadbeef"; * } * }*/ } #endif // Get the differences List <KeyValuePair <DifferenceType, string> > differences = BcatCheckerUtils.GetTopicChanges(oldTopic, topic); // Check if there aren't any if (differences.Count == 0) { // Nothing to do here goto finished; } // Download all data Dictionary <string, byte[]> data = await BcatCheckerUtils.DownloadAllData(topic, bcatPairEntry.Value.TitleId, bcatPairEntry.Value.Passphrase, targetFolder); // Loop over every difference foreach (KeyValuePair <DifferenceType, string> differencePair in differences) { // Log the difference await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** diff: ``" + differencePair.Value + "`` (" + differencePair.Key.ToString() + ")"); // Get the FileType FileType fileType = FileTypeExtensions.GetTypeFromFilePath(differencePair.Value); // Create a ByamlSerializer instance ByamlSerializer serializer = new ByamlSerializer(new ByamlSerializerSettings() { ByteOrder = ByteOrder.LittleEndian, SupportPaths = false, Version = ByamlVersion.Version1 }); // Create the difference handler parameters based off the FileType and difference type object[] parameters; if (differencePair.Key != DifferenceType.Removed) { // Get the raw file byte[] rawFile = data[differencePair.Value]; // Deserialize the object from byaml if necessary object deserializedObject; using (MemoryStream memoryStream = new MemoryStream(rawFile)) { switch (fileType) { case FileType.VersusSetting: deserializedObject = serializer.Deserialize <VersusSetting>(memoryStream); break; case FileType.CoopSetting: deserializedObject = serializer.Deserialize <CoopSetting>(memoryStream); break; case FileType.FestivalByaml: deserializedObject = serializer.Deserialize <FestivalSetting>(memoryStream); break; default: deserializedObject = data[differencePair.Value]; break; } } if (differencePair.Key == DifferenceType.Added) { parameters = new object[] { bcatPairEntry.Key, data, deserializedObject, rawFile }; } else // Changed { // Get the previous file object previousFile; switch (fileType) { case FileType.VersusSetting: previousFile = FileCache.GetVersusSettingForRomType(bcatPairEntry.Key); break; case FileType.CoopSetting: previousFile = FileCache.GetCoopSetting(); break; case FileType.FestivalByaml: previousFile = FileCache.GetLatestFestivalSettingForRomType(bcatPairEntry.Key); break; default: // Construct the previous file path string previousPath = Path.Combine((Configuration.LoadedConfiguration as JelonzoBotConfiguration).LastDownloadPaths[bcatPairEntry.Key], differencePair.Value.Replace('/', Path.DirectorySeparatorChar)); // Load it previousFile = File.ReadAllBytes(previousPath);; break; } // Create the parameters parameters = new object[] { bcatPairEntry.Key, data, previousFile, deserializedObject, rawFile }; } } else { parameters = new object[] { bcatPairEntry.Key, data }; } // Call every difference handler await BcatCheckerUtils.CallDifferenceHandlers((int)fileType, differencePair.Key, parameters); } // Write out the Topic File.WriteAllBytes(oldTopicPath, MessagePackSerializer.Serialize(topic)); // Set the last download path (Configuration.LoadedConfiguration as JelonzoBotConfiguration).LastDownloadPaths[bcatPairEntry.Key] = targetFolder; finished: await DiscordBot.LoggingChannel.SendMessageAsync("**[BCAT]** Check complete for " + bcatPairEntry.Key.ToString()); } } catch (Exception exception) { // Notify the logging channel await DiscordUtil.HandleException(exception, $"in ``BcatCheckerJob``"); } }
private void SubscribeEvents() { DiscordClient.Ready += () => { readyEvent.Set(); return(Task.CompletedTask); }; DiscordClient.Log += m => { Logger.Log(DiscordUtil.ToLoggable(m)); return(Task.CompletedTask); }; }
public async Task Execute(IJobExecutionContext context) { try { // Run app-specific boot tasks await RunAppSpecificBootTasks(); // Run one-time tasks await DiscordBot.LoggingChannel.SendMessageAsync($"**[BootHousekeepingJob]** Running one-time tasks"); foreach (Type type in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(OneTimeTask)) && !x.IsAbstract)) { // Create a new instance and run it await((OneTimeTask)Activator.CreateInstance(type)).RunImpl(); } await DiscordBot.LoggingChannel.SendMessageAsync($"**[BootHousekeepingJob]** Processing joined/left guilds"); // Get a list of guilds IReadOnlyCollection <SocketGuild> socketGuilds = DiscordBot.GetGuilds(); // Get all guild IDs that we have settings for List <ulong> configurationGuilds = new List <ulong>(); foreach (GuildSettings guildSettings in Configuration.LoadedConfiguration.DiscordConfig.GuildSettings) { configurationGuilds.Add(guildSettings.GuildId); } // Get all IDs for guilds that we are in List <ulong> currentGuilds = new List <ulong>(); foreach (SocketGuild socketGuild in DiscordBot.GetGuilds()) { currentGuilds.Add(socketGuild.Id); } // Get all the guilds we have joined IEnumerable <ulong> joinedGuilds = currentGuilds.Except(configurationGuilds); foreach (ulong id in joinedGuilds) { // TODO: find a better solution instead of spamming the Welcome message //await DiscordUtil.ProcessJoinedGuild(socketGuilds.Where(guild => guild.Id == id).FirstOrDefault()); } // Get all the guilds we have been removed from IEnumerable <ulong> removedGuilds = configurationGuilds.Except(currentGuilds); foreach (ulong id in removedGuilds) { await DiscordUtil.ProcessLeftGuild(id, null); } await DiscordBot.LoggingChannel.SendMessageAsync($"**[BootHousekeepingJob]** Saving configuration"); // Save the configuration Configuration.LoadedConfiguration.Write(); // Schedule the RecurringHousekeepingJob await QuartzScheduler.ScheduleJob(TypeUtils.GetSubclassOfType <RecurringHousekeepingJob>(), "Normal", Configuration.LoadedConfiguration.JobSchedules["Recurring"]); // Schedule jobs await SchedulePostBootJobs(); } catch (Exception e) { await DiscordUtil.HandleException(e, "in ``BootHousekeepingJob``"); } }