Ejemplo n.º 1
0
        public static void WriteBar(JournalLoadingPercentChangedEventArgs args)
        {
            StringBuilder output = new StringBuilder();
            int           fillLen = 0;
            char          filler = '#', spacer = ' ';

            output.Append(" ");
            for (int i = 0; i < 10; i++)
            {
                char c = i < args.Label.Length ? args.Label[i] : ' ';
                output.Append(c);
            }

            output.Append(" [");

            fillLen = Convert.ToInt32(((decimal)args.Percent / 100) * 60);

            for (int i = 0; i < 60; i++)
            {
                output.Append(i <= fillLen ? filler : spacer);
            }

            output.Append("] ");
            output.Append(args.Percent + "%");

            lock (__consoleWriteLock) {
                Console.Write("\r");
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.Write(output.ToString());
                Console.ResetColor();
            }
        }
Ejemplo n.º 2
0
        public void CleanJournal(PurgeOptions options)
        {
            long oldPercent = 0;
            IEnumerable <string> userList              = TShock.Users.GetUsers().Select(i => i.Name);
            List <long>          deleteList            = new List <long>();
            JournalLoadingPercentChangedEventArgs args = new JournalLoadingPercentChangedEventArgs()
            {
                Label   = "Purge",
                Percent = 0
            };

            if (JournalLoadingPercentChanged != null)
            {
                JournalLoadingPercentChanged(this, args);
            }

            for (int i = 0; i < this.BankAccounts.Count; i++)
            {
                double       pcc     = (double)i / (double)BankAccounts.Count * 100;
                IBankAccount account = bankAccounts.ElementAtOrDefault(i);

                if ((options & PurgeOptions.RemoveOrphanedAccounts) == PurgeOptions.RemoveOrphanedAccounts &&
                    userList.Contains(account.UserAccountName) == false)
                {
                    if (deleteList.Contains(account.BankAccountK) == false)
                    {
                        deleteList.Add(account.BankAccountK);
                        continue;
                    }
                }

                if ((options & PurgeOptions.RemoveZeroBalanceAccounts) == PurgeOptions.RemoveZeroBalanceAccounts &&
                    (account.Balance <= 0 && account.IsSystemAccount == false))
                {
                    if (deleteList.Contains(account.BankAccountK) == false)
                    {
                        deleteList.Add(account.BankAccountK);
                        continue;
                    }
                }

                if (oldPercent != (int)pcc)
                {
                    args.Percent = (int)pcc;
                    if (JournalLoadingPercentChanged != null)
                    {
                        JournalLoadingPercentChanged(this, args);
                    }
                    oldPercent = (int)pcc;
                }
            }

            if (deleteList.Count > 0)
            {
                args.Label   = "Clean";
                args.Percent = 0;
                for (int i = 0; i < deleteList.Count; i++)
                {
                    double pcc = (double)i / (double)deleteList.Count * 100;

                    DeleteBankAccount(deleteList[i]);

                    if (oldPercent != (int)pcc)
                    {
                        args.Percent = (int)pcc;
                        if (JournalLoadingPercentChanged != null)
                        {
                            JournalLoadingPercentChanged(this, args);
                        }
                        oldPercent = (int)pcc;
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public bool LoadJournal()
        {
            MemoryStream uncompressedData;
            JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Loading"
            };
            JournalLoadingPercentChangedEventArgs finalArgs = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Verify"
            };

            ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Using XML journal - {0}", path);

            try {
                byte[] fileData = new byte[0];
initPoint:
                try {
                    fileData = File.ReadAllBytes(path);
                } catch (Exception ex) {
                    Console.ForegroundColor = ConsoleColor.DarkCyan;

                    if (ex is System.IO.FileNotFoundException || ex is System.IO.DirectoryNotFoundException)
                    {
                        TShock.Log.ConsoleInfo(" * It appears you do not have a journal yet, one will be created for you.");
                        SaveJournal();
                        //yes there are valid uses for goto, don't judge me fool
                        goto initPoint;
                    }
                    else if (ex is System.Security.SecurityException)
                    {
                        TShock.Log.ConsoleError(" * Access denied to the journal file.  Check permissions.");
                    }
                    else
                    {
                        TShock.Log.ConsoleError(" * Loading your journal failed: " + ex.Message);
                    }
                }

                try {
                    uncompressedData = GZipDecompress(fileData);
                } catch {
                    TShock.Log.ConsoleError(" * Decompression failed.");
                    return(false);
                }

                if (JournalLoadingPercentChanged != null)
                {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                try {
                    Hashtable bankAccountMap = new Hashtable();
                    Hashtable transactionMap = new Hashtable();

                    //You can't use XDocument.Parse when you have an XDeclaration for some even dumber reason than the write
                    //issue, XDocument has to be constructed from a .net 3.5 XmlReader in this case
                    //or you get a parse exception complaining about literal content.
                    using (XmlTextReader xmlStream = new XmlTextReader(uncompressedData)) {
                        XDocument doc              = XDocument.Load(xmlStream);
                        var       bankAccountList  = doc.XPathSelectElements("/Journal/BankAccounts/BankAccount");
                        int       bankAccountCount = bankAccountList.Count();
                        int       i          = 0;
                        int       oldPercent = 0;

                        foreach (XElement elem in bankAccountList)
                        {
                            long   bankAccountK    = 0L;
                            double percentComplete = (double)i / (double)bankAccountCount * 100;

                            var account = new XmlBankAccount(this)
                            {
                                Description     = elem.Attribute("Description").Value,
                                UserAccountName = elem.Attribute("UserAccountName").Value,
                                WorldID         = long.Parse(elem.Attribute("WorldID").Value),
                                Flags           = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), elem.Attribute("Flags").Value)
                            };

                            if (!long.TryParse(elem.Attribute("BankAccountK").Value, out bankAccountK))
                            {
                                //we've overwritten the old bank account key, add it to the old/new map
                                bankAccountK = Interlocked.Increment(ref _bankAccountSeed);
                                bankAccountMap.Add(elem.Attribute("BankAccountK").Value, bankAccountK);
                            }

                            account.BankAccountK = bankAccountK;

                            //parse transactions under this node
                            if (elem.Element("Transactions") != null)
                            {
                                foreach (XElement txElement in elem.Element("Transactions").Elements("Transaction"))
                                {
                                    long     transactionK  = 0L;
                                    long     transactionFK = 0;
                                    long     amount        = long.Parse(txElement.Attribute("Amount").Value);
                                    DateTime transactionDate;
                                    BankAccountTransactionFlags flags;

                                    long.TryParse(txElement.Attribute("BankAccountTransactionK").Value, out transactionK);
                                    long.TryParse(txElement.Attribute("BankAccountTransactionFK").Value, out transactionFK);
                                    DateTime.TryParse(txElement.Attribute("TransactionDateUtc").Value, out transactionDate);
                                    Enum.TryParse <BankAccountTransactionFlags>(txElement.Attribute("Flags").Value, out flags);

                                    //ignore orphaned transactions
                                    var trans = new XmlTransaction(account)
                                    {
                                        Amount = amount,
                                        BankAccountTransactionK  = transactionK,
                                        BankAccountTransactionFK = transactionFK,
                                        TransactionDateUtc       = transactionDate,
                                        Flags = flags
                                    };

                                    trans.Message = txElement.Attribute("Message") != null?txElement.Attribute("Message").Value : null;

                                    account.AddTransaction(trans);
                                }
                            }

                            account.SyncBalance();

                            if (oldPercent != (int)percentComplete)
                            {
                                parsingArgs.Percent = (int)percentComplete;
                                if (JournalLoadingPercentChanged != null)
                                {
                                    JournalLoadingPercentChanged(this, parsingArgs);
                                }
                                oldPercent = (int)percentComplete;
                            }

                            Interlocked.Increment(ref i);

                            bankAccounts.Add(account);
                        }

                        Interlocked.Exchange(ref _bankAccountSeed, bankAccounts.Count() > 0 ? bankAccounts.Max(sum => sum.BankAccountK) : 0);

                        //delete transactions with duplicate IDs

                        var qAccounts = from summary in bankAccounts
                                        group summary by summary.BankAccountK into g
                                        where g.Count() > 1
                                        select new {
                            name  = g.Key,
                            count = g.Count()
                        };

                        long[] duplicateAccounts = qAccounts.Select(pred => pred.name).ToArray();

                        int removedAccounts = bankAccounts.RemoveAll(pred => duplicateAccounts.Contains(pred.BankAccountK));

                        if (removedAccounts > 0)
                        {
                            TShock.Log.Warn("seconomy journal: removed " + removedAccounts + " accounts with duplicate IDs.");
                        }

                        //transactions in the old schema.
                        int tranCount = doc.XPathSelectElements("/Journal/Transactions/Transaction").Count();
                        i = 0; //reset index

                        foreach (XElement elem in doc.XPathSelectElements("/Journal/Transactions/Transaction"))
                        {
                            //Parallel.ForEach(doc.XPathSelectElements("/Journal/Transactions/Transaction"), (elem) => {
                            double percentComplete = (double)i / (double)tranCount * 100;
                            long   bankAccountFK   = 0L;
                            long   transactionK    = 0L;
                            long   amount          = long.Parse(elem.Attribute("Amount").Value);

                            if (!long.TryParse(elem.Attribute("BankAccountFK").Value, out bankAccountFK))
                            {
                                if (bankAccountMap.ContainsKey(elem.Attribute("BankAccountFK").Value))
                                {
                                    Interlocked.Exchange(ref bankAccountFK, (long)bankAccountMap[elem.Attribute("BankAccountFK").Value]);
                                }
                            }

                            IBankAccount bankAccount = GetBankAccount(bankAccountFK);


                            long.TryParse(elem.Attribute("BankAccountTransactionK").Value, out transactionK);

                            //ignore orphaned transactions
                            if (bankAccount != null)
                            {
                                var trans = new XmlTransaction(bankAccount)
                                {
                                    Amount = amount,
                                    BankAccountTransactionK = transactionK
                                };

                                if (elem.Attribute("BankAccountTransactionFK") != null)
                                {
                                    trans.CustomValues.Add(XmlTransaction.kXmlTransactionOldTransactonFK, elem.Attribute("BankAccountTransactionFK").Value);
                                }

                                trans.Message = elem.Attribute("Message") != null?elem.Attribute("Message").Value : null;

                                bankAccount.AddTransaction(trans);

                                transactionMap.Add(elem.Attribute("BankAccountTransactionK").Value, trans.BankAccountTransactionK);
                            }

                            Interlocked.Increment(ref i);
                        }

                        int txCount = Transactions.Count();
                        int x       = 0;

                        finalArgs.Percent = 0;

                        if (JournalLoadingPercentChanged != null)
                        {
                            JournalLoadingPercentChanged(this, finalArgs);
                        }

                        foreach (IBankAccount account in bankAccounts)
                        {
                            foreach (XmlTransaction trans in account.Transactions)
                            {
                                double pcc = (double)x / (double)txCount * 100;

                                //assigns the transactionK according to the hashmap of the old key stored as custom values
                                if (trans.CustomValues.ContainsKey(XmlTransaction.kXmlTransactionOldTransactonFK))
                                {
                                    object value = transactionMap[trans.CustomValues[XmlTransaction.kXmlTransactionOldTransactonFK]];

                                    trans.BankAccountTransactionFK = value != null ? (long)value : -1L;
                                }
                                if (oldPercent != (int)pcc)
                                {
                                    if (JournalLoadingPercentChanged != null)
                                    {
                                        finalArgs.Percent = (int)pcc;
                                        JournalLoadingPercentChanged(this, finalArgs);
                                        oldPercent = (int)pcc;
                                    }
                                }
                                Interlocked.Increment(ref x);

                                trans.CustomValues.Clear();
                                trans.CustomValues = null;
                            }
                        }

                        bankAccountMap = null;
                        transactionMap = null;

                        // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

                        var accountCount = bankAccounts.Count;
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        Console.WriteLine("\r\n Journal clean: {0} accounts and {1} transactions.", accountCount, Transactions.Count());
                        Console.ResetColor();
                    }
                } catch (Exception ex) {
                    ConsoleEx.WriteAtEnd(2, ConsoleColor.Red, "[{0}]\r\n", SEconomyPlugin.Locale.StringOrDefault(79, "corrupt"));
                    TShock.Log.ConsoleError(ex.ToString());
                    Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(80, "Your transaction journal appears to be corrupt and transactions have been lost.\n\nYou will start with a clean journal.\nYour old journal file has been move to SEconomy.journal.xml.gz.corrupt"));
                    File.Move(path, path + "." + DateTime.Now.ToFileTime().ToString() + ".corrupt");

                    SaveJournal();

                    //yes there are valid uses for goto, don't judge me fool
                    goto initPoint;
                }
            } finally {
                Console.WriteLine();
            }

            return(true);
        }
