Archive

Posts Tagged ‘Perl’

Twitter Opens up OAuth, Where’s Perl?

March 23rd, 2009 Pankaj Comments

Twitter opened up their OAuth implementation last week. It's a much welcome aspect of working with Twitter's API since we're planning on implementing some functionality into Semblr that uses Twitter. Hence, understanding OAuth and prototyping it's use was important for us.

My problem with Twitter's implementation is that the documentation is sparse and there isn't a single example in Perl or Java. Maybe these two languages aren't cool enough to warrant examples but to me, they're important because they're all I know. I spent some time over the last few days trying to implement OAuth for Twitter in my Perl scripts. The example below is a bit messy but it works.

It will create a few temp files, request a token for you, ask you to go to the URL printed to authorize the application. When you've authorized the application, run the script again and it will allow you to submit a status update.

#! /usr/local/bin/perl
# $Author: pankaj $
# $Date: 2009-03-22 23:46:27 +0530 (Sun, 22 Mar 2009) $
# Author: Pankaj Jain
# Copyright: Teknatus Solutions LLC
################################################################################################################################
use Modern::Perl;
use Carp;
use Net::OAuth;
use Data::Random qw(rand_chars);
use LWP::UserAgent;
use Data::Dumper;
use JSON::Any;

main();

sub main{
    my $ua = LWP::UserAgent->new;

    my $consumer_key = 'sdBwlvTkpZr7eiCmB0Evig';
    my $consumer_secret = 'asSINZmwnxwIfLwmdNvVBW7OSVzFOWj4mjJeDDaA';
    my %tokens = getTokens();

    requestToken(consumer_key => $consumer_key,
                 consumer_secret => $consumer_secret,
                 %tokens,
                 ua => $ua);

    my $message = "This is a Perl Net::OAuth test for twitter!";
    my $foo = {status => $message};
    my $url = 'https://twitter.com/statuses/update.json';
    if (defined $message && $message ne "") {
        my $request = Net::OAuth->request("protected resource")->new(
            consumer_key => $consumer_key,
            consumer_secret => $consumer_secret,
            request_url => $url,
            request_method => 'POST',
            signature_method => 'HMAC-SHA1',
            timestamp => time,
            nonce => join('', rand_chars(size=>16, set=>'alphanumeric')),
            token => $tokens{token},
            token_secret => $tokens{secret},
            extra_params => $foo,
        );
        $request->sign;
        say Dumper($request);
        my $response = $ua->post($request->to_url);
        say Dumper($response);
        my $response_code    = $response->code;
        my $response_message = $response->message;
        my $response_error   = $response->content;
        if ($response->is_success) {
            my $retval = eval { JSON::Any->jsonToObj( $response->content ) };
            if ( !defined $retval ) {
                say "TWITTER RETURNED SUCCESS BUT PARSING OF THE RESPONSE FAILED - " . $response->content;
            }
        } else {
            say $response_code;
        }
        exit;
    }
}


