3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-10-09 04:48:43 +02:00
pbot/PBot/Pluggable.pm
Pragmatic Software 0d7f0bf184 Add loadable core plugins
These are different from the loadable factoid modules.  The factoid modules
are external executable shell commands that take stdin as arguments and print
to stdout as a return value.  As such, they are not integrated into the bot
and cannot make use of the bot's internal subroutines.

These plugins are loaded internally and integrated into the bot such that they
can interface with the bot's internal subroutines and state.

All files in the Pluggable directory not beginning with an underscore will be
automatically loaded at bot start-up.

Plugins (including those starting with an underscore) can be manually loaded
or unloaded with the `plug` and `unplug` commands.  Use `pluglist` to list
loaded plugins.
2015-09-06 22:17:07 -07:00

164 lines
3.6 KiB
Perl

# File: Pluggable.pm
# Author: pragma-
#
# Purpose: Loads and manages pluggable modules.
package PBot::Pluggable;
use warnings;
use strict;
use File::Basename;
use Carp ();
sub new {
if(ref($_[1]) eq 'HASH') {
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_;
my $self = bless {}, $class;
$self->initialize(%conf);
return $self;
}
sub initialize {
my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{modules} = {};
$self->{pbot}->{commands}->register(sub { $self->load_cmd(@_) }, "plug", 90);
$self->{pbot}->{commands}->register(sub { $self->unload_cmd(@_) }, "unplug", 90);
$self->{pbot}->{commands}->register(sub { $self->list_cmd(@_) }, "pluglist", 0);
$self->autoload();
}
sub autoload {
my $self = shift;
$self->{pbot}->{logger}->log("Loading pluggable modules ...\n");
my $module_count = 0;
my @modules = glob 'PBot/Pluggable/*.pm';
foreach my $module (sort @modules) {
$module = basename $module;
$module =~ s/.pm$//;
# do not load modules that begin with an underscore
next if $module =~ m/^_/;
$module_count++ if $self->load($module)
}
$self->{pbot}->{logger}->log("$module_count module" . ($module_count == 1 ? '' : 's') . " loaded.\n");
}
sub load {
my ($self, $module) = @_;
$self->unload($module);
my $class = "PBot::Pluggable::$module";
$self->{pbot}->{refresher}->{refresher}->refresh_module("PBot/Pluggable/$module.pm");
my $ret = eval {
eval "require $class";
if ($@) {
chomp $@;
$self->{pbot}->{logger}->log("Error loading $module: $@\n");
return 0;
}
$self->{pbot}->{logger}->log("Loading $module\n");
my $mod = $class->new(pbot => $self->{pbot});
$self->{modules}->{$module} = $mod;
$self->{pbot}->{refresher}->{refresher}->update_cache("PBot/Pluggable/$module.pm");
return 1;
};
if ($@) {
chomp $@;
$self->{pbot}->{logger}->log("Error loading $module: $@\n");
return 0;
}
return $ret;
}
sub unload {
my ($self, $module) = @_;
$self->{pbot}->{refresher}->{refresher}->unload_module("PBot::Pluggable::$module");
$self->{pbot}->{refresher}->{refresher}->unload_subs("PBot/Pluggable/$module.pm");
if (exists $self->{modules}->{$module}) {
eval {
$self->{modules}->{$module}->unload;
delete $self->{modules}->{$module};
};
if ($@) {
chomp $@;
$self->{pbot}->{logger}->log("Warning: got error unloading module $module: $@\n");
}
$self->{pbot}->{logger}->log("Pluggable module $module unloaded.\n");
return 1;
} else {
return 0;
}
}
sub load_cmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
if (not length $arguments) {
return "Usage: plug <plugin>";
}
if ($self->load($arguments)) {
return "Loaded $arguments plugin.";
} else {
return "Plugin $arguments not found.";
}
}
sub unload_cmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
if (not length $arguments) {
return "Usage: unplug <plugin>";
}
if ($self->unload($arguments)) {
return "Unloaded $arguments plugin.";
} else {
return "Plugin $arguments not found.";
}
}
sub list_cmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $result = "Loaded plugins: ";
my $count = 0;
my $comma = '';
foreach my $plugin (sort keys $self->{modules}) {
$result .= $comma . $plugin;
$count++;
$comma = ', ';
}
$result .= 'none' if $count == 0;
return $result;
}
1;