Ejemplo n.º 4
0
 static void journal_JournalLoadingPercentChanged(object sender, JournalLoadingPercentChangedEventArgs e)
 {
     ConsoleEx.WriteBar(e);
 }
Ejemplo n.º 5
0
        protected void Process()
        {
            sec = new SEconomy(null);
            SEconomyPlugin.Instance = sec;
            XmlTransactionJournal journal = null;
            int oldPercent = 0, skipped = 0;
            Dictionary <long, long> oldNewTransactions = new Dictionary <long, long>();
            JournalLoadingPercentChangedEventArgs args = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Accounts"
            };

            sec.Configuration = Config.FromFile(Config.BaseDirectory + Path.DirectorySeparatorChar + "seconomy.config.json");
            journal           = new XmlTransactionJournal(sec, Config.BaseDirectory + Path.DirectorySeparatorChar + "SEconomy.journal.xml.gz");

            JournalLoadingPercentChanged         += journal_JournalLoadingPercentChanged;
            journal.JournalLoadingPercentChanged += journal_JournalLoadingPercentChanged;
            journal.LoadJournal();

            Console.WriteLine();

            if (DatabaseExists() == false)
            {
                Console.WriteLine("Your SEconomy database does not exist.  Create it?");
                Console.Write("[y/n] ");
                if (Console.ReadKey().KeyChar != 'y')
                {
                    return;
                }
                CreateDatabase();
            }

            Console.WriteLine("Your SEconomy database will be flushed.  All accounts, and transactions will be deleted before the import.");
            Console.Write("Continue? [y/n] ");

            if (Console.ReadKey().KeyChar != 'y')
            {
                return;
            }

            Console.WriteLine();

            Connection.Query(string.Format("DELETE FROM `{0}`.`bank_account`;", sec.Configuration.SQLConnectionProperties.DbName));
            Connection.Query(string.Format("ALTER TABLE `{0}`.`bank_account` AUTO_INCREMENT 0;", sec.Configuration.SQLConnectionProperties.DbName));
            Connection.Query(string.Format("DELETE FROM `{0}`.`bank_account_transaction`;", sec.Configuration.SQLConnectionProperties.DbName));
            Connection.Query(string.Format("ALTER TABLE `{0}`.`bank_account_transaction` AUTO_INCREMENT 0;", sec.Configuration.SQLConnectionProperties.DbName));

            Console.WriteLine("This will probably take a while...\r\n");
            Console.WriteLine();
            if (JournalLoadingPercentChanged != null)
            {
                JournalLoadingPercentChanged(null, args);
            }

            for (int i = 0; i < journal.BankAccounts.Count; i++)
            {
                IBankAccount account         = journal.BankAccounts.ElementAtOrDefault(i);
                double       percentComplete = (double)i / (double)journal.BankAccounts.Count * 100;
                long         id    = -1;
                string       query = null;

                if (account == null)
                {
                    continue;
                }

                query = @"INSERT INTO `bank_account` 
							(user_account_name, world_id, flags, flags2, description, old_bank_account_k)
						  VALUES (@0, @1, @2, @3, @4, @5);"                        ;

                try {
                    Connection.QueryIdentity(query, out id, account.UserAccountName, account.WorldID,
                                             (int)account.Flags, 0, account.Description, account.BankAccountK);
                } catch (Exception ex) {
                    TShock.Log.ConsoleError("[SEconomy MySQL] Sql error adding bank account: " + ex.ToString());
                    continue;
                }

                for (int t = 0; t < account.Transactions.Count(); t++)
                {
                    long         tranId      = -1;
                    ITransaction transaction = account.Transactions.ElementAtOrDefault(t);
                    string       txQuery     = @"INSERT INTO `bank_account_transaction` 
										(bank_account_fk, amount, message, flags, flags2, transaction_date_utc, old_bank_account_transaction_k)
										VALUES (@0, @1, @2, @3, @4, @5, @6);"                                        ;

                    try {
                        Connection.QueryIdentity(txQuery, out tranId, id, (long)transaction.Amount, transaction.Message,
                                                 (int)BankAccountTransactionFlags.FundsAvailable, (int)transaction.Flags2, transaction.TransactionDateUtc,
                                                 transaction.BankAccountTransactionK);

                        if (oldNewTransactions.ContainsKey(transaction.BankAccountTransactionK) == false)
                        {
                            oldNewTransactions[transaction.BankAccountTransactionK] = tranId;
                        }
                    } catch (Exception ex) {
                        TShock.Log.ConsoleError("[SEconomy MySQL] Database error in BeginSourceTransaction: " + ex.Message);
                        continue;
                    }
                }

                if (oldPercent != (int)percentComplete)
                {
                    args.Percent = (int)percentComplete;
                    if (JournalLoadingPercentChanged != null)
                    {
                        JournalLoadingPercentChanged(null, args);
                    }
                    oldPercent = (int)percentComplete;
                }
            }

            args.Label   = "Reseed";
            args.Percent = 0;
            if (JournalLoadingPercentChanged != null)
            {
                JournalLoadingPercentChanged(null, args);
            }

            string updateQuery = @"update bank_account_transaction as OLDT
									inner join (
										select bank_account_transaction_id, old_bank_account_transaction_k
										from bank_account_transaction
									) as NEWT on OLDT.old_bank_account_transaction_k = NEWT.old_bank_account_transaction_k
									set OLDT.bank_account_transaction_fk = NEWT.bank_account_transaction_id"                                    ;

            Connection.Query(updateQuery);
            Connection.Query("update `bank_account_transaction` set `old_bank_account_transaction_k` = null;");
            args.Percent = 100;
            if (JournalLoadingPercentChanged != null)
            {
                JournalLoadingPercentChanged(null, args);
            }

            Console.WriteLine("import complete", skipped);
            Console.WriteLine("Press any key to exit");
            Console.Read();
        }
