private void OnServiceMethod(SteamUnifiedMessages.ServiceMethodResponse callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(request.Command, "Unable to make service request: {0}", callback.Result); return; } // .chat about grate switch (request.Type) { case JobManager.IRCRequestType.TYPE_GAMESERVERS: ServersCommand.OnServiceMethod(callback, request); return; case JobManager.IRCRequestType.TYPE_PUBFILE: case JobManager.IRCRequestType.TYPE_PUBFILE_SILENT: PubFileCommand.OnServiceMethod(callback, request); return; } CommandHandler.ReplyToCommand(request.Command, "Unknown request type, I don't know what to do."); }
private void OnUGCInfo(SteamCloud.UGCDetailsCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(request.Command, "Unable to request UGC info: {0}", callback.Result); return; } CommandHandler.ReplyToCommand(request.Command, "Creator: {0}{1}{2}, App: {3}{4}{5}, File: {6}{7}{8}, Size: {9}{10}{11} -{12} {13}", Colors.BLUE, callback.Creator.Render(true), Colors.NORMAL, Colors.BLUE, callback.AppID, Colors.NORMAL, Colors.BLUE, callback.FileName, Colors.NORMAL, Colors.BLUE, GetByteSizeString(callback.FileSize), Colors.NORMAL, Colors.DARKBLUE, callback.URL ); }
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); }
private static void OnPersonaState(SteamFriends.PersonaStateCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(new JobID(callback.FriendID), out job) || !job.IsCommand) { return; } var command = job.CommandRequest.Command; if (callback.FriendID.IsClanAccount) { var clantag = string.IsNullOrEmpty(callback.ClanTag) ? string.Empty : string.Format(" {0}(Clan tag: {1}{2}{3})", Colors.NORMAL, Colors.LIGHTGRAY, callback.ClanTag, Colors.NORMAL); CommandHandler.ReplyToCommand(command, "{0}{1}{2} -{3} https://steamcommunity.com/gid/{4}/{5}", Colors.BLUE, callback.Name, Colors.NORMAL, Colors.DARKBLUE, callback.FriendID.ConvertToUInt64(), clantag ); } else if (callback.FriendID.IsIndividualAccount) { CommandHandler.ReplyToCommand(command, "{0}{1}{2} -{3} https://steamcommunity.com/profiles/{4}/ {5}(Last login: {6}, Last logoff: {7})", Colors.BLUE, callback.Name, Colors.NORMAL, Colors.DARKBLUE, callback.FriendID.ConvertToUInt64(), Colors.DARKGRAY, callback.LastLogOn, callback.LastLogOff ); } else { CommandHandler.ReplyToCommand(command, callback.Name); } }
private static void OnNumberOfPlayers(SteamUserStats.NumberOfPlayersCallback callback) { JobAction job; if (!JobManager.TryRemoveJob(callback.JobID, out job) || !job.IsCommand) { return; } var request = job.CommandRequest; if (callback.Result != EResult.OK) { CommandHandler.ReplyToCommand(request.Command, "Unable to request player count: {0}{1}", Colors.RED, callback.Result); } else if (request.Target == 0) { CommandHandler.ReplyToCommand( request.Command, "{0}{1:N0}{2} people praising lord Gaben right now, influence:{3} {4}", Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(753, "graphs") ); } else { CommandHandler.ReplyToCommand( request.Command, "People playing {0}{1}{2} right now: {3}{4:N0}{5} -{6} {7}", Colors.BLUE, Steam.GetAppName(request.Target), Colors.NORMAL, Colors.OLIVE, callback.NumPlayers, Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetAppURL(request.Target, "graphs") ); } }
private static void OnPersonaState(SteamFriends.PersonaStateCallback callback) { if (!JobManager.TryRemoveJob(new JobID(callback.FriendID), out var job)) { return; } var command = job.Command; if (callback.FriendID.IsClanAccount) { var clantag = string.IsNullOrEmpty(callback.ClanTag) ? string.Empty : $" {Colors.NORMAL}(Clan tag: {Colors.LIGHTGRAY}{callback.ClanTag}{Colors.NORMAL})"; command.Reply($"{Colors.BLUE}{callback.Name}{Colors.NORMAL} -{Colors.DARKBLUE} https://steamcommunity.com/gid/{callback.FriendID.ConvertToUInt64()}/{clantag}"); } else if (callback.FriendID.IsIndividualAccount) { command.Reply($"{Colors.BLUE}{callback.Name}{Colors.NORMAL} -{Colors.DARKBLUE} https://steamcommunity.com/profiles/{callback.FriendID.ConvertToUInt64()}/"); } else { command.Reply(callback.Name); } }
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.RunAsync(() => { RefreshPackageNames(); foreach (var subID in packageIDs) { IRC.Instance.SendAnnounce("New free license granted: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.GetPackageName(subID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageURL(subID) ); } }); } }
private static void OnPersonaState(SteamFriends.PersonaStateCallback callback) { if (!JobManager.TryRemoveJob(new JobID(callback.FriendID), out var job)) { return; } var command = job.Command; if (callback.FriendID.IsClanAccount) { var clantag = string.IsNullOrEmpty(callback.ClanTag) ? string.Empty : string.Format(" {0}(Clan tag: {1}{2}{3})", Colors.NORMAL, Colors.LIGHTGRAY, callback.ClanTag, Colors.NORMAL); command.Reply("{0}{1}{2} -{3} https://steamcommunity.com/gid/{4}/{5}", Colors.BLUE, callback.Name, Colors.NORMAL, Colors.DARKBLUE, callback.FriendID.ConvertToUInt64(), clantag ); } else if (callback.FriendID.IsIndividualAccount) { command.Reply("{0}{1}{2} -{3} https://steamcommunity.com/profiles/{4}/", Colors.BLUE, callback.Name, Colors.NORMAL, Colors.DARKBLUE, callback.FriendID.ConvertToUInt64() ); } else { command.Reply(callback.Name); } }
private void OnFreeLicenseCallback(SteamApps.FreeLicenseCallback callback) { JobManager.TryRemoveJob(callback.JobID); var packageIDs = callback.GrantedPackages; var appIDs = callback.GrantedApps; Log.WriteDebug(nameof(FreeLicense), $"Received free license: {callback.Result} ({appIDs.Count} apps: {string.Join(", ", appIDs)}, {packageIDs.Count} packages: {string.Join(", ", packageIDs)})"); if (appIDs.Count > 0) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(appIDs, Enumerable.Empty <uint>()), new PICSTokens.RequestedTokens { Apps = appIDs.ToList() }); var removed = false; foreach (var appid in appIDs) { if (FreeLicensesToRequest.Remove(appid)) { removed = true; } } if (removed) { TaskManager.Run(Save); } } if (packageIDs.Count > 0) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(Enumerable.Empty <uint>(), packageIDs), new PICSTokens.RequestedTokens { Packages = packageIDs.ToList() }); TaskManager.Run(async() => { await RefreshPackageNames(); foreach (var subID in packageIDs) { IRC.Instance.SendAnnounce($"New free license granted: {Colors.BLUE}{Steam.GetPackageName(subID)}{Colors.NORMAL} -{Colors.DARKBLUE} {SteamDB.GetPackageUrl(subID)}"); } }); } }
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); } }
private static void OnPICSTokens(SteamApps.PICSTokensCallback callback) { JobManager.TryRemoveJob(callback.JobID, out var job); if (callback.AppTokens.Count > 0 || callback.AppTokensDenied.Count > 0) { Log.WriteInfo(nameof(PICSTokens), $"App tokens: {callback.AppTokens.Count} received, {callback.AppTokensDenied.Count} denied"); } else { Log.WriteInfo(nameof(PICSTokens), $"Package tokens: {callback.PackageTokens.Count} received, {callback.PackageTokensDenied.Count} denied"); } var apps = callback.AppTokensDenied .Select(NewAppRequest) .Concat(callback.AppTokens.Select(app => NewAppRequest(app.Key, app.Value))) .ToList(); var subs = callback.PackageTokensDenied .Select(NewPackageRequest) .Concat(callback.PackageTokens.Select(sub => NewPackageRequest(sub.Key, sub.Value))) .ToList(); if (job?.Metadata != default) { var requested = (RequestedTokens)job.Metadata; if (requested.Apps != null) { foreach (var appid in requested.Apps.Where(app => !callback.AppTokens.ContainsKey(app) && !callback.AppTokensDenied.Contains(app))) { Log.WriteError(nameof(PICSTokens), $"Requested token for app {appid} but Steam did not return it"); IRC.Instance.SendOps($"[TOKENS] Requested token for app {appid} but Steam did not return it"); apps.Add(NewAppRequest(appid)); } } if (requested.Packages != null) { foreach (var subid in requested.Packages.Where(sub => !callback.PackageTokens.ContainsKey(sub) && !callback.PackageTokensDenied.Contains(sub))) { Log.WriteError(nameof(PICSTokens), $"Requested token for package {subid} but Steam did not return it"); subs.Add(NewPackageRequest(subid)); } } } JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(apps, subs)); }
private static void OnPICSTokens(SteamApps.PICSTokensCallback callback) { JobManager.TryRemoveJob(callback.JobID); Log.WriteDebug("PICSTokens", "Tokens granted: {0} - Tokens denied: {1}", callback.AppTokens.Count, callback.AppTokensDenied.Count); var apps = callback.AppTokensDenied .Select(Utils.NewPICSRequest) .Concat(callback.AppTokens.Select(app => Utils.NewPICSRequest(app.Key, app.Value))); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(apps, Enumerable.Empty <SteamApps.PICSRequest>())); }
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 OnFreeLicenseCallback(SteamApps.FreeLicenseCallback callback) { JobManager.TryRemoveJob(callback.JobID); var packageIDs = callback.GrantedPackages; var appIDs = callback.GrantedApps; Log.WriteDebug(nameof(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>()), new PICSTokens.RequestedTokens { Apps = appIDs.ToList() }); foreach (var appid in appIDs) { LocalConfig.Current.FreeLicensesToRequest.Remove(appid); } LocalConfig.Save(); } if (packageIDs.Count > 0) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(Enumerable.Empty <uint>(), packageIDs), new PICSTokens.RequestedTokens { Packages = packageIDs.ToList() }); TaskManager.RunAsync(async() => { await RefreshPackageNames(); foreach (var subID in packageIDs) { IRC.Instance.SendAnnounce("New free license granted: {0}{1}{2} -{3} {4}", Colors.BLUE, Steam.GetPackageName(subID), Colors.NORMAL, Colors.DARKBLUE, SteamDB.GetPackageUrl(subID) ); } }); } }
private static void OnPICSTokens(SteamApps.PICSTokensCallback callback) { JobManager.TryRemoveJob(callback.JobID); Log.WriteDebug(nameof(PICSTokens), $"App tokens: {callback.AppTokens.Count} ({callback.AppTokensDenied.Count} denied) - Package tokens: {callback.PackageTokens.Count} ({callback.PackageTokensDenied.Count} denied)"); var apps = callback.AppTokensDenied .Select(NewAppRequest) .Concat(callback.AppTokens.Select(app => NewAppRequest(app.Key, app.Value))); var subs = callback.PackageTokensDenied .Select(NewPackageRequest) .Concat(callback.PackageTokens.Select(sub => NewPackageRequest(sub.Key, sub.Value))); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(apps, subs)); }
private void OnFreeLicenseCallback(SteamApps.FreeLicenseCallback callback) { JobManager.TryRemoveJob(callback.JobID); var packageIDs = callback.GrantedPackages; var appIDs = callback.GrantedApps; Log.WriteDebug(nameof(FreeLicense), $"Received free license: {callback.Result} ({appIDs.Count} apps: {string.Join(", ", appIDs)}, {packageIDs.Count} packages: {string.Join(", ", packageIDs)})"); if (appIDs.Count > 0) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(appIDs, Enumerable.Empty <uint>()), new PICSTokens.RequestedTokens { Apps = appIDs.ToList() }); var removed = false; foreach (var appid in appIDs) { if (FreeLicensesToRequest.TryRemove(appid, out _)) { removed = true; } } if (removed) { TaskManager.Run(Save); } } if (packageIDs.Count > 0) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(Enumerable.Empty <uint>(), packageIDs), new PICSTokens.RequestedTokens { Packages = packageIDs.ToList() }); TaskManager.Run(RefreshPackageNames); } }
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 OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobManager.TryRemoveJob(callback.JobID); var apps = callback.Apps.Concat(callback.UnknownApps.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); var packages = callback.Packages.Concat(callback.UnknownPackages.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); foreach (var workaround in apps) { var app = workaround; Log.WriteInfo("PICSProductInfo", "{0}AppID: {1}", app.Value == null ? "Unknown " : "", app.Key); Task mostRecentItem; lock (ProcessedApps) { ProcessedApps.TryGetValue(app.Key, out mostRecentItem); } var workerItem = TaskManager.Run(async() => { try { await ProcessorSemaphore.WaitAsync().ConfigureAwait(false); if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for app {0} to finish processing", app.Key); await mostRecentItem.ConfigureAwait(false); } using (var processor = new AppProcessor(app.Key)) { if (app.Value == null) { processor.ProcessUnknown(); } else { processor.Process(app.Value); } } } catch (MySqlException e) { ErrorReporter.Notify($"App {app.Key}", e); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(app.Key, null)); } catch (Exception e) { ErrorReporter.Notify($"App {app.Key}", e); } finally { lock (ProcessedApps) { if (ProcessedApps.TryGetValue(app.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedApps.Remove(app.Key); } } ProcessorSemaphore.Release(); } }); if (Settings.IsFullRun) { continue; } lock (ProcessedApps) { ProcessedApps[app.Key] = workerItem; } } foreach (var workaround in packages) { var package = workaround; Log.WriteInfo("PICSProductInfo", "{0}SubID: {1}", package.Value == null ? "Unknown " : "", package.Key); Task mostRecentItem; lock (ProcessedSubs) { ProcessedSubs.TryGetValue(package.Key, out mostRecentItem); } var workerItem = TaskManager.Run(async() => { try { await ProcessorSemaphore.WaitAsync().ConfigureAwait(false); if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for package {0} to finish processing", package.Key); await mostRecentItem.ConfigureAwait(false); } using (var processor = new SubProcessor(package.Key)) { if (package.Value == null) { processor.ProcessUnknown(); } else { processor.Process(package.Value); } } } catch (MySqlException e) { ErrorReporter.Notify($"Package {package.Key}", e); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(null, package.Key, false, false)); } catch (Exception e) { ErrorReporter.Notify($"Package {package.Key}", e); } finally { lock (ProcessedSubs) { if (ProcessedSubs.TryGetValue(package.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedSubs.Remove(package.Key); } } ProcessorSemaphore.Release(); } }); if (Settings.IsFullRun) { continue; } lock (ProcessedSubs) { ProcessedSubs[package.Key] = workerItem; } } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobManager.TryRemoveJob(callback.JobID); var apps = callback.Apps.Concat(callback.UnknownApps.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); var packages = callback.Packages.Concat(callback.UnknownPackages.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); foreach (var workaround in apps) { var app = workaround; Log.WriteInfo("PICSProductInfo", "{0}AppID: {1}", app.Value == null ? "Unknown " : "", app.Key); IWorkItemResult mostRecentItem; lock (ProcessedApps) { ProcessedApps.TryGetValue(app.Key, out mostRecentItem); } var workerItem = ProcessorThreadPool.QueueWorkItem(delegate { try { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for app {0} to finish processing", app.Key); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } using (var processor = new AppProcessor(app.Key)) { if (app.Value == null) { processor.ProcessUnknown(); } else { processor.Process(app.Value); } } } catch (MySqlException e) { Log.WriteError("PICSProductInfo", "App {0} faulted: {1}", app.Key, e); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetAccessTokens(app.Key, null)); } catch (Exception e) { Log.WriteError("PICSProductInfo", "App {0} faulted: {1}", app.Key, e); } finally { lock (ProcessedApps) { if (ProcessedApps.TryGetValue(app.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedApps.Remove(app.Key); } } } }); if (Settings.IsFullRun) { continue; } lock (ProcessedApps) { ProcessedApps[app.Key] = workerItem; } } foreach (var workaround in packages) { var package = workaround; Log.WriteInfo("PICSProductInfo", "{0}SubID: {1}", package.Value == null ? "Unknown " : "", package.Key); IWorkItemResult mostRecentItem; lock (ProcessedSubs) { ProcessedSubs.TryGetValue(package.Key, out mostRecentItem); } var workerItem = ProcessorThreadPool.QueueWorkItem(delegate { try { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for package {0} to finish processing", package.Key); SmartThreadPool.WaitAll(new IWaitableResult[] { mostRecentItem }); } using (var processor = new SubProcessor(package.Key)) { if (package.Value == null) { processor.ProcessUnknown(); } else { processor.Process(package.Value); } } } catch (MySqlException e) { Log.WriteError("PICSProductInfo", "Package {0} faulted: {1}", package.Key, e); JobManager.AddJob(() => Steam.Instance.Apps.PICSGetProductInfo(null, package.Key, false, false)); } catch (Exception e) { Log.WriteError("PICSProductInfo", "Package {0} faulted: {1}", package.Key, e); } finally { lock (ProcessedSubs) { if (ProcessedSubs.TryGetValue(package.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedSubs.Remove(package.Key); } } } }); if (Settings.IsFullRun) { continue; } lock (ProcessedSubs) { ProcessedSubs[package.Key] = workerItem; } } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobManager.TryRemoveJob(callback.JobID); var processors = new List <BaseProcessor>( callback.Apps.Count + callback.Packages.Count + callback.UnknownApps.Count + callback.UnknownPackages.Count ); processors.AddRange(callback.Apps.Select(app => new AppProcessor(app.Key, app.Value))); processors.AddRange(callback.Packages.Select(package => new SubProcessor(package.Key, package.Value))); processors.AddRange(callback.UnknownApps.Select(app => new AppProcessor(app, null))); processors.AddRange(callback.UnknownPackages.Select(package => new SubProcessor(package, null))); foreach (var workaround in processors) { var processor = workaround; Task mostRecentItem; lock (CurrentlyProcessing) { CurrentlyProcessing.TryGetValue(processor.Id, out mostRecentItem); } var workerItem = TaskManager.Run(async() => { await Semaphore.WaitAsync(TaskManager.TaskCancellationToken.Token).ConfigureAwait(false); try { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for {0} to finish processing", processor.ToString()); await mostRecentItem.ConfigureAwait(false); } await processor.Process().ConfigureAwait(false); } finally { Semaphore.Release(); processor.Dispose(); } }).Unwrap(); lock (CurrentlyProcessing) { CurrentlyProcessing[processor.Id] = workerItem; } workerItem.ContinueWith(task => { lock (CurrentlyProcessing) { if (CurrentlyProcessing.TryGetValue(processor.Id, out mostRecentItem) && mostRecentItem.IsCompleted) { CurrentlyProcessing.Remove(processor.Id); } } }, TaskManager.TaskCancellationToken.Token); } }
public override void OnCommand(CommandArguments command) { if (command.Message.Length == 0) { CommandHandler.ReplyToCommand(command, "Usage:{0} steamid <steamid> [individual/group/gamegroup]", Colors.OLIVE); return; } var args = command.Message.Split(' '); var urlType = EVanityURLType.Default; if (args.Length > 1) { switch (args[1]) { case "individual": urlType = EVanityURLType.Individual; break; case "group": urlType = EVanityURLType.Group; break; case "game": case "gamegroup": urlType = EVanityURLType.OfficialGameGroup; break; default: CommandHandler.ReplyToCommand(command, "Invalid vanity url type."); return; } } SteamID steamID; if (urlType != EVanityURLType.Default || !TrySetSteamID(args[0], out steamID)) { if (urlType == EVanityURLType.Default) { urlType = EVanityURLType.Individual; } var eResult = ResolveVanityURL(args[0], urlType, out steamID); if (eResult != EResult.OK) { CommandHandler.ReplyToCommand(command, "Failed to resolve vanity url: {0}{1}", Colors.RED, eResult.ToString()); return; } } CommandHandler.ReplyToCommand(command, ExpandSteamID(steamID)); if (!steamID.IsValid || (!steamID.IsIndividualAccount && !steamID.IsClanAccount)) { return; } JobAction job; if (JobManager.TryRemoveJob(new JobID(steamID), out job) && job.IsCommand) { CommandHandler.ReplyToCommand(job.CommandRequest.Command, true, "Your !steamid request was lost in space."); } JobManager.AddJob( () => FakePersonaStateJob(steamID), new JobManager.IRCRequest { Command = command } ); }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobManager.TryRemoveJob(callback.JobID); var processors = new List <BaseProcessor>( callback.Apps.Count + callback.Packages.Count + callback.UnknownApps.Count + callback.UnknownPackages.Count ); processors.AddRange(callback.Apps.Select(app => new AppProcessor(app.Key, app.Value))); processors.AddRange(callback.Packages.Select(package => new SubProcessor(package.Key, package.Value))); processors.AddRange(callback.UnknownApps.Select(app => new AppProcessor(app, null))); processors.AddRange(callback.UnknownPackages.Select(package => new SubProcessor(package, null))); foreach (var workaround in processors) { var processor = workaround; Task mostRecentItem; lock (CurrentlyProcessing) { CurrentlyProcessing.TryGetValue(processor.Id, out mostRecentItem); } var workerItem = TaskManager.Run(async() => { try { await Semaphore.WaitAsync(TaskManager.TaskCancellationToken.Token).ConfigureAwait(false); if (mostRecentItem?.IsCompleted == false) { Log.WriteDebug(processor.ToString(), $"Waiting for previous task to finish processing ({CurrentlyProcessing.Count})"); await mostRecentItem.ConfigureAwait(false); #if DEBUG Log.WriteDebug(processor.ToString(), "Previous task lock ended"); #endif } await processor.Process().ConfigureAwait(false); } catch (Exception e) { ErrorReporter.Notify(processor.ToString(), e); } finally { Semaphore.Release(); processor.Dispose(); } return(processor); }).Unwrap(); lock (CurrentlyProcessing) { CurrentlyProcessing[processor.Id] = workerItem; } // Register error handler on inner task and the continuation TaskManager.RegisterErrorHandler(workerItem); TaskManager.RegisterErrorHandler(workerItem.ContinueWith(RemoveProcessorLock, TaskManager.TaskCancellationToken.Token)); } }
private static void OnPICSProductInfo(SteamApps.PICSProductInfoCallback callback) { JobManager.TryRemoveJob(callback.JobID); var apps = callback.Apps.Concat(callback.UnknownApps.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); var packages = callback.Packages.Concat(callback.UnknownPackages.ToDictionary(x => x, x => (SteamApps.PICSProductInfoCallback.PICSProductInfo)null)); foreach (var workaround in apps) { var app = workaround; Log.WriteInfo("PICSProductInfo", "{0}AppID: {1}", app.Value == null ? "Unknown " : "", app.Key); Task mostRecentItem; lock (ProcessedApps) { ProcessedApps.TryGetValue(app.Key, out mostRecentItem); } var workerItem = TaskManager.Run(async delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for app {0} to finish processing", app.Key); await mostRecentItem; } using (var processor = new AppProcessor(app.Key)) { if (app.Value == null) { processor.ProcessUnknown(); } else { processor.Process(app.Value); } } }); if (Settings.IsFullRun) { continue; } lock (ProcessedApps) { ProcessedApps[app.Key] = workerItem; } workerItem.ContinueWith(task => { lock (ProcessedApps) { if (ProcessedApps.TryGetValue(app.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedApps.Remove(app.Key); } } }); } foreach (var workaround in packages) { var package = workaround; Log.WriteInfo("PICSProductInfo", "{0}SubID: {1}", package.Value == null ? "Unknown " : "", package.Key); Task mostRecentItem; lock (ProcessedSubs) { ProcessedSubs.TryGetValue(package.Key, out mostRecentItem); } var workerItem = TaskManager.Run(async delegate { if (mostRecentItem != null && !mostRecentItem.IsCompleted) { Log.WriteDebug("PICSProductInfo", "Waiting for package {0} to finish processing", package.Key); await mostRecentItem; } using (var processor = new SubProcessor(package.Key)) { if (package.Value == null) { processor.ProcessUnknown(); } else { processor.Process(package.Value); } } }); if (Settings.IsFullRun) { continue; } lock (ProcessedSubs) { ProcessedSubs[package.Key] = workerItem; } workerItem.ContinueWith(task => { lock (ProcessedSubs) { if (ProcessedSubs.TryGetValue(package.Key, out mostRecentItem) && mostRecentItem.IsCompleted) { ProcessedSubs.Remove(package.Key); } } }); } }
public override async Task OnCommand(CommandArguments command) { await Task.Yield(); if (command.Message.Length == 0) { command.Reply("Usage:{0} steamid <steamid> [individual/group/gamegroup]", Colors.OLIVE); return; } var args = command.Message.Split(' '); var urlType = EVanityURLType.Default; if (args.Length > 1) { switch (args[1]) { case "individual": urlType = EVanityURLType.Individual; break; case "group": urlType = EVanityURLType.Group; break; case "game": case "gamegroup": urlType = EVanityURLType.OfficialGameGroup; break; default: command.Reply("Invalid vanity url type."); return; } } SteamID steamID; if (urlType != EVanityURLType.Default || !TrySetSteamID(args[0], out steamID)) { if (urlType == EVanityURLType.Default) { urlType = EVanityURLType.Individual; } var eResult = ResolveVanityURL(args[0], urlType, out steamID); if (eResult != EResult.OK) { command.Reply("Failed to resolve vanity url: {0}{1}", Colors.RED, eResult.ToString()); return; } } command.Reply(ExpandSteamID(steamID)); if (!steamID.IsValid || (!steamID.IsIndividualAccount && !steamID.IsClanAccount)) { return; } JobManager.TryRemoveJob(new JobID(steamID)); // Remove previous "job" if any JobManager.AddJob( () => FakePersonaStateJob(steamID), command ); }
private static 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.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!"); } }