private void OnFreeLicenseCallback(SteamApps.FreeLicenseCallback callback) { JobManager.TryRemoveJob(callback.JobID); var packageIDs = callback.GrantedPackages; var appIDs = callback.GrantedApps; Log.WriteDebug("FreeLicense", "Received free license: {0} ({1} apps: {2}, {3} packages: {4})", callback.Result, appIDs.Count, string.Join(", ", appIDs), packageIDs.Count, string.Join(", ", packageIDs)); if (appIDs.Any()) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(appIDs, Enumerable.Empty<uint>())); } if (packageIDs.Any()) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty<uint>(), packageIDs)); TaskManager.Run(() => { RefreshPackageNames(); foreach (var subID in packageIDs) { IRC.Instance.SendMain("New free license granted: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.GetPackageName(subID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(subID) ); } }); } }
public SteamCdnClientPool(SteamContentClient steamContentClient, SteamContentServerQualityProvider steamContentServerQualityProvider) { _steamApps = steamContentClient.SteamClient.InternalClient.GetHandler <SteamKit2.SteamApps>(); _steamContentClient = steamContentClient; _steamContentServerQualityProvider = steamContentServerQualityProvider; _steamContentServerQualities = _steamContentServerQualityProvider.Load() ?? new List <SteamContentServerQuality>(); }
private void OnPICSChangesFullRun(SteamApps.PICSChangesCallback callback) { PreviousChangeNumber = 2; Log.WriteInfo("PICSChanges", "Requesting info for {0} apps and {1} packages", callback.AppChanges.Count, callback.PackageChanges.Count); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty<SteamApps.PICSRequest>(), callback.PackageChanges.Keys.Select(package => Utils.NewPICSRequest(package)))); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(callback.AppChanges.Keys, Enumerable.Empty<uint>())); }
static void Main( string[] args ) { if ( args.Length < 2 ) { Console.WriteLine( "Sample9: No username and password specified!" ); return; } // save our logon details user = args[ 0 ]; pass = args[ 1 ]; // create our steamclient instance steamClient = new SteamClient(); // create the callback manager which will route callbacks to function calls manager = new CallbackManager( steamClient ); // get the steamuser handler, which is used for logging on after successfully connecting steamUser = steamClient.GetHandler<SteamUser>(); // get our steamapps handler, we'll use this as an example of how async jobs can be handled steamApps = steamClient.GetHandler<SteamApps>(); // register a few callbacks we're interested in // these are registered upon creation to a callback manager, which will then route the callbacks // to the functions specified manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected ); manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected ); manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn ); manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff ); // notice that we're not subscribing to the SteamApps.PICSProductInfoCallback callback here (or other SteamApps callbacks) // since this sample is using the async job directly, we no longer need to subscribe to the callback. // however, if we still wish to use callbacks (or have existing code which subscribes to callbacks, they will // continue to operate alongside direct async job handling. (i.e.: steamclient will still post callbacks for // any async jobs that are completed) isRunning = true; Console.WriteLine( "Connecting to Steam..." ); // initiate the connection steamClient.Connect(); // create our callback handling loop while ( isRunning ) { // in order for the callbacks to get routed, they need to be handled by the manager manager.RunWaitCallbacks( TimeSpan.FromSeconds( 1 ) ); } }
public Steam3Session( SteamUser.LogOnDetails details ) { this.logonDetails = details; this.authenticatedUser = details.Username != null; this.credentials = new Credentials(); this.bConnected = false; this.bConnecting = false; this.bAborted = false; this.seq = 0; this.AppTickets = new Dictionary<uint, byte[]>(); this.AppTokens = new Dictionary<uint, ulong>(); this.DepotKeys = new Dictionary<uint, byte[]>(); this.CDNAuthTokens = new Dictionary<Tuple<uint, string>, SteamApps.CDNAuthTokenCallback>(); this.AppInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>(); this.PackageInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>(); this.steamClient = new SteamClient(); this.steamUser = this.steamClient.GetHandler<SteamUser>(); this.steamApps = this.steamClient.GetHandler<SteamApps>(); this.callbacks = new CallbackManager(this.steamClient); this.callbacks.Subscribe<SteamClient.ConnectedCallback>(ConnectedCallback); this.callbacks.Subscribe<SteamClient.DisconnectedCallback>(DisconnectedCallback); this.callbacks.Subscribe<SteamUser.LoggedOnCallback>(LogOnCallback); this.callbacks.Subscribe<SteamUser.SessionTokenCallback>(SessionTokenCallback); this.callbacks.Subscribe<SteamApps.LicenseListCallback>(LicenseListCallback); this.callbacks.Subscribe<SteamUser.UpdateMachineAuthCallback>(UpdateMachineAuthCallback); Console.Write( "Connecting to Steam3..." ); if ( authenticatedUser ) { FileInfo fi = new FileInfo(String.Format("{0}.sentryFile", logonDetails.Username)); if (ConfigStore.TheConfig.SentryData != null && ConfigStore.TheConfig.SentryData.ContainsKey(logonDetails.Username)) { logonDetails.SentryFileHash = Util.SHAHash(ConfigStore.TheConfig.SentryData[logonDetails.Username]); } else if (fi.Exists && fi.Length > 0) { var sentryData = File.ReadAllBytes(fi.FullName); logonDetails.SentryFileHash = Util.SHAHash(sentryData); ConfigStore.TheConfig.SentryData[logonDetails.Username] = sentryData; ConfigStore.Save(); } } Connect(); }
private void OnPICSChanges(SteamApps.PICSChangesCallback callback) { if (PreviousChangeNumber == callback.CurrentChangeNumber) { return; } if (Application.ProcessorPool.IsIdle) { Log.WriteDebug("PICSChanges", "Cleaning processed {0} apps and {1} subs", Application.ProcessedApps.Count, Application.ProcessedSubs.Count); // TODO: Do we really need to clear? Find a better solution for this Application.ProcessedApps.Clear(); Application.ProcessedSubs.Clear(); } var packageChangesCount = callback.PackageChanges.Count; var appChangesCount = callback.AppChanges.Count; Log.WriteInfo("PICSChanges", "Changelist {0} -> {1} ({2} apps, {3} packages)", PreviousChangeNumber, callback.CurrentChangeNumber, appChangesCount, packageChangesCount); PreviousChangeNumber = 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.Instance.SendAnnounce("{0}»{1} Changelist {2}{3}{4} (empty)", Colors.RED, Colors.NORMAL, Colors.OLIVE, PreviousChangeNumber, Colors.DARKGRAY); return; } if (appChangesCount > 0) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(callback.AppChanges.Keys, Enumerable.Empty<uint>())); Application.SecondaryPool.QueueWorkItem(HandleApps, callback, WorkItemPriority.AboveNormal); } if (packageChangesCount > 0) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty<SteamApps.PICSRequest>(), callback.PackageChanges.Keys.Select(package => Utils.NewPICSRequest(package)))); Application.SecondaryPool.QueueWorkItem(HandlePackages, callback, WorkItemPriority.AboveNormal); } Application.SecondaryPool.QueueWorkItem(SendChangelistsToIRC, callback); PrintImportants(callback); }
void OnAppChanges( SteamApps.AppChangesCallback callback ) { if ( lastChangeNumber == callback.CurrentChangeNumber ) return; lastChangeNumber = callback.CurrentChangeNumber; IRC.Instance.SendAnnounce( "Got AppInfo changelist {0} with info for {1} apps! (fullupdate? {2})", lastChangeNumber, callback.AppIDs.Count, callback.ForceFullUpdate ); if ( callback.AppIDs.Count > 0 ) { IRC.Instance.SendAnnounce( "AppInfo Apps: {0}", string.Join( ", ", callback.AppIDs ) ); } }
private static void OnPICSTokens(SteamApps.PICSTokensCallback callback) { if (!JobManager.TryRemoveJob(callback.JobID)) { Log.WriteDebug("PICSTokens", "Got tokens, but we had no job"); return; } Log.WriteDebug("PICSTokens", "Tokens granted: {0} - Tokens denied: {1}", callback.AppTokens.Count, callback.AppTokensDenied.Count); var apps = callback.AppTokensDenied .Select(app => Utils.NewPICSRequest(app)) .Concat(callback.AppTokens.Select(app => Utils.NewPICSRequest(app.Key, app.Value))); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(apps, Enumerable.Empty<SteamApps.PICSRequest>())); }
private static void OnLicenseListCallback(SteamApps.LicenseListCallback licenseList) { if (licenseList.Result != EResult.OK) { Log.WriteError("LicenseList", "Failed: {0}", licenseList.Result); return; } Log.WriteInfo("LicenseList", "Received {0} licenses from Steam", licenseList.LicenseList.Count); if (!licenseList.LicenseList.Any()) { Application.OwnedSubs.Clear(); Application.OwnedApps.Clear(); return; } var ownedSubs = new Dictionary<uint, byte>(); var ownedApps = new Dictionary<uint, byte>(); foreach (var license in licenseList.LicenseList) { // For some obscure reason license list can contain duplicates if (ownedSubs.ContainsKey(license.PackageID)) { Log.WriteError("LicenseList", "Already contains {0} ({1})", license.PackageID, license.PaymentMethod); continue; } ownedSubs.Add(license.PackageID, (byte)license.PaymentMethod); } using (MySqlDataReader Reader = DbWorker.ExecuteReader(string.Format("SELECT DISTINCT `AppID` FROM `SubsApps` WHERE `SubID` IN ({0})", string.Join(", ", ownedSubs.Keys)))) { while (Reader.Read()) { ownedApps.Add(Reader.GetUInt32("AppID"), 1); } } Application.OwnedSubs = ownedSubs; Application.OwnedApps = ownedApps; }
public SteamKit(ARKUpdater p, AutoResetEvent r) { this._Parent = p; this._ResetEvent = r; this.Ready = false; this.Failed = false; this._ThreadRunning = true; this._Client = new SteamClient(); this._CManager = new CallbackManager(this._Client); this._User = this._Client.GetHandler<SteamUser>(); this._Apps = this._Client.GetHandler<SteamApps>(); this.SubscribeCallbacks(); this._Client.Connect(); }
public Steam3Session( SteamUser.LogOnDetails details ) { this.logonDetails = details; this.authenticatedUser = details.Username != null; this.credentials = new Credentials(); this.bConnected = false; this.bAborted = false; this.AppTickets = new Dictionary<uint, byte[]>(); this.AppTokens = new Dictionary<uint, ulong>(); this.DepotKeys = new Dictionary<uint, byte[]>(); this.AppInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>(); this.PackageInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>(); this.AppInfoOverridesCDR = new Dictionary<uint, bool>(); this.steamClient = new SteamClient(); this.steamUser = this.steamClient.GetHandler<SteamUser>(); this.steamApps = this.steamClient.GetHandler<SteamApps>(); this.callbacks = new CallbackManager(this.steamClient); this.callbacks.Register(new Callback<SteamClient.ConnectedCallback>(ConnectedCallback)); this.callbacks.Register(new Callback<SteamClient.DisconnectedCallback>(DisconnectedCallback)); this.callbacks.Register(new Callback<SteamUser.LoggedOnCallback>(LogOnCallback)); this.callbacks.Register(new Callback<SteamUser.SessionTokenCallback>(SessionTokenCallback)); this.callbacks.Register(new Callback<SteamApps.LicenseListCallback>(LicenseListCallback)); this.callbacks.Register(new JobCallback<SteamUser.UpdateMachineAuthCallback>(UpdateMachineAuthCallback)); Console.Write( "Connecting to Steam3..." ); if ( authenticatedUser ) { FileInfo fi = new FileInfo(String.Format("{0}.sentryFile", logonDetails.Username)); if (fi.Exists && fi.Length > 0) { logonDetails.SentryFileHash = Util.SHAHash(File.ReadAllBytes(fi.FullName)); } } Connect(); }
public void Process(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { ChangeNumber = productInfo.ChangeNumber; #if !DEBUG if (Settings.Current.FullRun > 0) #endif { Log.WriteDebug("App Processor", "AppID: {0}", AppID); } try { TryProcess(productInfo); } catch (Exception e) { Log.WriteError("App Processor", "Caught exception while processing app {0}: {1}\n{2}", AppID, e.Message, e.StackTrace); } }
private void InitializeClient() { // client/manager creation Client = new SteamClient(); Manager = new CallbackManager(Client); _user = Client.GetHandler <SteamUser>(); _apps = Client.GetHandler <SteamApps>(); Client.AddHandler(new SteamTicketAuth()); // subscriptions Manager.Subscribe <SteamClient.DisconnectedCallback>(OnDisconnected); Manager.Subscribe <SteamClient.ConnectedCallback>(OnConnected); Manager.Subscribe <SteamUser.UpdateMachineAuthCallback>(OnMachineAuth); Manager.Subscribe <SteamUser.LoggedOnCallback>(OnLoggedOn); // internal subs Manager.Subscribe <SteamApps.GameConnectTokensCallback>(OnGcTokens); }
private static void OnPICSTokens(SteamApps.PICSTokensCallback callback) { Log.WriteDebug("Steam", "Tokens granted: {0} - Tokens denied: {1}", callback.AppTokens.Count, callback.AppTokensDenied.Count); var apps = callback.AppTokensDenied .Select(app => Utils.NewPICSRequest(app)) .Concat(callback.AppTokens.Select(app => Utils.NewPICSRequest(app.Key, app.Value))); Func<JobID> func = () => Steam.Instance.Apps.PICSGetProductInfo(apps, Enumerable.Empty<SteamApps.PICSRequest>()); JobAction job; // We have to preserve CommandRequest between jobs if (JobManager.TryRemoveJob(callback.JobID, out job) && job.IsCommand) { JobManager.AddJob(func, job.CommandRequest); return; } JobManager.AddJob(func); }
private static void OnLicenseListCallback(SteamApps.LicenseListCallback licenseList) { if (licenseList.Result != EResult.OK) { Log.WriteError("LicenseList", "Failed: {0}", licenseList.Result); return; } Log.WriteInfo("LicenseList", "Received {0} licenses from Steam", licenseList.LicenseList.Count); if (!licenseList.LicenseList.Any()) { OwnedSubs.Clear(); OwnedApps.Clear(); return; } var ownedSubs = new Dictionary<uint, byte>(); foreach (var license in licenseList.LicenseList) { // For some obscure reason license list can contain duplicates if (ownedSubs.ContainsKey(license.PackageID)) { Log.WriteWarn("LicenseList", "Already contains {0} ({1})", license.PackageID, license.PaymentMethod); continue; } ownedSubs.Add(license.PackageID, (byte)license.PaymentMethod); } OwnedSubs = ownedSubs; RefreshApps(); }
public SteamBot() { reconnectBackoff = new ExponentialBackoff(); // create our steamclient instance steamClient = new SteamClient(); // create the callback manager which will route callbacks to function calls manager = new CallbackManager(steamClient); // get the steamuser handler, which is used for logging on after successfully connecting steamUser = steamClient.GetHandler<SteamUser>(); // get the steam friends handler, which is used for interacting with friends on the network after logging on steamFriends = steamClient.GetHandler<SteamFriends>(); steamApps = steamClient.GetHandler<SteamApps>(); steamClient.AddHandler(new CustomHandler()); // register a few callbacks we're interested in // these are registered upon creation to a callback manager, which will then route the callbacks // to the functions specified manager.Subscribe<SteamClient.ConnectedCallback>(OnConnected); manager.Subscribe<SteamClient.DisconnectedCallback>(OnDisconnected); manager.Subscribe<SteamUser.LoggedOnCallback>(OnLoggedOn); manager.Subscribe<SteamUser.LoggedOffCallback>(OnLoggedOff); //manager.Subscribe<SteamUser.MarketingMessageCallback>(OnMarketing); // we use the following callbacks for friends related activities manager.Subscribe<SteamUser.AccountInfoCallback>(OnAccountInfo); manager.Subscribe<SteamFriends.FriendsListCallback>(OnFriendsList); manager.Subscribe<SteamFriends.PersonaStateCallback>(OnPersonaState); manager.Subscribe<SteamFriends.FriendAddedCallback>(OnFriendAdded); manager.Subscribe<SteamFriends.FriendMsgCallback>(OnFriendMsg); manager.Subscribe<SteamFriends.FriendMsgEchoCallback>(EchoMsg); manager.Subscribe<SteamFriends.FriendMsgHistoryCallback>(ch_OnOfflineMessage2); manager.Subscribe<SteamFriends.ChatInviteCallback>(OnChatInvite); manager.Subscribe<SteamUser.UpdateMachineAuthCallback>(OnMachineAuth); }
private void OnDepotKeyCallback(SteamApps.DepotKeyCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job)) { RemoveLock(callback.DepotID); return; } var request = job.ManifestJob; if (callback.Result != EResult.OK) { if (callback.Result != EResult.AccessDenied || FileDownloader.IsImportantDepot(request.DepotID)) { Log.WriteError("Depot Processor", "Failed to get depot key for depot {0} (parent {1}) - {2}", callback.DepotID, request.ParentAppID, callback.Result); } RemoveLock(request.DepotID); return; } request.DepotKey = callback.DepotKey; request.Tries = CDNServers.Count; request.Server = GetContentServer(); JobManager.AddJob(() => Steam.Instance.Apps.GetCDNAuthToken(request.DepotID, request.Server), request); var decryptionKey = Utils.ByteArrayToString(callback.DepotKey); using (var db = Database.GetConnection()) { var currentDecryptionKey = db.ExecuteScalar<string>("SELECT `Key` FROM `DepotsKeys` WHERE `DepotID` = @DepotID", new { callback.DepotID }); if (decryptionKey != currentDecryptionKey) { if (currentDecryptionKey != null) { Log.WriteInfo("Depot Processor", "Decryption key for {0} changed: {1} -> {2}", callback.DepotID, currentDecryptionKey, decryptionKey); IRC.Instance.SendOps("Decryption key for {0} changed: {1} -> {2}", callback.DepotID, currentDecryptionKey, decryptionKey); } db.Execute("INSERT INTO `DepotsKeys` (`DepotID`, `Key`) VALUES (@DepotID, @Key) ON DUPLICATE KEY UPDATE `Key` = VALUES(`Key`)", new { callback.DepotID, Key = decryptionKey }); } } }
private void OnCDNAuthTokenCallback(SteamApps.CDNAuthTokenCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job)) { return; } var request = job.ManifestJob; if (callback.Result != EResult.OK) { if (FileDownloader.IsImportantDepot(request.DepotID)) { Log.WriteError("Depot Processor", "Failed to get CDN auth token for depot {0} (parent {1} - server {2}) - {3} (#{4})", request.DepotID, request.ParentAppID, request.Server, callback.Result, request.Tries); } if (--request.Tries >= 0) { request.Server = GetContentServer(request.Tries); JobManager.AddJob(() => Steam.Instance.Apps.GetCDNAuthToken(request.DepotID, request.Server), request); return; } RemoveLock(request.DepotID); return; } request.CDNToken = callback.Token; // TODO: Using tasks makes every manifest download timeout // TODO: which seems to be bug with mono's threadpool implementation /*TaskManager.Run(() => DownloadManifest(request)).ContinueWith(task => { RemoveLock(request.DepotID); Log.WriteDebug("Depot Processor", "Processed depot {0} ({1} depot locks left)", request.DepotID, DepotLocks.Count); });*/ try { DownloadManifest(request); } catch (Exception) { RemoveLock(request.DepotID); } }
public void Process(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { ChangeNumber = productInfo.ChangeNumber; if (Settings.IsFullRun) { Log.WriteDebug("App Processor", "AppID: {0}", AppID); DbConnection.Execute("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeNumber) ON DUPLICATE KEY UPDATE `Date` = `Date`", new { productInfo.ChangeNumber }); DbConnection.Execute("INSERT INTO `ChangelistsApps` (`ChangeID`, `AppID`) VALUES (@ChangeNumber, @AppID) ON DUPLICATE KEY UPDATE `AppID` = `AppID`", new { AppID, productInfo.ChangeNumber }); } var app = DbConnection.Query<App>("SELECT `Name`, `AppType` FROM `Apps` WHERE `AppID` = @AppID LIMIT 1", new { AppID }).SingleOrDefault(); var newAppName = productInfo.KeyValues["common"]["name"].AsString(); if (newAppName != null) { int newAppType = -1; string currentType = productInfo.KeyValues["common"]["type"].AsString().ToLower(); using (var reader = DbConnection.ExecuteReader("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType })) { if (reader.Read()) { newAppType = reader.GetInt32(reader.GetOrdinal("AppType")); } } if (newAppType == -1) { DbConnection.Execute("INSERT INTO `AppsTypes` (`Name`, `DisplayName`) VALUES(@Name, @DisplayName)", new { Name = currentType, DisplayName = productInfo.KeyValues["common"]["type"].AsString() }); // We don't need to lower display name Log.WriteInfo("App Processor", "Creating new apptype \"{0}\" (AppID {1})", currentType, AppID); IRC.Instance.SendOps("New app type: {0}{1}{2} for app {3}{4}{5}", Colors.BLUE, currentType, Colors.NORMAL, Colors.BLUE, AppID, Colors.NORMAL); newAppType = DbConnection.ExecuteScalar<int>("SELECT `AppType` FROM `AppsTypes` WHERE `Name` = @Type LIMIT 1", new { Type = currentType }); } if (string.IsNullOrEmpty(app.Name) || app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) { DbConnection.Execute("INSERT INTO `Apps` (`AppID`, `AppType`, `Name`, `LastKnownName`) VALUES (@AppID, @Type, @AppName, @AppName) ON DUPLICATE KEY UPDATE `Name` = VALUES(`Name`), `LastKnownName` = VALUES(`LastKnownName`), `AppType` = VALUES(`AppType`)", new { AppID, Type = newAppType, AppName = newAppName } ); MakeHistory("created_app"); MakeHistory("created_info", SteamDB.DATABASE_NAME_TYPE, string.Empty, newAppName); // TODO: Testy testy if (!Settings.IsFullRun && Settings.Current.ChatRooms.Count > 0) { Steam.Instance.Friends.SendChatRoomMessage(Settings.Current.ChatRooms[0], EChatEntryType.ChatMsg, string.Format( "New {0} was published: {1}\nSteamDB: {2}\nSteam: https://store.steampowered.com/app/{3}/", currentType, newAppName, SteamDB.GetAppURL(AppID), AppID ) ); } if ((newAppType > 9 && newAppType != 13) || Triggers.Any(newAppName.Contains)) { IRC.Instance.SendOps("New {0}: {1}{2}{3} -{4} {5}", currentType, Colors.BLUE, newAppName, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } } else if (!app.Name.Equals(newAppName)) { DbConnection.Execute("UPDATE `Apps` SET `Name` = @AppName, `LastKnownName` = @AppName WHERE `AppID` = @AppID", new { AppID, AppName = newAppName }); MakeHistory("modified_info", SteamDB.DATABASE_NAME_TYPE, app.Name, newAppName); } if (app.AppType == 0 || app.AppType != newAppType) { DbConnection.Execute("UPDATE `Apps` SET `AppType` = @Type WHERE `AppID` = @AppID", new { AppID, Type = newAppType }); if (app.AppType == 0) { MakeHistory("created_info", SteamDB.DATABASE_APPTYPE, string.Empty, newAppType.ToString()); } else { MakeHistory("modified_info", SteamDB.DATABASE_APPTYPE, app.AppType.ToString(), newAppType.ToString()); } } } foreach (var 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) { ProcessKey(keyName, keyvalue.Name, Utils.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, Utils.JsonifyKeyValue(section), true) && sectionName.Equals("root_depots")) { DbConnection.Execute("UPDATE `Apps` SET `LastDepotUpdate` = CURRENT_TIMESTAMP() WHERE `AppID` = @AppID", new { AppID }); } } } foreach (var data in CurrentData.Values) { if (!data.Processed && !data.KeyName.StartsWith("website", StringComparison.Ordinal)) { DbConnection.Execute("DELETE FROM `AppsInfo` WHERE `AppID` = @AppID AND `Key` = @Key", new { AppID, data.Key }); MakeHistory("removed_key", data.Key, data.Value); if (newAppName != null && data.Key.Equals("common_section_type") && data.Value.Equals("ownersonly")) { IRC.Instance.SendMain("Removed ownersonly from: {0}{1}{2} -{3} {4}", Colors.BLUE, app.Name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); } } } if (newAppName == null) { if (string.IsNullOrEmpty(app.Name)) // We don't have the app in our database yet { DbConnection.Execute("INSERT INTO `Apps` (`AppID`, `Name`) VALUES (@AppID, @AppName) ON DUPLICATE KEY UPDATE `AppType` = `AppType`", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); } else if (!app.Name.StartsWith(SteamDB.UNKNOWN_APP, StringComparison.Ordinal)) // We do have the app, replace it with default name { IRC.Instance.SendMain("App deleted: {0}{1}{2} -{3} {4}", Colors.BLUE, app.Name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(AppID, "history")); DbConnection.Execute("UPDATE `Apps` SET `Name` = @AppName, `AppType` = 0 WHERE `AppID` = @AppID", new { AppID, AppName = string.Format("{0} {1}", SteamDB.UNKNOWN_APP, AppID) }); MakeHistory("deleted_app", 0, app.Name); } } if (productInfo.KeyValues["depots"] != null) { Steam.Instance.DepotProcessor.Process(AppID, ChangeNumber, productInfo.KeyValues["depots"]); } }
public void Process(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { ChangeNumber = productInfo.ChangeNumber; #if !DEBUG if (Settings.Current.FullRun > 0) #endif { Log.WriteDebug("App Processor", "AppID: {0}", AppID); } if (productInfo.KeyValues == null) { Log.WriteWarn("App Processor", "AppID {0} is empty, wot do I do?", AppID); return; } 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); } else if (!appName.Equals(productInfo.KeyValues["common"]["name"].Value)) { DbWorker.ExecuteNonQuery("UPDATE `Apps` SET `Name` = @AppName WHERE `AppID` = @AppID", new MySqlParameter("@AppID", AppID), new MySqlParameter("@AppName", productInfo.KeyValues["common"]["name"].Value) ); MakeHistory("modified_info", DATABASE_NAME_TYPE, appName, productInfo.KeyValues["common"]["name"].Value); } 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 with unknowns, process depots too bool depotsSectionModified = Settings.Current.FullRun >= 2 && 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"; ProcessKey(sectionName, "change_number", 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; } // TODO: This is godlike hackiness if (keyName.Equals("extended_de") || keyName.Equals("extended_jp") || keyName.Equals("extended_cn") || keyName.Equals("extended_us") || keyName.StartsWith("extended_us ", StringComparison.Ordinal) || keyName.StartsWith("extended_im ", StringComparison.Ordinal) || keyName.StartsWith("extended_af ax al dz as ad ao ai aq ag ", StringComparison.Ordinal) ) { Log.WriteWarn("App Processor", "Dammit Valve, why these long keynames: {0} - {1} ", AppID, keyName); 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)", 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) { 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.Current.FullRun == 0 && 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} - {2}", currentType, productInfo.KeyValues["common"]["name"].AsString(), SteamDB.GetAppURL(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.Current.FullRun == 0 && 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 with unknowns, process depots too bool depotsSectionModified = Settings.Current.FullRun >= 2 && 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 static void OnFreeLicenseCallback(SteamApps.FreeLicenseCallback callback) { JobAction job; JobManager.TryRemoveJob(callback.JobID, out job); var packageIDs = callback.GrantedPackages; var appIDs = callback.GrantedApps; Log.WriteDebug("FreeLicense", "Received free license: {0} ({1} apps: {2}, {3} packages: {4})", callback.Result, appIDs.Count, string.Join(", ", appIDs), packageIDs.Count, string.Join(", ", packageIDs)); if (appIDs.Count > 0) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(appIDs, Enumerable.Empty<uint>())); } if (packageIDs.Count > 0) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty<uint>(), packageIDs)); // We don't want to block our main thread with web requests TaskManager.Run(() => { string data = null; try { var response = WebAuth.PerformRequest("GET", "https://store.steampowered.com/account/licenses/"); using (var responseStream = response.GetResponseStream()) { using (var reader = new StreamReader(responseStream)) { data = reader.ReadToEnd(); } } } catch (WebException e) { Log.WriteError("FreeLicense", "Failed to fetch account details page: {0}", e.Message); } using (var db = Database.GetConnection()) { foreach (var package in packageIDs) { var packageData = db.Query<Package>("SELECT `SubID`, `Name`, `LastKnownName` FROM `Subs` WHERE `SubID` = @SubID", new { SubID = package }).FirstOrDefault(); if (!string.IsNullOrEmpty(data)) { // Tell me all about using regex var match = Regex.Match(data, string.Format("RemoveFreeLicense\\( ?{0}, ?'(.+)' ?\\)", package)); if (match.Success) { var grantedName = Encoding.UTF8.GetString(Convert.FromBase64String(match.Groups[1].Value)); // Update last known name if we can if (packageData.SubID > 0 && (string.IsNullOrEmpty(packageData.LastKnownName) || packageData.LastKnownName.StartsWith("Steam Sub ", StringComparison.Ordinal))) { db.Execute("UPDATE `Subs` SET `LastKnownName` = @Name WHERE `SubID` = @SubID", new { SubID = package, Name = grantedName }); db.Execute(SubProcessor.GetHistoryQuery(), new PICSHistory { ID = package, Key = SteamDB.DATABASE_NAME_TYPE, OldValue = "free on demand; account page", NewValue = grantedName, Action = "created_info" } ); // Add a app comment on each app in this package var comment = string.Format("This app is in a free on demand package called <b>{0}</b>", SecurityElement.Escape(grantedName)); var apps = db.Query<PackageApp>("SELECT `AppID` FROM `SubsApps` WHERE `SubID` = @SubID", new { SubID = package }).ToList(); var types = db.Query<App>("SELECT `AppID` FROM `Apps` WHERE `AppType` > 0 AND `AppID` IN @Ids", new { Ids = apps.Select(x => x.AppID) }).ToDictionary(x => x.AppID, x => true); var key = db.ExecuteScalar<uint>("SELECT `ID` FROM `KeyNames` WHERE `Name` = 'website_comment'"); foreach (var app in apps) { if (types.ContainsKey(app.AppID)) { continue; } db.Execute("INSERT INTO `AppsInfo` VALUES (@AppID, @Key, @Value) ON DUPLICATE KEY UPDATE `Key` = `Key`", new {app.AppID, Key = key, value = comment }); } } packageData.LastKnownName = grantedName; } } IRC.Instance.SendMain("New free license granted: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.FormatPackageName(package, packageData), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(package) ); } } }); } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (request.Type == JobManager.IRCRequestType.TYPE_SUB) { if (!callback.Packages.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown SubID: {0}{1}{2}", Colors.BLUE, request.Target, LicenseList.OwnedSubs.ContainsKey(request.Target) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Packages[request.Target]; var kv = info.KeyValues.Children.FirstOrDefault(); string name; if (kv["name"].Value != null) { name = Utils.RemoveControlCharacters(kv["name"].AsString()); } else { name = Steam.GetPackageName(info.ID); } try { kv.SaveToFile(Path.Combine(Application.Path, "sub", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawPackageURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedSubs.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); } else if (request.Type == JobManager.IRCRequestType.TYPE_APP) { if (!callback.Apps.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown AppID: {0}{1}{2}", Colors.BLUE, request.Target, LicenseList.OwnedApps.ContainsKey(request.Target) ? SteamDB.StringCheckmark : string.Empty); return; } var info = callback.Apps[request.Target]; string name; if (info.KeyValues["common"]["name"].Value != null) { name = Utils.RemoveControlCharacters(info.KeyValues["common"]["name"].AsString()); } else { name = Steam.GetAppName(info.ID); } try { info.KeyValues.SaveToFile(Path.Combine(Application.Path, "app", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.BLUE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawAppURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, LicenseList.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); } else { CommandHandler.ReplyToCommand(request.Command, "I have no idea what happened here!"); } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobAction job; if (JobManager.TryRemoveJob(callback.JobID, out job) && job.IsCommand) { OnProductInfoForIRC(job.CommandRequest, callback); } foreach (var app in callback.Apps) { Log.WriteInfo("PICSProductInfo", "AppID: {0}", app.Key); var workaround = app; IWorkItemResult mostRecentItem; Application.ProcessedApps.TryGetValue(workaround.Key, out mostRecentItem); var workerItem = Application.ProcessorPool.QueueWorkItem(delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for app {0} to finish processing", workaround.Key); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } new AppProcessor(workaround.Key).Process(workaround.Value); }); if (!Settings.IsFullRun) { Application.ProcessedApps.AddOrUpdate(app.Key, workerItem, (key, oldValue) => workerItem); } } foreach (var package in callback.Packages) { Log.WriteInfo("PICSProductInfo", "SubID: {0}", package.Key); var workaround = package; IWorkItemResult mostRecentItem; Application.ProcessedSubs.TryGetValue(workaround.Key, out mostRecentItem); var workerItem = Application.ProcessorPool.QueueWorkItem(delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for package {0} to finish processing", workaround.Key); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } new SubProcessor(workaround.Key).Process(workaround.Value); }); if (!Settings.IsFullRun) { Application.ProcessedSubs.AddOrUpdate(package.Key, workerItem, (key, oldValue) => workerItem); } } foreach (uint app in callback.UnknownApps) { Log.WriteInfo("PICSProductInfo", "Unknown AppID: {0}", app); uint workaround = app; IWorkItemResult mostRecentItem; Application.ProcessedApps.TryGetValue(workaround, out mostRecentItem); var workerItem = Application.ProcessorPool.QueueWorkItem(delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for app {0} to finish processing (unknown)", workaround); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } new AppProcessor(workaround).ProcessUnknown(); }); if (!Settings.IsFullRun) { Application.ProcessedApps.AddOrUpdate(app, workerItem, (key, oldValue) => workerItem); } } foreach (uint package in callback.UnknownPackages) { Log.WriteInfo("PICSProductInfo", "Unknown SubID: {0}", package); uint workaround = package; IWorkItemResult mostRecentItem; Application.ProcessedSubs.TryGetValue(workaround, out mostRecentItem); var workerItem = Application.ProcessorPool.QueueWorkItem(delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for package {0} to finish processing (unknown)", workaround); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } new SubProcessor(workaround).ProcessUnknown(); }); if (!Settings.IsFullRun) { Application.ProcessedSubs.AddOrUpdate(package, workerItem, (key, oldValue) => workerItem); } } }
private void OnFreeLicense(SteamApps.FreeLicenseCallback callback) { if (callback == null) { Logging.LogNullError(nameof(callback), BotName); } }
private async void OnLicenseList(SteamApps.LicenseListCallback callback) { if (callback?.LicenseList == null) { Logging.LogNullError(nameof(callback) + " || " + nameof(callback.LicenseList), BotName); return; } OwnedPackageIDs.Clear(); foreach (SteamApps.LicenseListCallback.License license in callback.LicenseList) { OwnedPackageIDs.Add(license.PackageID); } OwnedPackageIDs.TrimExcess(); await Task.Delay(1000).ConfigureAwait(false); // Wait a second for eventual PlayingSessionStateCallback if (!ArchiWebHandler.Ready) { for (byte i = 0; (i < Program.GlobalConfig.HttpTimeout) && !ArchiWebHandler.Ready; i++) { await Task.Delay(1000).ConfigureAwait(false); } if (!ArchiWebHandler.Ready) { return; } } await CardsFarmer.OnNewGameAdded().ConfigureAwait(false); }
internal Bot(string botName) { if (string.IsNullOrEmpty(botName)) { throw new ArgumentNullException(nameof(botName)); } if (Bots.ContainsKey(botName)) { throw new ArgumentException("That bot is already defined!"); } string botPath = Path.Combine(SharedInfo.ConfigDirectory, botName); BotName = botName; SentryFile = botPath + ".bin"; string botConfigFile = botPath + ".json"; BotConfig = BotConfig.Load(botConfigFile); if (BotConfig == null) { Logging.LogGenericError("Your bot config is invalid, please verify content of " + botConfigFile + " and try again!", botName); return; } // Register bot as available for ASF if (!Bots.TryAdd(botName, this)) { throw new ArgumentException("That bot is already defined!"); } string botDatabaseFile = botPath + ".db"; BotDatabase = BotDatabase.Load(botDatabaseFile); if (BotDatabase == null) { Logging.LogGenericError("Bot database could not be loaded, refusing to create this bot instance! In order to recreate it, remove " + botDatabaseFile + " and try again!", botName); return; } if (BotDatabase.MobileAuthenticator != null) { BotDatabase.MobileAuthenticator.Init(this); } else { // Support and convert SDA files string maFilePath = botPath + ".maFile"; if (File.Exists(maFilePath)) { ImportAuthenticator(maFilePath); } } // Initialize SteamClient = new SteamClient(Program.GlobalConfig.SteamProtocol); if (Program.GlobalConfig.Debug && Directory.Exists(SharedInfo.DebugDirectory)) { string debugListenerPath = Path.Combine(SharedInfo.DebugDirectory, botName); try { Directory.CreateDirectory(debugListenerPath); SteamClient.DebugNetworkListener = new NetHookNetworkListener(debugListenerPath); } catch (Exception e) { Logging.LogGenericException(e, botName); } } ArchiHandler = new ArchiHandler(this); SteamClient.AddHandler(ArchiHandler); CallbackManager = new CallbackManager(SteamClient); CallbackManager.Subscribe<SteamClient.ConnectedCallback>(OnConnected); CallbackManager.Subscribe<SteamClient.DisconnectedCallback>(OnDisconnected); SteamApps = SteamClient.GetHandler<SteamApps>(); CallbackManager.Subscribe<SteamApps.FreeLicenseCallback>(OnFreeLicense); CallbackManager.Subscribe<SteamApps.GuestPassListCallback>(OnGuestPassList); CallbackManager.Subscribe<SteamApps.LicenseListCallback>(OnLicenseList); SteamFriends = SteamClient.GetHandler<SteamFriends>(); CallbackManager.Subscribe<SteamFriends.ChatInviteCallback>(OnChatInvite); CallbackManager.Subscribe<SteamFriends.ChatMsgCallback>(OnChatMsg); CallbackManager.Subscribe<SteamFriends.FriendsListCallback>(OnFriendsList); CallbackManager.Subscribe<SteamFriends.FriendMsgCallback>(OnFriendMsg); CallbackManager.Subscribe<SteamFriends.FriendMsgHistoryCallback>(OnFriendMsgHistory); CallbackManager.Subscribe<SteamFriends.PersonaStateCallback>(OnPersonaState); SteamUser = SteamClient.GetHandler<SteamUser>(); CallbackManager.Subscribe<SteamUser.AccountInfoCallback>(OnAccountInfo); CallbackManager.Subscribe<SteamUser.LoggedOffCallback>(OnLoggedOff); CallbackManager.Subscribe<SteamUser.LoggedOnCallback>(OnLoggedOn); CallbackManager.Subscribe<SteamUser.LoginKeyCallback>(OnLoginKey); CallbackManager.Subscribe<SteamUser.UpdateMachineAuthCallback>(OnMachineAuth); CallbackManager.Subscribe<SteamUser.WebAPIUserNonceCallback>(OnWebAPIUserNonce); CallbackManager.Subscribe<ArchiHandler.NotificationsCallback>(OnNotifications); CallbackManager.Subscribe<ArchiHandler.OfflineMessageCallback>(OnOfflineMessage); CallbackManager.Subscribe<ArchiHandler.PlayingSessionStateCallback>(OnPlayingSessionState); CallbackManager.Subscribe<ArchiHandler.PurchaseResponseCallback>(OnPurchaseResponse); CallbackManager.Subscribe<ArchiHandler.SharedLibraryLockStatusCallback>(OnSharedLibraryLockStatus); ArchiWebHandler = new ArchiWebHandler(this); CardsFarmer = new CardsFarmer(this) { Paused = BotConfig.Paused }; Trading = new Trading(this); HeartBeatTimer = new Timer( async e => await HeartBeat().ConfigureAwait(false), null, TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay TimeSpan.FromMinutes(1) // Period ); Initialize().Forget(); }
private void OnCDNAuthTokenCallback(SteamApps.CDNAuthTokenCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job)) { return; } var request = job.ManifestJob; if (callback.Result != EResult.OK) { RemoveLock(request.DepotID); return; } request.CDNToken = callback.Token; JobManager.AddJob(() => Steam.Instance.Apps.GetDepotDecryptionKey(request.DepotID, request.ParentAppID), request); }
private async void OnGuestPassList(SteamApps.GuestPassListCallback callback) { if (callback?.GuestPasses == null) { Logging.LogNullError(nameof(callback) + " || " + nameof(callback.GuestPasses), BotName); return; } if ((callback.CountGuestPassesToRedeem == 0) || (callback.GuestPasses.Count == 0) || !BotConfig.AcceptGifts) { return; } foreach (ulong gid in callback.GuestPasses.Select(guestPass => guestPass["gid"].AsUnsignedLong()).Where(gid => (gid != 0) && !HandledGifts.Contains(gid))) { HandledGifts.Add(gid); Logging.LogGenericInfo("Accepting gift: " + gid + "...", BotName); await LimitGiftsRequestsAsync().ConfigureAwait(false); ArchiHandler.RedeemGuestPassResponseCallback response = await ArchiHandler.RedeemGuestPass(gid).ConfigureAwait(false); if (response != null) { if (response.Result == EResult.OK) { Logging.LogGenericInfo("Success!", BotName); } else { Logging.LogGenericWarning("Failed with error: " + response.Result, BotName); } } else { Logging.LogGenericWarning("Failed!", BotName); } } }
private void OnDepotKeyCallback(SteamApps.DepotKeyCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job)) { return; } var request = job.ManifestJob; if (callback.Result != EResult.OK) { 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); } RemoveLock(request.DepotID); return; } Log.WriteInfo("Depot Processor", "DepotID: {0}", request.DepotID); request.DepotKey = callback.DepotKey; // In full run, process depots after everything else if (Settings.IsFullRun) { Application.ProcessorPool.QueueWorkItem(TryDownloadManifest, request, WorkItemPriority.Lowest); } else { Application.SecondaryPool.QueueWorkItem(TryDownloadManifest, request); } }
public void Process(SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo) { ChangeNumber = productInfo.ChangeNumber; #if !DEBUG if (Settings.IsFullRun) #endif { Log.WriteDebug("Sub Processor", "SubID: {0}", SubID); } var appAddedToThisPackage = false; var packageOwned = LicenseList.OwnedSubs.ContainsKey(SubID); var kv = productInfo.KeyValues.Children.FirstOrDefault(); var newPackageName = kv["name"].AsString(); var apps = DbConnection.Query<PackageApp>("SELECT `AppID`, `Type` FROM `SubsApps` WHERE `SubID` = @SubID", new { SubID }).ToDictionary(x => x.AppID, x => x.Type); // TODO: Ideally this should be SteamDB Unknown Package and proper checks like app processor does if (newPackageName == null) { newPackageName = string.Concat("Steam Sub ", SubID); } if (newPackageName != null) { if (string.IsNullOrEmpty(PackageName)) { DbConnection.Execute("INSERT INTO `Subs` (`SubID`, `Name`, `LastKnownName`) VALUES (@SubID, @Name, @Name) ON DUPLICATE KEY UPDATE `Name` = @Name", new { SubID, Name = newPackageName }); MakeHistory("created_sub"); MakeHistory("created_info", SteamDB.DATABASE_NAME_TYPE, string.Empty, newPackageName); } else if (!PackageName.Equals(newPackageName)) { if (newPackageName.StartsWith("Steam Sub ", StringComparison.Ordinal)) { DbConnection.Execute("UPDATE `Subs` SET `Name` = @Name WHERE `SubID` = @SubID", new { SubID, Name = newPackageName }); } else { DbConnection.Execute("UPDATE `Subs` SET `Name` = @Name, `LastKnownName` = @Name WHERE `SubID` = @SubID", new { SubID, Name = newPackageName }); } MakeHistory("modified_info", SteamDB.DATABASE_NAME_TYPE, PackageName, newPackageName); } } foreach (var 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")) { // Remove "ids", so we get "app" from appids and "depot" from depotids string type = sectionName.Replace("ids", string.Empty); var isAppSection = type.Equals("app"); var typeID = (uint)(isAppSection ? 0 : 1); // 0 = app, 1 = depot; can't store as string because it's in the `key` field foreach (var 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) { DbConnection.Execute("UPDATE `SubsApps` SET `Type` = @Type WHERE `SubID` = @SubID AND `AppID` = @AppID", new { SubID, AppID = appID, Type = type }); MakeHistory("added_to_sub", typeID, apps[appID].Equals("app") ? "0" : "1", childrenApp.Value); appAddedToThisPackage = true; // TODO: Log relevant add/remove history for depot/app? } apps.Remove(appID); } else { DbConnection.Execute("INSERT INTO `SubsApps` (`SubID`, `AppID`, `Type`) VALUES(@SubID, @AppID, @Type) ON DUPLICATE KEY UPDATE `Type` = @Type", new { SubID, AppID = appID, Type = type }); MakeHistory("added_to_sub", typeID, string.Empty, childrenApp.Value); if (isAppSection) { DbConnection.Execute(AppProcessor.GetHistoryQuery(), new PICSHistory { ID = appID, ChangeID = ChangeNumber, NewValue = SubID.ToString(), Action = "added_to_sub" } ); } else { DbConnection.Execute(DepotProcessor.GetHistoryQuery(), new DepotHistory { DepotID = appID, ChangeID = ChangeNumber, NewValue = SubID, Action = "added_to_sub" } ); } appAddedToThisPackage = true; if (packageOwned && !LicenseList.OwnedApps.ContainsKey(appID)) { LicenseList.OwnedApps.Add(appID, (byte)1); } } } } else if (sectionName.Equals("extended")) { string keyName; foreach (var children in section.Children) { keyName = string.Format("{0}_{1}", sectionName, children.Name); if (children.Children.Count > 0) { ProcessKey(keyName, children.Name, Utils.JsonifyKeyValue(children), true); } else { ProcessKey(keyName, children.Name, children.Value); } } } else if (section.Children.Any()) { sectionName = string.Format("root_{0}", sectionName); ProcessKey(sectionName, sectionName, Utils.JsonifyKeyValue(section), true); } else if (!string.IsNullOrEmpty(section.Value)) { string keyName = string.Format("root_{0}", sectionName); ProcessKey(keyName, sectionName, section.Value); } } foreach (var data in CurrentData.Values) { if (!data.Processed && !data.KeyName.StartsWith("website", StringComparison.Ordinal)) { DbConnection.Execute("DELETE FROM `SubsInfo` WHERE `SubID` = @SubID AND `Key` = @Key", new { SubID, data.Key }); MakeHistory("removed_key", data.Key, data.Value); } } var appsRemoved = apps.Any(); foreach (var app in apps) { DbConnection.Execute("DELETE FROM `SubsApps` WHERE `SubID` = @SubID AND `AppID` = @AppID AND `Type` = @Type", new { SubID, AppID = app.Key, Type = app.Value }); var isAppSection = app.Value.Equals("app"); var typeID = (uint)(isAppSection ? 0 : 1); // 0 = app, 1 = depot; can't store as string because it's in the `key` field MakeHistory("removed_from_sub", typeID, app.Key.ToString()); if (isAppSection) { DbConnection.Execute(AppProcessor.GetHistoryQuery(), new PICSHistory { ID = app.Key, ChangeID = ChangeNumber, OldValue = SubID.ToString(), Action = "removed_from_sub" } ); } else { DbConnection.Execute(DepotProcessor.GetHistoryQuery(), new DepotHistory { DepotID = app.Key, ChangeID = ChangeNumber, OldValue = SubID, Action = "removed_from_sub" } ); } } if (appsRemoved) { LicenseList.RefreshApps(); } if (kv["billingtype"].AsInteger() == 12 && !packageOwned) // 12 == free on demand { Log.WriteDebug("Sub Processor", "Requesting apps in SubID {0} as a free license", SubID); JobManager.AddJob(() => SteamDB.RequestFreeLicense(kv["appids"].Children.Select(appid => (uint)appid.AsInteger()).ToList())); } // Re-queue apps in this package so we can update depots and whatnot if (appAddedToThisPackage && !Settings.IsFullRun && !string.IsNullOrEmpty(PackageName)) { JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(kv["appids"].Children.Select(x => (uint)x.AsInteger()), Enumerable.Empty<uint>())); } }
private static void OnProductInfoForIRC(JobManager.IRCRequest request, SteamApps.PICSProductInfoCallback callback) { if (request.Type == JobManager.IRCRequestType.TYPE_SUB) { if (!callback.Packages.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown SubID: {0}{1}", Colors.OLIVE, request.Target); return; } var info = callback.Packages[request.Target]; var kv = info.KeyValues.Children.FirstOrDefault(); string name = string.Format("SubID {0}", info.ID); if (kv["name"].Value != null) { name = kv["name"].AsString(); } try { kv.SaveToFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sub", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.OLIVE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawPackageURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, Application.OwnedSubs.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); } else if (request.Type == JobManager.IRCRequestType.TYPE_APP) { if (!callback.Apps.ContainsKey(request.Target)) { CommandHandler.ReplyToCommand(request.Command, "Unknown AppID: {0}{1}", Colors.OLIVE, request.Target); return; } var info = callback.Apps[request.Target]; string name = string.Format("AppID {0}", info.ID); if (info.KeyValues["common"]["name"].Value != null) { name = info.KeyValues["common"]["name"].AsString(); } try { info.KeyValues.SaveToFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app", string.Format("{0}.vdf", info.ID)), false); } catch (Exception e) { CommandHandler.ReplyToCommand(request.Command, "Unable to save file for {0}: {1}", name, e.Message); return; } CommandHandler.ReplyToCommand(request.Command, "{0}{1}{2} -{3} {4}{5} - Dump:{6} {7}{8}{9}{10}", Colors.OLIVE, name, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(info.ID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetRawAppURL(info.ID), Colors.NORMAL, info.MissingToken ? SteamDB.StringNeedToken : string.Empty, Application.OwnedApps.ContainsKey(info.ID) ? SteamDB.StringCheckmark : string.Empty ); } else { CommandHandler.ReplyToCommand(request.Command, "I have no idea what happened here!"); } }