Implementing the Twitter streaming API in Perl, nothing gets printed - perl

I am trying to use the Twitter streaming API to demo tweets in the console but nothing is being printed on screen at the moment. I am using the AnyEvent::Twitter::Stream package to do so, I have taken the OAuth example contained on that page and edited it slightly:
#!/usr/local/bin/perl -w
use AnyEvent::Twitter::Stream;
# to use OAuth authentication
my $listener = AnyEvent::Twitter::Stream->new(
consumer_key => "my_consumer_key",
consumer_secret => "my_consumer_secret",
token => "my_token",
token_secret => "my_token_secret",
method => "sample",
api_url => "https://stream.twitter.com/1.1/statuses/sample.json",
track => "apple",
on_tweet => sub {
my $tweet = shift;
print "$tweet->{user}{screen_name}: $tweet->{text}\n";
},
);
I was expecting this to print to stdout all tweets mentioning "apple", but when I execute this code, the script exits immediately and I am back to the shell. I was kind of expecting this to keep running and keep printing messages to stdout. Have I misunderstood how this works?

You may want to check out the provided example:
http://cpansearch.perl.org/src/MIYAGAWA/AnyEvent-Twitter-Stream-0.27/eg/track.pl
It involves creating an AE::cv object, and, after setting up the Twitter stream listener, calling recv on that object so that it actually loops waiting for data.

Related

perl jira rest api port number

my $jira = JIRA::REST->new({
url => 'https://something.com:8443',
username => 'username',
password => 'password',
session => 1,
});
The above code doesn't work and fails with below error probably due to port number at the end
Can't connect to something.com:8443 (Bad file descriptor)
is there a way/variable to mention the port number?
You need to add the setting ssl_verify_none => 1 into the hash used in your constructor.
The underlying LWP code allows you to not verify the certs of systems you connect to (which is not recommended for production), or it also allows you to specify a Certificate Authority (CA) cert that can be used to verify certs of systems you connect to. It looks like JIRA::REST has only supported the first option.
You might be better off just using the underlying LWP code, like this:
use LWP::UserAgent;
my $ua = LWP::UserAgent->new(
ssl_opts => { verify_hostname => 1, SSL_ca_file => 'myCA.cer' },
protocols_allowed => ['https'],
);
my $req = HTTP::Request->new(
GET => 'https://something.com:8443/rest/api/latest/issue/ABC-123',
);
$req->authorization_basic('username','password');
my $res = $ua->request($req);
It looks like JIRA::REST is just providing the raw JSON response to you anyway, so it's not really saving you all that much processing.
The main advantage of REST::Client is that it saves some stuff for you to add to each request implicitly. There's nothing particularly REST-y or helpful beyond sending a request and giving its response back to you.
The JIRA::Client has a few advantages, though, since it knows how to get a session cookie and properly attach files, and, more importantly, deal with paginated results. But often, when I'm doing things with Jira, I want more power.
Back in LWP's heyday, it was very frustrating to track transactions: a request-response pair. You could, but you had to manage it yourself. And, there weren't hooks in the process, so you had to create everything every time.
Then, LWP tried to work around some SSL issues (verifying host names, etc) and also split out LWP::Protocol::https. That's not a big deal when you understand that, but even though I do, it's something I have to remember every time I want to use LWP for something. There are reasons for everything that happened, but that doesn't make it any less annoying. That leads to the sort of work jimtut showed in his answer. Every time. But, it's a small speed bump on the way to insecurity.
I like Mojolicious much more because it represents complete transactions but also has hooks (well, events) that allow you to fiddle with things automatically while the process is chugging along.
Here's an example from Mojo Web Clients that shows me creating a user-agent for each service and setting some stuff for each transaction. I can adjust the request any way that I please before it does its work (and this is mostly what that REST::Client and JIRA::Client are doing for you):
my $travis_ua = Mojo::UserAgent->new();
$travis_ua->on( start => sub {
my( $ua, $tx ) = #_;
$tx->req->headers->authorization(
"token $ENV{TRAVIS_API_KEY}" );
$tx->req->headers->accept(
'application/vnd.travis-ci.2.1+json' );
} );
my $appveyor_ua = Mojo::UserAgent->new();
$appveyor_ua->on( start => sub {
my( $ua, $tx ) = #_;
$tx->req->headers->authorization(
"Bearer $ENV{APPVEYOR_API_KEY}" );
} );
In the Basic auth case, it's just a different value in that header:
use Mojo::Util qw(b64_encode);
my $jira_ua = Mojo::UserAgent->new();
$jira_ua->on( start => sub {
my( $ua, $tx ) = #_;
$tx->req->headers->authorization(
'Basic ' . b64_encode( join ':', $username, $password ) );
} );
Now, when I use those user-agents, the auth stuff is automatically added:
my $tx = $travis_ua->get( $url );
And, that $tx gives me access to the request and the response, so I don't need REST::Client to handle that for me either.
Since Mojolicious is handling all of this in one convenient package, I don't have to wrangle different objects. As such, there's not much left over that REST::Client can do for me.

