Wednesday, March 14, 2012

Setup Tortoise Git and Winmerge


Winmerge has been my favorite diff and merge tool for a long time. I always use Winmerge for those purposes so when I use Tortoise softwares like TortoiseSVN, TortoiseHG, Winmerge always is my first option. Now I prefer same thing with GIT. Unlike TortoiseHG which helps you integrate with Winmerge by 1 single click. TortoiseGIT requires some more steps:

1. For diff tool:

  • Go to Settings
  • Click on Diff Viewer node on the left
  • Enter following line to the textboxes like the picture below. Remember to choose External for the diff tool:

C:\Program Files (x86)\WinMerge\WinMergeU.exe -s -e -x -ul -ur -wl -dl %bname -dr %yname %base %mine

Diff Settings

2. For merge tool:

  • Click on Merge Tool node on the left
  • Enter following line to the textbox like the picture below. Remember to choose External for the merge tool:

C:\Program Files (x86)\WinMerge\WinMergeU.exe %theirs %mine %merged

Merge Settings

Now, enjoy GIT

Cheers

Tuesday, March 6, 2012

Consume Twitter Stream with OAuth in .NET

- Twitter has announced that they're going to abandon the basic username/password authentication. OAuth seems to be the widely supported authentication standard among many big websites. I have dealed with Yahoo OAuth in the past and to be honest, their documentation is not as good as Twitters. Anyway, in my use case, I won't need to build any fancy UI to ask the users whether they allow my application works on their behalf to access their twitter stream. In other words, I won't need to obtain access tokens because I just want to authorize all my stream requests using OAuth and the access tokens are easily obtained from Twitter dev site. Really good job, Twitter.
Now, given that I have got the following tokens from twitter dev site:
  • twitterConsumerKey
  • twitterConsumerSecret
  • twitterAccessToken
  • twitterAccessTokenSecret
What I need to do next is following their awesome document to create the "Authentication" header. And the most important step to have that is generating the oauth_signature.
They have said very clear about the parameters included in the request. I want to say another point about these parameters: If you're sending a post request, all the parameter value also have to be url encoded. My case is quite simple, I'm going to use HttpWebRequest object to send OAuth request to Twitter. POST data will be url encoded and sent once the HttpWebRequest object is created. So I need something to authorise the request, something look like:
public interface IRequestAuthorizer
{
    void Authorize(HttpWebRequest request, string postData);
}

And here is the implementation:
public class OAuthRequestAuthorizer : OAuthBase, IRequestAuthorizer
{
    private readonly string _twitterConsumerKey;
    private readonly string _twitterConsumerSecret;
    private readonly string _twitterAccessToken;
    private readonly string _twitterAccessTokenSecret;

    public OAuthRequestAuthorizer(string twitterConsumerKey, string twitterConsumerSecret, string twitterAccessToken, string twitterAccessTokenSecret)
    {
        _twitterConsumerKey = twitterConsumerKey;
        _twitterConsumerSecret = twitterConsumerSecret;
        _twitterAccessToken = twitterAccessToken;
        _twitterAccessTokenSecret = twitterAccessTokenSecret;
    }

    public override string GenerateNonce()
    {
        return new Nonce().Value;
    }

    private string BuildHeader(HttpWebRequest request, Uri uri)
    {
        var nonce = GenerateNonce();
        var timeStamp = GenerateTimeStamp();
        
        string normalizedUrl;
        string normalizedRequestParameters;
        
        var httpMethod = request.Method;
        var signature = GenerateSignature(uri, _twitterConsumerKey, _twitterConsumerSecret, _twitterAccessToken, _twitterAccessTokenSecret,
                                          httpMethod, timeStamp, nonce, out normalizedUrl,
                                          out normalizedRequestParameters);

        // https://dev.twitter.com/docs/auth/authorizing-request
        return
            string.Format(
                "OAuth oauth_consumer_key=\"{0}\", " +
                "oauth_nonce=\"{1}\", " +
                "oauth_signature=\"{2}\", " +
                "oauth_signature_method=\"HMAC-SHA1\", " +
                "oauth_timestamp=\"{3}\", " +
                "oauth_token=\"{4}\", " +
                "oauth_version=\"1.0\"", 
                
                UrlEncoder.Encode(_twitterConsumerKey), 
                UrlEncoder.Encode(nonce), 
                UrlEncoder.Encode(signature), 
                UrlEncoder.Encode(timeStamp), 
                UrlEncoder.Encode(_twitterAccessToken));
    }

    public void Authorize(HttpWebRequest request, string postData)
    {
        //NOTE: It's a must to collect all param either in the header/querystring or post body
        var baseUri = string.IsNullOrEmpty(postData) || request.Method.ToUpper() == "GET"
                    ? request.RequestUri
                    : new Uri(string.Format("{0}?{1}", request.RequestUri.AbsoluteUri, postData));

        request.Headers["Authorization"] = BuildHeader(request, baseUri);
    }
}

Nonce is a custom class I created to generate the unique nonce. You can make your self this unique value like a GUID or a DateTime tick. OAuthBase is the base class I got from oauth.googlecode.com. This class did a good job to generate the signature based on what you provide. So utilizing this object will give you the "Authorization" value to put to the request header. UrlEncoder static class is extracted from the UrlEncode method in OAuthBase class. If you encode the Post data as mentioned above, Twitter stream and API is your oyster like they said :D.

Here is the demo code to consume the twitter stream:
var postData = "track=" + UrlEncoder.Encode("IPhone,IPad");
var requestContentBuffer = Encoding.UTF8.GetBytes(postData);

var request = (HttpWebRequest)WebRequest.Create(new Uri("https://stream.twitter.com/1/statuses/filter.json"));
request.Method = "POST";
request.ContentLength = requestContentBuffer.Length;
request.ContentType = "application/x-www-form-urlencoded";

request.UserAgent = "OAuthTwitterStream";
request.Headers["Accept-Encoding"] = "deflate, gzip";
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

_requestAuthorizer.Authorize(request, postData);

using (var dataStream = request.GetRequestStream())
{
    dataStream.Write(requestContentBuffer, 0, requestContentBuffer.Length);
}

var apiResponse = (HttpWebResponse) apiRequest.GetResponse();
apiResponseStream = apiResponse.GetResponseStream();

while(true)
{
    var bytesReadCount = apiResponseStream.Read(readBuffer, 0, readBufferSize);
    // Parse Json content
}

I didn't expect the job would be as simple as this because lastime when I tried to consume Yahoo OAuth service, It took me a while to debug since a small mistake while encoding for example would give you the no clue Unauthorized error :D.

Cheers