| 1 | # ----------------------------------------------------------------------------- |
|---|
| 2 | # $Id$ |
|---|
| 3 | # ----------------------------------------------------------------------------- |
|---|
| 4 | # Optional Modules Loader |
|---|
| 5 | # ----------------------------------------------------------------------------- |
|---|
| 6 | # copyright (C) 2004 Topia <topia@clovery.jp>. all rights reserved. |
|---|
| 7 | package Tiarra::OptionalModules; |
|---|
| 8 | use strict; |
|---|
| 9 | use warnings; |
|---|
| 10 | use Tiarra::SharedMixin; |
|---|
| 11 | use Tiarra::Utils; |
|---|
| 12 | # failsafe to module-reload |
|---|
| 13 | our $status = {}; |
|---|
| 14 | our %modules = ( |
|---|
| 15 | 'threads' => { |
|---|
| 16 | requires => [qw(threads threads::shared Thread::Queue)], |
|---|
| 17 | note => 'for threading dns resolving', |
|---|
| 18 | }, |
|---|
| 19 | 'ipv6' => { |
|---|
| 20 | requires => [qw(IO::Socket::INET6 Socket6)], |
|---|
| 21 | note => 'for ipv6 support', |
|---|
| 22 | }, |
|---|
| 23 | 'time_hires' => { |
|---|
| 24 | requires => [qw(Time::HiRes)], |
|---|
| 25 | note => 'for hi-resolution timer support', |
|---|
| 26 | }, |
|---|
| 27 | 'unix_dom' => { |
|---|
| 28 | requires => [qw(IO::Socket::UNIX)], |
|---|
| 29 | note => 'for control port support', |
|---|
| 30 | }, |
|---|
| 31 | 'encode' => { |
|---|
| 32 | requires => [qw(Encode)], |
|---|
| 33 | note => 'for Tiarra::Encoding::Encode encoding driver', |
|---|
| 34 | }, |
|---|
| 35 | 'base64' => { |
|---|
| 36 | requires => [qw(MIME::Base64)], |
|---|
| 37 | note => 'for Tiarra::Encoding::Encode\'s base64 support', |
|---|
| 38 | }, |
|---|
| 39 | ); |
|---|
| 40 | |
|---|
| 41 | sub _new { |
|---|
| 42 | bless $status, shift; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | sub all_modules { |
|---|
| 46 | keys %modules; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | sub repr_modules { |
|---|
| 50 | my $this = shift->_this; |
|---|
| 51 | my $verbose = shift; |
|---|
| 52 | my %status = $this->check_all; |
|---|
| 53 | my @enabled = sort grep $status{$_}, keys %status; |
|---|
| 54 | my @disabled = sort grep !$status{$_}, keys %status; |
|---|
| 55 | |
|---|
| 56 | my $repr_module = sub { |
|---|
| 57 | my ($modname, $eachmod) = @_; |
|---|
| 58 | my $ver; |
|---|
| 59 | my $error = $this->{$modname}->{errors}->{$eachmod}; |
|---|
| 60 | if (defined $error) { |
|---|
| 61 | if ($verbose) { |
|---|
| 62 | $error =~ s/ at .*//s; |
|---|
| 63 | $error =~ s/ \(\@INC .*\)//g; |
|---|
| 64 | $error =~ s/[\r\n]+/ /sg; |
|---|
| 65 | $error =~ s/ +$//g; |
|---|
| 66 | "[failed: $error]"; |
|---|
| 67 | } else { |
|---|
| 68 | "[failed to load]"; |
|---|
| 69 | } |
|---|
| 70 | } else { |
|---|
| 71 | eval { |
|---|
| 72 | $ver = $eachmod->VERSION; |
|---|
| 73 | }; |
|---|
| 74 | if (!defined $ver) { |
|---|
| 75 | 'unknown'; |
|---|
| 76 | } else { |
|---|
| 77 | $ver; |
|---|
| 78 | } |
|---|
| 79 | } |
|---|
| 80 | }; |
|---|
| 81 | |
|---|
| 82 | my $repr_modules = sub { |
|---|
| 83 | my $title = shift; |
|---|
| 84 | my $modname; |
|---|
| 85 | (@_ ? |
|---|
| 86 | ("$title:", |
|---|
| 87 | map { |
|---|
| 88 | $modname = $_; |
|---|
| 89 | " - $_ (" . join(', ', map { |
|---|
| 90 | "$_ " . $repr_module->($modname, $_); |
|---|
| 91 | } @{$modules{$_}->{requires}}) . ") " . |
|---|
| 92 | $modules{$_}->{note} |
|---|
| 93 | } @_) : ()) |
|---|
| 94 | }; |
|---|
| 95 | |
|---|
| 96 | ($repr_modules->("enabled", @enabled), |
|---|
| 97 | $repr_modules->("disabled", @disabled)); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | sub check_all { |
|---|
| 101 | my $this = shift->_this; |
|---|
| 102 | map { ($_, $this->check($_)) } $this->all_modules; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | sub check { |
|---|
| 106 | my ($class_or_this, $name) = @_; |
|---|
| 107 | my $this = $class_or_this->_this; |
|---|
| 108 | |
|---|
| 109 | return $this->{$name}->{status} if defined $this->{$name}; |
|---|
| 110 | die "module $name spec. not found" unless defined $modules{$name}; |
|---|
| 111 | |
|---|
| 112 | my $failed; |
|---|
| 113 | for my $mod (@{$modules{$name}->{requires}}) { |
|---|
| 114 | if (!eval "require $mod") { |
|---|
| 115 | $failed = 1; |
|---|
| 116 | }; |
|---|
| 117 | if ($@) { |
|---|
| 118 | $this->{$name}->{errors}->{$mod} = $@; |
|---|
| 119 | } |
|---|
| 120 | } |
|---|
| 121 | $this->{$name}->{status} = !$failed; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | sub AUTOLOAD { |
|---|
| 125 | my $this = shift; |
|---|
| 126 | our $AUTOLOAD; |
|---|
| 127 | if ($AUTOLOAD =~ /::DESTROY$/) { |
|---|
| 128 | # DESTROYは伝達させない。 |
|---|
| 129 | return; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | (my $key = $AUTOLOAD) =~ s/.+?:://g; |
|---|
| 133 | $this->check($key); |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | 1; |
|---|