Perl Mojolicious routes call sub only once

Iam using Mojolicious::Lite to declare routes for a webservice.
Maybe i missunderstood the routes behaviour but if iam calling a subroutine in the routes definition it gets only called once.
I thougt the sub should get triggered every time the webservice route is called... which isn't the case.
For example i wrote a test route:
use Mojolicious::Lite;
get '/test' => {
text => get_test()
};
sub get_test {
say 'Hello iam only showing up once';
return 'test';
};
This is the console output on starting the server and visiting the localhost:3000/test route:
Hello iam only showing up once
[2020-04-04 22:07:21.09011] [69050] [info] Listening at "http://*:3000"
Server available at http://127.0.0.1:3000
[2020-04-04 22:07:28.26033] [69050] [debug] [78278b87] GET "/test"
[2020-04-04 22:07:28.26097] [69050] [debug] [78278b87] 200 OK
(0.000626s, 1597.444/s)
The "Hello iam only showing up once" is outputted once as the server starts. Visiting the route is not triggering the sub again.
If this is the wanted behaviour how can i get my routes to triggering the sub everytime the route is visited?
I need this because i use this webservice in my application to scan the network and return the result. And i want to rescan the network everytime i call the webservice GET route. Otherwise the data would be useless if its not up to date.
Thanks for your help and explanations.
Your code isn't actually rendering. Your get sub needs to call the render method from Mojolicious::Controller. Inside the get sub, $_[0] is an instance of the controller. In a Mojolicious::Lite app, the route and controller are combined, so you do need to render. If you change your code to this, it will do what you might expect.
use Mojolicious::Lite;
get '/test' => sub {
shift()->render(text => get_test());
};
sub get_test {
warn "Hello I show up on every hit.\n";
return 'test';
};
The key difference is the shift()->render(...) call, which could also be written like this:
get '/test' => sub {
my $c = shift;
$c->render(text => get_text());
}
The above answer is good, but one of the key problems in your code is that you seem to have incorrectly defined your route code ref:
get '/test' => {
should be:
get '/test' => sub {
This is why your get_test only gets called once - you are defining a hash and populating it with the result of get_test, instead of defining a subroutine. But see #DavidO's answer for the full detail on how to approach this.

How can I see all active sessions in a Mojolicious Lite app?

I'm building an app with Mojolicious Lite and I'm looking to give myself a way to watch any and all data about the active sessions. I'm mostly doing this because this is my first foray into using sessions with Mojolicious Lite, and I want to watch what's going on under the hood.
A couple notes:
I'm pretty new to Mojolicious, as you might guess by the fact that I'm using Mojolicious Lite. Any Mojolicious Lite apps I've written before have been pretty trivial, so my familiarity with it is not deep.
For that matter, I'm still 'early intermediate, at best' with perl, so poking around the inner workings of anything OO in perl is largely foreign territory for me.
That said, I made myself a few little routes like so:
get '/firstpage' => sub{
my $self = shift;
my $usr = $self->session(user => 'first_user');
$self->render(text => $usr);
};
get '/secondpage' => sub{
my $self = shift;
my $usr = $self->session(user => 'second_user');
$self->render(text => $usr);
};
get '/sessions' => sub{
my $self = shift;
$self->render(text => Dumper(app->sessions));
};
I'm working off the assumption that, after I visit the first two urls, Mojolicious will have 'some' data somewhere that would confirm that it knows about first_user and second_user. (I could also be totally off base in my understanding of how to use Mojolicious Lite sessions...honestly, from the documentation, I'm not really sure.)
Sadly, /sessions just shows me the contents of the Mojolicious::Sessions object:
$VAR1 = bless( {
'cookie_path' => '/',
'secure' => 0,
'cookie_name' => 'mojolicious',
'default_expiration' => 3600
}, 'Mojolicious::Sessions' );
But I'm assuming that, somewhere, I can get to a hash of all of the session-related data that Mojolicious has. I've been poking around the documentation for a while but I have yet to find any leads.
Any insight?
I'm working off the assumption that, after I visit the first two urls, Mojolicious will have 'some' data somewhere that would confirm that it knows about first_user and second_user. (I could also be totally off base in my understand of how to use Mojolicious Lite sessions...honestly, from the documentation, I'm not really sure.)
Yeah, I think you're missing the point of sessions. The server/app doesn't remember the state of every user who visits. To allow it to look as if it did, we have cookies. A session is a per-client persistence thing.
Session information is just a hashreference, encoded as JSON and stored in a cookie on the client side. This is useful for remembering that you are logged in, as what username, perhaps an arrayref of things in your shopping cart. When you request a page, this cookie is sent back to the server, which can access the data and prepare the response for you knowing the state of your session.
As such there is no record of "active sessions". All that information is distributed amongst all the clients.
If you would like to get a better idea of what's going on, may I recommend tempire's plugin Mojolicious::Plugin::ConsoleLogger which for the current request shows all of the relevant information (session, stash etc) in your browser's javascript console.
Here is an example.
#!/usr/bin/env perl
use Mojolicious::Lite;
#plugin 'ConsoleLogger'; # if desired
any '/' => sub {
my $self = shift;
my $name = $self->session('name') || 'Unknown'; # get the name from the session
$self->render( text => "Hello $name" );
};
any '/name/:name' => sub {
my $self = shift;
my $name = $self->stash('name'); # get name from path
$self->session( name => $name ); # and store it in the session
$self->redirect_to('/');
};
any '/logout' => sub {
my $self = shift;
$self->session( expires => 1 );
$self->redirect_to('/');
};
app->start;
If you visit /name/ghorahn it will store your name in a cookie. From then on, every time you visit / it will say hello to you until:
Your session expires (default 1 hour from your last visit)
You change your name via /name/whatever
You visit /logout to manually expire the session
You will notice that another user (either on another computer or even a different browser on your same computer) may have a different name, but both are persistent. That is what a session is for. :-)

