Example #1
0
        /// <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;
        }
Example #2
0
 public BotDataStructure(BackupData backup)
 {
     Access       = new SemaphoreSlim(1, 1);
     DiscordUplay = backup.discordUplayDict;
     QuietPlayers = backup.quietSet;
     DiscordRanks = backup.discordRanksDict;
 }
Example #3
0
        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);
        }
Example #4
0
        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);
                }
        }
Example #5
0
        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);
        }
Example #6
0
        /// <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);
        }
Example #7
0
        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);
        }
Example #8
0
        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);
        }