File Coverage

blib/lib/App/Twirc.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package App::Twirc;
2             $App::Twirc::VERSION = '0.18'; # TRIAL
3 1     1   2969 use Moose;
  1         307126  
  1         8  
4 1     1   5277 use Config::Any;
  1         5835  
  1         36  
5 1     1   243 use POE qw/Loop::AnyEvent Wheel::ReadWrite/;
  0            
  0            
6             use AnyEvent::Twitter;
7             use POE::Component::Server::Twirc;
8             use Proc::Daemon;
9             use Path::Class::File;
10             use Log::Log4perl qw/:easy/;
11              
12             with 'MooseX::Getopt',
13             'MooseX::Log::Log4perl::Easy';
14              
15             has configfile => (
16             metaclass => 'Getopt',
17             cmd_aliases => 'c',
18             isa => 'Str',
19             is => 'ro',
20             documentation => 'configration file name',
21             );
22              
23             has background => (
24             metaclass => 'Getopt',
25             cmd_aliases => 'b',
26             isa => 'Bool',
27             is => 'ro',
28             documentation => 'run as daemon',
29             );
30              
31             has authenticate => (
32             metaclass => 'Getopt',
33             cmd_aliases => [qw/a auth/],
34             isa => 'Bool',
35             is => 'ro',
36             default => 0,
37             documentation => 'force Twitter authentication',
38             );
39              
40             has state_file => (
41             metaclass => 'Getopt',
42             cmd_aliases => 's',
43             isa => 'Str',
44             is => 'ro',
45             predicate => 'has_state_file',
46             documentation => 'state file name',
47             );
48              
49             has debug => (
50             metaclass => 'Getopt',
51             cmd_aliases => 'd',
52             isa => 'Bool',
53             is => 'ro',
54             default => 0,
55             documentation => 'set logging level to DEBUG',
56             );
57              
58             sub run {
59             my $self = shift;
60              
61             my $config;
62             if ( my $file = $self->configfile ) {
63             $config = Config::Any->load_files({ files => [ $file ], use_ext => 1 });
64             $config = $config->[0]{$file};
65             }
66              
67             # override/provide config options from the commandline
68             $$config{state_file} = $self->state_file if $self->has_state_file;
69             $$config{log_level} = 'DEBUG' if $self->debug;
70              
71             Log::Log4perl->easy_init({
72             layout => '%d{HH:mm:ss} [%p] %m%n',
73             level => $$config{log_level} && eval "\$$$config{log_level}" || $WARN,
74             });
75              
76             # Make sure state_file is absolute before we background (which does a cd /).
77             $$config{state_file} = Path::Class::File->new($config->{state_file})->absolute->stringify
78             if $$config{state_file};
79              
80             my $state = $$config{state_file} && -r $$config{state_file}
81             ? POE::Component::Server::Twirc::State->load($$config{state_file})
82             : POE::Component::Server::Twirc::State->new;
83              
84             $self->oauth_handshake($state, $$config{sate_file}) if $self->authenticate || !$state->access_token;
85              
86             if ( $self->background ) {
87             Proc::Daemon::Init;
88             POE::Kernel->has_forked;
89             }
90             else {
91             eval 'use POE qw(Component::TSTP)';
92             die "$@\n" if $@;
93             }
94              
95             $config->{plugins} = $self->_init_plugins($config);
96             POE::Component::Server::Twirc->new(%{$config || {}}, state => $state);
97             POE::Kernel->run;
98             }
99              
100             sub oauth_handshake {
101             my ( $self, $state, $state_file ) = @_;
102              
103             my %consumer = POE::Component::Server::Twirc->_twitter_auth;
104              
105             my ( $wheel, $oauth );
106             POE::Session->create(
107             inline_states => {
108             _start => sub {
109             my $cb = $_[SESSION]->postback('get_pin');
110             my $w; $w = AnyEvent::Twitter->get_request_token(
111             %consumer,
112             callback_url => 'oob',
113             cb => sub { $cb->(@_); undef $w }
114             );
115             },
116             get_pin => sub {
117             my ( $url, $r, $body, $header ) = @{ $_[ARG1] };
118             $oauth = $r;
119             $wheel = POE::Wheel::ReadWrite->new(
120             InputHandle => \*STDIN,
121             OutputHandle => \*STDOUT,
122             InputEvent => 'got_pin'
123             );
124             print "Authorize twirc at $url\nThen, enter the PIN# provided: ";
125             },
126             got_pin => sub {
127             undef $wheel;
128             my $pin = $_[ARG0];
129             my $cb = $_[SESSION]->postback('got_access_token');
130             my $w; $w = AnyEvent::Twitter->get_access_token(
131             %consumer,
132             oauth_token => $$oauth{oauth_token},
133             oauth_token_secret => $$oauth{oauth_token_secret},
134             oauth_verifier => $pin,
135             cb => sub { $cb->(@_); undef $w }
136             );
137             },
138             got_access_token => sub {
139             my ( $r, $body, $header ) = @{ $_[ARG1] };
140             $state->access_token($$r{oauth_token});
141             $state->access_token_secret($$r{oauth_token_secret});
142             $state->store($state_file) if $state_file;
143             },
144             },
145             );
146              
147             POE::Kernel->run;
148             }
149              
150             sub _init_plugins {
151             my ($self, $config) = @_;
152              
153             my $plugins = delete $config->{plugins};
154              
155             my @plugins;
156             for my $plugin ( @$plugins ) {
157             my ($class, $options) = ref $plugin ? %$plugin : ($plugin, {});
158             $class = "App::Twirc::Plugin::$class" unless $class =~ s/^\+//;
159              
160             eval "use $class";
161             die $@ if $@;
162              
163             push @plugins, $class->new($options);
164             }
165             return \@plugins;
166             }
167              
168             no Moose;
169              
170             __PACKAGE__->meta->make_immutable;
171              
172             1;
173              
174             __END__
175              
176             =head1 NAME
177              
178             App::Twirc - IRC is my twitter client
179              
180             =head1 SYNOPSIS
181              
182             use App::Twirc;
183              
184             my $app = App::Twirc->new_with_options();
185             $app->run;
186              
187             =head1 DESCRIPTION
188              
189             C<App::Twirc> is an IRC server making the IRC client of your choice your twitter client. The C<twirc>
190             program in this distribution launches the application.
191              
192             See L<App::Twirc::Manual> for more details.
193              
194             =head1 OPTIONS
195              
196             =over 4
197              
198             =item configfile
199              
200             Required. The name of the configuration file containing options for L<POE::Component::Server::Twirc>.
201              
202             =item background
203              
204             Boolean value to determine whether to run in the foreground (0), or background (1).
205              
206             =item authenticate
207              
208             Forces OAuth authentication with Twitter, supplying a URL for Twitter OAuth
209             authentication and prompting for the OAuth verifier PIN. Use this method
210             re-authenticate with Twitter, if necessary.
211              
212             =item state_file
213              
214             Specifies a file name for loading/storing state information, including a list
215             of friends, followers_ids, and OAuth access tokens.
216              
217             =item debug
218              
219             Boolean, when set to 1, enables DEBUG level logging.
220              
221             =back
222              
223             =head1 METHODS
224              
225             =over 4
226              
227             =item run
228              
229             Run the application.
230              
231             =back
232              
233             =head1 AUTHOR
234              
235             Marc Mims <marc@questright.com>
236              
237             =head1 LICENSE
238              
239             Copyright (c) 2008 Marc Mims
240              
241             You may distribute this code and/or modify it under the same terms as Perl itself.