Perl SOAP::Lite and Service Description to Request Object

I'm using Perl's SOAP::Lite to access a remote web service defined by a WSDL. That means I have:
use strict;
use Data::Dumper;
use SOAP::Lite +trace => 'debug';
my $service = SOAP::Lite->service('http://path/wsdl');
Ok so far. Problem is that I need access to the HTTP::Request object to send along custom HTTP request headers (and I'm not talking about authentication headers). It looks like I can access the request object after doing a successful call:
my $result = $service->getClient('parameters');
print Dumper($service->transport->http_request);
That'll give me the correct HTTP::Request object:
$VAR1 = bless( {
'_content' => '',
'_uri' => undef,
'_headers' => bless( {}, 'HTTP::Headers' ),
'_method' => undef
}, 'HTTP::Request' );
If I try to access the request object before doing an autoDispatch (the $service->getClient part), the transport object is empty and I have no way of modifying the request. It seems like everything would work fine if I were going the SOAP::Lite->proxy way -- but that defeats the helpfulness of having a pre-defined service definition.
Any ideas how I'm suppose to access the request object from a service definition without first having to make a call? Chicken and egg problem really...
Thanks!
What I'm trying to accomplish is populating the transport before doing a service call.
And you do exactly that by adding the appropriate handler, because the transport is not empty
Add a handler to the transport, see LWP::Debug for example, see LWP::UserAgent for documentation, or perlmonks.org/?node_id=904166 for example

How do I use Perl's LWP to log in to a web application?

I would like to write a script to login to a web application and then move to other parts
of the application:
use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
use Data::Dumper;
$ua = LWP::UserAgent->new(keep_alive=>1);
my $req = POST "http://example.com:5002/index.php",
[ user_name => 'username',
user_password => "password",
module => 'Users',
action => 'Authenticate',
return_module => 'Users',
return_action => 'Login',
];
my $res = $ua->request($req);
print Dumper(\$res);
if ( $res->is_success ) {
print $res->as_string;
}
When I try this code I am not able to login to the application. The HTTP status code returned is 302 that is found, but with no data.
If I post username/password with all required things then it should return the home page of the application and keep the connection live to move other parts of the application.
You may be able to use WWW::Mechanize for this purpose:
Mech supports performing a sequence of page fetches including following links and submitting forms. Each fetched page is parsed and its links and forms are extracted. A link or a form can be selected, form fields can be filled and the next page can be fetched. Mech also stores a history of the URLs you've visited, which can be queried and revisited.
I'm guessing that LWP isn't following the redirect:
push #{ $ua->requests_redirectable }, 'POST';
Any reason why you're not using WWW::Mechanize?
I've used LWP to log in to plenty of web sites and do stuff with the content, so there should be no problem doing what you want. Your code looks good so far but two things I'd suggest:
As mentioned, you may need to make the requests redirectable
You may also need to enable cookies:
$ua->cookie_jar( {} );
Hope this helps