Как создать новое событие в twitter, чтобы клиенты могли получать уведомления о событии?

Я извлекаю твиты с помощью LINQ to Twitter 4.1.0 поиск определенного хэштега, например.#abc. Теперь хотите получать уведомления, когда кто-то чирикает в моем аккаунте, используя тот же хэштег, например.#abc. Кто-нибудь может подсказать мне, как это сделать?

1 ответ

  1. Если вы используете REST API, вы можете выполнить поисковый запрос, который выполняется периодически, используяSinceID/MaxID, чтобы убедиться, что вы не ищете твиты, которые вы уже видели. Это работает так:

        static async Task DoPagedSearchAsync(TwitterContext twitterCtx)
        {
            const int MaxSearchEntriesToReturn = 100;
    
            string searchTerm = "twitter";
    
            // oldest id you already have for this search term
            ulong sinceID = 1;
    
            // used after the first query to track current session
            ulong maxID; 
    
            var combinedSearchResults = new List<Status>();
    
            List<Status> searchResponse =
                await
                (from search in twitterCtx.Search
                 where search.Type == SearchType.Search &&
                       search.Query == searchTerm &&
                       search.Count == MaxSearchEntriesToReturn &&
                       search.SinceID == sinceID
                 select search.Statuses)
                .SingleOrDefaultAsync();
    
            combinedSearchResults.AddRange(searchResponse);
            ulong previousMaxID = ulong.MaxValue;
            do
            {
                // one less than the newest id you've just queried
                maxID = searchResponse.Min(status => status.StatusID) - 1;
    
                Debug.Assert(maxID < previousMaxID);
                previousMaxID = maxID;
    
                searchResponse =
                    await
                    (from search in twitterCtx.Search
                     where search.Type == SearchType.Search &&
                           search.Query == searchTerm &&
                           search.Count == MaxSearchEntriesToReturn &&
                           search.MaxID == maxID &&
                           search.SinceID == sinceID
                     select search.Statuses)
                    .SingleOrDefaultAsync();
    
                combinedSearchResults.AddRange(searchResponse);
            } while (searchResponse.Any());
    
            combinedSearchResults.ForEach(tweet =>
                Console.WriteLine(
                    "\n  User: {0} ({1})\n  Tweet: {2}",
                    tweet.User.ScreenNameResponse,
                    tweet.User.UserIDResponse,
                    tweet.Text));
        }
    

    В этом примере SinceIDустановлено значение 1, чтобы получить все твиты с начала Twitter. Однако вы должны передать это в качестве параметра, предварительно сохранив самый старый идентификатор твита из предыдущего запроса.

    Поскольку вы не опубликовали код, показывающий, что вы хотите, я предполагаю, что вы используете какую-то форму опроса на REST API, не слишком далеко в отличие от примера выше. Тем не менее, вы также можете использовать API потоковой передачи, который возвращает соответствующий твит в течение нескольких секунд после его создания. Вот пример использования Filterпотока:

        static async Task DoFilterStreamAsync(TwitterContext twitterCtx)
        {
            Console.WriteLine("\nStreamed Content: \n");
            int count = 0;
            var cancelTokenSrc = new CancellationTokenSource();
    
            try
            {
                await
                    (from strm in twitterCtx.Streaming
                                            .WithCancellation(cancelTokenSrc.Token)
                     where strm.Type == StreamingType.Filter &&
                           strm.Track == "twitter"
                     select strm)
                    .StartAsync(async strm =>
                    {
                        await HandleStreamResponse(strm);
    
                        if (count++ >= 5)
                            cancelTokenSrc.Cancel();
                    });
            }
            catch (IOException ex)
            {
                // Twitter might have closed the stream,
                // which they do sometimes. You should
                // restart the stream, but be sure to
                // read Twitter documentation on stream
                // back-off strategies to prevent your
                // app from being blocked.
                Console.WriteLine(ex.ToString());
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Stream cancelled.");
            }
        }
    

    HandleStreamResponse()Это метод, который вы бы написали для обработки уведомления. Мое предложение заключается в том, что вы используете очередь сообщений или что-то еще, чтобы не блокировать поток, если термин, который вы используете, является трендом или получает высокий трафик. Просто быстро обработайте сообщение.

    Если вы предпочитаете реактивное программирование, вы можете сделать это так:

        static async Task DoRxObservableStreamAsync(TwitterContext twitterCtx)
        {
            Console.WriteLine("\nStreamed Content: \n");
            int count = 0;
            var cancelTokenSrc = new CancellationTokenSource();
    
            try
            {
                var observable =
                    await
                        (from strm in twitterCtx.Streaming
                                                .WithCancellation(cancelTokenSrc.Token)
                         where strm.Type == StreamingType.Filter &&
                               strm.Track == "twitter"
                         select strm)
                        .ToObservableAsync();
    
                observable.Subscribe(
                    async strm =>
                    {
                        await HandleStreamResponse(strm);
    
                        if (count++ >= 5)
                            cancelTokenSrc.Cancel();
                    },
                    ex => Console.WriteLine(ex.ToString()),
                    () => Console.WriteLine("Completed"));
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Stream cancelled.");
            }
        }
    

    Как в сценариях обратного вызова, так и в реактивных сценариях следите за steam, чтобы увидеть, был ли он закрыт (например OperationCancelledException). Затем необходимо создать новый экземпляр потока для повторного запуска. Если это произойдет, следите за последнимTweetID, что вы видели, и используйте REST API для поиска всех твитов между этим и временем запуска нового потока.

    Обновить

    В каждой демонстрации есть HandleStreamResponseметод, который есть async. Вы можете скачать исходный код демо и пройти через него, чтобы получить представление о том, как он работает. По существу, у StreamContentтипа есть EntityTypeсвойство, которое говорит, Какой тип ответа. Поскольку демо в исходном коде используют различные типы потоков, switchинструкция учитывает все возможные типы сообщений. Однако в случае Searchпотока будут только ответыStreamEntityType.Status, которые упростят ваш код, потому что вы можете исключить другие случаи. После того, как тип известен, вы можете просто выполнить преобразование с помощью asоператора на Entityсвойстве likevar status = strm.Entity as Status, а затем запросить status свойства переменных для необходимой информации.

        static async Task<int> HandleStreamResponse(StreamContent strm)
        {
            switch (strm.EntityType)
            {
                case StreamEntityType.Control:
                    var control = strm.Entity as Control;
                    Console.WriteLine("Control URI: {0}", control.URL);
                    break;
                case StreamEntityType.Delete:
                    var delete = strm.Entity as Delete;
                    Console.WriteLine("Delete - User ID: {0}, Status ID: {1}", delete.UserID, delete.StatusID);
                    break;
                case StreamEntityType.DirectMessage:
                    var dm = strm.Entity as DirectMessage;
                    Console.WriteLine("Direct Message - Sender: {0}, Text: {1}", dm.Sender, dm.Text);
                    break;
                case StreamEntityType.Disconnect:
                    var disconnect = strm.Entity as Disconnect;
                    Console.WriteLine("Disconnect - {0}", disconnect.Reason);
                    break;
                case StreamEntityType.Event:
                    var evt = strm.Entity as Event;
                    Console.WriteLine("Event - Event Name: {0}", evt.EventName);
                    break;
                case StreamEntityType.ForUser:
                    var user = strm.Entity as ForUser;
                    Console.WriteLine("For User - User ID: {0}, # Friends: {1}", user.UserID, user.Friends.Count);
                    break;
                case StreamEntityType.FriendsList:
                    var friends = strm.Entity as FriendsList;
                    Console.WriteLine("Friends List - # Friends: {0}", friends.Friends.Count);
                    break;
                case StreamEntityType.GeoScrub:
                    var scrub = strm.Entity as GeoScrub;
                    Console.WriteLine("GeoScrub - User ID: {0}, Up to Status ID: {1}", scrub.UserID, scrub.UpToStatusID);
                    break;
                case StreamEntityType.Limit:
                    var limit = strm.Entity as Limit;
                    Console.WriteLine("Limit - Track: {0}", limit.Track);
                    break;
                case StreamEntityType.Stall:
                    var stall = strm.Entity as Stall;
                    Console.WriteLine("Stall - Code: {0}, Message: {1}, % Full: {2}", stall.Code, stall.Message, stall.PercentFull);
                    break;
                case StreamEntityType.Status:
                    var status = strm.Entity as Status;
                    Console.WriteLine("Status - @{0}: {1}", status.User.ScreenNameResponse, status.Text);
                    break;
                case StreamEntityType.StatusWithheld:
                    var statusWithheld = strm.Entity as StatusWithheld;
                    Console.WriteLine("Status Withheld - Status ID: {0}, # Countries: {1}", statusWithheld.StatusID, statusWithheld.WithheldInCountries.Count);
                    break;
                case StreamEntityType.TooManyFollows:
                    var follows = strm.Entity as TooManyFollows;
                    Console.WriteLine("Too Many Follows - Message: {0}", follows.Message);
                    break;
                case StreamEntityType.UserWithheld:
                    var userWithheld = strm.Entity as UserWithheld;
                    Console.WriteLine("User Withheld - User ID: {0}, # Countries: {1}", userWithheld.UserID, userWithheld.WithheldInCountries.Count);
                    break;
                case StreamEntityType.ParseError:
                    var unparsedJson = strm.Entity as string;
                    Console.WriteLine("Parse Error - {0}", unparsedJson);
                    break;
                case StreamEntityType.Unknown:
                default:
                    Console.WriteLine("Unknown - " + strm.Content + "\n");
                    break;
            }
    
            return await Task.FromResult(0);
        }