private async void TimedCleanAsync(object state) { logger.LogInformation("Starting broadcast cleaning task"); var inactiveLimit = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(1)); Expression <Func <Broadcast, bool> > filter = x => x.Expired != true && x.Activity.Value.CompareTo(inactiveLimit) <= 0; var broadcasts = await repository.FindRangeAsync(filter); var first = broadcasts.FirstOrDefault(); if (first == null) { return; } logger.LogDebug("Inactive broadcast: {object}", new { id = first.Id, timestamp = first.Activity.Value.Ticks }); HttpResponseMessage response = default; var clusteringClient = new HttpClient { BaseAddress = new Uri(configuration.GetValue <string>("CLUSTERING_URL")) }; var relayClient = new HttpClient { BaseAddress = new Uri($"{configuration.GetValue<string>("RELAY_URL")}") }; HttpStatusCode statusCode = default; foreach (var id in broadcasts.Select(x => x.Id)) { try { await relayClient.DeleteAsync(id); response = await clusteringClient.PostAsJsonAsync("/data/remove", new { id = id }); } catch (OperationCanceledException) { continue; } if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NotFound) { // Calculate score var viewerResponse = await viewers.FindRangeAsync(x => x.BroadcastId == id); var date = DateTime.UtcNow; var score = BroadcastUtility.CalculateScore(viewerResponse, date); var broadcast = await repository.UpdateAsync( x => x.Id == id, new Broadcast { Expired = true, Activity = DateTime.UtcNow, Score = score }); // Update account score var account = await accounts.FindAsync(x => x.Id == broadcast.AccountId); if (account != null) { var accountScore = account.Score; if (accountScore == null) { accountScore = 0; } account.Score = score + accountScore; await accounts.UpdateAsync(x => x.Id == broadcast.AccountId, account); } logger.LogDebug( "Broadcast {id} stopped due to inactivity", id); } else { if (statusCode == response.StatusCode) { continue; } logger.LogError( "{status}: {message}", response.StatusCode.ToString(), await response.Content.ReadAsStringAsync()); statusCode = response.StatusCode; } } }
public BroadcastType(IRepository <Account> accounts, IRepository <Viewer> viewers) { Field(x => x.Id); Field(x => x.Location, type: typeof(LocationType)); Field(x => x.Activity, type: typeof(DateTimeGraphType)); Field(x => x.Categories); FieldAsync <NonNullGraphType <IntGraphType> >( "score", resolve: async context => { if (context.Source.Score == null) { var response = await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken); var score = BroadcastUtility.CalculateScore(response, context.Source.Activity); // TODO: Update broadcast to contain score? return(score); } else { return(context.Source.Score); } } ); FieldAsync <ListGraphType <ViewerDateTimePairType> >( "joinedTimeStamps", resolve: async context => { var response = await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken); return(BroadcastUtility.GetJoinedTimeStamps(response)); } ); FieldAsync <ListGraphType <ViewerDateTimePairType> >( "leftTimeStamps", resolve: async context => { var response = await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken); return(BroadcastUtility.GetLeftTimeStamps(response)); } ); Field(x => x.Reports); Field <NonNullGraphType <IntGraphType> >( "positiveRatings", resolve: context => context.Source.PositiveRatings.GetValueOrDefault() ); Field <NonNullGraphType <IntGraphType> >( "negativeRatings", resolve: context => context.Source.NegativeRatings.GetValueOrDefault() ); FieldAsync <ListGraphType <ViewerType> >( "viewers", "The viewers associated with this broadcast", resolve: async context => await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken) ); FieldAsync <IntGraphType>( "viewer_count", "The number of viewers currently viewing this broadcast.", resolve: async context => (await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken)) .GroupBy(x => x.AccountId) .Count(x => x.Count() % 2 != 0), deprecationReason: "'viewer_count' is changed to 'current_viewer_count' in the coming update" ); FieldAsync <IntGraphType>( "current_viewer_count", "The number of viewers currently viewing this broadcast.", resolve: async context => (await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken)) .GroupBy(x => x.AccountId) .Count(x => x.Count() % 2 != 0) ); FieldAsync <IntGraphType>( "total_viewer_count", "The total number of viewers that has viewed this broadcast.", resolve: async context => (await viewers.FindRangeAsync(x => x.BroadcastId == context.Source.Id, context.CancellationToken)) .GroupBy(x => x.AccountId) .Count() ); FieldAsync <AccountType>( "broadcaster", "the broadcast owner", resolve: async context => await accounts.FindAsync(x => x.Id == context.Source.AccountId, context.CancellationToken) ); }