| Jaipo documentation | Contained in the Jaipo distribution. |
Jaipo - Micro-blogging Client
Version 0.02
Jaipo ( 宅噗 )
This project started for Jaiku.com, but now is going to support as-much-as-we-can micro-blogging sites.
"Jaiku" pronunced close to "宅窟" in Chinese, which means an area full of computer/internet users, and it really is one of the most popular sites recently. As jaiku is part of google and growing, there're still only few linux client.
it's writen in perl, so it can run on any platform that you can get perl on it. we got the first feedback that somebody use it on ARM embedded system at May 2008.
return Jaipo::Config
Find plugins by class name, which is full-qualified class name.
if trigger name is specified, and it doesn't exist in config. Jaipo will create a new service object, and assign the trigger name to it.
if trigger name is specified, and Jaipo will try to search the service config by trigger name and load the service.
if trigger name is not specified. Jaipo will try to find service configs by service name. if there are two or more same service, Jaipo will load the default trigger name ( service name in lowcase )
command start with :[service] ( e.g. :twitter or :plurk ) something
like that will call the servcie dispatch method, service plugin will decide
what to do with.
BlueT, <bluet at blue.org>
Cornelius, cornelius.howl at gmail.com
Please report any bugs or feature requests to bug-jaipo at rt.cpan.org, or through
the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Jaipo. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
You can find documentation for this module with the perldoc command.
perldoc Jaipo
You can also look for information at:
Copyright 2009 , all rights reserved.
This program is released under the following license: GPL
| Jaipo documentation | Contained in the Jaipo distribution. |
package Jaipo; use warnings; use strict; use feature qw(:5.10); use Jaipo::Config; use Jaipo::Notify; use Jaipo::Logger; use base qw/Class::Accessor::Fast/; __PACKAGE__->mk_accessors(qw/config/); use vars qw/$NOTIFY $CONFIG $LOGGER $HANDLER $PUB_SUB @PLUGINS @SERVICES/; my $debug = 0;
our $VERSION = '0.21';
sub new { my $class = shift; my %args = @_; my $self = {}; bless $self, $class; return $self; }
sub config { my $class = shift; $CONFIG = shift if (@_); $CONFIG ||= Jaipo::Config->new (); return $CONFIG; } sub notify { my $class = shift; $NOTIFY ||= Jaipo::Notify->new; return $NOTIFY; }
sub services { my $class = shift; @SERVICES = @_ if @_; return @SERVICES; } sub logger { my $class = shift; $LOGGER = shift if (@_); return $LOGGER; }
sub init { my $self = shift; my $caller = shift; # Logger turn on Jaipo->logger ( Jaipo::Logger->new ); # prereserve arguments for service plugin # my $args = { # # }; Jaipo->notify; # we initialize service plugin class here # Set up plugins my @services; my @services_to_load = @{ Jaipo->config->app ('Services') }; my @plugins; my @plugins_to_load; for ( my $i = 0; my $service = $services_to_load[$i]; $i++ ) { # Prepare to learn the plugin class name my ($service_name) = keys %{$service}; say "Jaipo: Init " . $service_name; my $class; # Is the plugin name a fully-qualified class name? if ( $service_name =~ /^Jaipo::Service::/ ) { # app-specific plugins use fully qualified names, Jaipo service plugins may $class = $service_name; } # otherwise, assume it's a short name, qualify it else { $class = "Jaipo::Service::" . $service_name; } # Load the service plugin options my %options = ( %{ $service->{$service_name} } ); if ( !$options{enable} ) { Jaipo->logger->info ( '%s is disabled', $service_name ); next; } # Load the service plugin code $self->_try_to_require ($class); # XXX: if Service don't have trigger_name, we have to do something # # Initialize the plugin and mark the prerequisites for loading too my $plugin_obj = $class->new (%options); $plugin_obj->init ($caller); push @services, $plugin_obj; foreach my $name ( $plugin_obj->prereq_plugins ) { next if grep { $_ eq $name } @plugins_to_load; push @plugins_to_load, { $name => {} }; } } # All plugins loaded, save them for later reference Jaipo->services (@services); # XXX: need to implement plugin loader # warn "No supported service provider initialled!\n" if not $has_site; # when initialize jaipo, there are some new settings that we need to save. Jaipo->config->save; Jaipo->logger->info ('Configuration saved.'); }
sub list_loaded_triggers { my @services = Jaipo->services; for my $s (@services) { print $s->trigger_name, " => ", ref ($s), "\n"; } }
sub list_triggers { my @service_configs = @{ Jaipo->config->app ('Services') }; for my $s (@service_configs) { my @v = values %$s; print $v[0]->{trigger_name}, " => ", join ( q||, keys (%$s) ), "\n"; } }
sub find_service_by_trigger { my ( $self, $tg, $services ) = @_; $services ||= [ Jaipo->services ]; for my $s (@$services) { my $s_tg = $s->trigger_name; return $s if $s->trigger_name eq $tg; } }
sub _require { my $self = shift; my %args = @_; my $class = $args{module}; return 1 if $self->_already_required ($class); my $file = $class; $file .= '.pm' unless $file =~ /\.pm$/; $file =~ s|::|/|g; my $retval = eval { CORE::require "$file" }; my $error = $@; if ( my $message = $error ) { $message =~ s/ at .*?\n$//; if ( $args{'quiet'} and $message =~ /^Can't locate $file/ ) { return 0; } elsif ( $error !~ /^Can't locate $file/ ) { die $error; } else { #log->error(sprintf("$message at %s line %d\n", (caller(1))[1,2])); return 0; } } }
sub _already_required { my $self = shift; my $class = shift; my ($path) = ( $class =~ s|::|/|g ); $path .= '.pm'; return $INC{$path} ? 1 : 0; }
sub _try_to_require { my $self = shift; my $module = shift; $self->_require ( module => $module, quiet => 0 ); }
sub find_plugin { my $self = shift; my $name = shift; my @plugins = grep { $_->isa ($name) } Jaipo->plugins; return wantarray ? @plugins : $plugins[0]; }
# this may used by runtime_load_service sub set_plugin_trigger { my ( $self, $plugin_obj, $options, $class, $services ) = @_; # give a trigger to plugin obj , take a look. :p my $trigger_name; if ( defined $options->{trigger_name} ) { $trigger_name = $options->{trigger_name}; } else { ($trigger_name) = ( $class =~ m/(?<=Service::)(\w+)$/ ); $trigger_name = lc $trigger_name; # lower case } # repeat service trigger name while ( my $s = $self->find_service_by_trigger ( $trigger_name, $services ) ) { # give an another trigger name for it or ask user # TODO: provide a config option to let user set jaipo to ask $trigger_name .= '_'; } # set trigger name $plugin_obj->trigger_name ($trigger_name); print "set trigger: ", $trigger_name, ' for ', $class, "\n"; }
# XXX: need to re-check logic sub runtime_load_service { my ( $self, $caller, $service_name, $trigger_name ) = @_; $trigger_name ||= lc $service_name; my $class = "Jaipo::Service::" . ucfirst $service_name; my $options = {}; my @sp_options = Jaipo->config->find_service_option_by_trigger ($trigger_name); # can not find option , set default trigger name and sp_id if ( !@sp_options ) { $options->{trigger_name} = $trigger_name; my $num_rec = Number::RecordLocator->new; $options->{sp_id} = $num_rec->encode ( Jaipo->config->last_sp_cnt ); } elsif ( scalar @sp_options == 1 ) { $options = $sp_options[0]; } # XXX: # actually won't happen, config loader will canonicalize the config # service plugin will get it's default trigger namd from service name. else { # find by service name # elsif ( scalar @sp_options > 1 ) { # # find service by trigger name # for my $s (@sp_options) { # $options = $s if ( $s->{trigger_name} eq $trigger_name ); # } # } } # Load the service plugin code $self->_try_to_require ($class); # Jaipo::ClassLoader->new(base => $class)->require; my $plugin_obj = $class->new (%$options); $plugin_obj->init ($caller); # $self->set_plugin_trigger( $plugin_obj , $class ); my @services = Jaipo->services; push @services, $plugin_obj; foreach my $name ( $plugin_obj->prereq_plugins ) { # next if grep { $_ eq $name } @plugins_to_load; #push @plugins_to_load, {$name => {}}; } Jaipo->services (@services); # call save configuration here # TODO: this may overwrites other plugins afterload options # make sure that user did config jaipo , or we don't need to rewrite config Jaipo->config->save; }
sub dispatch_to_service { my ( $self, $service_tg, $line ) = @_; my $s = $self->find_service_by_trigger ($service_tg); my ($sub_command) = ($line =~ m[^(\w+)] ); $s->dispatch_sub_command( $sub_command , $line ); } sub cache_clear { my @services = Jaipo->services; foreach my $service (@services) { if( UNIVERSAL::can( $service , 'get_cache' ) ) { my $c = $service->get_cache; $c->clear; } } }
sub action { my ( $self, $action, $param ) = @_; my @services = Jaipo->services; foreach my $service (@services) { if ( UNIVERSAL::can( $service, $action ) ) { my $ret = $service->$action($param); if ($debug) { use Data::Dumper::Simple; warn Dumper( $ret ); } # XXX: # - we should check ret->{type} eq 'notification' # - and call Notify::init if ( ref $ret and $ret->{type} eq 'notification' and $ret->{updates} > 0 ) { Jaipo->notify->create($ret); } } else { # service plugin doesn't support this kind of action } } }
1; # End of Jaipo