File Coverage

blib/lib/Bot/Cobalt/Plugin/PluginMgr.pm
Criterion Covered Total %
statement 21 127 16.5
branch 0 40 0.0
condition 0 17 0.0
subroutine 8 20 40.0
pod 0 4 0.0
total 29 208 13.9


line stmt bran cond sub pod time code
1             package Bot::Cobalt::Plugin::PluginMgr;
2             $Bot::Cobalt::Plugin::PluginMgr::VERSION = '0.021003';
3             ## handles and eats: !plugin
4              
5 1     1   934 use strictures 2;
  1         5  
  1         42  
6 1     1   143 use v5.10;
  1         2  
7              
8 1     1   6 use Bot::Cobalt;
  1         1  
  1         5  
9 1     1   573 use Bot::Cobalt::Common;
  1         1  
  1         5  
10 1     1   376 use Bot::Cobalt::Conf;
  1         3  
  1         32  
11 1     1   5 use Bot::Cobalt::Core::Loader;
  1         2  
  1         21  
12              
13 1     1   3 use Scalar::Util qw/blessed/;
  1         2  
  1         1311  
14              
15              
16 1     1 0 342 sub new { bless [], shift }
17              
18             sub Cobalt_register {
19 0     0 0   my ($self, $core) = splice @_, 0, 2;
20              
21 0           register( $self, 'SERVER',
22             'public_cmd_plugin',
23             );
24              
25 0           logger->info("Registered");
26              
27 0           return PLUGIN_EAT_NONE
28             }
29              
30             sub Cobalt_unregister {
31 0     0 0   my ($self, $core) = splice @_, 0, 2;
32              
33 0           logger->info("Unregistered");
34              
35 0           return PLUGIN_EAT_NONE
36             }
37              
38             sub Bot_public_cmd_plugin {
39 0     0 0   my ($self, $core) = splice @_, 0, 2;
40 0           my $msg = ${$_[0]};
  0            
41              
42 0           my $context = $msg->context;
43 0           my $chan = $msg->channel;
44 0           my $nick = $msg->src_nick;
45              
46 0           my $pcfg = core()->get_plugin_cfg( $self );
47              
48             ## default to superuser-only:
49 0   0       my $required_lev = $pcfg->{LevelRequired} // 9999;
50              
51 0           my $resp;
52              
53 0   0       my $op = lc($msg->message_array->[0]||'');
54              
55 0 0         if ( core()->auth->level($context, $nick) < $required_lev ) {
56 0           $resp = core->rpl( q{RPL_NO_ACCESS}, { nick => $nick } );
57             } else {
58 0 0 0       unless ($op && grep { $_ eq $op } qw/load unload reload list/) {
  0            
59              
60 0           broadcast( 'message', $context, $chan,
61             "Valid PluginMgr commands: list, load, unload, reload"
62             );
63              
64 0           return PLUGIN_EAT_ALL
65             }
66              
67 0           my $method = '_cmd_plug_'.lc($op);
68              
69 0 0         if ($self->can($method)) {
70 0           $resp = $self->$method($msg);
71             } else {
72 0           logger->error("Bug; can($method) failed in dispatcher");
73 0           $resp = "Could not find method $method"
74             }
75              
76             }
77              
78 0 0         broadcast('message', $context, $chan, $resp) if defined $resp;
79              
80 0           return PLUGIN_EAT_ALL
81             }
82              
83             sub _cmd_plug_load {
84 0     0     my ($self, $msg) = @_;
85              
86             ## !load Alias
87             ## !load Alias Module
88              
89 0           my ($alias, $module) = @{ $msg->message_array }[1,2];
  0            
90              
91 0           return $self->_load($alias, $module)
92             }
93              
94             sub _cmd_plug_unload {
95 0     0     my ($self, $msg) = @_;
96              
97             ## !unload Alias
98              
99 0           my $alias = $msg->message_array->[1];
100              
101 0   0       return $self->_unload($alias) || "Bug; no reply from _unload"
102             }
103              
104             sub _cmd_plug_list {
105 0     0     my ($self, $msg) = @_;
106              
107 0           my $pluglist = core()->plugin_list;
108              
109 0           my @loaded = sort keys %$pluglist;
110              
111 0           my $str = sprintf("Loaded (%d):", scalar @loaded);
112 0           while (my $plugin_alias = shift @loaded) {
113 0           $str .= ' ' . $plugin_alias;
114              
115 0 0 0       if ($str && (length($str) > 300 || !@loaded) ) {
      0        
116             ## either this string has gotten long or we're done
117 0           broadcast( 'message', $msg->context, $msg->channel, $str );
118 0           $str = '';
119             }
120             }
121             }
122              
123             sub _cmd_plug_reload {
124 0     0     my ($self, $msg) = @_;
125              
126 0           my $alias = $msg->message_array->[1];
127              
128 0           my $plug_obj = core()->plugin_get($alias);
129              
130 0           my $resp;
131 0 0         if (!$alias) {
    0          
    0          
132              
133 0           broadcast( 'message', $msg->context, $msg->channel,
134             "Bad syntax; no plugin alias specified"
135             );
136              
137             return
138              
139 0           } elsif (!$plug_obj) {
140              
141 0           broadcast( 'message', $msg->context, $msg->channel,
142             core->rpl( q{RPL_PLUGIN_UNLOAD_ERR},
143             plugin => $alias,
144             err => 'No such plugin found, is it loaded?'
145             )
146             );
147              
148             return
149              
150 0           } elsif (core()->State->{NonReloadable}->{$alias}) {
151              
152 0           broadcast( 'message', $msg->context, $msg->channel,
153             core->rpl( q{RPL_PLUGIN_UNLOAD_ERR},
154             plugin => $alias,
155             err => "Plugin $alias is marked as non-reloadable",
156             )
157             );
158              
159             return
160 0           }
161              
162             ## call _unload and send any response from there
163 0           my $unload_resp = $self->_unload($alias);
164              
165 0           broadcast( 'message', $msg->context, $msg->channel, $unload_resp );
166              
167 0           my $pkgisa = ref $plug_obj;
168              
169 0           return $self->_load($alias, $pkgisa);
170             }
171              
172             sub _unload {
173 0     0     my ($self, $alias) = @_;
174              
175 0           my $resp;
176              
177 0           my $plug_obj = core()->plugin_get($alias);
178 0   0       my $plugisa = ref $plug_obj || return "_unload broken? no PLUGISA";
179              
180 0 0         return "Bad syntax; no plugin alias specified"
181             unless defined $alias;
182              
183 0 0         return core->rpl( q{RPL_PLUGIN_UNLOAD_ERR},
184             plugin => $alias,
185             err => 'No such plugin found, is it loaded?'
186             ) unless $plug_obj;
187              
188 0 0         return core->rpl( q{RPL_PLUGIN_UNLOAD_ERR},
189             plugin => $alias,
190             err => "Plugin $alias is marked as non-reloadable",
191             ) unless Bot::Cobalt::Core::Loader->is_reloadable($plug_obj);
192              
193 0           logger->info("Attempting to unload $alias ($plugisa) per request");
194              
195 0 0         if ( core()->plugin_del($alias) ) {
196 0           delete core()->PluginObjects->{$plug_obj};
197              
198 0           Bot::Cobalt::Core::Loader->unload($plugisa);
199              
200             ## and timers:
201 0           core()->timer_del_alias($alias);
202              
203 0           return core->rpl( q{RPL_PLUGIN_UNLOAD},
204             plugin => $alias
205             )
206             } else {
207 0           return core->rpl( q{RPL_PLUGIN_UNLOAD_ERR},
208             plugin => $alias,
209             err => 'Unknown core->plugin_del failure'
210             )
211             }
212              
213             return
214 0           }
215              
216             sub _load {
217 0     0     my ($self, $alias, $module) = @_;
218              
219             ## Called for !load / !reload
220             ## Return string for IRC
221              
222 0 0         return "Bad syntax; usage: load [module]"
223             unless defined $alias;
224              
225             return "Plugin already loaded: $alias"
226 0 0         if grep { $_ eq $alias } keys %{ core()->plugin_list };
  0            
  0            
227              
228 0 0         return $self->_load_module($alias, $module)
229             if defined $module;
230              
231 0           my $plugin_cfg;
232             ## No module specified; do we know this alias?
233 0 0         unless ( $plugin_cfg = core()->cfg->plugins->plugin($alias) ) {
234 0           return core->rpl( q{RPL_PLUGIN_ERR},
235             plugin => $alias,
236             err => "Plugin '$alias' not found in plugins conf",
237             )
238             }
239              
240 0           return $self->_load_module(
241             $alias,
242             $plugin_cfg->module
243             )
244             }
245              
246             sub _load_module {
247             ## _load_module( 'Auth', 'Bot::Cobalt::Plugin::Auth' ) f.ex
248             ## load to Core
249             ## returns a response string for irc
250 0     0     my ($self, $alias, $module) = @_;
251              
252 0           my ($err, $obj);
253             try {
254 0     0     $obj = Bot::Cobalt::Core::Loader->load($module);
255             } catch {
256 0     0     $err = $_
257 0           };
258              
259 0 0         if ($err) {
260 0           logger->warn("Plugin load failure; $err");
261              
262 0           Bot::Cobalt::Core::Loader->unload($module);
263              
264 0           return core->rpl( q{RPL_PLUGIN_ERR},
265             plugin => $alias,
266             err => "Module $module cannot be found/loaded: $err",
267             );
268             }
269              
270             ## store plugin objects:
271 0           core()->PluginObjects->{$obj} = $alias;
272              
273             ## plugin_add returns # of plugins in pipeline on success:
274 0 0         if (my $loaded = core()->plugin_add( $alias, $obj ) ) {
275 0 0         unless ( Bot::Cobalt::Core::Loader->is_reloadable($obj) ) {
276 0           core()->State->{NonReloadable}->{$alias} = 1;
277 0           logger->debug("$alias flagged non-reloadable");
278             }
279              
280 0 0         my $modversion = $obj->can('VERSION') ? $obj->VERSION : 1 ;
281              
282 0           return core->rpl( q{RPL_PLUGIN_LOAD},
283             plugin => $alias,
284             module => $module,
285             version => $modversion,
286             );
287             } else {
288             ## Couldn't plugin_add
289 0           logger->error("plugin_add failure for $alias");
290              
291             ## run cleanup
292 0           Bot::Cobalt::Core::Loader->unload($module);
293              
294 0           delete core()->PluginObjects->{$obj};
295              
296 0           return core->rpl( q{RPL_PLUGIN_ERR},
297             plugin => $alias,
298             err => "Unknown plugin_add failure",
299             );
300             }
301              
302             }
303              
304              
305             1;
306             __END__