Beispiel #1
0
        public void ReloadImportant(CommandHandler.CommandArguments command = null)
        {
            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `ImportantApps` WHERE `Announce` = 1"))
            {
                ImportantApps.Clear();

                while (Reader.Read())
                {
                    ImportantApps.Add(Reader.GetUInt32("AppID"));
                }
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `SubID` FROM `ImportantSubs`"))
            {
                ImportantSubs.Clear();

                while (Reader.Read())
                {
                    ImportantSubs.Add(Reader.GetUInt32("SubID"));
                }
            }

            if (command == null)
            {
                Log.WriteInfo("IRC Proxy", "Loaded {0} important apps and {1} packages", ImportantApps.Count, ImportantSubs.Count);
            }
            else
            {
                CommandHandler.ReplyToCommand(command, "{0}{1}{2}: Reloaded {3} important apps and {4} packages", Colors.OLIVE, command.Nickname, Colors.NORMAL, ImportantApps.Count, ImportantSubs.Count);
            }
        }
Beispiel #2
0
        private static void Cleanup()
        {
            Log.WriteInfo("Main", "Exiting...");

            foreach (var idler in GCIdlers)
            {
                try
                {
                    idler.IsRunning = false;
                    idler.Client.Disconnect();
                }
                catch { }
            }

            Steam.Instance.IsRunning = false;

            try { Steam.Instance.Timer.Stop(); } catch { }
            try { DepotProcessor.ThreadPool.Shutdown(true, 1000); } catch { }
            try { Steam.Instance.SecondaryPool.Shutdown(true, 1000); } catch { }
            try { Steam.Instance.ProcessorPool.Shutdown(true, 1000); } catch { }
            try { Steam.Instance.Client.Disconnect(); } catch { }

            if (Settings.Current.IRC.Enabled)
            {
                IRC.Instance.Kill();
            }

            DbWorker.ExecuteNonQuery("DELETE FROM `GC`");
        }
 public static void UpdateStatus(uint appID, string status)
 {
     DbWorker.ExecuteNonQuery("INSERT INTO `GC` (`AppID`, `Status`) VALUES(@AppID, @Status) ON DUPLICATE KEY UPDATE `Status` = @Status",
                              new MySqlParameter("@AppID", appID),
                              new MySqlParameter("@Status", status)
                              );
 }
Beispiel #4
0
        private void GetLastChangeNumber()
        {
            // If we're in a full run, request all changes from #1
            if (Settings.IsFullRun)
            {
                PreviousChange = 1;

                return;
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ChangeID` FROM `Changelists` ORDER BY `ChangeID` DESC LIMIT 1"))
            {
                if (Reader.Read())
                {
                    PreviousChange = Reader.GetUInt32("ChangeID");

                    Log.WriteInfo("Steam", "Previous changelist was {0}", PreviousChange);
                }
            }

            if (PreviousChange == 0)
            {
                Log.WriteWarn("Steam", "Looks like there are no changelists in the database.");
                Log.WriteWarn("Steam", "If you want to fill up your database first, restart with \"FullRun\" setting set to 1.");
            }
        }
        private void TryProcessUnknown()
        {
            string name;

            using (MySqlDataReader MainReader = DbWorker.ExecuteReader("SELECT `Name` FROM `Subs` WHERE `SubID` = @SubID LIMIT 1", new MySqlParameter("SubID", SubID)))
            {
                if (!MainReader.Read())
                {
                    return;
                }

                name = DbWorker.GetString("Name", MainReader);
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Key`, `Value` FROM `SubsInfo` INNER JOIN `KeyNamesSubs` ON `SubsInfo`.`Key` = `KeyNamesSubs`.`ID` WHERE `SubID` = @SubID", new MySqlParameter("SubID", SubID)))
            {
                while (Reader.Read())
                {
                    if (!DbWorker.GetString("Name", Reader).StartsWith("website", StringComparison.Ordinal))
                    {
                        MakeHistory("removed_key", Reader.GetUInt32("Key"), DbWorker.GetString("Value", Reader));
                    }
                }
            }

            DbWorker.ExecuteNonQuery("DELETE FROM `Subs` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID));
            DbWorker.ExecuteNonQuery("DELETE FROM `SubsInfo` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID));
            DbWorker.ExecuteNonQuery("DELETE FROM `StoreSubs` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID));

            // TODO
            MakeHistory("deleted_sub", 0, name);
        }
        public static void OnMarketingMessage(SteamUser.MarketingMessageCallback callback)
        {
            foreach (var message in callback.Messages)
            {
                // TODO: Move this query outside this loop
                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ID` FROM `MarketingMessages` WHERE `ID` = @ID", new MySqlParameter("ID", message.ID)))
                {
                    if (Reader.Read())
                    {
                        continue;
                    }
                }

                if (message.Flags == EMarketingMessageFlags.None)
                {
                    IRC.SendMain("New marketing message:{0} {1}", Colors.DARK_BLUE, message.URL);
                }
                else
                {
                    IRC.SendMain("New marketing message:{0} {1} {2}({3})", Colors.DARK_BLUE, message.URL, Colors.DARK_GRAY, message.Flags.ToString().Replace("Platform", string.Empty));
                }

                DbWorker.ExecuteNonQuery("INSERT INTO `MarketingMessages` (`ID`, `Flags`) VALUES (@ID, @Flags)",
                                         new MySqlParameter("@ID", message.ID),
                                         new MySqlParameter("@Flags", message.Flags)
                                         );
            }
        }
 private void InsertInfo(uint id, string value)
 {
     DbWorker.ExecuteNonQuery("INSERT INTO `SubsInfo` VALUES (@SubID, @KeyNameID, @Value) ON DUPLICATE KEY UPDATE `Value` = @Value",
                              new MySqlParameter("@SubID", SubID),
                              new MySqlParameter("@KeyNameID", id),
                              new MySqlParameter("@Value", value)
                              );
 }
Beispiel #8
0
        private static void OnCommandApp(CommandArguments command)
        {
            if (command.Message.Length == 0)
            {
                ReplyToCommand(command, "Usage:{0} !app <appid or partial game name>", Colors.OLIVE);

                return;
            }

            uint appID;

            if (uint.TryParse(command.Message, out appID))
            {
                var apps = new List <uint>();

                apps.Add(appID);

                var jobID = Steam.Instance.Apps.PICSGetAccessTokens(apps, Enumerable.Empty <uint>());

                SteamProxy.Instance.IRCRequests.Add(new SteamProxy.IRCRequest
                {
                    JobID   = jobID,
                    Target  = appID,
                    Type    = SteamProxy.IRCRequestType.TYPE_APP,
                    Command = command
                });
            }
            else
            {
                string name = string.Format("%{0}%", command.Message);

                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `Apps` WHERE `Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name ORDER BY `LastUpdated` DESC LIMIT 1", new MySqlParameter("Name", name)))
                {
                    if (Reader.Read())
                    {
                        appID = Reader.GetUInt32("AppID");

                        var apps = new List <uint>();

                        apps.Add(appID);

                        var jobID = Steam.Instance.Apps.PICSGetAccessTokens(apps, Enumerable.Empty <uint>());

                        SteamProxy.Instance.IRCRequests.Add(new SteamProxy.IRCRequest
                        {
                            JobID   = jobID,
                            Target  = appID,
                            Type    = SteamProxy.IRCRequestType.TYPE_APP,
                            Command = command
                        });
                    }
                    else
                    {
                        ReplyToCommand(command, "{0}{1}{2}: Nothing was found matching your request", Colors.OLIVE, command.Nickname, Colors.NORMAL);
                    }
                }
            }
        }
 private void MakeHistory(string action, uint keyNameID = 0, string oldValue = "", string newValue = "")
 {
     DbWorker.ExecuteNonQuery("INSERT INTO `SubsHistory` (`ChangeID`, `SubID`, `Action`, `Key`, `OldValue`, `NewValue`) VALUES (@ChangeID, @SubID, @Action, @KeyNameID, @OldValue, @NewValue)",
                              new MySqlParameter("@SubID", SubID),
                              new MySqlParameter("@ChangeID", ChangeNumber),
                              new MySqlParameter("@Action", action),
                              new MySqlParameter("@KeyNameID", keyNameID),
                              new MySqlParameter("@OldValue", oldValue),
                              new MySqlParameter("@NewValue", newValue)
                              );
 }
Beispiel #10
0
 public static void MakeHistory(uint appID, uint changeNumber, string action, uint keyNameID = 0, string oldValue = "", string newValue = "")
 {
     DbWorker.ExecuteNonQuery("INSERT INTO `AppsHistory` (`ChangeID`, `AppID`, `Action`, `Key`, `OldValue`, `NewValue`) VALUES (@ChangeID, @AppID, @Action, @KeyNameID, @OldValue, @NewValue)",
                              new MySqlParameter("@AppID", appID),
                              new MySqlParameter("@ChangeID", changeNumber),
                              new MySqlParameter("@Action", action),
                              new MySqlParameter("@KeyNameID", keyNameID),
                              new MySqlParameter("@OldValue", oldValue),
                              new MySqlParameter("@NewValue", newValue)
                              );
 }
 private static void MakeHistory(ManifestJob request, string file, string action, ulong oldValue = 0, ulong newValue = 0)
 {
     DbWorker.ExecuteNonQuery("INSERT INTO `DepotsHistory` (`ChangeID`, `DepotID`, `File`, `Action`, `OldValue`, `NewValue`) VALUES (@ChangeID, @DepotID, @File, @Action, @OldValue, @NewValue)",
                              new MySqlParameter("@DepotID", request.DepotID),
                              new MySqlParameter("@ChangeID", request.ChangeNumber),
                              new MySqlParameter("@File", file),
                              new MySqlParameter("@Action", action),
                              new MySqlParameter("@OldValue", oldValue),
                              new MySqlParameter("@NewValue", newValue)
                              );
 }
        private static uint GetKeyNameID(string keyName)
        {
            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ID` FROM `KeyNamesSubs` WHERE `Name` = @KeyName LIMIT 1", new MySqlParameter("KeyName", keyName)))
            {
                if (Reader.Read())
                {
                    return(Reader.GetUInt32("ID"));
                }
            }

            return(0);
        }
Beispiel #13
0
        private static void OnCommandPlayers(CommandArguments command)
        {
            if (command.Message.Length == 0)
            {
                ReplyToCommand(command, "Usage:{0} !players <appid or partial game name>", Colors.OLIVE);

                return;
            }

            uint appID;

            if (uint.TryParse(command.Message, out appID))
            {
                var jobID = Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID);

                SteamProxy.Instance.IRCRequests.Add(new SteamProxy.IRCRequest
                {
                    JobID   = jobID,
                    Target  = appID,
                    Command = command
                });
            }
            else
            {
                string name = string.Format("%{0}%", command.Message);

                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `Apps` LEFT JOIN `AppsTypes` ON `Apps`.`AppType` = `AppsTypes`.`AppType` WHERE `AppsTypes`.`Name` IN ('game', 'application') AND (`Apps`.`StoreName` LIKE @Name OR `Apps`.`Name` LIKE @Name) ORDER BY `LastUpdated` DESC LIMIT 1", new MySqlParameter("Name", name)))
                {
                    if (Reader.Read())
                    {
                        appID = Reader.GetUInt32("AppID");

                        var jobID = Steam.Instance.UserStats.GetNumberOfCurrentPlayers(appID);

                        SteamProxy.Instance.IRCRequests.Add(new SteamProxy.IRCRequest
                        {
                            JobID   = jobID,
                            Target  = appID,
                            Command = command
                        });
                    }
                    else
                    {
                        ReplyToCommand(command, "{0}{1}{2}: Nothing was found matching your request", Colors.OLIVE, command.Nickname, Colors.NORMAL);
                    }
                }
            }
        }
Beispiel #14
0
        public static string JsonifyKeyValue(KeyValue keys)
        {
            string value = string.Empty;

            using (var sw = new StringWriter(new StringBuilder()))
            {
                using (JsonWriter w = new JsonTextWriter(sw))
                {
                    DbWorker.JsonifyKeyValue(w, keys.Children);
                }

                value = sw.ToString();
            }

            return(value);
        }
        private static void OnDepotKeyCallback(SteamApps.DepotKeyCallback callback, JobID jobID)
        {
            ManifestJob request;

            lock (ManifestJobs)
            {
                request = ManifestJobs.Find(r => r.JobID == jobID);
            }

            if (request == null)
            {
                return;
            }

            if (callback.Result != EResult.OK)
            {
                lock (ManifestJobs)
                {
                    ManifestJobs.Remove(request);
                }

                if (callback.Result != EResult.Blocked)
                {
                    Log.WriteError("Depot Processor", "Failed to get depot key for depot {0} (parent {1}) - {2}", callback.DepotID, request.ParentAppID, callback.Result);
                }

                return;
            }

            Log.WriteInfo("Depot Processor", "DepotID: {0}", request.DepotID);

            if (request.PreviousManifestID != request.ManifestID)
            {
                // Update manifestid here because actually downloading the manifest has chances of failing
                DbWorker.ExecuteNonQuery("INSERT INTO `Depots` (`DepotID`, `Name`, `ManifestID`) VALUES (@DepotID, @Name, @ManifestID) ON DUPLICATE KEY UPDATE `LastUpdated` = CURRENT_TIMESTAMP(), `Name` = @Name, `ManifestID` = @ManifestID",
                                         new MySqlParameter("@DepotID", request.DepotID),
                                         new MySqlParameter("@ManifestID", request.ManifestID),
                                         new MySqlParameter("@Name", request.DepotName)
                                         );

                MakeHistory(request, string.Empty, "manifest_change", request.PreviousManifestID, request.ManifestID);
            }

            request.DepotKey = callback.DepotKey;

            ThreadPool.QueueWorkItem(TryDownloadManifest, request);
        }
Beispiel #16
0
        private void TryProcessUnknown()
        {
            string AppName;

            using (MySqlDataReader MainReader = DbWorker.ExecuteReader("SELECT `Name` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new MySqlParameter("AppID", AppID)))
            {
                if (!MainReader.Read())
                {
                    return;
                }

                AppName = DbWorker.GetString("Name", MainReader);
            }

            bool historyChanged = false;

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Key`, `Value` FROM `AppsInfo` INNER JOIN `KeyNames` ON `AppsInfo`.`Key` = `KeyNames`.`ID` WHERE `AppID` = @AppID", new MySqlParameter("AppID", AppID)))
            {
                while (Reader.Read())
                {
                    if (!DbWorker.GetString("Name", Reader).StartsWith("website", StringComparison.Ordinal))
                    {
                        MakeHistory("removed_key", Reader.GetUInt32("Key"), DbWorker.GetString("Value", Reader));

                        historyChanged = true;
                    }
                }
            }

            DbWorker.ExecuteNonQuery("DELETE FROM `Apps` WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID));
            DbWorker.ExecuteNonQuery("DELETE FROM `AppsInfo` WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID));
            DbWorker.ExecuteNonQuery("DELETE FROM `Store` WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID));

            if (!AppName.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal))
            {
                MakeHistory("deleted_app", 0, AppName);

                historyChanged = true;
            }

            // TODO: This is a dirty hack so we somehow track these app changes
            if (!historyChanged && !Settings.IsFullRun)
            {
                MakeHistory("removed_key", GetKeyNameID("root_change_number"), "0", "0");
            }
        }
Beispiel #17
0
        public static string GetAppName(uint appID, bool returnEmptyOnFailure = false)
        {
            using (MySqlDataReader reader = DbWorker.ExecuteReader("SELECT `Name`, `StoreName`, `LastKnownName` FROM `Apps` WHERE `AppID` = @AppID", new MySqlParameter("AppID", appID)))
            {
                if (reader.Read())
                {
                    string name = DbWorker.GetString("Name", reader);
                    //string nameStore = DbWorker.GetString("StoreName", reader);
                    string nameLast = DbWorker.GetString("LastKnownName", reader);

                    if (!string.IsNullOrEmpty(nameLast) && !name.Equals(nameLast))
                    {
                        return(string.Format("{0} {1}({2}){3}", name, Colors.DARK_GRAY, nameLast, Colors.NORMAL));
                    }

                    return(name);
                }
            }

            return(returnEmptyOnFailure ? string.Empty : string.Format("AppID {0}", appID));
        }
Beispiel #18
0
        public void OnNumberOfPlayers(SteamUserStats.NumberOfPlayersCallback callback, JobID jobID)
        {
            var request = IRCRequests.Find(r => r.JobID == jobID);

            if (request == null)
            {
                return;
            }

            IRCRequests.Remove(request);

            if (callback.Result != EResult.OK)
            {
                CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: Unable to request player count: {3}", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL, callback.Result);
            }
            else if (request.Target == 0)
            {
                CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: {3}{4:N0}{5} people praising lord Gaben right now, influence:{6} {7}", Colors.OLIVE, request.Command.Nickname, Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetGraphURL(0));
            }
            else
            {
                string graphUrl = string.Empty;
                string name     = GetAppName(request.Target);

                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID` FROM `ImportantApps` WHERE (`Graph` = 1 OR `MaxPlayers` > 0) AND `AppID` = @AppID", new MySqlParameter("AppID", request.Target)))
                {
                    if (Reader.Read())
                    {
                        graphUrl = string.Format("{0} -{1} {2}", Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetGraphURL(request.Target));
                    }
                }

                CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2}: People playing {3}{4}{5} right now: {6}{7:N0}{8} -{9} {10}{11}",
                                              Colors.OLIVE, request.Command.Nickname, Colors.NORMAL,
                                              Colors.OLIVE, name, Colors.NORMAL,
                                              Colors.GREEN, callback.NumPlayers, Colors.NORMAL,
                                              Colors.DARK_BLUE, SteamDB.GetAppURL(request.Target), graphUrl);
            }
        }
Beispiel #19
0
        public static string GetPackageName(uint subID, bool returnEmptyOnFailure = false)
        {
            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `StoreName` FROM `Subs` WHERE `SubID` = @SubID", new MySqlParameter("SubID", subID)))
            {
                if (Reader.Read())
                {
                    string name = DbWorker.GetString("Name", Reader);

                    if (name.StartsWith("Steam Sub", StringComparison.Ordinal))
                    {
                        string nameStore = DbWorker.GetString("StoreName", Reader);

                        if (!string.IsNullOrEmpty(nameStore))
                        {
                            name = string.Format("{0} {1}({2}){3}", name, Colors.DARK_GRAY, nameStore, Colors.NORMAL);
                        }
                    }

                    return(name);
                }
            }

            return(returnEmptyOnFailure ? string.Empty : string.Format("SubID {0}", subID));
        }
Beispiel #20
0
        private void OnPICSChanges(SteamApps.PICSChangesCallback callback, JobID job)
        {
            if (PreviousChange == callback.CurrentChangeNumber)
            {
                return;
            }

            if (ProcessorPool.IsIdle)
            {
                Log.WriteDebug("Steam", "Cleaning processed apps and subs");

                ProcessedApps.Clear();
                ProcessedSubs.Clear();
            }

            var packageChangesCount = callback.PackageChanges.Count;
            var appChangesCount     = callback.AppChanges.Count;

            Log.WriteInfo("Steam", "Changelist {0} -> {1} ({2} apps, {3} packages)", PreviousChange, callback.CurrentChangeNumber, appChangesCount, packageChangesCount);

            PreviousChange = callback.CurrentChangeNumber;

            DbWorker.ExecuteNonQuery("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeID) ON DUPLICATE KEY UPDATE `Date` = CURRENT_TIMESTAMP()", new MySqlParameter("@ChangeID", callback.CurrentChangeNumber));

            if (appChangesCount == 0 && packageChangesCount == 0)
            {
                IRC.SendAnnounce("{0}»{1} Changelist {2}{3}{4} (empty)", Colors.RED, Colors.NORMAL, Colors.OLIVE, PreviousChange, Colors.DARK_GRAY);

                return;
            }

            SecondaryPool.QueueWorkItem(SteamProxy.Instance.OnPICSChanges, callback);

            // Packages have no tokens so we request info for them right away
            if (packageChangesCount > 0)
            {
                Apps.PICSGetProductInfo(Enumerable.Empty <SteamApps.PICSRequest>(), callback.PackageChanges.Keys.Select(package => NewPICSRequest(package)));
            }

            if (appChangesCount > 0)
            {
                // Get all app tokens
                Apps.PICSGetAccessTokens(callback.AppChanges.Keys, Enumerable.Empty <uint>());

                SecondaryPool.QueueWorkItem(delegate
                {
                    string changes = string.Empty;

                    foreach (var app in callback.AppChanges.Values)
                    {
                        if (callback.CurrentChangeNumber != app.ChangeNumber)
                        {
                            DbWorker.ExecuteNonQuery("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeID) ON DUPLICATE KEY UPDATE `Date` = `Date`", new MySqlParameter("@ChangeID", app.ChangeNumber));
                        }

                        DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `LastUpdated` = CURRENT_TIMESTAMP() WHERE `AppID` = @AppID", new MySqlParameter("@AppID", app.ID));

                        changes += string.Format("({0}, {1}),", app.ChangeNumber, app.ID);
                    }

                    if (!changes.Equals(string.Empty))
                    {
                        changes = string.Format("INSERT INTO `ChangelistsApps` (`ChangeID`, `AppID`) VALUES {0} ON DUPLICATE KEY UPDATE `AppID` = `AppID`", changes.Remove(changes.Length - 1));

                        DbWorker.ExecuteNonQuery(changes);
                    }
                });
            }

            if (packageChangesCount > 0)
            {
                SecondaryPool.QueueWorkItem(delegate
                {
                    string changes = string.Empty;

                    foreach (var package in callback.PackageChanges.Values)
                    {
                        if (callback.CurrentChangeNumber != package.ChangeNumber)
                        {
                            DbWorker.ExecuteNonQuery("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeID) ON DUPLICATE KEY UPDATE `Date` = `Date`", new MySqlParameter("@ChangeID", package.ChangeNumber));
                        }

                        DbWorker.ExecuteNonQuery("UPDATE `Subs` SET `LastUpdated` = CURRENT_TIMESTAMP() WHERE `SubID` = @SubID", new MySqlParameter("@SubID", package.ID));

                        changes += string.Format("({0}, {1}),", package.ChangeNumber, package.ID);
                    }

                    if (!changes.Equals(string.Empty))
                    {
                        changes = string.Format("INSERT INTO `ChangelistsSubs` (`ChangeID`, `SubID`) VALUES {0} ON DUPLICATE KEY UPDATE `SubID` = `SubID`", changes.Remove(changes.Length - 1));

                        DbWorker.ExecuteNonQuery(changes);
                    }
                });
            }
        }
        public static void Process(uint appID, uint changeNumber, KeyValue depots)
        {
            foreach (KeyValue depot in depots.Children)
            {
                // Ignore these for now, parent app should be updated too anyway
                if (depot["depotfromapp"].Value != null)
                {
                    ////Log.WriteDebug("Depot Processor", "Ignoring depot {0} with depotfromapp value {1} (parent {2})", depot.Name, depot["depotfromapp"].AsString(), AppID);

                    continue;
                }

                uint depotID;

                if (!uint.TryParse(depot.Name, out depotID))
                {
                    // Ignore keys that aren't integers, for example "branches"
                    continue;
                }

                lock (ManifestJobs)
                {
                    if (ManifestJobs.Find(r => r.DepotID == depotID) != null)
                    {
                        // If we already have this depot in our job list, ignore it
                        continue;
                    }
                }

                ulong manifestID;

                if (depot["manifests"]["public"].Value == null || !ulong.TryParse(depot["manifests"]["public"].Value, out manifestID))
                {
#if false
                    Log.WriteDebug("Depot Processor", "Failed to public branch for depot {0} (parent {1}) - {2}", DepotID, AppID);

                    // If there is no public manifest for this depot, it still could have some sort of open beta

                    var branch = depot["manifests"].Children.SingleOrDefault(x => x.Name != "local");

                    if (branch == null || !ulong.TryParse(branch.Value, out ManifestID))
                    {
                        continue;
                    }
#endif

                    continue;
                }

                var request = new ManifestJob
                {
                    ChangeNumber = changeNumber,
                    ParentAppID  = appID,
                    DepotID      = depotID,
                    ManifestID   = manifestID,
                    DepotName    = depot["name"].AsString()
                };

                // Check if manifestid in our database is equal
                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `ManifestID` FROM `Depots` WHERE `DepotID` = @DepotID AND `Files` != '' LIMIT 1", new MySqlParameter("DepotID", depotID)))
                {
                    if (Reader.Read())
                    {
                        request.PreviousManifestID = Reader.GetUInt64("ManifestID");

                        if (request.PreviousManifestID == manifestID && Settings.Current.FullRun < 2)
                        {
                            continue;
                        }
                    }
                }

                lock (ManifestJobs)
                {
                    ManifestJobs.Add(request);
                }

                request.Server = CDNServers[new Random().Next(CDNServers.Count)];
                request.JobID  = Steam.Instance.Apps.GetCDNAuthToken(depotID, request.Server);
            }
        }
        private static void DownloadManifest(ManifestJob request)
        {
            DepotManifest depotManifest = null;
            string        lastError     = string.Empty;

            // CDN is very random, just keep trying
            for (var i = 0; i <= 5; i++)
            {
                try
                {
                    depotManifest = CDNClient.DownloadManifest(request.DepotID, request.ManifestID, request.Server, request.DepotKey, request.CDNToken);

                    break;
                }
                catch (Exception e)
                {
                    lastError = e.Message;
                }
            }

            if (depotManifest == null)
            {
                Log.WriteError("Depot Processor", "Failed to download depot manifest for depot {0} (jobs still in queue: {1}) ({2}: {3})", request.DepotID, ManifestJobs.Count - 1, request.Server, lastError);

                if (SteamProxy.Instance.ImportantApps.Contains(request.ParentAppID))
                {
                    IRC.SendMain("Important depot update: {0}{1}{2} -{3} failed to download depot manifest", Colors.OLIVE, request.DepotName, Colors.NORMAL, Colors.RED);
                }

                return;
            }

            if (SteamProxy.Instance.ImportantApps.Contains(request.ParentAppID))
            {
                IRC.SendMain("Important depot update: {0}{1}{2} -{3} {4}", Colors.OLIVE, request.DepotName, Colors.NORMAL, Colors.DARK_BLUE, SteamDB.GetDepotURL(request.DepotID, "history"));
            }

            var sortedFiles = depotManifest.Files.OrderBy(f => f.FileName, StringComparer.OrdinalIgnoreCase);

            bool shouldHistorize = false;
            var  filesNew        = new List <DepotFile>();
            var  filesOld        = new Dictionary <string, DepotFile>();

            foreach (var file in sortedFiles)
            {
                System.Text.Encoding.UTF8.GetString(file.FileHash);

                var depotFile = new DepotFile
                {
                    Name   = file.FileName.Replace('\\', '/'),
                    Size   = file.TotalSize,
                    Chunks = file.Chunks.Count,
                    Flags  = (int)file.Flags
                };

                // TODO: Ideally we would check if filehash is not empty
                if (!file.Flags.HasFlag(EDepotFileFlag.Directory))
                {
                    depotFile.Hash = string.Concat(Array.ConvertAll(file.FileHash, x => x.ToString("X2")));
                }

                filesNew.Add(depotFile);
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Files` FROM `Depots` WHERE `DepotID` = @DepotID LIMIT 1", new MySqlParameter("DepotID", request.DepotID)))
            {
                if (Reader.Read())
                {
                    string files = Reader.GetString("Files");

                    if (!string.IsNullOrEmpty(files))
                    {
                        shouldHistorize = true;

                        var _filesOld = JsonConvert.DeserializeObject <List <DepotFile> >(files);

                        filesOld = _filesOld.ToDictionary(x => x.Name);
                    }
                }
            }

            DbWorker.ExecuteNonQuery("UPDATE `Depots` SET `Files` = @Files WHERE `DepotID` = @DepotID",
                                     new MySqlParameter("@DepotID", request.DepotID),
                                     new MySqlParameter("@Files", JsonConvert.SerializeObject(filesNew, new JsonSerializerSettings {
                DefaultValueHandling = DefaultValueHandling.Ignore
            }))
                                     );

            if (shouldHistorize)
            {
                var filesAdded = new List <string>();

                foreach (var file in filesNew)
                {
                    if (filesOld.ContainsKey(file.Name))
                    {
                        var oldFile = filesOld[file.Name];

                        if (oldFile.Size != file.Size)
                        {
                            MakeHistory(request, file.Name, "modified", oldFile.Size, file.Size);
                        }
                        else if (file.Hash != null && oldFile.Hash != null && !file.Hash.Equals(oldFile.Hash))
                        {
                            MakeHistory(request, file.Name, "modified", oldFile.Size, file.Size);
                        }

                        filesOld.Remove(file.Name);
                    }
                    else
                    {
                        // We want to historize modifications first, and only then deletions and additions
                        filesAdded.Add(file.Name);
                    }
                }

                foreach (var file in filesOld)
                {
                    MakeHistory(request, file.Value.Name, "removed");
                }

                foreach (string file in filesAdded)
                {
                    MakeHistory(request, file, "added");
                }
            }

            lock (ManifestJobs)
            {
                Log.WriteDebug("Depot Processor", "DepotID: Processed {0} (jobs still in queue: {1})", request.DepotID, ManifestJobs.Count - 1);
            }
        }
Beispiel #23
0
        private void TryProcess(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo)
        {
            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Value` FROM `AppsInfo` INNER JOIN `KeyNames` ON `AppsInfo`.`Key` = `KeyNames`.`ID` WHERE `AppID` = @AppID", new MySqlParameter("AppID", AppID)))
            {
                while (Reader.Read())
                {
                    CurrentData.Add(DbWorker.GetString("Name", Reader), DbWorker.GetString("Value", Reader));
                }
            }

            string appName = string.Empty;
            string appType = "0";

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `AppType` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new MySqlParameter("AppID", AppID)))
            {
                if (Reader.Read())
                {
                    appName = DbWorker.GetString("Name", Reader);
                    appType = DbWorker.GetString("AppType", Reader);
                }
            }

            if (productInfo.KeyValues["common"]["name"].Value != null)
            {
                string newAppType  = "0";
                string currentType = productInfo.KeyValues["common"]["type"].AsString().ToLower();

                using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new MySqlParameter("Type", currentType)))
                {
                    if (Reader.Read())
                    {
                        newAppType = DbWorker.GetString("AppType", Reader);
                    }
                    else
                    {
                        // TODO: Create it?
                        Log.WriteError("App Processor", "AppID {0} - unknown app type: {1}", AppID, currentType);

                        // TODO: This is debuggy just so we are aware of new app types
                        IRC.SendAnnounce("Unknown app type \"{0}\" for appid {1}, cc Alram and xPaw", currentType, AppID);
                    }
                }

                if (string.IsNullOrEmpty(appName) || appName.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal))
                {
                    DbWorker.ExecuteNonQuery("INSERT INTO `Apps` (`AppID`, `AppType`, `Name`) VALUES (@AppID, @Type, @AppName) ON DUPLICATE KEY UPDATE `Name` = @AppName, `AppType` = @Type",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@Type", newAppType),
                                             new MySqlParameter("@AppName", productInfo.KeyValues["common"]["name"].Value)
                                             );

                    MakeHistory("created_app");
                    MakeHistory("created_info", DATABASE_NAME_TYPE, string.Empty, productInfo.KeyValues["common"]["name"].Value);

                    // TODO: Testy testy
                    if (!Settings.IsFullRun &&
                        Settings.Current.ChatRooms.Count > 0 &&
                        !appName.StartsWith("SteamApp", StringComparison.Ordinal) &&
                        !appName.StartsWith("ValveTest", StringComparison.Ordinal))
                    {
                        Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg,
                                                                   string.Format(
                                                                       ":retreat: New {0} was published: {1}\nSteamDB: {2}\nSteam: http://store.steampowered.com/app/{3}/",
                                                                       currentType,
                                                                       productInfo.KeyValues["common"]["name"].AsString(),
                                                                       SteamDB.GetAppURL(AppID),
                                                                       AppID
                                                                       )
                                                                   );
                    }
                }
                else if (!appName.Equals(productInfo.KeyValues["common"]["name"].Value))
                {
                    string newAppName = productInfo.KeyValues["common"]["name"].AsString();

                    DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `Name` = @AppName WHERE `AppID` = @AppID",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@AppName", newAppName)
                                             );

                    MakeHistory("modified_info", DATABASE_NAME_TYPE, appName, newAppName);

                    // TODO: Testy testy
                    if (!Settings.IsFullRun &&
                        Settings.Current.ChatRooms.Count > 0 &&
                        !string.Equals(appName, newAppName, StringComparison.OrdinalIgnoreCase) &&
                        !newAppName.StartsWith("SteamApp", StringComparison.Ordinal) &&
                        !newAppName.StartsWith("ValveTest", StringComparison.Ordinal))
                    {
                        Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg,
                                                                   string.Format(
                                                                       ":retreat: {0} name was changed - {1}\n« {2}\n» {3}",
                                                                       currentType,
                                                                       SteamDB.GetAppURL(AppID, "history"),
                                                                       appName,
                                                                       newAppName
                                                                       )
                                                                   );
                    }
                }

                if (appType.Equals("0"))
                {
                    DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@Type", newAppType)
                                             );

                    MakeHistory("created_info", DATABASE_APPTYPE, string.Empty, newAppType);
                }
                else if (!appType.Equals(newAppType))
                {
                    DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@Type", newAppType)
                                             );

                    MakeHistory("modified_info", DATABASE_APPTYPE, appType, newAppType);
                }
            }

            // If we are full running, process depots too
            bool depotsSectionModified = Settings.IsFullRun && productInfo.KeyValues["depots"].Children.Count > 0;

            foreach (KeyValue section in productInfo.KeyValues.Children)
            {
                string sectionName = section.Name.ToLower();

                if (sectionName == "appid" || sectionName == "public_only")
                {
                    continue;
                }

                if (sectionName == "change_number") // Carefully handle change_number
                {
                    sectionName = "root_change_number";

                    // TODO: Remove this key, move it to Apps table itself
                    ProcessKey(sectionName, "change_number", productInfo.ChangeNumber.ToString()); //section.AsString());
                }
                else if (sectionName == "common" || sectionName == "extended")
                {
                    string keyName;

                    foreach (KeyValue keyvalue in section.Children)
                    {
                        keyName = string.Format("{0}_{1}", sectionName, keyvalue.Name);

                        if (keyName.Equals("common_type") || keyName.Equals("common_gameid") || keyName.Equals("common_name") || keyName.Equals("extended_order"))
                        {
                            // Ignore common keys that are either duplicated or serve no real purpose
                            continue;
                        }

                        if (keyvalue.Children.Count > 0)
                        {
                            if (keyName.Equals("common_languages"))
                            {
                                ProcessKey(keyName, keyvalue.Name, string.Join(",", keyvalue.Children.Select(x => x.Name)));
                            }
                            else
                            {
                                ProcessKey(keyName, keyvalue.Name, DbWorker.JsonifyKeyValue(keyvalue), true);
                            }
                        }
                        else if (!string.IsNullOrEmpty(keyvalue.Value))
                        {
                            ProcessKey(keyName, keyvalue.Name, keyvalue.Value);
                        }
                    }
                }
                else
                {
                    sectionName = string.Format("root_{0}", sectionName);

                    if (ProcessKey(sectionName, sectionName, DbWorker.JsonifyKeyValue(section), true) && sectionName.Equals("root_depots"))
                    {
                        depotsSectionModified = true;
                    }
                }
            }

            foreach (string keyName in CurrentData.Keys)
            {
                if (!keyName.StartsWith("website", StringComparison.Ordinal))
                {
                    uint ID = GetKeyNameID(keyName);

                    DbWorker.ExecuteNonQuery("DELETE FROM AppsInfo WHERE `AppID` = @AppID AND `Key` = @KeyNameID",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@KeyNameID", ID)
                                             );

                    MakeHistory("removed_key", ID, CurrentData[keyName]);
                }
            }

            if (productInfo.KeyValues["common"]["name"].Value == null)
            {
                if (string.IsNullOrEmpty(appName)) // We don't have the app in our database yet
                {
                    DbWorker.ExecuteNonQuery("INSERT INTO `Apps` (`AppID`, `Name`) VALUES (@AppID, @AppName) ON DUPLICATE KEY UPDATE `AppType` = `AppType`",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@AppName", string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID))
                                             );
                }
                else if (!appName.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) // We do have the app, replace it with default name
                {
                    DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `Name` = @AppName, `AppType` = 0 WHERE `AppID` = @AppID",
                                             new MySqlParameter("@AppID", AppID),
                                             new MySqlParameter("@AppName", string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID))
                                             );

                    MakeHistory("deleted_app", 0, appName);
                }
            }

            if (depotsSectionModified)
            {
                DepotProcessor.Process(AppID, ChangeNumber, productInfo.KeyValues["depots"]);
            }
        }
        private void TryProcess(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo)
        {
            string packageName = string.Empty;
            var    apps        = new Dictionary <uint, string>();

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name`, `Value` FROM `SubsInfo` INNER JOIN `KeyNamesSubs` ON `SubsInfo`.`Key` = `KeyNamesSubs`.`ID` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID)))
            {
                while (Reader.Read())
                {
                    CurrentData.Add(DbWorker.GetString("Name", Reader), DbWorker.GetString("Value", Reader));
                }
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `Name` FROM `Subs` WHERE `SubID` = @SubID LIMIT 1", new MySqlParameter("@SubID", SubID)))
            {
                if (Reader.Read())
                {
                    packageName = DbWorker.GetString("Name", Reader);
                }
            }

            using (MySqlDataReader Reader = DbWorker.ExecuteReader("SELECT `AppID`, `Type` FROM `SubsApps` WHERE `SubID` = @SubID", new MySqlParameter("@SubID", SubID)))
            {
                while (Reader.Read())
                {
                    apps.Add(Reader.GetUInt32("AppID"), Reader.GetString("Type"));
                }
            }

            var kv = productInfo.KeyValues.Children.FirstOrDefault();

            if (kv["name"].Value != null)
            {
                if (string.IsNullOrEmpty(packageName))
                {
                    DbWorker.ExecuteNonQuery("INSERT INTO `Subs` (`SubID`, `Name`) VALUES (@SubID, @Name) ON DUPLICATE KEY UPDATE `Name` = @Name",
                                             new MySqlParameter("@SubID", SubID),
                                             new MySqlParameter("@Name", kv["name"].Value)
                                             );

                    MakeHistory("created_sub");
                    MakeHistory("created_info", DATABASE_NAME_TYPE, string.Empty, kv["name"].Value);
                }
                else if (!packageName.Equals(kv["name"].Value))
                {
                    DbWorker.ExecuteNonQuery("UPDATE `Subs` SET `Name` = @Name WHERE `SubID` = @SubID",
                                             new MySqlParameter("@SubID", SubID),
                                             new MySqlParameter("@Name", kv["name"].Value)
                                             );

                    MakeHistory("modified_info", DATABASE_NAME_TYPE, packageName, kv["name"].Value);
                }
            }

            foreach (KeyValue section in kv.Children)
            {
                string sectionName = section.Name.ToLower();

                if (string.IsNullOrEmpty(sectionName) || sectionName.Equals("packageid") || sectionName.Equals("name"))
                {
                    // Ignore common keys
                    continue;
                }

                if (sectionName.Equals("appids") || sectionName.Equals("depotids"))
                {
                    string type = sectionName.Replace("ids", string.Empty); // Remove "ids", so we get app from appids and depot from depotids

                    uint typeID = (uint)(type.Equals("app") ? 0 : 1);       // TODO: Remove legacy 0/1 and replace with type

                    foreach (KeyValue childrenApp in section.Children)
                    {
                        uint appID = uint.Parse(childrenApp.Value);

                        // Is this appid already in this package?
                        if (apps.ContainsKey(appID))
                        {
                            // Is this appid's type the same?
                            if (apps[appID] != type)
                            {
                                DbWorker.ExecuteNonQuery("UPDATE `SubsApps` SET `Type` = @Type WHERE `SubID` = @SubID AND `AppID` = @AppID",
                                                         new MySqlParameter("@SubID", SubID),
                                                         new MySqlParameter("@AppID", appID),
                                                         new MySqlParameter("@Type", type)
                                                         );

                                MakeHistory("added_to_sub", typeID, apps[appID].Equals("app") ? "0" : "1", childrenApp.Value);
                            }

                            apps.Remove(appID);
                        }
                        else
                        {
                            DbWorker.ExecuteNonQuery("INSERT INTO `SubsApps` (`SubID`, `AppID`, `Type`) VALUES(@SubID, @AppID, @Type) ON DUPLICATE KEY UPDATE `Type` = @Type",
                                                     new MySqlParameter("@SubID", SubID),
                                                     new MySqlParameter("@AppID", appID),
                                                     new MySqlParameter("@Type", type)
                                                     );

                            MakeHistory("added_to_sub", typeID, string.Empty, childrenApp.Value);
                            AppProcessor.MakeHistory(appID, ChangeNumber, "added_to_sub", typeID, string.Empty, SubID.ToString());

                            if (SteamProxy.Instance.ImportantApps.Contains(appID))
                            {
                                IRC.SendMain("Important app {0}{1}{2} was added to package {3}{4}{5} -{6} {7}",
                                             Colors.OLIVE, SteamProxy.GetAppName(appID), Colors.NORMAL,
                                             Colors.OLIVE, packageName, Colors.NORMAL,
                                             Colors.DARK_BLUE, SteamDB.GetPackageURL(SubID, "history")
                                             );
                            }
                        }
                    }
                }
                else if (sectionName.Equals("extended"))
                {
                    string keyName;

                    foreach (KeyValue children in section.Children)
                    {
                        if (children.Children.Count > 0)
                        {
                            Log.WriteError("Sub Processor", "SubID {0} has childen in extended section", SubID);
                        }

                        keyName = string.Format("{0}_{1}", sectionName, children.Name);

                        ProcessKey(keyName, children.Name, children.Value);
                    }
                }
                else if (section.Children.Count > 0)
                {
                    sectionName = string.Format("root_{0}", sectionName);

                    ProcessKey(sectionName, sectionName, DbWorker.JsonifyKeyValue(section), true);
                }
                else if (!string.IsNullOrEmpty(section.Value))
                {
                    string keyName = string.Format("root_{0}", sectionName);

                    ProcessKey(keyName, sectionName, section.Value);
                }
            }

            foreach (string keyName in CurrentData.Keys)
            {
                if (!keyName.StartsWith("website", StringComparison.Ordinal))
                {
                    uint ID = GetKeyNameID(keyName);

                    DbWorker.ExecuteNonQuery("DELETE FROM `SubsInfo` WHERE `SubID` = @SubID AND `Key` = @KeyNameID",
                                             new MySqlParameter("@SubID", SubID),
                                             new MySqlParameter("@KeyNameID", ID)
                                             );

                    MakeHistory("removed_key", ID, CurrentData[keyName]);
                }
            }

            foreach (var app in apps)
            {
                DbWorker.ExecuteNonQuery("DELETE FROM `SubsApps` WHERE `SubID` = @SubID AND `AppID` = @AppID AND `Type` = @Type",
                                         new MySqlParameter("@SubID", SubID),
                                         new MySqlParameter("@AppID", app.Key),
                                         new MySqlParameter("@Type", app.Value)
                                         );

                uint typeID = (uint)(app.Value.Equals("app") ? 0 : 1); // TODO: Remove legacy 0/1 and replace with type

                MakeHistory("removed_from_sub", typeID, app.Key.ToString());
                AppProcessor.MakeHistory(app.Key, ChangeNumber, "removed_from_sub", typeID, SubID.ToString());

                if (SteamProxy.Instance.ImportantApps.Contains(app.Key))
                {
                    IRC.SendMain("Important app {0}{1}{2} was removed from package {3}{4}{5} -{6} {7}",
                                 Colors.OLIVE, SteamProxy.GetAppName(app.Key), Colors.NORMAL,
                                 Colors.OLIVE, packageName, Colors.NORMAL,
                                 Colors.DARK_BLUE, SteamDB.GetPackageURL(SubID, "history")
                                 );
                }
            }

#if DEBUG
            if (kv["name"].Value == null)
            {
                if (string.IsNullOrEmpty(packageName)) // We don't have the package in our database yet
                {
                    // Don't do anything then
                    Log.WriteError("Sub Processor", "Got a package without a name, and we don't have it in our database: {0}", SubID);
                }
                else
                {
                    ////MakeHistory("deleted_sub", "0", packageName, "", true);

                    Log.WriteError("Sub Processor", "Got a package without a name, but we have it in our database: {0}", SubID);
                }
            }
#endif
        }
        private bool ProcessKey(string keyName, string displayName, string value, bool isJSON = false)
        {
            // All keys in PICS are supposed to be lower case.
            // But currently some keys in packages are not lowercased,
            // this lowercases everything to make sure nothing breaks in future
            keyName = keyName.ToLower();

            if (!CurrentData.ContainsKey(keyName))
            {
                uint ID = GetKeyNameID(keyName);

                if (ID == 0)
                {
                    if (isJSON)
                    {
                        const uint DB_TYPE_JSON = 86;

                        DbWorker.ExecuteNonQuery("INSERT INTO `KeyNamesSubs` (`Name`, `Type`, `DisplayName`) VALUES(@Name, @Type, @DisplayName) ON DUPLICATE KEY UPDATE `Type` = `Type`",
                                                 new MySqlParameter("@Name", keyName),
                                                 new MySqlParameter("@DisplayName", displayName),
                                                 new MySqlParameter("@Type", DB_TYPE_JSON)
                                                 );
                    }
                    else
                    {
                        DbWorker.ExecuteNonQuery("INSERT INTO `KeyNamesSubs` (`Name`, `DisplayName`) VALUES(@Name, @DisplayName) ON DUPLICATE KEY UPDATE `Type` = `Type`",
                                                 new MySqlParameter("@Name", keyName),
                                                 new MySqlParameter("@DisplayName", displayName)
                                                 );
                    }

                    ID = GetKeyNameID(keyName);

                    if (ID == 0)
                    {
                        // We can't insert anything because key wasn't created
                        Log.WriteError("Sub Processor", "Failed to create key {0} for SubID {1}, not inserting info.", keyName, SubID);

                        return(false);
                    }
                }

                InsertInfo(ID, value);
                MakeHistory("created_key", ID, string.Empty, value);

                return(true);
            }

            string currentValue = CurrentData[keyName];

            CurrentData.Remove(keyName);

            if (!currentValue.Equals(value))
            {
                uint ID = GetKeyNameID(keyName);

                InsertInfo(ID, value);
                MakeHistory("modified_key", ID, currentValue, value);

                return(true);
            }

            return(false);
        }