public TwitterBot(TwitterSettings settings, PokeTradeHub <PK8> hub) { Hub = hub; Settings = settings; client = new TwitterClient(Settings.ConsumerKey, Settings.ConsumerSecret, Settings.AccessToken, Settings.AccessTokenSecret); client.Events.OnTwitterException += HandleTwitterException; try { var taskAuthenticate = Task.Run(async() => await client.Users.GetAuthenticatedUserAsync()); TwitterUser = taskAuthenticate.Result; LogUtil.LogText($"Successfully authenticated as: @{TwitterUser.ScreenName}"); MentionParams = new GetMentionsTimelineParameters { PageSize = Settings.MentionCount }; var taskGetInitialMentions = Task.Run(async() => await client.Timelines.GetMentionsTimelineAsync(MentionParams)); localMentions = new TwitterMentions(taskGetInitialMentions.Result); Task.Run(() => CheckMentionsForTradesAsync(localMentions, CancellationToken.None)); } catch (Exception e) { LogUtil.LogError($"Unable to authenticate with error: {e.Message}", nameof(TwitterBot)); } }
public async Task <ITweet[]> FetchMentionsAsync(IEnumerable <long> inFlight) { try { var parameters = new GetMentionsTimelineParameters(); var latestMention = await _repository.GetLatestMention(); if (latestMention != null) { Log.Information("Latest mention {Mention} on {Date}", latestMention.TweetId, latestMention.Timestamp); parameters.SinceId = latestMention.TweetId; } var mentions = await _client.Timelines.GetMentionsTimelineAsync(parameters); var alreadyReplied = await _repository.FindByTweetId(mentions.Select(it => it.Id)); var repliedIds = alreadyReplied.Select(it => it.TweetId); return(mentions .Where(it => !repliedIds.Contains(it.Id)) .Where(it => !inFlight.Contains(it.Id)) .ToArray()); } catch (Exception e) { Log.Error(e, "Failed to fetch tweets"); return(Array.Empty <ITweet>()); } }
public ITwitterPageIterator <ITwitterResult <ITweetDTO[]>, long?> GetMentionsTimelineIterator(IGetMentionsTimelineParameters parameters, ITwitterRequest request) { return(_pageCursorIteratorFactories.Create(parameters, cursor => { var cursoredParameters = new GetMentionsTimelineParameters(parameters) { MaxId = cursor }; return _timelineQueryExecutor.GetMentionsTimeline(cursoredParameters, new TwitterRequest(request)); })); }
public void GetMentionsTimelineIterator_ReturnsFromPageCursorIteratorFactories() { // arrange var parameters = new GetMentionsTimelineParameters { PageSize = 2 }; var request = A.Fake <ITwitterRequest>(); var expectedResult = A.Fake <ITwitterPageIterator <ITwitterResult <ITweetDTO[]>, long?> >(); A.CallTo(() => _fakePageCursorIteratorFactories.Create(parameters, It.IsAny <Func <long?, Task <ITwitterResult <ITweetDTO[]> > > >())) .Returns(expectedResult); var controller = CreateTimelineController(); var iterator = controller.GetMentionsTimelineIterator(parameters, request); // assert Assert.Equal(iterator, expectedResult); }
public async Task GetMentionsTimelineQuery_ReturnsTweetsAsync() { // Arrange var queryExecutor = CreateTimelineQueryExecutor(); var expectedQuery = TestHelper.GenerateString(); var parameters = new GetMentionsTimelineParameters(); var request = A.Fake <ITwitterRequest>(); var expectedResult = A.Fake <ITwitterResult <ITweetDTO[]> >(); A.CallTo(() => _fakeTimelineQueryGenerator.GetMentionsTimelineQuery(parameters, It.IsAny <TweetMode?>())).Returns(expectedQuery); A.CallTo(() => _fakeTwitterAccessor.ExecuteRequestAsync <ITweetDTO[]>(request)).Returns(expectedResult); // Act var result = await queryExecutor.GetMentionsTimelineAsync(parameters, request); // Assert Assert.Equal(result, expectedResult); Assert.Equal(request.Query.Url, expectedQuery); Assert.Equal(HttpMethod.GET, request.Query.HttpMethod); }
public void GetMentionsTimelineQuery_ReturnsExpectedQuery() { // Arrange var queryGenerator = CreateTimelineQueryGenerator(); var parameters = new GetMentionsTimelineParameters { IncludeEntities = true, TrimUser = true, IncludeContributorDetails = true, MaxId = 42, SinceId = 43, PageSize = 44, CustomQueryParameters = { new Tuple <string, string>("hello", "world") } }; // Act var result = queryGenerator.GetMentionsTimelineQuery(parameters, ComputedTweetMode.Extended); // Assert Assert.Equal(result, $"https://api.twitter.com/1.1/statuses/mentions_timeline.json?count=44&since_id=43&max_id=42" + $"&include_entities=true&trim_user=true&tweet_mode=extended&hello=world"); }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { Logger.LogInformation("TwitterBotMentionHostedService started"); while (!stoppingToken.IsCancellationRequested) { try { long lastTweetId = await _twitterMentionLogService.GetLastTweetId(); var getMentionParameters = new GetMentionsTimelineParameters(); if (lastTweetId == 0) { getMentionParameters.PageSize = TwitterBotSettings.TimelineFirstLoadPageSize; } else { getMentionParameters.SinceId = lastTweetId; } var mentions = await TwitterClient.Timelines.GetMentionsTimelineAsync(getMentionParameters); var myUser = await TwitterClient.Users.GetUserAsync(TwitterBotSettings.BotUsername); foreach (var mention in mentions.Where(x => x.Text.Contains($"@{TwitterBotSettings.BotUsername}") && (x.InReplyToStatusId.HasValue || x.QuotedStatusId.HasValue))) { // Avoid correcting replies to my own tweets if (mention.InReplyToUserId == myUser.Id) { continue; } var tweet = await GetTweetFromMention(mention); if (tweet == null) { continue; } var tweetText = StringUtils.RemoveHashtags(StringUtils.RemoveMentions(StringUtils.RemoveEmojis(tweet.Text))); var correctionsResult = await _grammarService.GetCorrections(tweetText); if (!correctionsResult.HasCorrections) { await PublishReplyTweet($"@{mention.CreatedBy.ScreenName} I don't see anything wrong here.", mention.Id); continue; } var messageBuilder = new StringBuilder(); messageBuilder.Append($"@{mention.CreatedBy.ScreenName}"); foreach (var correction in correctionsResult.Corrections) { // Only suggest the first possible replacement messageBuilder.AppendLine($"*{correction.PossibleReplacements.First()} [{correction.Message}]"); } var correctionString = messageBuilder.ToString(); Logger.LogInformation($"Sending reply to: {mention.CreatedBy.ScreenName}"); if (correctionString.Length >= Defaults.TwitterTextMaxLength) { var replyTweets = correctionString.SplitInParts(Defaults.TwitterTextMaxLength); foreach (var(reply, index) in replyTweets.WithIndex()) { var correctionStringSplitted = index == 0 ? reply : $"@{mention.CreatedBy.ScreenName} {reply}"; await PublishReplyTweet(correctionStringSplitted, mention.Id); await Task.Delay(TwitterBotSettings.PublishTweetDelayMilliseconds, stoppingToken); } continue; } await PublishReplyTweet(correctionString, mention.Id); await Task.Delay(TwitterBotSettings.PublishTweetDelayMilliseconds, stoppingToken); } if (mentions.Any()) { var lastTweet = mentions.OrderByDescending(v => v.Id).First(); // Save last Tweet Id await _twitterMentionLogService.LogTweet(lastTweet.Id, default); } var followersTask = TwitterClient.Users.GetFollowersAsync(TwitterBotSettings.BotUsername); var friendIdsTask = TwitterClient.Users.GetFriendIdsAsync(TwitterBotSettings.BotUsername); await FollowBackUsers(await followersTask, await friendIdsTask); await PublishScheduledTweets(); await LikeRepliesToBot(mentions); } // TODO: Move all this to some "CatchExceptionService" catch (TwitterException ex) when(ex.TwitterDescription.Contains("Try again later") || ex.TwitterDescription.Contains("Timeout limit")) { Logger.LogWarning(ex, ex.TwitterDescription); } catch (SqlException ex) when(ex.Message.Contains("SHUTDOWN")) { Logger.LogWarning(ex, "Sql Server shutdown in progress"); } catch (Exception ex) { var message = ex is TwitterException tEx ? tEx.TwitterDescription : ex.Message; var innerExceptions = ex.GetInnerExceptions(); if (innerExceptions.Any(x => x.GetType() == typeof(SocketException) && x.Message.Contains("Connection reset by peer"))) { // The server has reset the connection. Logger.LogWarning(ex, "Socket reseted."); } else { Logger.LogError(ex, message); // fire and forget _ = _githubService.CreateBugIssue($"Application Exception: {message}", ex, GithubIssueLabels.Twitter); } } await Task.Delay(TwitterBotSettings.HostedServiceIntervalMilliseconds); } }