I've been trying to work on my pet today and this coming week since my free time is about to be gobbled up by my new job. But I'm running into the same problem I was last time I almost gave up with the project. Here's a rundown.
The program receives stimulus from any number of inputs. The dispatcher breaks this down into three simple variables:
my ($thischan, $thisuser, $thismsg) = (@_);
This way, no matter what our output method is (or where our data came from), or even what language our code is written in, we have a very smooth API for how to process data. At present we have about 55 modules responding in this API. However, some of them take a long time. Herein lies the crux of the problem. IRC wants you to respond to pings every N interval (I think its 60 seconds). Some of these modules are:
select_map.pm: allows free-form database queries slashdot.pm: grabs slashdot headlines, greps for older stories on request. shorten.pm: uses's metamark's url shortening service translation.pm: attempts to translate text via babelfish market.pm: all kinds of stock market quotes and the ability to track a portfolio
Sometimes yahoo's quote service times out. Sometimes metamark is down. Sometimes, I want to run a query like:
Normally, I'd like petunia to run off and grab the quote for Apple, and then say hello. But in this case, she actually has to form the LWP agent, make the request of yahoo's servers, scrape it, and reply. What if yahoo is down? Then the bot never comes back from "last", and the server disconnects her. So what we're looking for is this:
&c: wha? he can code? I thought all he did was whine about not having a job!
select count(quip) from log
where substr( date_trunc( 'day', stamp ), 1, 10 ) = substr( date_trunc( 'day', now() ), 1, 10 )
and channel = lower( ? )
which might take more than a minute to run. So here is how I'm doing it presently: foreach my $module (@modules) {
$module -> run( @args );
}
Each module has a set of "trigger" subroutines. It runs through them to see if it has seen anything it wants to reply to, and then replies if it does. If not, it doesn't, and it really doesn't take much time to make that choice. However, Imagine this interaction: :last AAPL Hello, petunia!
Normally, I'd like petunia to run off and grab the quote for Apple, and then say hello. But in this case, she actually has to form the LWP agent, make the request of yahoo's servers, scrape it, and reply. What if yahoo is down? Then the bot never comes back from "last", and the server disconnects her. So what we're looking for is this:
eval 'undef &utility::spew';
eval '*utility::spew = \&async_spew';
foreach my $module (@modules) {
$module -> run( @args );
}
sub async_spew {
# shovel data to the kernel
my $filter = POE::Filter::Reference->new();
my %result = ( spew => [@_] );
my $output = $filter->put( [ \%result ] );
}where spew() was her original output handler, and async_spew() now runs in its own little POE container. I'm having problems, though with POE forking them off, and no longer having access to critical variables. Like the global %config hash, and the $dbh that I had originally passed them. I'm almost getting to the point where a rewrite is necessary, and I really hate to do that.
&c: wha? he can code? I thought all he did was whine about not having a job!