internal static void Restart(ulong channelId, string?restartMsg) { Config.Log.Info($"Saving channelId {channelId} into settings..."); using var db = new BotDb(); var ch = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel"); if (ch is null) { ch = new BotState { Key = "bot-restart-channel", Value = channelId.ToString() }; db.BotState.Add(ch); } else { ch.Value = channelId.ToString(); } var msg = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-msg"); if (msg is null) { msg = new BotState { Key = "bot-restart-msg", Value = restartMsg }; db.BotState.Add(msg); } else { msg.Value = restartMsg; } db.SaveChanges(); Config.TelemetryClient?.TrackEvent("Restart"); RestartNoSaving(); }
public override void Run(List <DataObject> result) { List <MessageBase> messages = result.OfType <MessageBase>().ToList(); if (!messages.Any()) { return; } int[] messageIds = messages.Select(s => s.MessageId).ToArray(); using (BotDb db = new BotDb()) { HashSet <int> existing = db.Messages.Where(s => messageIds.Contains(s.MessageId)).Select(s => s.MessageId).ToHashset(); foreach (MessageBase message in messages.Where(s => !existing.Contains(s.MessageId))) { db.Messages.Add(new DbMessage { MessageId = message.MessageId, Message = message, TabType = message.TabType }); } db.SaveChanges(); } }
public override void Run(List <DataObject> result) { List <EspionageReport> reports = result.OfType <EspionageReport>().ToList(); if (!reports.Any()) { return; } using (BotDb db = new BotDb()) { long[] locIds = reports.Select(s => s.Coordinate.Id).ToArray(); Dictionary <long, DbPlanet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId); foreach (EspionageReport report in reports) { Logger.Instance.Log(LogLevel.Info, $"Saving esp report on {report.Coordinate}, level: {report.Details}"); DbPlanet item; if (!existing.TryGetValue(report.Coordinate, out item)) { item = new DbPlanet { Coordinate = report.Coordinate }; db.Planets.Add(item); } if (report.Details.HasFlag(ReportDetails.Resources)) { item.Resources = report.Resources; item.LastResourcesTime = report.Sent; } if (report.Details.HasFlag(ReportDetails.Buildings)) { item.PlanetInfo.Buildings = report.DetectedBuildings; item.LastBuildingsTime = report.Sent; } if (report.Details.HasFlag(ReportDetails.Defense)) { item.PlanetInfo.Defences = report.DetectedDefence; item.LastDefencesTime = report.Sent; } if (report.Details.HasFlag(ReportDetails.Ships)) { item.PlanetInfo.Ships = report.DetectedShips; item.LastShipsTime = report.Sent; } } db.SaveChanges(); } }
public static void Clear() { lock (DisabledCommands) { DisabledCommands.Clear(); using var db = new BotDb(); db.DisabledCommands.RemoveRange(db.DisabledCommands); db.SaveChanges(); } }
public override void Run(List <DataObject> result) { using (BotDb db = new BotDb()) { var logs = FromGalaxy(result).ToList(); var newLogs = logs.Where(log => !db.PlanetActivityLog.Where(existing => existing.LocationId == log.LocationId && existing.CreatedOn == log.CreatedOn).Any()); db.PlanetActivityLog.AddRange(newLogs); db.SaveChanges(); } }
public static void Disable(string command) { lock (DisabledCommands) if (DisabledCommands.Add(command)) { using var db = new BotDb(); db.DisabledCommands.Add(new DisabledCommand { Command = command }); db.SaveChanges(); } }
private void ProcessData(PlayersContainer model) { using (BotDb db = new BotDb()) { Dictionary <int, Db.Player> allPlayers = db.Players.ToDictionary(s => s.PlayerId); List <Db.Player> newPlayers = new List <Db.Player>(); for (int i = 0; i < model.Players.Length; i++) { var player = model.Players[i]; Db.Player dbPlayer; if (!allPlayers.TryGetValue(player.Id, out dbPlayer)) { dbPlayer = new Db.Player { PlayerId = player.Id }; newPlayers.Add(dbPlayer); allPlayers[player.Id] = dbPlayer; } dbPlayer.Name = player.Name; dbPlayer.Status = ParseStatus(player.Status); if (i % 250 == 0) { db.Players.AddRange(newPlayers); db.SaveChanges(); newPlayers.Clear(); } } db.Players.AddRange(newPlayers); db.SaveChanges(); } }
private void Run(CommandQueueElement next, BotDb db) { lock (_lock) { if (next.Id == 0) { db.CommandQueue.Add(next); db.SaveChanges(); } else { db.CommandQueue.Attach(next); } // Execute if ((next.ScheduledAt ?? DateTimeOffset.Now) <= DateTimeOffset.Now) { Logger.Instance.Log(LogLevel.Debug, $"Running {next.Command} (id: {next.Id})"); CommandQueueElement following = next.Command.RunInternal(); next.ScheduledAt = null; Logger.Instance.Log(LogLevel.Debug, $"Finished {next.Command} (id: {next.Id})"); if (following != null) { if (following.Command == next.Command) { next.ScheduledAt = following.ScheduledAt; Logger.Instance.Log(LogLevel.Debug, $"Requeueing {next.Command} (id: {next.Id})"); } else { db.CommandQueue.Add(following); Logger.Instance.Log(LogLevel.Debug, $"Queueing {following.Command} (id: {following.Id}, by: {next.Id})"); } } db.SaveChanges(); } } }
private void ProcessData(HighscoreContainer model) { using (BotDb db = new BotDb()) { Dictionary <int, Db.Player> allPlayers = db.Players.ToDictionary(s => s.PlayerId); for (int i = 0; i < model.Highscores.Length; i++) { var highscore = model.Highscores[i]; Db.Player dbPlayer; if (allPlayers.TryGetValue(highscore.Id, out dbPlayer)) { dbPlayer.Ranking = highscore.Position; if (i % 250 == 0) { db.SaveChanges(); } } } db.SaveChanges(); } }
public static void Enable(string command) { lock (DisabledCommands) if (DisabledCommands.Remove(command)) { using var db = new BotDb(); var cmd = db.DisabledCommands.FirstOrDefault(c => c.Command == command); if (cmd == null) { return; } db.DisabledCommands.Remove(cmd); db.SaveChanges(); } }
public override void Run(List <DataObject> result) { GalaxyPageSystem systemDetails = result.OfType <GalaxyPageSystem>().FirstOrDefault(); if (systemDetails == null) { return; } using (BotDb db = new BotDb()) { long lower = systemDetails.System.LowerCoordinate; long upper = systemDetails.System.UpperCoordinate; Dictionary <long, DebrisField> toRemove = db.DebrisFields.Where(s => lower <= s.LocationId && s.LocationId <= upper).ToDictionary(s => s.LocationId); foreach (GalaxyPageInfoItem item in result.OfType <GalaxyPageInfoItem>()) { if (item.DebrisField.Total <= 0) { continue; } DebrisField field; if (!toRemove.TryRemove(item.Planet.Coordinate, out field)) { field = new DebrisField { Coordinate = item.Planet.Coordinate }; db.DebrisFields.Add(field); } field.LastSeen = DateTimeOffset.Now; field.Resources = item.DebrisField; } db.DebrisFields.RemoveRange(toRemove.Values); db.SaveChanges(); } }
internal static void Restart(ulong channelId) { if (SandboxDetector.Detect() == SandboxType.Docker) { Config.Log.Info($"Saving channelId {channelId} into settings..."); using var db = new BotDb(); var ch = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel"); if (ch is null) { ch = new BotState { Key = "bot-restart-channel", Value = channelId.ToString() }; db.BotState.Add(ch); } else { ch.Value = channelId.ToString(); } db.SaveChanges(); } RestartNoSaving(channelId); }
internal static async Task Main(string[] args) { Config.TelemetryClient?.TrackEvent("startup"); Console.WriteLine("Confinement: " + SandboxDetector.Detect()); if (args.Length > 0 && args[0] == "--dry-run") { Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData)))); if (Assembly.GetEntryAssembly().GetCustomAttribute <UserSecretsIdAttribute>() != null) { Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath))); } return; } if (Process.GetCurrentProcess().Id == 0) { Config.Log.Info("Well, this was unexpected"); } var singleInstanceCheckThread = new Thread(() => { using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot"); if (instanceLock.WaitOne(1000)) { try { InstanceCheck.Release(); ShutdownCheck.Wait(); } finally { instanceLock.ReleaseMutex(); } } }); try { singleInstanceCheckThread.Start(); if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false)) { Config.Log.Fatal("Another instance is already running."); return; } if (string.IsNullOrEmpty(Config.Token) || Config.Token.Length < 16) { Config.Log.Fatal("No token was specified."); return; } if (SandboxDetector.Detect() == SandboxType.Docker) { Config.Log.Info("Checking for updates..."); try { var(updated, stdout) = await Sudo.Bot.UpdateAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(stdout) && updated) { Config.Log.Debug(stdout); } if (updated) { Sudo.Bot.Restart(InvalidChannelId, "Restarted due to new bot updates not present in this Docker image"); return; } } catch (Exception e) { Config.Log.Error(e, "Failed to check for updates"); } } using (var db = new BotDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } using (var db = new ThumbnailDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } await SqlConfiguration.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored configuration variables from persistent storage"); await StatsStorage.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored stats from persistent storage"); var backgroundTasks = Task.WhenAll( AmdDriverVersionProvider.RefreshAsync(), #if !DEBUG new PsnScraper().RunAsync(Config.Cts.Token), GameTdbScraper.RunAsync(Config.Cts.Token), #endif StatsStorage.BackgroundSaveAsync(), CompatList.ImportCompatListAsync() ); try { if (!Directory.Exists(Config.IrdCachePath)) { Directory.CreateDirectory(Config.IrdCachePath); } } catch (Exception e) { Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}"); } var config = new DiscordConfiguration { Token = Config.Token, TokenType = TokenType.Bot, MessageCacheSize = Config.MessageCacheSize, LoggerFactory = Config.LoggerFactory, }; using var client = new DiscordClient(config); var commands = client.UseCommandsNext(new CommandsNextConfiguration { StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix }, Services = new ServiceCollection().BuildServiceProvider(), }); commands.RegisterConverter(new TextOnlyDiscordChannelConverter()); commands.RegisterCommands <Misc>(); commands.RegisterCommands <CompatList>(); commands.RegisterCommands <Sudo>(); commands.RegisterCommands <CommandsManagement>(); commands.RegisterCommands <ContentFilters>(); commands.RegisterCommands <Warnings>(); commands.RegisterCommands <Explain>(); commands.RegisterCommands <Psn>(); commands.RegisterCommands <Invites>(); commands.RegisterCommands <Moderation>(); commands.RegisterCommands <Ird>(); commands.RegisterCommands <BotMath>(); commands.RegisterCommands <Pr>(); commands.RegisterCommands <Events>(); commands.RegisterCommands <E3>(); commands.RegisterCommands <Cyberpunk2077>(); commands.RegisterCommands <Rpcs3Ama>(); commands.RegisterCommands <BotStats>(); commands.RegisterCommands <Syscall>(); commands.RegisterCommands <ForcedNicknames>(); commands.RegisterCommands <Minesweeper>(); if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey)) { commands.RegisterCommands <Vision>(); } commands.CommandErrored += UnknownCommandHandler.OnError; client.UseInteractivity(new InteractivityConfiguration()); client.Ready += async(c, _) => { var admin = await c.GetUserAsync(Config.BotAdminId).ConfigureAwait(false); Config.Log.Info("Bot is ready to serve!"); Config.Log.Info(""); Config.Log.Info($"Bot user id : {c.CurrentUser.Id} ({c.CurrentUser.Username})"); Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({admin.Username ?? "???"}#{admin.Discriminator ?? "????"})"); Config.Log.Info(""); }; client.GuildAvailable += async(c, gaArgs) => { await BotStatusMonitor.RefreshAsync(c).ConfigureAwait(false); Watchdog.DisconnectTimestamps.Clear(); Watchdog.TimeSinceLastIncomingMessage.Restart(); if (gaArgs.Guild.Id != Config.BotGuildId) { #if DEBUG Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})"); #else Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving..."); await gaArgs.Guild.LeaveAsync().ConfigureAwait(false); #endif return; } Config.Log.Info($"Server {gaArgs.Guild.Name} is available now"); Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}..."); try { await Task.WhenAll( Starbucks.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default), DiscordInviteFilter.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default) ).ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e, "Error running backlog tasks"); } Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}."); }; client.GuildAvailable += (c, _) => UsernameValidationMonitor.MonitorAsync(c, true); client.GuildUnavailable += (_, guArgs) => { Config.Log.Warn($"{guArgs.Guild.Name} is unavailable"); return(Task.CompletedTask); }; #if !DEBUG /* * client.GuildDownloadCompleted += async gdcArgs => * { * foreach (var guild in gdcArgs.Guilds) * await ModProvider.SyncRolesAsync(guild.Value).ConfigureAwait(false); * }; */ #endif client.MessageReactionAdded += Starbucks.Handler; client.MessageReactionAdded += ContentFilterMonitor.OnReaction; client.MessageCreated += (_, __) => { Watchdog.TimeSinceLastIncomingMessage.Restart(); return(Task.CompletedTask); }; client.MessageCreated += ContentFilterMonitor.OnMessageCreated; // should be first client.MessageCreated += GlobalMessageCache.OnMessageCreated; var mediaScreenshotMonitor = new MediaScreenshotMonitor(client); if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey)) { client.MessageCreated += mediaScreenshotMonitor.OnMessageCreated; } client.MessageCreated += ProductCodeLookup.OnMessageCreated; client.MessageCreated += LogParsingHandler.OnMessageCreated; client.MessageCreated += LogAsTextMonitor.OnMessageCreated; client.MessageCreated += DiscordInviteFilter.OnMessageCreated; client.MessageCreated += PostLogHelpHandler.OnMessageCreated; client.MessageCreated += BotReactionsHandler.OnMessageCreated; client.MessageCreated += GithubLinksHandler.OnMessageCreated; client.MessageCreated += NewBuildsMonitor.OnMessageCreated; client.MessageCreated += TableFlipMonitor.OnMessageCreated; client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated; client.MessageCreated += EmpathySimulationHandler.OnMessageCreated; client.MessageUpdated += GlobalMessageCache.OnMessageUpdated; client.MessageUpdated += ContentFilterMonitor.OnMessageUpdated; client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated; client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated; client.MessageDeleted += GlobalMessageCache.OnMessageDeleted; if (Config.DeletedMessagesLogChannelId > 0) { client.MessageDeleted += DeletedMessagesMonitor.OnMessageDeleted; } client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted; client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted; client.MessagesBulkDeleted += GlobalMessageCache.OnMessagesBulkDeleted; client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated; client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated; client.GuildMemberAdded += Greeter.OnMemberAdded; client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameValidationMonitor.OnMemberAdded; client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameValidationMonitor.OnMemberUpdated; Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); try { await client.ConnectAsync().ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Failed to connect to Discord: " + e.Message); throw; } ulong? channelId = null; string restartMsg = null; using (var db = new BotDb()) { var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel"); if (chState != null) { if (ulong.TryParse(chState.Value, out var ch)) { channelId = ch; } db.BotState.Remove(chState); } var msgState = db.BotState.FirstOrDefault(i => i.Key == "bot-restart-msg"); if (msgState != null) { restartMsg = msgState.Value; db.BotState.Remove(msgState); } db.SaveChanges(); } if (string.IsNullOrEmpty(restartMsg)) { restartMsg = null; } if (channelId.HasValue) { Config.Log.Info($"Found channelId {channelId}"); DiscordChannel channel; if (channelId == InvalidChannelId) { channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false); await channel.SendMessageAsync(restartMsg ?? "Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false); } else { channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false); await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false); } } else { Config.Log.Debug($"Args count: {args.Length}"); var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]"); Config.Log.Debug("Args: " + string.Join(" ", pArgs)); } Config.Log.Debug("Running RPCS3 update check thread"); backgroundTasks = Task.WhenAll( backgroundTasks, NewBuildsMonitor.MonitorAsync(client), Watchdog.Watch(client), InviteWhitelistProvider.CleanupAsync(client), UsernameValidationMonitor.MonitorAsync(client), Psn.Check.MonitorFwUpdates(client, Config.Cts.Token), Watchdog.SendMetrics(client), Watchdog.CheckGCStats(), mediaScreenshotMonitor.ProcessWorkQueue() ); while (!Config.Cts.IsCancellationRequested) { if (client.Ping > 1000) { Config.Log.Warn($"High ping detected: {client.Ping}"); } await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false); } await backgroundTasks.ConfigureAwait(false); } catch (Exception e) { if (!Config.inMemorySettings.ContainsKey("shutdown")) { Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart..."); } } finally { Config.TelemetryClient?.Flush(); ShutdownCheck.Release(); if (singleInstanceCheckThread.IsAlive) { singleInstanceCheckThread.Join(100); } } if (!Config.inMemorySettings.ContainsKey("shutdown")) { Sudo.Bot.Restart(InvalidChannelId, null); } }
public override void Run(List <DataObject> result) { List <EspionageReport> reports = result.OfType <EspionageReport>().ToList(); if (!reports.Any()) { return; } using (BotDb db = new BotDb()) { long[] locIds = reports.Select(s => s.Coordinate.Id).ToArray(); Dictionary <long, Planet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId); foreach (EspionageReport report in reports) { Logger.Instance.Log(LogLevel.Info, $"Saving esp report on {report.Coordinate}, level: {report.Details}"); Planet item; if (!existing.TryGetValue(report.Coordinate, out item)) { item = new Planet { Coordinate = report.Coordinate }; db.Planets.Add(item); } if (report.Details.HasFlag(ReportDetails.Resources) && (!item.LastResourcesTime.HasValue || report.Sent > item.LastResourcesTime)) { item.Resources = report.Resources; item.LastResourcesTime = report.Sent; } if (report.Details.HasFlag(ReportDetails.Buildings) && item.Buildings.NeedsUpdate(report.Sent)) { item.Buildings = report.DetectedBuildings; item.Buildings.LastUpdated = report.Sent; } if (report.Details.HasFlag(ReportDetails.Defense) && item.Defences.NeedsUpdate(report.Sent)) { item.Defences = report.DetectedDefence; item.Defences.LastUpdated = report.Sent; } if (report.Details.HasFlag(ReportDetails.Ships) && item.Ships.NeedsUpdate(report.Sent)) { item.Ships = report.DetectedShips; item.Ships.LastUpdated = report.Sent; } if (report.Details.HasFlag(ReportDetails.Research) && (item.Player?.Research.NeedsUpdate(report.Sent)).GetValueOrDefault(false)) { item.Player.Research = report.DetectedResearch; item.Player.Research.LastUpdated = report.Sent; } if (report.Details.HasFlag(ReportDetails.Ships) && report.DetectedShips != null) { if (!db.PlanetShipLog.Where(s => s.LocationId == item.Coordinate.Id && s.CreatedOn == report.Sent).Any()) { PlanetShipLog log = new PlanetShipLog() { Planet = item, Ships = report.DetectedShips, CreatedOn = report.Sent }; db.PlanetShipLog.Add(log); } } var strippedTime = report.Sent.TruncateToMinute(); if (!db.PlanetActivityLog.Where(s => s.LocationId == item.Coordinate.Id && s.CreatedOn == strippedTime).Any()) { PlanetActivityLog log = new PlanetActivityLog() { Planet = item, Activity = report.Activity, CreatedOn = strippedTime }; db.PlanetActivityLog.Add(log); } } db.SaveChanges(); } }
public override void Run(List <DataObject> result) { OgamePageInfo current = result.OfType <OgamePageInfo>().FirstOrDefault(); if (current == null) { return; } var playerPlanets = result.OfType <PlanetListItem>(); PlanetResources resources = result.OfType <PlanetResources>().FirstOrDefault(); var buildings = result.OfType <DetectedBuilding>().ToDictionary(s => s.Building, s => s.Level); var ships = result.OfType <DetectedShip>().ToDictionary(s => s.Ship, s => s.Count); var defences = result.OfType <DetectedDefence>().ToDictionary(s => s.Building, s => s.Count); var research = result.OfType <DetectedResearch>().ToDictionary(s => s.Research, s => s.Level); using (BotDb db = new BotDb()) { long[] locIds = playerPlanets.Select(s => s.Coordinate.Id).ToArray(); Dictionary <long, Planet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId); if (!_isPlayerSeeded) { if (!db.Players.Where(s => s.PlayerId == current.PlayerId).Any()) { db.Players.Add(new Player() { PlayerId = current.PlayerId, Name = current.PlayerName, Status = PlayerStatus.None }); db.SaveChanges(); } _isPlayerSeeded = true; } foreach (var playerPlanet in playerPlanets) { Planet item; if (!existing.TryGetValue(playerPlanet.Coordinate.Id, out item)) { item = new Planet() { Coordinate = playerPlanet.Coordinate, Name = playerPlanet.Name, PlanetId = playerPlanet.Id, PlayerId = current.PlayerId }; db.Planets.Add(item); } if (resources.Coordinate.Id == playerPlanet.Coordinate.Id) { item.Resources = resources.Resources; } if (current.PlanetId == playerPlanet.Id) { if (ships.Count > 0) { item.Ships.FromPartialResult(ships); item.Ships.LastUpdated = DateTimeOffset.UtcNow; } else if (defences.Count > 0) { item.Defences.FromPartialResult(defences); item.Defences.LastUpdated = DateTimeOffset.UtcNow; } else if (buildings.Count > 0) { item.Buildings.FromPartialResult(buildings); item.Buildings.LastUpdated = DateTimeOffset.UtcNow; } else if (research.Count > 0) { item.Player.Research.FromPartialResult(research); item.Player.Research.LastUpdated = DateTimeOffset.UtcNow; } } item.Name = playerPlanet.Name; item.PlayerId = current.PlayerId; item.PlanetId = playerPlanet.Id; db.SaveChanges(); } } List <MessageBase> messages = result.OfType <MessageBase>().ToList(); if (!messages.Any()) { return; } int[] messageIds = messages.Select(s => s.MessageId).ToArray(); using (BotDb db = new BotDb()) { HashSet <int> existing = db.Messages.Where(s => messageIds.Contains(s.MessageId)).Select(s => s.MessageId).ToHashset(); foreach (MessageBase message in messages.Where(s => !existing.Contains(s.MessageId))) { db.Messages.Add(new Message { MessageId = message.MessageId, Body = message, TabType = message.TabType }); } db.SaveChanges(); } }
public override void Run(List <DataObject> result) { GalaxyPageSystem systemDetails = result.OfType <GalaxyPageSystem>().FirstOrDefault(); if (systemDetails == null) { return; } using (BotDb db = new BotDb()) { int systemId = systemDetails.System; GalaxyScan scanInfo = db.Scans.SingleOrDefault(s => s.LocationId == systemId); if (scanInfo == null) { scanInfo = new GalaxyScan { SystemCoordinate = systemDetails.System }; db.Scans.Add(scanInfo); } scanInfo.LastScan = DateTimeOffset.Now; // Prep players int[] playerIds = result.OfType <GalaxyPageInfoItem>().Select(s => s.PlayerId).ToArray(); Dictionary <int, Player> players = db.Players.Where(s => playerIds.Contains(s.PlayerId)).ToDictionary(s => s.PlayerId); // Individual items long systemLower = systemDetails.System.LowerCoordinate; long systemUpper = systemDetails.System.UpperCoordinate; Dictionary <long, Planet> toRemove = db.Planets.Where(s => systemLower <= s.LocationId && s.LocationId <= systemUpper).ToDictionary(s => s.LocationId); foreach (GalaxyPageInfoItem row in result.OfType <GalaxyPageInfoItem>()) { Player player = null; // not self if (row.PlayerId != -1) { if (!players.TryGetValue(row.PlayerId, out player)) { player = new Player { PlayerId = row.PlayerId }; db.Players.Add(player); players[row.PlayerId] = player; } player.Name = row.PlayerName; player.Status = row.PlayerStatus; } Planet planet; if (!toRemove.TryRemove(row.Planet.Coordinate, out planet)) { planet = new Planet { Coordinate = row.Planet.Coordinate }; db.Planets.Add(planet); } planet.Name = row.Planet.Name; if (player != null) { planet.Player = player; } if (row.Moon != null) { Planet moon; if (!toRemove.TryRemove(row.Moon.Coordinate, out moon)) { moon = new Planet { Coordinate = row.Moon.Coordinate }; db.Planets.Add(moon); } moon.Name = row.Moon.Name; moon.Player = player; } } db.Planets.RemoveRange(toRemove.Values); toRemove.Clear(); db.SaveChanges(); } }
internal static async Task Main(string[] args) { Console.WriteLine("Confinement: " + SandboxDetector.Detect()); if (args.Length > 0 && args[0] == "--dry-run") { Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData)))); if (Assembly.GetEntryAssembly().GetCustomAttribute <UserSecretsIdAttribute>() != null) { Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath))); } return; } var singleInstanceCheckThread = new Thread(() => { using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot"); if (instanceLock.WaitOne(1000)) { try { InstanceCheck.Release(); ShutdownCheck.Wait(); } finally { instanceLock.ReleaseMutex(); } } }); try { singleInstanceCheckThread.Start(); if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false)) { Config.Log.Fatal("Another instance is already running."); return; } if (string.IsNullOrEmpty(Config.Token) || Config.Token.Length < 16) { Config.Log.Fatal("No token was specified."); return; } if (SandboxDetector.Detect() == SandboxType.Docker) { Config.Log.Info("Checking for updates..."); try { var(updated, stdout) = await Sudo.Bot.UpdateAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(stdout) && updated) { Config.Log.Debug(stdout); } if (updated) { Sudo.Bot.RestartNoSaving(0); return; } } catch (Exception e) { Config.Log.Error(e, "Failed to check for updates"); } } using (var db = new BotDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } using (var db = new ThumbnailDb()) if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token)) { return; } await StatsStorage.RestoreAsync().ConfigureAwait(false); Config.Log.Debug("Restored stats from persistent storage"); var backgroundTasks = Task.WhenAll( AmdDriverVersionProvider.RefreshAsync(), new PsnScraper().RunAsync(Config.Cts.Token), GameTdbScraper.RunAsync(Config.Cts.Token), new AppveyorClient.Client().GetBuildAsync(Guid.NewGuid().ToString(), Config.Cts.Token), StatsStorage.BackgroundSaveAsync() ); try { if (!Directory.Exists(Config.IrdCachePath)) { Directory.CreateDirectory(Config.IrdCachePath); } } catch (Exception e) { Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}"); } var config = new DiscordConfiguration { Token = Config.Token, TokenType = TokenType.Bot, }; using var client = new DiscordClient(config); var commands = client.UseCommandsNext(new CommandsNextConfiguration { StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix }, Services = new ServiceCollection().BuildServiceProvider(), }); commands.RegisterConverter(new TextOnlyDiscordChannelConverter()); commands.RegisterCommands <Misc>(); commands.RegisterCommands <CompatList>(); commands.RegisterCommands <Sudo>(); commands.RegisterCommands <CommandsManagement>(); commands.RegisterCommands <ContentFilters>(); commands.RegisterCommands <Warnings>(); commands.RegisterCommands <Explain>(); commands.RegisterCommands <Psn>(); commands.RegisterCommands <Invites>(); commands.RegisterCommands <Moderation>(); commands.RegisterCommands <Ird>(); commands.RegisterCommands <BotMath>(); commands.RegisterCommands <Pr>(); commands.RegisterCommands <Events>(); commands.RegisterCommands <E3>(); commands.RegisterCommands <Cyberpunk2077>(); commands.RegisterCommands <Rpcs3Ama>(); commands.RegisterCommands <BotStats>(); commands.RegisterCommands <Syscall>(); commands.RegisterCommands <ForcedNicknames>(); commands.CommandErrored += UnknownCommandHandler.OnError; var interactivityConfig = new InteractivityConfiguration { }; client.UseInteractivity(interactivityConfig); client.Ready += async r => { Config.Log.Info("Bot is ready to serve!"); Config.Log.Info(""); Config.Log.Info($"Bot user id : {r.Client.CurrentUser.Id} ({r.Client.CurrentUser.Username})"); Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({(await r.Client.GetUserAsync(Config.BotAdminId)).Username})"); Config.Log.Info(""); }; client.GuildAvailable += async gaArgs => { await BotStatusMonitor.RefreshAsync(gaArgs.Client).ConfigureAwait(false); Watchdog.DisconnectTimestamps.Clear(); Watchdog.TimeSinceLastIncomingMessage.Restart(); if (gaArgs.Guild.Id != Config.BotGuildId) { #if DEBUG Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})"); #else Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving..."); await gaArgs.Guild.LeaveAsync().ConfigureAwait(false); #endif return; } Config.Log.Info($"Server {gaArgs.Guild.Name} is available now"); Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}..."); try { await Task.WhenAll( Starbucks.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default), DiscordInviteFilter.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default) ).ConfigureAwait(false); } catch (Exception e) { Config.Log.Warn(e, "Error running backlog tasks"); } Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}."); }; client.GuildAvailable += gaArgs => UsernameValidationMonitor.MonitorAsync(gaArgs.Client, true); client.GuildUnavailable += guArgs => { Config.Log.Warn($"{guArgs.Guild.Name} is unavailable"); return(Task.CompletedTask); }; client.MessageReactionAdded += Starbucks.Handler; client.MessageReactionAdded += ContentFilterMonitor.OnReaction; client.MessageCreated += _ => { Watchdog.TimeSinceLastIncomingMessage.Restart(); return(Task.CompletedTask); }; client.MessageCreated += ContentFilterMonitor.OnMessageCreated; // should be first client.MessageCreated += ProductCodeLookup.OnMessageCreated; client.MessageCreated += LogParsingHandler.OnMessageCreated; client.MessageCreated += LogAsTextMonitor.OnMessageCreated; client.MessageCreated += DiscordInviteFilter.OnMessageCreated; client.MessageCreated += PostLogHelpHandler.OnMessageCreated; client.MessageCreated += BotReactionsHandler.OnMessageCreated; client.MessageCreated += AppveyorLinksHandler.OnMessageCreated; client.MessageCreated += GithubLinksHandler.OnMessageCreated; client.MessageCreated += NewBuildsMonitor.OnMessageCreated; client.MessageCreated += TableFlipMonitor.OnMessageCreated; client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated; client.MessageCreated += EmpathySimulationHandler.OnMessageCreated; client.MessageUpdated += ContentFilterMonitor.OnMessageUpdated; client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated; client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated; client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted; client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted; client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated; client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated; client.GuildMemberAdded += Greeter.OnMemberAdded; client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded; client.GuildMemberAdded += UsernameValidationMonitor.OnMemberAdded; client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated; client.GuildMemberUpdated += UsernameValidationMonitor.OnMemberUpdated; client.DebugLogger.LogMessageReceived += (sender, eventArgs) => { Action <Exception, string> logLevel = Config.Log.Info; if (eventArgs.Level == LogLevel.Debug) { logLevel = Config.Log.Debug; } else if (eventArgs.Level == LogLevel.Info) { //logLevel = Config.Log.Info; if (eventArgs.Message?.Contains("Session resumed") ?? false) { Watchdog.DisconnectTimestamps.Clear(); } } else if (eventArgs.Level == LogLevel.Warning) { logLevel = Config.Log.Warn; if (eventArgs.Message?.Contains("Dispatch:PRESENCES_REPLACE") ?? false) { BotStatusMonitor.RefreshAsync(client).ConfigureAwait(false).GetAwaiter().GetResult(); } } else if (eventArgs.Level == LogLevel.Error) { logLevel = Config.Log.Error; } else if (eventArgs.Level == LogLevel.Critical) { logLevel = Config.Log.Fatal; if ((eventArgs.Message?.Contains("Socket connection terminated") ?? false) || (eventArgs.Message?.Contains("heartbeats were skipped. Issuing reconnect.") ?? false)) { Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); } } logLevel(eventArgs.Exception, eventArgs.Message); }; Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow); try { await client.ConnectAsync().ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Failed to connect to Discord: " + e.Message); throw; } ulong?channelId = null; if (SandboxDetector.Detect() == SandboxType.Docker) { using var db = new BotDb(); var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel"); if (chState != null) { if (ulong.TryParse(chState.Value, out var ch)) { channelId = ch; } db.BotState.Remove(chState); db.SaveChanges(); } } if (args.LastOrDefault() is string strCh && ulong.TryParse(strCh, out var chId)) { channelId = chId; } if (channelId.HasValue) { Config.Log.Info($"Found channelId {channelId}"); DiscordChannel channel; if (channelId == InvalidChannelId) { channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false); await channel.SendMessageAsync("Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false); } else { channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false); await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false); } } else { Config.Log.Debug($"Args count: {args.Length}"); var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]"); Config.Log.Debug("Args: " + string.Join(" ", pArgs)); } Config.Log.Debug("Running RPCS3 update check thread"); backgroundTasks = Task.WhenAll( backgroundTasks, NewBuildsMonitor.MonitorAsync(client), Watchdog.Watch(client), InviteWhitelistProvider.CleanupAsync(client), UsernameValidationMonitor.MonitorAsync(client) ); while (!Config.Cts.IsCancellationRequested) { if (client.Ping > 1000) { Config.Log.Warn($"High ping detected: {client.Ping}"); } await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false); } await backgroundTasks.ConfigureAwait(false); } catch (Exception e) { if (!Config.inMemorySettings.ContainsKey("shutdown")) { Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart..."); } } finally { ShutdownCheck.Release(); if (singleInstanceCheckThread.IsAlive) { singleInstanceCheckThread.Join(100); } } if (!Config.inMemorySettings.ContainsKey("shutdown")) { Sudo.Bot.Restart(InvalidChannelId); } }
private void ProcessData(Universe model) { using (BotDb db = new BotDb()) { Dictionary <long, Db.Planet> allPlanets = db.Planets.ToDictionary(s => s.LocationId); Dictionary <int, Db.Player> allPlayers = db.Players.ToDictionary(s => s.PlayerId); List <Db.Planet> newPlanets = new List <Db.Planet>(); List <Db.Player> newPlayers = new List <Db.Player>(); for (int i = 0; i < model.Planets.Length; i++) { OgameApi.Objects.Planet planet = model.Planets[i]; Coordinate planetCoords = Coordinate.Parse(planet.Coords, CoordinateType.Planet); Db.Planet dbPlanet; if (!allPlanets.TryGetValue(planetCoords.Id, out dbPlanet)) { dbPlanet = new Db.Planet { Coordinate = planetCoords }; newPlanets.Add(dbPlanet); allPlanets[planetCoords.Id] = dbPlanet; } dbPlanet.Name = planet.Name; dbPlanet.PlayerId = planet.Player; if (planet.Moon != null) { Coordinate moonCoords = Coordinate.Create(planetCoords, CoordinateType.Moon); Db.Planet dbMoon; if (!allPlanets.TryGetValue(moonCoords.Id, out dbMoon)) { dbMoon = new Db.Planet { Coordinate = moonCoords }; newPlanets.Add(dbMoon); allPlanets[moonCoords.Id] = dbMoon; } dbMoon.Name = planet.Moon.Name; } Db.Player dbPlayer; if (!allPlayers.TryGetValue(planet.Player, out dbPlayer)) { dbPlayer = new Db.Player { PlayerId = planet.Player }; newPlayers.Add(dbPlayer); allPlayers[dbPlayer.PlayerId] = dbPlayer; } if (i % 250 == 0) { db.Planets.AddRange(newPlanets); db.Players.AddRange(newPlayers); db.SaveChanges(); newPlanets.Clear(); newPlayers.Clear(); } } db.Planets.AddRange(newPlanets); db.Players.AddRange(newPlayers); db.SaveChanges(); } }