Ejemplo n.º 6
0
        protected void LoadBankAccounts()
        {
            long   bankAccountCount = 0, tranCount = 0;
            int    index = 0, oldPercent = 0;
            double percentComplete = 0;
            JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Loading"
            };

            try {
                if (JournalLoadingPercentChanged != null)
                {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                bankAccounts     = new List <IBankAccount>();
                bankAccountCount = Connection.QueryScalar <long>("select count(*) from `bank_account`;");
                tranCount        = Connection.QueryScalar <long>("select count(*) from `bank_account_transaction`;");

                QueryResult bankAccountResult = Connection.QueryReader(@"select bank_account.*, sum(bank_account_transaction.amount) as balance
                                                                         from bank_account 
                                                                             inner join bank_account_transaction on bank_account_transaction.bank_account_fk = bank_account.bank_account_id 
                                                                         group by bank_account.bank_account_id;");

                Action <int> percentCompleteFunc = i => {
                    percentComplete = (double)i / (double)bankAccountCount * 100;

                    if (oldPercent != (int)percentComplete)
                    {
                        parsingArgs.Percent = (int)percentComplete;
                        if (JournalLoadingPercentChanged != null)
                        {
                            JournalLoadingPercentChanged(this, parsingArgs);
                        }
                        oldPercent = (int)percentComplete;
                    }
                };

                foreach (var acc in bankAccountResult.AsEnumerable())
                {
                    MySQLBankAccount sqlAccount = null;
                    sqlAccount = new MySQLBankAccount(this)
                    {
                        BankAccountK    = acc.Get <long>("bank_account_id"),
                        Description     = acc.Get <string>("description"),
                        Flags           = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), acc.Get <int>("flags").ToString()),
                        UserAccountName = acc.Get <string>("user_account_name"),
                        WorldID         = acc.Get <long>("world_id"),
                        Balance         = acc.Get <long>("balance")
                    };

                    //sqlAccount.SyncBalance();
                    lock (BankAccounts) {
                        BankAccounts.Add(sqlAccount);
                    }

                    Interlocked.Increment(ref index);
                    percentCompleteFunc(index);
                }

                parsingArgs.Percent = 100;
                if (JournalLoadingPercentChanged != null)
                {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

                Console.WriteLine("\r\n");
                ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Journal clean: {0} accounts, {1} transactions", BankAccounts.Count(), tranCount);
            } catch (Exception ex) {
                TShock.Log.ConsoleError(" seconomy mysql: db error in LoadJournal: " + ex.Message);
                throw;
            }
        }
        public void CleanJournal(PurgeOptions options)
        {
            long oldPercent = 0;
            List<string> userList = TShock.Users.GetUsers().Select(i => i.Name).ToList();
            List<long> deleteList = new List<long>();
            JournalLoadingPercentChangedEventArgs args = new JournalLoadingPercentChangedEventArgs() {
                Label = "Scrub",
                Percent = 0
            };

            if (JournalLoadingPercentChanged != null) {
                JournalLoadingPercentChanged(this, args);
            }

            for (int i = 0; i < this.BankAccounts.Count; i++) {
                double pcc = (double)i / (double)BankAccounts.Count * 100;
                IBankAccount account = this.bankAccounts.ElementAtOrDefault(i);

                if ((options & PurgeOptions.RemoveOrphanedAccounts) == PurgeOptions.RemoveOrphanedAccounts
                    && userList.Contains(account.UserAccountName) == false) {
                    if (deleteList.Contains(account.BankAccountK) == false) {
                        deleteList.Add(account.BankAccountK);
                        userList.Remove(account.UserAccountName);
                        continue;
                    }
                }

                if ((options & PurgeOptions.RemoveZeroBalanceAccounts) == PurgeOptions.RemoveZeroBalanceAccounts
                    && (account.Balance <= 0 && account.IsSystemAccount == false)) {
                    if (deleteList.Contains(account.BankAccountK) == false) {
                        deleteList.Add(account.BankAccountK);
                        continue;
                    }
                }

                if (oldPercent != (int)pcc) {
                    args.Percent = (int)pcc;
                    if (JournalLoadingPercentChanged != null) {
                        JournalLoadingPercentChanged(this, args);
                    }
                    oldPercent = (int)pcc;
                }
            }

            if (deleteList.Count > 0) {
                args.Label = "Clean";
                args.Percent = 0;
                for (int i = 0; i < deleteList.Count; i++) {
                    double pcc = (double)i / (double)deleteList.Count * 100;

                    DeleteBankAccountAsync(deleteList[i]).Wait();

                    if (oldPercent != (int)pcc) {
                        args.Percent = (int)pcc;
                        if (JournalLoadingPercentChanged != null) {
                            JournalLoadingPercentChanged(this, args);
                        }
                        oldPercent = (int)pcc;
                    }
                }
            }
        }
		protected void LoadBankAccounts()
		{
			long bankAccountCount = 0, tranCount = 0;
			int index = 0, oldPercent = 0;
			double percentComplete = 0;
			JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs() {
				Label = "Loading"
			};

			try {
				if (JournalLoadingPercentChanged != null) {
					JournalLoadingPercentChanged(this, parsingArgs);
				}

				bankAccounts = new List<IBankAccount>();
				bankAccountCount = Connection.QueryScalar<long>("select count(*) from `bank_account`;");
				tranCount = Connection.QueryScalar<long>("select count(*) from `bank_account_transaction`;");

                QueryResult bankAccountResult = Connection.QueryReader(@"select bank_account.*, sum(bank_account_transaction.amount) as balance
                                                                         from bank_account 
                                                                             inner join bank_account_transaction on bank_account_transaction.bank_account_fk = bank_account.bank_account_id 
                                                                         group by bank_account.bank_account_id;");

				Action<int> percentCompleteFunc = i => {
					percentComplete = (double)i / (double)bankAccountCount * 100;

					if (oldPercent != (int)percentComplete) {
						parsingArgs.Percent = (int)percentComplete;
						if (JournalLoadingPercentChanged != null) {
							JournalLoadingPercentChanged(this, parsingArgs);
						}
						oldPercent = (int)percentComplete;
					}
				};

				foreach (var acc in bankAccountResult.AsEnumerable()) {
					MySQLBankAccount sqlAccount = null;
					sqlAccount = new MySQLBankAccount(this) {
						BankAccountK = acc.Get<long>("bank_account_id"),
						Description = acc.Get<string>("description"),
						Flags = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), acc.Get<int>("flags").ToString()),
						UserAccountName = acc.Get<string>("user_account_name"),
						WorldID = acc.Get<long>("world_id"),
                        Balance = acc.Get<long>("balance")
					};

					//sqlAccount.SyncBalance();
					lock (BankAccounts) {
						BankAccounts.Add(sqlAccount);
					}

					Interlocked.Increment(ref index);
					percentCompleteFunc(index);
				}

				parsingArgs.Percent = 100;
				if (JournalLoadingPercentChanged != null) {
					JournalLoadingPercentChanged(this, parsingArgs);
				}

               // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

				Console.WriteLine("\r\n");
				ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Journal clean: {0} accounts, {1} transactions", BankAccounts.Count(), tranCount);
			} catch (Exception ex) {
				TShock.Log.ConsoleError(" seconomy mysql: db error in LoadJournal: " + ex.Message);
				throw;
			}
		}
