Ejemplo n.º 1
0
        protected override async Task TaskActionAsync(Guid?id)
        {
            var parameters = new Dictionary <string, object>();

            parameters.Add("Method", "TaskActionAsync");
            if (id.HasValue)
            {
                parameters.Add("Job ID", id);
            }

            //  Attempt to convert the tweet response JSON string into a SearchStreamResult object.
            SearchStreamResult searchStreamResult;

            try
            {
                searchStreamResult = JsonConvert.DeserializeObject <SearchStreamResult>(_tweetResponse);
            }
            catch (Exception exception)
            {
                // Throws exception, if it's unable to convert it into a SearchStreamResult object.
                throw new ApiException("Unable to convert JSON to type SearchStreamResult.", exception, JObject.Parse(_tweetResponse));
            }

            if (searchStreamResult != null && searchStreamResult.Tweet == null)
            {
                // No tweet, so throw an exception.
                throw new ApiException("Tweet does not have an instance of Tweet.", JObject.Parse(_tweetResponse));
            }

            if (searchStreamResult != null && searchStreamResult.Tweet != null && (searchStreamResult.Tweet.ReferencedTweets == null || searchStreamResult.Tweet.ReferencedTweets.Count == 0))
            {
                var tweetParameters = new Dictionary <string, object>();
                foreach (var param in parameters)
                {
                    tweetParameters.Add(param.Key, param.Value);
                }
                tweetParameters.Add("Twitter API Tweet Id", searchStreamResult.Tweet.Id);

                _logger.LogWithParameters(LogLevel.Information, "Start importing incoming realtime tweet", tweetParameters);

                Tweet tweet = null;
                List <DashboardTweet> dashboardTweets = null;

                // Create a new scope from the service provider.
                using (var scope = _serviceProvider.CreateScope())
                {
                    // Gets the services freom the scope.
                    var blashDbContext        = scope.ServiceProvider.GetService <BlashDbContext>();
                    var dashboardService      = scope.ServiceProvider.GetService <IDashboardService>();
                    var dashboardTweetService = scope.ServiceProvider.GetService <IDashboardTweetService>();
                    var tweetService          = scope.ServiceProvider.GetService <ITweetService>();
                    var authorService         = scope.ServiceProvider.GetService <IAuthorService>();

                    var dashboards = new List <Dashboard>();
                    IList <DashboardTweet> dashboardTweetsToDelete = null;

                    using (var dbContextTransaction = await blashDbContext.Database.BeginTransactionAsync())
                    {
                        // Go through each rule that matches a tweet from the Twitter API.
                        foreach (var matchingRule in searchStreamResult.MatchingRules)
                        {
                            var dashboard = await dashboardService.GetByTwitterRuleAsync(matchingRule.Id); // Dashboard may have been deleted, so check it still exists.

                            if (dashboard == null)
                            {
                                // No dashboard exists, so continue with the next rule.
                                _logger.LogWithParameters(LogLevel.Information, "Dashboard no longer exists so finish processing.", tweetParameters);
                                continue;
                            }
                            dashboards.Add(dashboard); // Add to the list of dashboards.
                        }

                        if (dashboards == null || dashboards.Count == 0)
                        {
                            // If there are no dashboards assoicated with the tweet, finish with the task.
                            return;
                        }

                        // Create or update the tweet to the Blash database.
                        tweet = await TaskExtensions.CreateUpdateTweetAsync(scope, _logger, searchStreamResult.Tweet, searchStreamResult.Includes.Users, searchStreamResult.Includes.Media);

                        if (tweet == null)
                        {
                            return;
                        }

                        // Add it into a dashboard/tweet relationship.
                        dashboardTweets = null;

                        foreach (var dashboard in dashboards)
                        {
                            if (dashboardTweets == null)
                            {
                                dashboardTweets = new List <DashboardTweet>();
                            }

                            // Add all the relationships associated with the tweet.
                            dashboardTweets.Add(await TaskExtensions.CreateDashboardTweetRelationshipAsync(scope, _logger, dashboard.Id, tweet.Id));

                            // Ensure that we only have have the maximum number of tweets per dashboard as defined in appsettings.json under Api > Tweets > MaxPerDashboard.
                            dashboardTweetsToDelete = await dashboardTweetService.GetByDashboardAndAfterPositionAsync(dashboard.Id, _apiConfiguration.Value.Tweets?.MaxPerDashboard ?? 10);

                            if (dashboardTweetsToDelete != null && dashboardTweetsToDelete.Count > 0)
                            {
                                // Delete any dashboard/tweets that exceed the maximum number of tweets allowed for a dashboard.
                                await dashboardTweetService.DeleteMultipleAsync(dashboardTweetsToDelete.Select(dashboardTweet => dashboardTweet.Id).ToList());
                            }

                            // Make sure tweets are removed that aren't needed.
                            await tweetService.DeleteMissingTweetsFromDashboardAsync();

                            await authorService.DeleteMissingTweetsAsync();
                        }

                        // Commit the transaction to the database.
                        await dbContextTransaction.CommitAsync();
                    }

                    // Send the fact that a tweet has been created to the hub's connected clinets through SignalR.
                    await _blashHub.CreateTweetAsync(new CreateTweetResult { Data = new List <CreateTweetData> {
                                                                                 new CreateTweetData(tweet, dashboardTweets)
                                                                             } }, _cancellationToken);

                    if (dashboardTweetsToDelete != null && dashboardTweetsToDelete.Count > 0)
                    {
                        // Send the fact that tweets have been deleted from dashboards to the hub's connected clinets through SignalR.
                        await _blashHub.DeleteDashboardTweetAsync(dashboardTweetsToDelete, _cancellationToken);
                    }
                }

                _logger.LogWithParameters(LogLevel.Information, "Finish importing incoming realtime tweet", tweetParameters);
            }
        }