Inheritance: IBankAccount
Beispiel #1
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);
        }
        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;
        }