public static async Task FullUpdatePackagesMetadata() { Log.WriteInfo(nameof(FullUpdateProcessor), "Doing a full update for packages using metadata requests"); await using var db = await Database.GetConnectionAsync(); var subs = db.Query <uint>("SELECT `SubID` FROM `Subs` ORDER BY `SubID` DESC").ToList(); foreach (var list in subs.Split(IdsPerMetadataRequest)) { do { AsyncJobMultiple <SteamApps.PICSProductInfoCallback> job = null; try { job = Steam.Instance.Apps.PICSGetProductInfo(Enumerable.Empty <SteamApps.PICSRequest>(), list.Select(PICSTokens.NewPackageRequest), true); job.Timeout = TimeSpan.FromMinutes(1); await job; break; } catch (TaskCanceledException) { Log.WriteWarn(nameof(FullUpdateProcessor), $"Package metadata request timed out, job: {job?.JobID}"); } } while (true); do { await Task.Delay(500); }while (IsBusy()); } }
public void AsyncJobMultipleFinishedOnPredicate() { SteamClient client = new SteamClient(); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => call.IsFinished); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); bool jobFinished = asyncJob.AddResult(new Callback { JobID = 123, IsFinished = false }); Assert.False(jobFinished, "Async job should not inform that it is finished when completion predicate is false after a result is given"); Assert.False(asyncTask.IsCompleted, "Async job should not be completed when completion predicate is false"); Assert.False(asyncTask.IsCanceled, "Async job should not be canceled when completion predicate is false"); Assert.False(asyncTask.IsFaulted, "Async job should not be faulted when completion predicate is false"); jobFinished = asyncJob.AddResult(new Callback { JobID = 123, IsFinished = true }); Assert.True(jobFinished, "Async job should inform completion when completion predicat is passed after a result is given"); Assert.True(asyncTask.IsCompleted, "Async job should be completed when completion predicate is true"); Assert.False(asyncTask.IsCanceled, "Async job should not be canceled when completion predicate is true"); Assert.False(asyncTask.IsFaulted, "Async job should not be faulted when completion predicate is true"); }
public async Task AsyncJobMultipleCompletesOnIncompleteResult() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled(true); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => call.IsFinished); asyncJob.Timeout = TimeSpan.FromSeconds(1); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); Callback onlyResult = new Callback { JobID = 123, IsFinished = false }; asyncJob.AddResult(onlyResult); // adding a result will extend the job's timeout, but we'll cheat here and decrease it asyncJob.Timeout = TimeSpan.FromSeconds(1); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.True(asyncTask.IsCompleted, "AsyncJobMultiple should be completed on partial (timed out) result set"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled on partial (timed out) result set"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted on a partial (failed) result set"); AsyncJobMultiple <Callback> .ResultSet result = asyncTask.Result; Assert.False(result.Complete, "ResultSet should be incomplete"); Assert.False(result.Failed, "ResultSet should not be failed"); Assert.Equal(result.Results.Count, 1); Assert.Contains(onlyResult, result.Results); }
public void AsyncJobMultipleCompletesOnIncompleteResultAndFailure() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled(true); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => call.IsFinished); asyncJob.Timeout = TimeSpan.FromSeconds(1); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); Callback onlyResult = new Callback { JobID = 123, IsFinished = false }; asyncJob.AddResult(onlyResult); asyncJob.SetFailed(dueToRemoteFailure: true); Assert.True(asyncTask.IsCompleted, "AsyncJobMultiple should be completed on partial (failed) result set"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled on partial (failed) result set"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted on a partial (failed) result set"); AsyncJobMultiple <Callback> .ResultSet result = asyncTask.Result; Assert.False(result.Complete, "ResultSet should be incomplete"); Assert.True(result.Failed, "ResultSet should be failed"); Assert.Equal(result.Results.Count, 1); Assert.Contains(onlyResult, result.Results); }
public static async Task FullUpdateAppsMetadata(bool fromChangelist = false) { Log.WriteInfo(nameof(FullUpdateProcessor), "Doing a full update for apps using metadata requests"); await using var db = await Database.GetConnectionAsync(); var apps = db.Query <uint>("(SELECT `AppID` FROM `Apps` ORDER BY `AppID` DESC) UNION DISTINCT (SELECT `AppID` FROM `SubsApps` WHERE `Type` = 'app') ORDER BY `AppID` DESC").ToList(); foreach (var list in apps.Split(fromChangelist ? 1000 : IdsPerMetadataRequest)) { do { AsyncJobMultiple <SteamApps.PICSProductInfoCallback> job = null; try { job = Steam.Instance.Apps.PICSGetProductInfo(list.Select(PICSTokens.NewAppRequest), Enumerable.Empty <SteamApps.PICSRequest>(), true); job.Timeout = TimeSpan.FromMinutes(fromChangelist ? 2 : 1); await job; break; } catch (TaskCanceledException) { Log.WriteWarn(nameof(FullUpdateProcessor), $"Apps metadata request timed out, job: {job?.JobID}"); } } while (true); do { await Task.Delay(500); }while (IsBusy()); } }
public async Task <KeyValue> GetProductInfo(uint id) { if (IsLoggedIn == false) { throw new Exception("Steam not loggin in."); } try { SteamApps.PICSProductInfoCallback productInfo; var productJob = steamApps.PICSGetProductInfo(id, package: null, onlyPublic: false); AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet resultSet = await productJob; if (resultSet.Complete) { productInfo = resultSet.Results.First(); } else { productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(id)); } if (productInfo == null) { throw new Exception("Failed to get product info for app " + id); } return(productInfo.Apps[id].KeyValues); } catch (Exception e) { throw new Exception("Failed to get product info for app " + id + ". " + e.Message); } }
public async Task <KeyValue> GetProductInfo(uint id) { if (!IsConnected) { var connect = await Connect(); if (connect != EResult.OK) { connect = await Connect(); if (connect != EResult.OK) { throw new Exception("Failed to connect to Steam " + connect); } } isConnected = true; } if (!IsLoggedIn) { var logon = await Login(); if (logon != EResult.OK) { throw new Exception("Failed to logon to Steam " + logon); } isLoggedIn = true; } try { SteamApps.PICSProductInfoCallback productInfo; var productJob = steamApps.PICSGetProductInfo(id, package: null, onlyPublic: false); AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet resultSet = await productJob; if (resultSet.Complete) { productInfo = resultSet.Results.First(); } else { productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(id)); } if (productInfo == null) { throw new Exception("Failed to get product info for app " + id); } return(productInfo.Apps[id].KeyValues); } catch (Exception e) { throw new Exception("Failed to get product info for app " + id + ". " + e.Message); } }
public void AsyncJobMultipleThrowsExceptionOnNullCallback() { SteamClient client = new SteamClient(); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => true); Assert.Throws <ArgumentNullException>(() => asyncJob.AddResult(null)); }
public void AsyncJobMultipleClearsOnCompletion() { SteamClient client = new SteamClient(); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => call.IsFinished); client.PostCallback(new Callback { JobID = 123, IsFinished = true }); Assert.False(client.jobManager.asyncJobs.ContainsKey(asyncJob), "Async job dictionary should not contain jobid key for AsyncJobMultiple on completion"); Assert.False(client.jobManager.asyncJobs.ContainsKey(123), "Async job dictionary should not contain jobid key (as value type) for AsyncJobMultiple on completion"); }
public async Task AsyncJobMultipleClearsOnTimeout() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled(true); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, ccall => true); asyncJob.Timeout = TimeSpan.FromSeconds(1); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.False(client.jobManager.asyncJobs.ContainsKey(asyncJob), "Async job dictionary should no longer contain jobid key after timeout"); Assert.False(client.jobManager.asyncJobs.ContainsKey(123), "Async job dictionary should no longer contain jobid key (as value type) after timeout"); }
public async Task AsyncJobMultipleThrowsFailureExceptionOnFailure() { SteamClient client = new SteamClient(); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => false); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); asyncJob.SetFailed(dueToRemoteFailure: true); Assert.True(asyncTask.IsCompleted, "AsyncJobMultiple should be completed after job failure"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled after job failure"); Assert.True(asyncTask.IsFaulted, "AsyncJobMultiple should be faulted after job failure"); await Assert.ThrowsAsync(typeof(AsyncJobFailedException), async() => await asyncTask); }
public void AsyncJobMultipleFinishedOnEmptyPredicate() { SteamClient client = new SteamClient(); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => true); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); bool jobFinished = asyncJob.AddResult(new Callback { JobID = 123 }); Assert.True(jobFinished, "Async job should inform that it is completed when completion predicate is always true and a result is given"); Assert.True(asyncTask.IsCompleted, "Async job should be completed when empty predicate result is given"); Assert.False(asyncTask.IsCanceled, "Async job should not be canceled when empty predicate result is given"); Assert.False(asyncTask.IsFaulted, "Async job should not be faulted when empty predicate result is given"); }
public async Task AsyncJobMultipleExtendsTimeoutOnMessage() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled(true); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => call.IsFinished); asyncJob.Timeout = TimeSpan.FromSeconds(5); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); // wait 3 seconds before we post any results to this job at all await Task.Delay(TimeSpan.FromSeconds(3)); // we should not be completed or canceled yet Assert.False(asyncTask.IsCompleted, "AsyncJobMultiple should not be completed after 3 seconds of 5 second timeout"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled after 3 seconds of 5 second timeout"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 3 econds of 5 second timeout"); // give result 1 of 2 asyncJob.AddResult(new Callback { JobID = 123, IsFinished = false }); // delay for what the original timeout would have been await Task.Delay(TimeSpan.FromSeconds(5)); // we still shouldn't be completed or canceled (timed out) Assert.False(asyncTask.IsCompleted, "AsyncJobMultiple should not be completed 5 seconds after a result was added (result should extend timeout)"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled 5 seconds after a result was added (result should extend timeout)"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted 5 seconds aftr a result was added (result should extend timeout)"); asyncJob.AddResult(new Callback { JobID = 123, IsFinished = true }); // we should be completed but not canceled or faulted Assert.True(asyncTask.IsCompleted, "AsyncJobMultiple should be completed when final result is added to set"); Assert.False(asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled when final result is added to set"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted when final result is added to set"); }
public async Task AsyncJobMultipleTimesout() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled(true); AsyncJobMultiple <Callback> asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => false); asyncJob.Timeout = TimeSpan.FromSeconds(1); Task <AsyncJobMultiple <Callback> .ResultSet> asyncTask = asyncJob.ToTask(); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.True(asyncTask.IsCompleted, "AsyncJobMultiple should be completed after 5 seconds of a 1 second job timeout"); Assert.True(asyncTask.IsCanceled, "AsyncJobMultiple should be canceled after 5 seconds of a 1 second job timeout"); Assert.False(asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 5 seconds of a 1 second job timeout"); await Assert.ThrowsAsync(typeof(TaskCanceledException), async() => await asyncTask); }
public async Task <SteamApps.PICSProductInfoCallback.PICSProductInfo> GetAppInfo(uint appID) { // now request some product info for TF2 var productJob = steamApps.PICSGetProductInfo(appID, package: null, onlyPublic: false); // note that with some requests, Steam can return multiple results, so these jobs don't return the callback object directly, but rather // a result set that could contain multiple callback objects if Steam gives us multiple results AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet resultSet = await productJob; SteamApps.PICSProductInfoCallback productInfo; if (resultSet.Complete) { // the request fully completed, we can handle the data productInfo = resultSet.Results.First(); } else { // the request partially completed, but then we timed out. essentially the same as the previous case, but Steam didn't explicitly fail. // we still need to check our result set to see if we have our data productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(appID)); if (productInfo != null) { // we were lucky and Steam gave us the info we requested before timing out } else { throw new Exception("App Info couldn't be received"); } } if (productInfo.Apps.Count == 0) { throw new Exception("No package found"); } //return productInfo.Apps.FirstOrDefault(prod => prod.Key == appID).Value; return(productInfo.Apps[appID]); }
public void AsyncJobMultipleContinuesAsynchronously() { SteamClient client = new SteamClient(); var asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => true); var asyncTask = asyncJob.ToTask(); var continuationThreadID = -1; var continuation = asyncTask.ContinueWith(t => { continuationThreadID = Environment.CurrentManagedThreadId; }, TaskContinuationOptions.ExecuteSynchronously); var completionThreadID = Environment.CurrentManagedThreadId; asyncJob.AddResult(new Callback { JobID = 123 }); WaitForTaskWithoutRunningInline(continuation); Assert.NotEqual(-1, continuationThreadID); Assert.NotEqual(completionThreadID, continuationThreadID); }
public async Task AsyncJobMultipleContinuesAsynchronously() { SteamClient client = new SteamClient(); var asyncJob = new AsyncJobMultiple <Callback>(client, 123, call => true); var asyncTask = asyncJob.ToTask(); var continuationThreadID = -1; var continuation = asyncTask.ContinueWith(t => { continuationThreadID = Thread.CurrentThread.ManagedThreadId; }, TaskContinuationOptions.ExecuteSynchronously); var completionThreadID = Thread.CurrentThread.ManagedThreadId; asyncJob.AddResult(new Callback { JobID = 123 }); await continuation; Assert.NotEqual(-1, continuationThreadID); Assert.NotEqual(completionThreadID, continuationThreadID); }
public void AsyncJobMultipleClearsOnCompletion() { SteamClient client = new SteamClient(); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished ); client.PostCallback( new Callback { JobID = 123, IsFinished = true } ); Assert.False( client.jobManager.asyncJobs.ContainsKey( asyncJob ), "Async job dictionary should not contain jobid key for AsyncJobMultiple on completion" ); Assert.False( client.jobManager.asyncJobs.ContainsKey( 123 ), "Async job dictionary should not contain jobid key (as value type) for AsyncJobMultiple on completion" ); }
public async void AsyncJobMultipleExtendsTimeoutOnMessage() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished ); asyncJob.Timeout = TimeSpan.FromSeconds( 5 ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); // wait 3 seconds before we post any results to this job at all await Task.Delay( TimeSpan.FromSeconds( 3 ) ); // we should not be completed or canceled yet Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed after 3 seconds of 5 second timeout" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled after 3 seconds of 5 second timeout" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 3 econds of 5 second timeout" ); // give result 1 of 2 asyncJob.AddResult( new Callback { JobID = 123, IsFinished = false } ); // delay for what the original timeout would have been await Task.Delay( TimeSpan.FromSeconds( 5 ) ); // we still shouldn't be completed or canceled (timed out) Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed 5 seconds after a result was added (result should extend timeout)" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled 5 seconds after a result was added (result should extend timeout)" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted 5 seconds aftr a result was added (result should extend timeout)" ); asyncJob.AddResult( new Callback { JobID = 123, IsFinished = true } ); // we should be completed but not canceled or faulted Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed when final result is added to set" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled when final result is added to set" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted when final result is added to set" ); }
async Task <IEnumerable <IDeal> > IScraper.Scrape(CancellationToken token) { List <IDeal> deals = new List <IDeal>(); List <long> appIds = await GetModifiedGames(token); if (appIds == null) { logger.Warn("Null returned from GetModifiedGames"); return(new List <IDeal>()); } logger.Info("Found {count} modified games", appIds.Count); Dictionary <uint, int> filteredAppIds = await FilterAppIds(appIds, token); BaseDeals packageData = await CreateBaseDeals(filteredAppIds); foreach (PackageKeys package in packageData.Packages) { await Task.Delay(2000, token); logger.Info($"Querying AppId: {package.FilteredAppId}; SubId: {package.PackageId}"); AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet result = await apps.PICSGetProductInfo(package.FilteredAppId, package.PackageId); if (result.Failed || result.Results == null || result.Results.Count == 0) { continue; } foreach (SteamApps.PICSProductInfoCallback callback in result.Results) { if (!callback.Packages.TryGetValue(package.PackageId, out SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo)) { continue; } Deal deal = packageData.IdToDeal[package.FilteredAppId]; string?startTime = productInfo.KeyValues["extended"]["starttime"].Value; if (!string.IsNullOrEmpty(startTime)) { deal.Start = DateTimeOffset.FromUnixTimeSeconds(long.Parse(startTime)).UtcDateTime; } string?expiryTime = productInfo.KeyValues["extended"]["expirytime"].Value; if (!string.IsNullOrEmpty(expiryTime)) { deal.End = DateTimeOffset.FromUnixTimeSeconds(long.Parse(expiryTime)).UtcDateTime; } else { logger.Info("We're ignoring deals without end date for now"); continue; } logger.Info("Found date info for deal, finalizing"); deals.Add(deal); break; } } return(deals); }
public async void AsyncJobMultipleTimesout() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => false ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); await Task.Delay( TimeSpan.FromSeconds( 5 ) ); Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed after 5 seconds of a 1 second job timeout" ); Assert.True( asyncTask.IsCanceled, "AsyncJobMultiple should be canceled after 5 seconds of a 1 second job timeout" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 5 seconds of a 1 second job timeout" ); await Assert.ThrowsAsync( typeof( TaskCanceledException ), async () => await asyncTask ); }
public void AsyncJobMultipleCompletesOnIncompleteResultAndFailure() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); Callback onlyResult = new Callback { JobID = 123, IsFinished = false }; asyncJob.AddResult( onlyResult ); asyncJob.SetFailed( dueToRemoteFailure: true ); Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed on partial (failed) result set" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled on partial (failed) result set" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted on a partial (failed) result set" ); AsyncJobMultiple<Callback>.ResultSet result = asyncTask.Result; Assert.False( result.Complete, "ResultSet should be incomplete" ); Assert.True( result.Failed, "ResultSet should be failed" ); Assert.Equal( result.Results.Count, 1 ); Assert.Contains( onlyResult, result.Results ); }
public async void AsyncJobMultipleCompletesOnIncompleteResult() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); Callback onlyResult = new Callback { JobID = 123, IsFinished = false }; asyncJob.AddResult( onlyResult ); // adding a result will extend the job's timeout, but we'll cheat here and decrease it asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); await Task.Delay( TimeSpan.FromSeconds( 5 ) ); Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed on partial (timed out) result set" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled on partial (timed out) result set" ); Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted on a partial (failed) result set" ); AsyncJobMultiple<Callback>.ResultSet result = asyncTask.Result; Assert.False( result.Complete, "ResultSet should be incomplete" ); Assert.False( result.Failed, "ResultSet should not be failed" ); Assert.Equal( result.Results.Count, 1 ); Assert.Contains( onlyResult, result.Results ); }
public async void AsyncJobMultipleThrowsFailureExceptionOnFailure() { SteamClient client = new SteamClient(); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => false ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); asyncJob.SetFailed( dueToRemoteFailure: true ); Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed after job failure" ); Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled after job failure" ); Assert.True( asyncTask.IsFaulted, "AsyncJobMultiple should be faulted after job failure" ); await Assert.ThrowsAsync( typeof( AsyncJobFailedException ), async () => await asyncTask ); }
public void AsyncJobMultipleThrowsExceptionOnNullCallback() { SteamClient client = new SteamClient(); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => true ); Assert.Throws<ArgumentNullException>( () => asyncJob.AddResult( null ) ); }
public async Task <KeyValue> GetProductInfo(uint id) { if (!IsConnected) { var connect = await Connect(); if (connect != EResult.OK) { connect = await Connect(); if (connect != EResult.OK) { throw new Exception("Failed to connect to Steam " + connect); } } isConnected = true; } if (!IsLoggedIn) { var logon = await Login(); if (logon != EResult.OK) { throw new Exception("Failed to logon to Steam " + logon); } isLoggedIn = true; } try { SteamApps.PICSProductInfoCallback productInfo; AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet resultSet = null; var productJob = steamApps.PICSGetProductInfo(id, package: null, onlyPublic: false); // Workardound for rare case where PICSGetProductInfo would get stuck if there's some issue with computer's network. // For example if PC is woken up from sleep. var tsk = productJob.ToTask(); if (tsk.Wait(10000)) { resultSet = tsk.Result; } else { throw new Exception("Failed to get product info for app (timeout) " + id); } if (resultSet.Complete) { productInfo = resultSet.Results.First(); } else { productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(id)); } if (productInfo == null) { throw new Exception("Failed to get product info for app " + id); } return(productInfo.Apps[id].KeyValues); } catch (Exception e) { throw new Exception("Failed to get product info for app " + id + ". " + e.Message); } }
private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { if (callback.Result != EResult.OK) { if (callback.Result == EResult.AccountLogonDenied) { // if we recieve AccountLogonDenied or one of it's flavors (AccountLogonDeniedNoMailSent, etc) // then the account we're logging into is SteamGuard protected // see sample 5 for how SteamGuard can be handled _logger.LogWarning("Unable to logon to Steam: This account is SteamGuard protected."); return; } _logger.LogError("Unable to logon to Steam: {0} / {1}", callback.Result, callback.ExtendedResult); return; } // in this sample, we'll simply do a few async requests to acquire information about appid 440 (Team Fortress 2) // first, we'll request a depot decryption key for TF2's client/server shared depot (441) var depotJob = steamApps.GetDepotDecryptionKey(depotid: 441, appid: 440); // at this point, this request is now in-flight to the steam server, so we'll use te async/await pattern to wait for a response // the await pattern allows this code to resume once the Steam servers have replied to the request. // if Steam does not reply to the request in a timely fashion (controlled by the `Timeout` field on the AsyncJob object), the underlying // task for this job will be cancelled, and TaskCanceledException will be thrown. // additionally, if Steam encounters a remote failure and is unable to process your request, the job will be faulted and an AsyncJobFailedException // will be thrown. SteamApps.DepotKeyCallback depotKey = await depotJob; if (depotKey.Result == EResult.OK) { _logger.LogDebug($"Got our depot key: {BitConverter.ToString(depotKey.DepotKey)}"); } else { _logger.LogDebug("Unable to request depot key!"); } // now request some product info for TF2 var productJob = steamApps.PICSGetProductInfo(440, package: null); // note that with some requests, Steam can return multiple results, so these jobs don't return the callback object directly, but rather // a result set that could contain multiple callback objects if Steam gives us multiple results AsyncJobMultiple <SteamApps.PICSProductInfoCallback> .ResultSet resultSet = await productJob; if (resultSet.Complete) { // the request fully completed, we can handle the data SteamApps.PICSProductInfoCallback productInfo = resultSet.Results.First(); // ... do something with our product info } else if (resultSet.Failed) { // the request partially completed, and then Steam encountered a remote failure. for async jobs with only a single result (such as // GetDepotDecryptionKey), this would normally throw an AsyncJobFailedException. but since Steam had given us a partial set of callbacks // we get to decide what to do with the data // keep in mind that if Steam immediately fails to provide any data, or times out while waiting for the first result, an // AsyncJobFailedException or TaskCanceledException will be thrown // the result set might not have our data, so we need to test to see if we have results for our request SteamApps.PICSProductInfoCallback productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(440)); if (productInfo != null) { // we were lucky and Steam gave us the info we requested before failing } else { // bad luck } } else { // the request partially completed, but then we timed out. essentially the same as the previous case, but Steam didn't explicitly fail. // we still need to check our result set to see if we have our data SteamApps.PICSProductInfoCallback productInfo = resultSet.Results.FirstOrDefault(prodCallback => prodCallback.Apps.ContainsKey(440)); if (productInfo != null) { // we were lucky and Steam gave us the info we requested before timing out } else { // bad luck } } // lastly, if you're unable to use the async/await pattern (older VS/compiler, etc) you can still directly access the TPL Task associated // with the async job by calling `ToTask()` var depotTask = steamApps.GetDepotDecryptionKey(depotid: 441, appid: 440).ToTask(); // set up a continuation for when this task completes var ignored = depotTask.ContinueWith(task => { depotKey = task.Result; // do something with the depot key // we're finished with this sample, drop out of the callback loop }, TaskContinuationOptions.OnlyOnRanToCompletion); }
public async void AsyncJobMultipleClearsOnTimeout() { SteamClient client = new SteamClient(); client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, ccall => true ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); await Task.Delay( TimeSpan.FromSeconds( 5 ) ); Assert.False( client.jobManager.asyncJobs.ContainsKey( asyncJob ), "Async job dictionary should no longer contain jobid key after timeout" ); Assert.False( client.jobManager.asyncJobs.ContainsKey( 123 ), "Async job dictionary should no longer contain jobid key (as value type) after timeout" ); }
public void AsyncJobMultipleFinishedOnEmptyPredicate() { SteamClient client = new SteamClient(); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => true ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); bool jobFinished = asyncJob.AddResult( new Callback { JobID = 123 } ); Assert.True( jobFinished, "Async job should inform that it is completed when completion predicate is always true and a result is given" ); Assert.True( asyncTask.IsCompleted, "Async job should be completed when empty predicate result is given" ); Assert.False( asyncTask.IsCanceled, "Async job should not be canceled when empty predicate result is given" ); Assert.False( asyncTask.IsFaulted, "Async job should not be faulted when empty predicate result is given" ); }
public void AsyncJobMultipleFinishedOnPredicate() { SteamClient client = new SteamClient(); AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished ); Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask(); bool jobFinished = asyncJob.AddResult( new Callback { JobID = 123, IsFinished = false } ); Assert.False( jobFinished, "Async job should not inform that it is finished when completion predicate is false after a result is given" ); Assert.False( asyncTask.IsCompleted, "Async job should not be completed when completion predicate is false" ); Assert.False( asyncTask.IsCanceled, "Async job should not be canceled when completion predicate is false" ); Assert.False( asyncTask.IsFaulted, "Async job should not be faulted when completion predicate is false" ); jobFinished = asyncJob.AddResult( new Callback { JobID = 123, IsFinished = true } ); Assert.True( jobFinished, "Async job should inform completion when completion predicat is passed after a result is given" ); Assert.True( asyncTask.IsCompleted, "Async job should be completed when completion predicate is true" ); Assert.False( asyncTask.IsCanceled, "Async job should not be canceled when completion predicate is true" ); Assert.False( asyncTask.IsFaulted, "Async job should not be faulted when completion predicate is true" ); }