public static async Task <bool> CheckForRpcs3Updates(DiscordClient discordClient, DiscordChannel?channel, string?sinceCommit = null, DiscordMessage?emptyBotMsg = null) { var updateAnnouncement = channel is null; var updateAnnouncementRestore = emptyBotMsg != null; var info = await Client.GetUpdateAsync(Config.Cts.Token, sinceCommit).ConfigureAwait(false); if (info?.ReturnCode != 1 && sinceCommit != null) { info = await Client.GetUpdateAsync(Config.Cts.Token).ConfigureAwait(false); } if (updateAnnouncementRestore && info?.CurrentBuild != null) { info.LatestBuild = info.CurrentBuild; } var embed = await info.AsEmbedAsync(discordClient, updateAnnouncement).ConfigureAwait(false); if (info == null || embed.Color.Value.Value == Config.Colors.Maintenance.Value) { if (updateAnnouncementRestore) { Config.Log.Debug($"Failed to get update info for commit {sinceCommit}: {JsonSerializer.Serialize(info)}"); return(false); } embed = await cachedUpdateInfo.AsEmbedAsync(discordClient, updateAnnouncement).ConfigureAwait(false); } else if (!updateAnnouncementRestore) { if (cachedUpdateInfo?.LatestBuild?.Datetime is string previousBuildTimeStr && info.LatestBuild?.Datetime is string newBuildTimeStr && DateTime.TryParse(previousBuildTimeStr, out var previousBuildTime) && DateTime.TryParse(newBuildTimeStr, out var newBuildTime) && newBuildTime > previousBuildTime) { cachedUpdateInfo = info; } } if (!updateAnnouncement) { await channel !.SendMessageAsync(embed: embed.Build()).ConfigureAwait(false); return(true); } if (updateAnnouncementRestore) { if (embed.Title == "Error") { return(false); } Config.Log.Debug($"Restoring update announcement for build {sinceCommit}: {embed.Title}\n{embed.Description}"); await emptyBotMsg !.ModifyAsync(embed: embed.Build()).ConfigureAwait(false); return(true); } var latestUpdatePr = info?.LatestBuild?.Pr?.ToString(); var match = ( from field in embed.Fields let m = UpdateVersionRegex.Match(field.Value) where m.Success select m ).FirstOrDefault(); var latestUpdateBuild = match?.Groups["build"].Value; if (string.IsNullOrEmpty(latestUpdatePr) || lastUpdateInfo == latestUpdatePr || !await UpdateCheck.WaitAsync(0).ConfigureAwait(false)) { return(false); } try { if (!string.IsNullOrEmpty(lastFullBuildNumber) && !string.IsNullOrEmpty(latestUpdateBuild) && int.TryParse(lastFullBuildNumber, out var lastSaveBuild) && int.TryParse(latestUpdateBuild, out var latestBuild) && latestBuild <= lastSaveBuild) { return(false); } var compatChannel = await discordClient.GetChannelAsync(Config.BotChannelId).ConfigureAwait(false); var botMember = discordClient.GetMember(compatChannel.Guild, discordClient.CurrentUser); if (botMember == null) { return(false); } if (!compatChannel.PermissionsFor(botMember).HasPermission(Permissions.SendMessages)) { NewBuildsMonitor.Reset(); return(false); } if (embed.Color.Value.Value == Config.Colors.Maintenance.Value) { return(false); } await CheckMissedBuildsBetween(discordClient, compatChannel, lastUpdateInfo, latestUpdatePr, Config.Cts.Token).ConfigureAwait(false); await compatChannel.SendMessageAsync(embed : embed.Build()).ConfigureAwait(false); lastUpdateInfo = latestUpdatePr; lastFullBuildNumber = latestUpdateBuild; await using var db = new BotDb(); var currentState = await db.BotState.FirstOrDefaultAsync(k => k.Key == Rpcs3UpdateStateKey).ConfigureAwait(false); if (currentState == null) { await db.BotState.AddAsync(new() { Key = Rpcs3UpdateStateKey, Value = latestUpdatePr }).ConfigureAwait(false); } else { currentState.Value = latestUpdatePr; } var savedLastBuild = await db.BotState.FirstOrDefaultAsync(k => k.Key == Rpcs3UpdateBuildKey).ConfigureAwait(false); if (savedLastBuild == null) { await db.BotState.AddAsync(new() { Key = Rpcs3UpdateBuildKey, Value = latestUpdateBuild }).ConfigureAwait(false); } else { savedLastBuild.Value = latestUpdateBuild; } await db.SaveChangesAsync(Config.Cts.Token).ConfigureAwait(false); NewBuildsMonitor.Reset(); return(true); } catch (Exception e) { Config.Log.Warn(e, "Failed to check for RPCS3 update info"); } finally { UpdateCheck.Release(); } return(false); }