/// <summary> /// Fills in the data fields from some backup. Previously we did that on Bot() initialization, /// we do that in a separate function now. /// </summary> /// <returns></returns> public async Task DelayedConstruction() { if (_primary == null) { throw new PrimaryGuildException("DelayedConstruction() called too early, the Discord API is not ready yet."); } if (Settings.BotFirstRun) { FirstRunDelayedConstruction(); return; } if (constructionComplete) { throw new PrimaryGuildException("Construction called twice, that is not allowed."); } Console.WriteLine("Restoring guild list configuration from message backup."); BackupGuildConfiguration bgc = await RestoreGuildConfiguration(); guilds = new DiscordGuilds(bgc, client); // We check for role creation here, instead of inside the constructor of DiscordGuild. // We do this not to make the constructor async itself. It might be better to check there. foreach (DiscordGuild g in guilds.byID.Values) { await g.RolePresenceCheckAsync(); } Console.WriteLine("Populating data from the message backup."); BackupData recoverData = await RestoreDataStructures(); _data = new BotDataStructure(recoverData); if (Settings.UsingExtensionBanTracking) { // Temporary: if the bds structure was not parsed from the backup, because it didn't exist, just create a new empty one. if (recoverData.bds == null) { Console.WriteLine("Unable to restore the old ban data structure, creating an empty one."); recoverData.bds = new Extensions.BanDataStructure(); } bt = new Extensions.BanTracking(guilds, recoverData.bds); } if (Settings.UsingExtensionRoleHighlights) { _highlighter = new Extensions.MainHighlighter(guilds); } Console.WriteLine("Loaded " + _data.DiscordUplay.Count + " discord -- uplay connections."); Console.WriteLine("Loaded " + _data.QuietPlayers.Count + " players who wish not to be pinged."); Console.WriteLine("Loaded " + _data.DiscordRanks.Count + " current player ranks."); constructionComplete = true; }
public BotDataStructure(BackupData backup) { Access = new SemaphoreSlim(1, 1); DiscordUplay = backup.discordUplayDict; QuietPlayers = backup.quietSet; DiscordRanks = backup.discordRanksDict; }
public static BackupData RestoreFromString(string content) { BackupData ret = null; TextReader stringr = new StringReader(content); JsonSerializer serializer = new JsonSerializer(); ret = (BackupData)serializer.Deserialize(stringr, typeof(BackupData)); return(ret); }
public static void BackupToFile(BackupData bd, string fileName) { JsonSerializer serializer = new JsonSerializer(); using (StreamWriter sw = new StreamWriter(fileName)) using (JsonWriter jw = new JsonTextWriter(sw)) { serializer.Serialize(jw, bd); } }
public async Task PerformBackup() { BackupData backup = await _data.PrepareBackup(); bt.ExtendBackup(backup); // We have the backup data now, we can continue without the lock, as long as this was indeed a deep copy. Console.WriteLine($"Saving backup data to {Settings.backupFile}."); backup.BackupToFile(Settings.backupFile); await _primary.BackupFileToMessage(Settings.backupFile, Settings.DataBackupChannel); }
/// <summary> /// Creates a copy of the current data structures for backup. /// Extensions need to be handled separately. /// </summary> /// <returns></returns> public async Task <BackupData> PrepareBackup() { await Access.WaitAsync(); BackupData data = new BackupData(); data.discordRanksDict = new Dictionary <ulong, Rank>(DiscordRanks); data.discordUplayDict = new Dictionary <ulong, string>(DiscordUplay); data.quietSet = new HashSet <ulong>(QuietPlayers); Access.Release(); return(data); }
public static BackupData RestoreFromFile(string fileName) { BackupData ret = null; if (File.Exists(fileName)) { JsonSerializer serializer = new JsonSerializer(); StreamReader fileStream = File.OpenText(fileName); JsonTextReader file = new JsonTextReader(fileStream); ret = (BackupData)serializer.Deserialize(file, typeof(BackupData)); file.Close(); } return(ret); }
public async Task <BackupData> RestoreDataStructures() { // First, check that the primary guild is already loaded. if (!_primaryServerLoaded) { throw new PrimaryGuildException("Primary guild (Discord server) did not load and yet RestoreDataStructures() is called."); } BackupData bd = null; SocketTextChannel backupChannel = _primary._socket.TextChannels.Single(ch => ch.Name == Settings.DataBackupChannel); if (backupChannel == null) { throw new PrimaryGuildException("Unable to find the primary data backup channel. Even if you are trying to restore from a file, create this channel first."); } var messages = backupChannel.GetMessagesAsync().Flatten(); var msgarray = await messages.ToArrayAsync(); if (msgarray.Count() != 1) { Console.WriteLine($"Restoration expects exactly one message, found {msgarray.Count()}."); } else { var client = new HttpClient(); var dataString = await client.GetStringAsync(msgarray[0].Attachments.First().Url); // TODO: exception handling here. bd = BackupData.RestoreFromString(dataString); } // If the above fails, attempt to read it from a backup file. if (bd == null) { bd = BackupData.RestoreFromFile(Settings.backupFile); if (bd == null) { throw new PrimaryGuildException("Unable to restore guild configuration from any backup."); } } return(bd); }