sub requestToken {
    my %args = @_;
    if (defined $args{consumer_key} && defined $args{consumer_secret} && 
            !defined $args{access_token} && !defined $args{access_secret} && 
            !defined $args{token} && !defined $args{token_secret}) {
        my $token;
        my $secret;
        my $request = Net::OAuth->request("consumer")->new(
            consumer_key => $args{consumer_key},
            consumer_secret => $args{consumer_secret},
            request_url => 'https://twitter.com/oauth/request_token',
            request_method => 'GET',
            signature_method => 'HMAC-SHA1',
            timestamp => time,
            nonce => join('', rand_chars(size=>16, set=>'alphanumeric'))
        );
        $request->sign;
        my $res = $args{ua}->get($request->to_url); # Post message to the Service Provider
        if ($res->is_success) {
            my $response = Net::OAuth->response('request token')->from_post_body($res->content);
            print "Got Request Token ", $response->token, "\n";
            $token = $response->token;
            print "Got Request Token Secret ", $response->token_secret, "\n";
            $secret = $response->token_secret;
            if (defined $token) {
                my $auth_url = "https://twitter.com/oauth/authorize?oauth_token=" . $token;
                my $message = "Please visit $auth_url and authorize this application to access your twitter account.  You may revoke access at any time you wish.\n";
                say $message . "\n";
                open(TMP,">/tmp/request_token.txt");
                say TMP $token . "|" . $secret;
                close TMP;
                exit;
            }
        } else {
            die "Something went wrong";
        }
    } elsif (defined $args{access_token} && defined $args{access_secret} && 
            defined $args{consumer_key} && defined $args{consumer_secret} && 
            !defined $args{token} && !defined $args{token_secret}) {
        my $auth_req = Net::OAuth->request("access token")->new(
            consumer_key => $args{consumer_key},
            consumer_secret => $args{consumer_secret},
            token => $args{access_token},
            token_secret => $args{access_secret},
            request_url => 'http://twitter.com/oauth/access_token',
            request_method => 'POST',
            signature_method => 'HMAC-SHA1',
            timestamp => time,
            nonce => join('', rand_chars(size=>16, set=>'alphanumeric'))
        );
        $auth_req->sign();
        my $res2 = $args{ua}->post($auth_req->to_url); # Post message to the Service Provider
        if (!$res2->is_success) {
            die 'Could not get an Access Token: ' . $res2->status_line . ' ' . $res2->content;
        } else {
            open(TF, ">$ENV{HOME}/.teknatus/.twitter_token");
            my $response = Net::OAuth->response('access token')->from_post_body($res2->content);
            print STDERR "Got Access Token ", $response->token, "\n";
            my $access_tok = $response->token;
            print STDERR "Got Access Token Secret ", $response->token_secret, "\n";
            my $access_secret = $response->token_secret;
            say TF $access_tok . "|" .$access_secret;
            close TF;
            unlink("/tmp/request_token.txt") if (-e "/tmp/request_token.txt");
        }
        exit;
    }
}

sub getTokens {
    my %args = @_;
    my %tokens;
    my $tokenFile = $ENV{HOME} ."/.teknatus/.twitter_token";
    my $reqTokenFile = "/tmp/request_token.txt";
    if (-e $tokenFile ) {
        open (TF, "<$tokenFile");
        while() {
            chop($_);
            next if ( $_ =~ /^\s?$/);
            my @tmp = split(/\|/, $_);
            $tokens{token} = $tmp[0];
            $tokens{secret} = $tmp[1];
        }
        close TF;
    }
    if (-e $reqTokenFile) {
        open (TF, "<$reqTokenFile");
        while() {
            chop($_);
            next if ( $_ =~ /^\s?$/);
            my @tmp = split(/\|/, $_);
            $tokens{access_token} = $tmp[0];
            $tokens{access_secret} = $tmp[1];

        }
        close TF;
    }
    return %tokens;
}

1;

MySQL 64bit, Perl 32bit and OS X Leopard

December 26th, 2008 Pankaj Comments

This is a little tip on how to get Perl(32bit) working with a 64bit version of MySQL on OS X Leopard.

I was working on a small project today that required MySQL 5.067 and I opted to do it in Perl 5.10. You may remember a post that I put up in August describing how to compile MySQL 64 bit for OS X Leopard. Well, since then I also compiled and installed Perl 5.10 (not replacing Apple’s system install of Perl). I wanted to take advantage of some of the Perl 6 features that have been backported to Perl 5.10 (the first Perl release in two years).

Back to today’s project, I decided to use the awesome Class::DBI Perl module to do my little project. I wrote all my code and began to run it in the perl debugger and realized that I need to install the DBD::mysql module. During the installation process for DBD::mysql, the Perl module is compiled using the mysql libraries and header files. Compilation wasn’t a problem. It’s when we got to the ‘make test’ step that all hell broke loose.

To cut a very long story short, I kept getting the error below:


# Failed test 'use DBD::mysql;'
# at t/00base.t line 21.
# Tried to use 'DBD::mysql'.
# Error: Can't find 'boot_DBD__mysql' symbol in /Users/pankaj/.cpanplus/5.10.0/build/DBD-mysql-4.010/blib/arch/auto/DBD/mysql/mysql.bundle

I dug around a bit and decided to run the installation manually. The problem here has to do with compiler flags that were used for mysql. MySQL was compiled as a 64 bit Leopard binary. However, Perl 5.10 was compiled as a 32bit binary because many Perl modules don’t support 64 bit out of the box.

To solve the problem, I had to recompile the mysql client libraries:


--($:~/src/mysql-5.0.67)-- export ARCHFLAGS="-arch i386"
--($:~/src/mysql-5.0.67)-- CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors \
-fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql.32 --without-server --with-extra-charsets=complex --enable-thread-safe-client --enable-local-infile --enable-shared
--($:~/src/mysql-5.0.67)-- make
--($:~/src/mysql-5.0.67)-- make test
--($:~/src/mysql-5.0.67)-- sudo make install

Once the mysql client libs were done compiling and installed into /usr/local/mysql.32, I changed my PATH to ensure that the newly compiled mysql libraries and binaries were picked up before anything else.


export PATH=/usr/local/mysql.32/bin:${PATH}

Once that was done, I went back to my DBD::mysql source directory and built it using the following commands:


--($:~/src/DBD-mysql-4.010)-- perl Makefile.PL --libs="-L/usr/local/mysql.32/lib/mysql -lmysqlclient -lz -lm" --cflags="-I/usr/local/mysql.32/include/mysql"
--($:~/src/DBD-mysql-4.010)-- make
--($:~/src/DBD-mysql-4.010)-- make test
--($:~/src/DBD-mysql-4.010)-- sudo make install

This time, make test ran beautifully with a few minor exceptions because I didn’t actually give it a mysql db to connect to.

The mysql 32bit client can easily connect to the 64 bit server. Perl, Class:DBI are now very happy and the application is running as planned.

Recent Posts at Teknatus

October 27th, 2008 Pankaj Comments

Perl for Beginners at BarCamp Delhi

October 13th, 2008 Pankaj Comments

Yesterday at BarCamp Delhi Prateek and Pratul decided to hold a hack-a-thon. The idea being, that in 2 to 3 hours, the group of programmers assembled would hack together some application. Some of the ideas thrown around were:

  • A Firefox Plugin
  • A Firefox Greasemonkey Extension
  • A manufacturing, logistical support web app

Pratul and Prateek probably have a more complete list than I do. The hack-a-thon broke apart into a few groups, each doing something different. No applications were built but a few Windows programmers were interested enough that I spent about 20 minutes showing them a few "Hello World" Perl scripts.

I've attached the Perl scripts for the folks who asked for them and any others that might be interested. Also, if anyone is interested in learning Perl, I highly recommend this book. It says 21 days to learn Perl but most of you will probably pick it up in less than a week.

Unfortunately, the extensions of the files are being changed to .txt so please take off the .txt once you download the files. I'm also putting the scripts inline.

hello.pl: A simple Hello World script


#! /usr/bin/perl

use warnings;
use strict;

my $name = "Pankaj";
print "Hello $name.\n";


hello2.pl: A "Hello World" script that uses a very simple Perl module (below)


#! /usr/bin/perl

use warnings;
use strict;

use lib("../lib");
use Hello;

my $name = "Pankaj";
Hello::hello($name);


Please put the Hello.pm in a relative path to where you put hello2.pl as described in "use lib" line above in hello2.pl.

Hello.pm Our very simplistic Perl module


package Hello;

sub new {
}

sub hello{
my $name = $_[0];
print "hello " . $name;
} #
# ------------------------------------------------------------
1;


And our final example that one of the campers asked for was a Perl script that would take input from the command line interactively.

hello3.pl: Our final "Hello World" script that interactively asks for names on the command line.


#! /usr/bin/perl

use warnings;
use strict;
use Getopt::Long;
use Term::ReadLine;

my $foo;
my @bar;

GetOptions("foo=i" => \$foo);

my $count = 0;
my $term = Term::ReadLine->new();

while ($count < $foo) {
my $line = $term->readline("What is your name? ");
$bar[$count] = $line;
$count++;
}

foreach my $f (@bar) {

print "bar is $f\n";
}


We didn't get to it but would one of the campers like to take one of these scripts and turn them into a CGI script or a mod_perl application? Please post your changes in a comment to this post.
Cheers

Perl, PHP, Ruby, and Java Programmers Wanted

December 18th, 2007 Pankaj Comments

I am looking for Perl, PHP, Ruby, and Java Programmers looking to join a brand new startup, right at the ground level, here in New Delhi. Of course, all work will be done on either Linux or OS X, so some experience with *nix is important. If you fit the ticket or know of anyone who does, please drop me a comment or an email. I’d love to hear from all of you.

Categories: Delhi, India, New Delhi Tags: , , , , ,

LinOSX TechnoMash is Digg proof thanks to caching by WP Super Cache!