# # modules.pl: pseudo-Module handler # Author: dms # Version: v0.2 (20000629) # Created: 20000624 # use strict; use vars qw($AUTOLOAD $no_timehires); ### ### REQUIRED MODULES. ### eval "use IO::Socket"; if ($@) { &ERROR("no IO::Socket?"); exit 1; } &showProc(" (IO::Socket)"); ### THIS IS NOT LOADED ON RELOAD :( my @myModulesLoadNow; my @myModulesReloadNot; BEGIN { @myModulesLoadNow = ('Topic', 'Uptime', 'News', 'RootWarn', 'DumpVars2', 'botmail'); @myModulesReloadNot = ('IRC/Irc.pl','IRC/Schedulers.pl'); } sub loadCoreModules { my @mods = &getPerlFiles($bot_src_dir); &status("Loading CORE modules..."); foreach (sort @mods) { my $mod = "$bot_src_dir/$_"; eval "require \"$mod\""; if ($@) { &ERROR("lCM => $@"); &shutdown(); exit 1; } $moduleAge{$mod} = (stat $mod)[9]; &showProc(" ($_)") if (&IsParam("DEBUG")); } } sub loadDBModules { my $f; # TODO: use function to load module. if ($param{'DBType'} =~ /^(mysql|SQLite(2)?|pgsql)$/i) { eval "use DBI"; if ($@) { &ERROR("No support for DBI::" . $param{'DBType'} . ", exiting!"); exit 1; } &status("Loading " . $param{'DBType'} . " support."); $f = "$bot_src_dir/dbi.pl"; require $f; $moduleAge{$f} = (stat $f)[9]; &showProc(" (DBI::" . $param{'DBType'} . ")"); } else { &WARN("DB support DISABLED."); return; } } sub loadFactoidsModules { if (!&IsParam("factoids")) { &status("Factoid support DISABLED."); return; } &status("Loading Factoids modules..."); foreach ( &getPerlFiles("$bot_src_dir/Factoids") ) { my $mod = "$bot_src_dir/Factoids/$_"; eval "require \"$mod\""; if ($@) { &ERROR("lFM: $@"); exit 1; } $moduleAge{$mod} = (stat $mod)[9]; &showProc(" ($_)") if (&IsParam("DEBUG")); } } sub loadIRCModules { my ($interface) = &whatInterface(); if ($interface =~ /IRC/) { &status("Loading IRC modules..."); eval "use Net::IRC"; if ($@) { &ERROR("libnet-irc-perl is not installed!"); exit 1; } &showProc(" (Net::IRC)"); } else { &status("IRC support DISABLED."); # disabling forking. Why? #$param{forking} = 0; #$param{noSHM} = 1; } foreach ( &getPerlFiles("$bot_src_dir/$interface") ) { my $mod = "$bot_src_dir/$interface/$_"; # hrm... use another config option besides DEBUG to display # change in memory usage. &status("Loading Modules \"$mod\"") if (!&IsParam("DEBUG")); eval "require \"$mod\""; if ($@) { &ERROR("require \"$mod\" => $@"); &shutdown(); exit 1; } $moduleAge{$mod} = (stat $mod)[9]; &showProc(" ($_)") if (&IsParam("DEBUG")); } } sub loadMyModulesNow { my $loaded = 0; my $total = 0; &status("Loading MyModules..."); foreach (@myModulesLoadNow) { $total++; if (!defined $_) { &WARN("mMLN: null element."); next; } if (!&IsParam($_) and !&IsChanConf($_) and !&getChanConfList($_)) { &DEBUG("loadMyModuleNow: $_ (2) not loaded."); next; } &loadMyModule($_); $loaded++; } &status("Module: Runtime: Loaded/Total [$loaded/$total]"); } ### rename to moduleReloadAll? sub reloadAllModules { my $retval = ""; &VERB("Module: reloading all.",2); # obscure usage of map and regex :) foreach (map { s/.*?\/?src/src/; $_ } keys %moduleAge) { $retval .= &reloadModule($_); } &VERB("Module: reloading done.",2); return $retval; } ### rename to modulesReload? sub reloadModule { my ($mod) = @_; my $file = (grep /\/$mod/, keys %INC)[0]; my $retval = ""; # don't reload if it's not our module. if ($mod =~ /::/ or $mod !~ /pl$/) { &VERB("Not reloading $mod.",3); return $retval; } if (!defined $file) { &WARN("rM: Cannot reload $mod since it was not loaded anyway."); return $retval; } if (! -f $file) { &ERROR("rM: file '$file' does not exist?"); return $retval; } if (grep /$mod/, @myModulesReloadNot) { &DEBUG("rM: should not reload $mod"); return $retval; } my $age = (stat $file)[9]; if (!exists $moduleAge{$file}) { &DEBUG("Looks like $file was not loaded; fixing."); } else { return $retval if ($age == $moduleAge{$file}); if ($age < $moduleAge{$file}) { &WARN("rM: we're not gonna downgrade '$file'; use touch."); &DEBUG("age => $age, mA{$file} => $moduleAge{$file}"); return $retval; } my $dc = &Time2String($age - $moduleAge{$file}); my $ago = &Time2String(time() - $moduleAge{$file}); &VERB("Module: delta change: $dc",2); &VERB("Module: ago: $ago",2); } &status("Module: Loading $mod..."); delete $INC{$file}; eval "require \"$file\""; # require or use? if (@$) { &DEBUG("rM: failure: @$ "); } else { my $basename = $file; $basename =~ s/^.*\///; &status("Module: reloaded $basename"); $retval = " $basename"; $moduleAge{$file} = $age; } return $retval; } ### ### OPTIONAL MODULES. ### my %perlModulesLoaded = (); my %perlModulesMissing = (); sub loadPerlModule { return 0 if (exists $perlModulesMissing{$_[0]}); &reloadModule($_[0]); return 1 if (exists $perlModulesLoaded{$_[0]}); eval "use $_[0]"; if ($@) { &WARN("Module: $_[0] is not installed!"); $perlModulesMissing{$_[0]} = 1; return 0; } else { $perlModulesLoaded{$_[0]} = 1; &status("Loaded $_[0]"); &showProc(" ($_[0])"); return 1; } } sub loadMyModule { my ($modulename) = @_; if (!defined $modulename) { &WARN("loadMyModule: module is NULL."); return 0; } my $modulefile = "$bot_src_dir/Modules/$modulename.pl"; # call reloadModule() which checks age of file and reload. if (grep /\/$modulename$/, keys %INC) { &reloadModule($modulename); return 1; # depend on reloadModule? } if (! -f $modulefile) { &ERROR("lMM: module ($modulename) does not exist."); if ($$ == $bot_pid) { # parent. &shutdown() if (defined $shm and defined $dbh); } else { # child. &DEBUG("b4 delfork 1"); &delForked($modulename); } exit 1; } eval "require \"$modulefile\""; if ($@) { &ERROR("cannot load my module: $modulename"); if ($bot_pid != $$) { # child. &DEBUG("b4 delfork 2"); &delForked($modulename); exit 1; } return 0; } else { $moduleAge{$modulefile} = (stat $modulefile)[9]; &status("Loaded $modulename"); &showProc(" ($modulename)"); return 1; } } $no_timehires = 0; eval "use Time::HiRes qw(gettimeofday tv_interval)"; if ($@) { &WARN("No Time::HiRes?"); $no_timehires = 1; } &showProc(" (Time::HiRes)"); sub AUTOLOAD { if (!defined $AUTOLOAD and defined $::AUTOLOAD) { &DEBUG("AUTOLOAD: hrm.. ::AUTOLOAD defined!"); } return unless (defined $AUTOLOAD); return if ($AUTOLOAD =~ /__/); # internal. my $str = join(', ', @_); my ($package, $filename, $line) = caller; &ERROR("UNKNOWN FUNCTION CALLED: $AUTOLOAD ($str) $filename line $line"); $AUTOLOAD =~ s/^(\S+):://g; # hopefully this will work. &DEBUG("Trying to load module $AUTOLOAD..."); &loadMyModule($AUTOLOAD); } sub getPerlFiles { my($dir) = @_; if (!opendir(DIR, $dir)) { &ERROR("Cannot open source directory ($dir): $!"); exit 1; } my @mods; while (defined(my $file = readdir DIR)) { next unless $file =~ /\.pl$/; next unless $file =~ /^[A-Z]/; push(@mods, $file); } closedir DIR; return reverse sort @mods; } 1;