Ejemplo n.º 9
0
        public bool LoadJournal()
        {
            MemoryStream uncompressedData;
            JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs() {
                Label = "Loading"
            };
            JournalLoadingPercentChangedEventArgs finalArgs = new JournalLoadingPercentChangedEventArgs() {
                Label = "Verify"
            };

            ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Using XML journal - {0}", path);

            try {
                byte[] fileData = new byte[0];
            initPoint:
                try {
                    fileData = File.ReadAllBytes(path);
                } catch (Exception ex) {
                    Console.ForegroundColor = ConsoleColor.DarkCyan;

                    if (ex is System.IO.FileNotFoundException || ex is System.IO.DirectoryNotFoundException) {
                        TShock.Log.ConsoleInfo(" * It appears you do not have a journal yet, one will be created for you.");
                        SaveJournal();
                        //yes there are valid uses for goto, don't judge me fool
                        goto initPoint;
                    } else if (ex is System.Security.SecurityException) {
                        TShock.Log.ConsoleError(" * Access denied to the journal file.  Check permissions.");
                    } else {
                        TShock.Log.ConsoleError(" * Loading your journal failed: " + ex.Message);
                    }
                }

                try {
                    uncompressedData = GZipDecompress(fileData);
                } catch {
                    TShock.Log.ConsoleError(" * Decompression failed.");
                    return false;
                }

                if (JournalLoadingPercentChanged != null) {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                try {
                    Hashtable bankAccountMap = new Hashtable();
                    Hashtable transactionMap = new Hashtable();

                    //You can't use XDocument.Parse when you have an XDeclaration for some even dumber reason than the write
                    //issue, XDocument has to be constructed from a .net 3.5 XmlReader in this case
                    //or you get a parse exception complaining about literal content.
                    using (XmlTextReader xmlStream = new XmlTextReader(uncompressedData)) {
                        XDocument doc = XDocument.Load(xmlStream);
                        var bankAccountList = doc.XPathSelectElements("/Journal/BankAccounts/BankAccount");
                        int bankAccountCount = bankAccountList.Count();
                        int i = 0;
                        int oldPercent = 0;

                        foreach (XElement elem in bankAccountList) {
                            long bankAccountK = 0L;
                            double percentComplete = (double)i / (double)bankAccountCount * 100;

                            var account = new XmlBankAccount(this) {
                                Description = elem.Attribute("Description").Value,
                                UserAccountName = elem.Attribute("UserAccountName").Value,
                                WorldID = long.Parse(elem.Attribute("WorldID").Value),
                                Flags = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), elem.Attribute("Flags").Value)
                            };

                            if (!long.TryParse(elem.Attribute("BankAccountK").Value, out bankAccountK)) {
                                //we've overwritten the old bank account key, add it to the old/new map
                                bankAccountK = Interlocked.Increment(ref _bankAccountSeed);
                                bankAccountMap.Add(elem.Attribute("BankAccountK").Value, bankAccountK);
                            }

                            account.BankAccountK = bankAccountK;

                            //parse transactions under this node
                            if (elem.Element("Transactions") != null) {
                                foreach (XElement txElement in elem.Element("Transactions").Elements("Transaction")) {
                                    long transactionK = 0L;
                                    long transactionFK = 0;
                                    long amount = long.Parse(txElement.Attribute("Amount").Value);
                                    DateTime transactionDate;
                                    BankAccountTransactionFlags flags;

                                    long.TryParse(txElement.Attribute("BankAccountTransactionK").Value, out transactionK);
                                    long.TryParse(txElement.Attribute("BankAccountTransactionFK").Value, out transactionFK);
                                    DateTime.TryParse(txElement.Attribute("TransactionDateUtc").Value, out transactionDate);
                                    Enum.TryParse<BankAccountTransactionFlags>(txElement.Attribute("Flags").Value, out flags);

                                    //ignore orphaned transactions
                                    var trans = new XmlTransaction(account) {
                                        Amount = amount,
                                        BankAccountTransactionK = transactionK,
                                        BankAccountTransactionFK = transactionFK,
                                        TransactionDateUtc = transactionDate,
                                        Flags = flags
                                    };

                                    trans.Message = txElement.Attribute("Message") != null ? txElement.Attribute("Message").Value : null;

                                    account.AddTransaction(trans);
                                }
                            }

                            account.SyncBalance();

                            if (oldPercent != (int)percentComplete) {
                                parsingArgs.Percent = (int)percentComplete;
                                if (JournalLoadingPercentChanged != null) {
                                    JournalLoadingPercentChanged(this, parsingArgs);
                                }
                                oldPercent = (int)percentComplete;
                            }

                            Interlocked.Increment(ref i);

                            bankAccounts.Add(account);
                        }

                        Interlocked.Exchange(ref _bankAccountSeed, bankAccounts.Count() > 0 ? bankAccounts.Max(sum => sum.BankAccountK) : 0);

                        //delete transactions with duplicate IDs

                        var qAccounts = from summary in bankAccounts
                                        group summary by summary.BankAccountK into g
                                        where g.Count() > 1
                                        select new {
                                            name = g.Key,
                                            count = g.Count()
                                        };

                        long[] duplicateAccounts = qAccounts.Select(pred => pred.name).ToArray();

                        int removedAccounts = bankAccounts.RemoveAll(pred => duplicateAccounts.Contains(pred.BankAccountK));

                        if (removedAccounts > 0) {
                            TShock.Log.Warn("seconomy journal: removed " + removedAccounts + " accounts with duplicate IDs.");
                        }

                        //transactions in the old schema.
                        int tranCount = doc.XPathSelectElements("/Journal/Transactions/Transaction").Count();
                        i = 0; //reset index

                        foreach (XElement elem in doc.XPathSelectElements("/Journal/Transactions/Transaction")) {
                            //Parallel.ForEach(doc.XPathSelectElements("/Journal/Transactions/Transaction"), (elem) => {
                            double percentComplete = (double)i / (double)tranCount * 100;
                            long bankAccountFK = 0L;
                            long transactionK = 0L;
                            long amount = long.Parse(elem.Attribute("Amount").Value);

                            if (!long.TryParse(elem.Attribute("BankAccountFK").Value, out bankAccountFK)) {
                                if (bankAccountMap.ContainsKey(elem.Attribute("BankAccountFK").Value)) {
                                    Interlocked.Exchange(ref bankAccountFK, (long)bankAccountMap[elem.Attribute("BankAccountFK").Value]);
                                }
                            }

                            IBankAccount bankAccount = GetBankAccount(bankAccountFK);


                            long.TryParse(elem.Attribute("BankAccountTransactionK").Value, out transactionK);

                            //ignore orphaned transactions
                            if (bankAccount != null) {
                                var trans = new XmlTransaction(bankAccount) {
                                    Amount = amount,
                                    BankAccountTransactionK = transactionK
                                };

                                if (elem.Attribute("BankAccountTransactionFK") != null) {
                                    trans.CustomValues.Add(XmlTransaction.kXmlTransactionOldTransactonFK, elem.Attribute("BankAccountTransactionFK").Value);
                                }

                                trans.Message = elem.Attribute("Message") != null ? elem.Attribute("Message").Value : null;

                                bankAccount.AddTransaction(trans);

                                transactionMap.Add(elem.Attribute("BankAccountTransactionK").Value, trans.BankAccountTransactionK);
                            }

                            Interlocked.Increment(ref i);
                        }

                        int txCount = Transactions.Count();
                        int x = 0;

                        finalArgs.Percent = 0;

                        if (JournalLoadingPercentChanged != null) {
                            JournalLoadingPercentChanged(this, finalArgs);
                        }

                        foreach (IBankAccount account in bankAccounts) {
                            foreach (XmlTransaction trans in account.Transactions) {
                                double pcc = (double)x / (double)txCount * 100;

                                //assigns the transactionK according to the hashmap of the old key stored as custom values
                                if (trans.CustomValues.ContainsKey(XmlTransaction.kXmlTransactionOldTransactonFK)) {
                                    object value = transactionMap[trans.CustomValues[XmlTransaction.kXmlTransactionOldTransactonFK]];

                                    trans.BankAccountTransactionFK = value != null ? (long)value : -1L;
                                }
                                if (oldPercent != (int)pcc) {
                                    if (JournalLoadingPercentChanged != null) {
                                        finalArgs.Percent = (int)pcc;
                                        JournalLoadingPercentChanged(this, finalArgs);
                                        oldPercent = (int)pcc;
                                    }
                                }
                                Interlocked.Increment(ref x);

                                trans.CustomValues.Clear();
                                trans.CustomValues = null;
                            }
                        }

                        bankAccountMap = null;
                        transactionMap = null;

                       // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

                        var accountCount = bankAccounts.Count;
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        Console.WriteLine("\r\n Journal clean: {0} accounts and {1} transactions.", accountCount, Transactions.Count());
                        Console.ResetColor();
                    }
                } catch (Exception ex) {
                    ConsoleEx.WriteAtEnd(2, ConsoleColor.Red, "[{0}]\r\n", SEconomyPlugin.Locale.StringOrDefault(79, "corrupt"));
                    TShock.Log.ConsoleError(ex.ToString());
                    Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(80, "Your transaction journal appears to be corrupt and transactions have been lost.\n\nYou will start with a clean journal.\nYour old journal file has been move to SEconomy.journal.xml.gz.corrupt"));
                    File.Move(path, path + "." + DateTime.Now.ToFileTime().ToString() + ".corrupt");

                    SaveJournal();

                    //yes there are valid uses for goto, don't judge me fool
                    goto initPoint;
                }
            } finally {
                Console.WriteLine();
            }

            return true;
        }