| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package App::RoboBot::Config; | 
| 2 |  |  |  |  |  |  | $App::RoboBot::Config::VERSION = '4.002'; | 
| 3 | 5 |  |  | 5 |  | 50 | use v5.20; | 
|  | 5 |  |  |  |  | 11 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 5 |  |  | 5 |  | 24 | use namespace::autoclean; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 46 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 5 |  |  | 5 |  | 476 | use Moose; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 39 |  | 
| 8 | 5 |  |  | 5 |  | 25013 | use MooseX::SetOnce; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 130 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 5 |  |  | 5 |  | 2453 | use Config::Any::Merge; | 
|  | 5 |  |  |  |  | 22507 |  | 
|  | 5 |  |  |  |  | 142 |  | 
| 11 | 5 |  |  | 5 |  | 937 | use DBD::Pg; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | use DBIx::DataStore; | 
| 13 |  |  |  |  |  |  | use File::HomeDir; | 
| 14 |  |  |  |  |  |  | use Try::Tiny; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | use App::RoboBot::NetworkFactory; | 
| 17 |  |  |  |  |  |  | use App::RoboBot::Channel; | 
| 18 |  |  |  |  |  |  | use App::RoboBot::Nick; | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | has 'bot' => ( | 
| 21 |  |  |  |  |  |  | is       => 'ro', | 
| 22 |  |  |  |  |  |  | isa      => 'App::RoboBot', | 
| 23 |  |  |  |  |  |  | required => 1, | 
| 24 |  |  |  |  |  |  | ); | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | has 'config_paths' => ( | 
| 27 |  |  |  |  |  |  | is        => 'rw', | 
| 28 |  |  |  |  |  |  | isa       => 'ArrayRef[Str]', | 
| 29 |  |  |  |  |  |  | traits    => [qw( SetOnce )], | 
| 30 |  |  |  |  |  |  | predicate => 'has_config_paths', | 
| 31 |  |  |  |  |  |  | ); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | has 'config' => ( | 
| 34 |  |  |  |  |  |  | is        => 'rw', | 
| 35 |  |  |  |  |  |  | isa       => 'HashRef', | 
| 36 |  |  |  |  |  |  | predicate => 'has_config', | 
| 37 |  |  |  |  |  |  | ); | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | has 'networks' => ( | 
| 40 |  |  |  |  |  |  | is  => 'rw', | 
| 41 |  |  |  |  |  |  | isa => 'HashRef', | 
| 42 |  |  |  |  |  |  | ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | has 'channels' => ( | 
| 45 |  |  |  |  |  |  | is  => 'rw', | 
| 46 |  |  |  |  |  |  | isa => 'ArrayRef[App::RoboBot::Channel]', | 
| 47 |  |  |  |  |  |  | ); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | has 'plugins' => ( | 
| 50 |  |  |  |  |  |  | is      => 'rw', | 
| 51 |  |  |  |  |  |  | isa     => 'HashRef', | 
| 52 |  |  |  |  |  |  | default => sub { {} }, | 
| 53 |  |  |  |  |  |  | ); | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | has 'db' => ( | 
| 56 |  |  |  |  |  |  | is => 'rw', | 
| 57 |  |  |  |  |  |  | isa => 'DBIx::DataStore', | 
| 58 |  |  |  |  |  |  | traits => [qw( SetOnce )], | 
| 59 |  |  |  |  |  |  | ); | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | sub load_config { | 
| 62 |  |  |  |  |  |  | my ($self) = @_; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | try { | 
| 65 |  |  |  |  |  |  | unless ($self->has_config) { | 
| 66 |  |  |  |  |  |  | $self->locate_config unless $self->has_config_paths; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | if (my $cfg = Config::Any::Merge->load_files({ files => $self->config_paths, use_ext => 1, override => 1 })) { | 
| 69 |  |  |  |  |  |  | $self->config($cfg); | 
| 70 |  |  |  |  |  |  | } else { | 
| 71 |  |  |  |  |  |  | die "Could not load configuration files: " . join(', ', @{$self->config_paths}); | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | $self->validate_database; | 
| 76 |  |  |  |  |  |  | $self->validate_globals; | 
| 77 |  |  |  |  |  |  | $self->validate_networks; | 
| 78 |  |  |  |  |  |  | $self->validate_plugins; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | $self->bot->networks([ values %{$self->networks} ]); | 
| 81 |  |  |  |  |  |  | } catch { | 
| 82 |  |  |  |  |  |  | die "Could not load and validate configuration: $_"; | 
| 83 |  |  |  |  |  |  | }; | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub locate_config { | 
| 87 |  |  |  |  |  |  | my ($self) = @_; | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | my $home = File::HomeDir->my_home(); | 
| 90 |  |  |  |  |  |  | my @exts = qw( conf yml yaml json xml ini ); | 
| 91 |  |  |  |  |  |  | my @bases = ("$home/.lispy/lispy.", "$home/.lispy.", "/etc/lispy."); | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | my @configs; | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | foreach my $base (@bases) { | 
| 96 |  |  |  |  |  |  | foreach my $ext (@exts) { | 
| 97 |  |  |  |  |  |  | push(@configs, $base . $ext); | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  | } | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | my @found; | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | CONFIG_FILE: | 
| 104 |  |  |  |  |  |  | foreach my $path (@configs) { | 
| 105 |  |  |  |  |  |  | if (-f $path && -r _) { | 
| 106 |  |  |  |  |  |  | push(@found, $path); | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | $self->config_paths([reverse @found]); | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | die "Unable to locate a configuration file!" unless $self->has_config_paths; | 
| 113 |  |  |  |  |  |  | } | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | sub validate_globals { | 
| 116 |  |  |  |  |  |  | my ($self) = @_; | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | my %global = ( | 
| 119 |  |  |  |  |  |  | nick => 'lispy', | 
| 120 |  |  |  |  |  |  | ); | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | $self->config->{'global'} = \%global unless exists $self->config->{'global'}; | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | foreach my $k (keys %global) { | 
| 125 |  |  |  |  |  |  | $self->config->{'global'}{$k} = $global{$k} unless exists $self->config->{'global'}{$k}; | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | $self->config->{'global'}{'nick'} = App::RoboBot::Nick->new( | 
| 129 |  |  |  |  |  |  | config => $self, | 
| 130 |  |  |  |  |  |  | name   => $self->config->{'global'}{'nick'} | 
| 131 |  |  |  |  |  |  | ); | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | sub validate_database { | 
| 135 |  |  |  |  |  |  | my ($self) = @_; | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | my %database = ( | 
| 138 |  |  |  |  |  |  | name => 'robobot', | 
| 139 |  |  |  |  |  |  | ); | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | $self->config->{'database'} = \%database unless exists $self->config->{'database'}; | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | foreach my $k (keys %database) { | 
| 144 |  |  |  |  |  |  | $self->config->{'database'}{$k} = $database{$k} unless exists $self->config->{'database'}{$k}; | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | if (exists $self->config->{'database'}{'primary'} && ref($self->config->{'database'}{'primary'}) eq 'HASH') { | 
| 148 |  |  |  |  |  |  | $self->db(DBIx::DataStore->new({ config => $self->config->{'database'} })) or die "Could not validate explicit database connection!"; | 
| 149 |  |  |  |  |  |  | } else { | 
| 150 |  |  |  |  |  |  | $self->db(DBIx::DataStore->new($self->config->{'database'}{'name'})) or die "Could not validate named database connection!"; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | $self->bot->migrate_database; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | sub validate_networks { | 
| 157 |  |  |  |  |  |  | my ($self) = @_; | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | my @networks; | 
| 160 |  |  |  |  |  |  | my @channels; | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | my $nfactory = App::RoboBot::NetworkFactory->new( | 
| 163 |  |  |  |  |  |  | bot    => $self->bot, | 
| 164 |  |  |  |  |  |  | config => $self, | 
| 165 |  |  |  |  |  |  | nick   => $self->config->{'global'}{'nick'}, | 
| 166 |  |  |  |  |  |  | ); | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | foreach my $network_name (keys %{$self->config->{'network'}}) { | 
| 169 |  |  |  |  |  |  | my $net_cfg = $self->config->{'network'}{$network_name}; | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # Do not load (and eventually connect to) the network if the 'enabled' | 
| 172 |  |  |  |  |  |  | # property exists and is set to a falsey value. | 
| 173 |  |  |  |  |  |  | next if exists $self->config->{'network'}{$network_name}{'enabled'} | 
| 174 |  |  |  |  |  |  | && !$self->config->{'network'}{$network_name}{'enabled'}; | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | push(@networks, $nfactory->create($network_name, $net_cfg)); | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | my @network_channels; | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | # Coerce channel list into an arrayref if only a single channel is | 
| 181 |  |  |  |  |  |  | # listed for this network. | 
| 182 |  |  |  |  |  |  | $net_cfg->{'channel'} = [] unless exists $net_cfg->{'channel'}; | 
| 183 |  |  |  |  |  |  | $net_cfg->{'channel'} = [$net_cfg->{'channel'}] if ref($net_cfg->{'channel'}) ne 'ARRAY'; | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | foreach my $chan_name (@{$net_cfg->{'channel'}}) { | 
| 186 |  |  |  |  |  |  | push(@network_channels, App::RoboBot::Channel->new( config => $self, network => $networks[-1], name => $chan_name)); | 
| 187 |  |  |  |  |  |  | push(@channels, $network_channels[-1]); | 
| 188 |  |  |  |  |  |  | } | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | $networks[-1]->channels([@network_channels]); | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | $self->networks({ map { $_->name => $_ } @networks }); | 
| 194 |  |  |  |  |  |  | $self->channels(\@channels); | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | sub validate_plugins { | 
| 198 |  |  |  |  |  |  | my ($self) = @_; | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | foreach my $plugin_name (keys %{$self->config->{'plugin'}}) { | 
| 201 |  |  |  |  |  |  | $self->plugins->{lc($plugin_name)} = $self->config->{'plugin'}{$plugin_name}; | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | } | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | __PACKAGE__->meta->make_immutable; | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | 1; |