Read UserStream

Mar 21, 2013 at 9:13 AM
Edited Mar 21, 2013 at 3:47 PM
Hi,

First of all, thanks for this great project! I hope it's being continued for generations :-)
It's a great help for a lot of people.

I'm pretty new to LinqToTwitter and so far got a lot of things running (reading the home feed, reading a users timeline, paging, etc.)

But so far my app polled the Twitter API for the latest tweets on the Homefeed every minute but i read up a bit on the UserStreaming API and decided to use that instead and got the Setup working.

After solving some issues i have the problem, that for some reason the User Stream will only work for one authenticated Account although some Twitter developers say "a handfull" should work.

Currently i'm trying with two authenticated accounts (both can make pull requests).

The Contexts are stored in two different Objects and as soon as the Authentification was successfull i try to register the UserStream but for some reason it will only work for the first Account.
Coordinator
Mar 21, 2013 at 4:30 PM
I'll take a look. One thing you might observe is that the most recent tweet seems to be buffered. Therefore, you might not see any activity until after a couple tweets. I'm still working on this to find out why. However, I just wanted to mention it in case that's what you're seeing.

@JoeMayo
Mar 21, 2013 at 5:07 PM
Thank you so much!

It seems the second Context that is trying to register for its Stream never reaches the anonymous StreamingCallback method therefore the StreamContent stays null.

// I've just found out that the problem must be with the associated account ... event if i try to register only that specific one it won't work.
Would you know the reason for that from the top of your head? (Pulling tweets still works :-/ )
Coordinator
Mar 21, 2013 at 5:11 PM
I'd be interested in knowing why too. Is there a difference in the account settings?
Coordinator
Mar 21, 2013 at 5:34 PM
You might want to review the Twitter User Streams documentation too. In particular, the section titled "Connections" might give you some ideas to compare with your own situation.

@JoeMayo
Mar 21, 2013 at 5:54 PM
Not that i would see, no.

I've tried with a different account, too now - but it won't work either.
Mar 21, 2013 at 6:03 PM
I read that before implementing the Stream and it won't work even with a brand new account - which definitely hasn't reached any limit yet - either.
Can't be an "app-ban" either, because for one account it's working properly.

I receive no Error / Exception either - creating the UserStream without calling the anonymous StreamingCallback work's like a charm.
Coordinator
Mar 21, 2013 at 6:29 PM
Here's a couple settings you might want to try:
twitterCtx.AuthorizedClient.UseCompression = false;
twitterCtx.Log = Console.Out;
The first setting, UseCompression, is because I think I have a problem associated with GZip compression buffering in HttpWebRequest - where the result is that you don't receive a tweet until another tweet comes after it. You can test my doing multiple tweets. The second setting will let you know if any errors are occurring on the stream. LINQ to Twitter tries to reconnect automatically for you, but if you're getting a 401 and it keeps trying to reconnect, then Twitter may block the account for a while. I'm looking at both these issues.

@JoeMayo
Mar 21, 2013 at 7:23 PM
Edited Mar 21, 2013 at 7:26 PM
Is there a way to use TwitterContext.Log in a WinRT Application?

It keeps working for that one account, but none of the others although there is no difference.

I'll post some code - maybe there is an issue I don't see:
// I store the Credentials in PasswordVault and call them on Appstart.
List<myUtils.TwitterCredentials> creds = myUtils.CredentialManager.GetTwitterCredentials();
            if (creds != null && creds.Count != 0)
            {
                foreach (myUtils.TwitterCredentials cred in creds)
                {
                    SingleUserAuthorizer auth = new SingleUserAuthorizer
                    {
                        Credentials = new TemporaryDataCredentials
                        {
                            AccessToken = cred.AccessToken,
                            OAuthToken = cred.OAuthToken,
                            ConsumerKey = APP_KEY,
                            ConsumerSecret = APP_SECRET,
                            UserId = cred.UserID
                        },
                        UseCompression = false,
                    };
                    try
                    {
                        if (auth != null && auth.IsAuthorized)
                        {
                            TwitterContext context = new TwitterContext(auth);
                            OnLogin_Success(context);
                        }
                    }
                    catch (LinqToTwitter.TwitterQueryException ex)
                    {
                        OnLogin_Fail(null);
                    }
                    catch { }
When the Login is Successfull i create a new object of this:
 class TwitterPack : ServicePack
    {
        internal LinqToTwitter.TwitterContext Context { get; private set; }

        public TwitterPack(LinqToTwitter.TwitterContext context)
        {
            this.ClientID = (context.AuthorizedClient as LinqToTwitter.OAuthAuthorizer).Credentials.UserId;
            this.HomeFeed = new TwitterFeed(context, ClientID);
            this.Context = context;
            Task.Run(() => this.RefreshTask());
        }

        private StreamContent stream = null;

        private async void RefreshTask()
        {
            int timeWaited = 0;
            try
            {
                var iStream = (from strm in this.Context.UserStream
                           where strm.Type == UserStreamType.User
                           select strm).StreamingCallback(strm =>
                           {
                               if (strm.Status == TwitterErrorStatus.RequestProcessingException) return;
                               stream = strm;
                               if (!string.IsNullOrEmpty(strm.Content))
                               {
                                   string streamContent = strm.Content;
                                   GetLatestFeed(streamContent);
                               }
                           }).SingleOrDefault();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
            }
            while (stream == null)
            {
                await Task.Delay(1000);
                timeWaited++;
            }
        }

        CoreDispatcher Dispatcher = App.Current.Resources.Dispatcher;
        public async void GetLatestFeed(string streamContent)
        {
            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                                {
                                    List<Status> latestStatusList = TwitterStatus.CreateStatusFromStreamContent(this.Context, this.ClientID, streamContent);
                                    OnFeedReceived(latestStatusList);
                                });
        }
Coordinator
Mar 22, 2013 at 3:57 AM
Your code looks okay to me. I just checked in an update that turns off compression for UserStreams. I discovered that Twitter is sending posts, but they're being buffered by gzip logic somewhere in HttpWebRequest/HttpWebResponse. I'll have to write code to do this manually later. This may or may not be related to your problem, but it was something that needed to be addressed. Maybe download the latest source and see if it helps.

I also saw another problem where some HTTP errors were being processed undetected. I'll work on that one either tomorrow or this weekend. In the meantime, you can hook up to TwitterContext.Log to see if that might be the problem on some of your other accounts. The Log property is a TextWriter, so you can use a TextWriter derived type in the .NET class library or create your own type that derives from TextWriter and sends output to the destination of your choice.

My suggestion though would be to resolve the stream problems in a console application first, perhaps using my streaming demo code in the downloadable source code. It might be much quicker and better to isolate the issues before moving to the more complex scenario of your Windows 8 app.

@JoeMayo
Mar 22, 2013 at 9:03 AM
Edited Mar 22, 2013 at 6:52 PM
Hi,

In the ConsoleApp it works well for 2 Accounts - a third one just won't ever get into the CallbackMethod either.
In my WinRT App i hooked up a TextWriter to the TwitterContext.Log Property but there is no output for UserStream at all (only the regular calls the app makes to populate the HomeFeeds)

The Result of the Console Application is, that the first two authorized contexts that register a UserStream work - the third one won't.
// In WinRT it works for the first two connecting now, too. Is there a reason why the third one's UserStream doesn't work?

// I now got following error:

Query:Unhandled exception in your StreamingCallback code. System.NullReferenceException: Object reference not set to an instance of an object.
at LinqToTwitter.TwitterExecute.InvokeStreamCallback(Object content)