File Coverage

blib/lib/IO/Iron/Common.pm
Criterion Covered Total %
statement 87 89 97.7
branch 12 14 85.7
condition n/a
subroutine 21 21 100.0
pod 4 4 100.0
total 124 128 96.8


line stmt bran cond sub pod time code
1             package IO::Iron::Common;
2              
3             ## no critic (Documentation::RequirePodAtEnd)
4             ## no critic (Documentation::RequirePodSections)
5             ## no critic (Subroutines::RequireArgUnpacking)
6              
7 8     8   744 use 5.010_000;
  8         25  
8 8     8   59 use strict;
  8         15  
  8         162  
9 8     8   35 use warnings;
  8         22  
  8         199  
10              
11             # Global creator
12       8     BEGIN {
13             # No exports
14             }
15              
16             # Global destructor
17       8     END {
18             }
19              
20             # ABSTRACT: Common routines for Client Libraries to Iron services IronCache, IronMQ and IronWorker.
21              
22             our $VERSION = '0.14'; # VERSION: generated by DZP::OurPkgVersion
23              
24 8     8   7560 use Path::Tiny qw{path};
  8         108670  
  8         510  
25 8     8   606 use Try::Tiny;
  8         2069  
  8         427  
26 8     8   563 use Log::Any qw{$log};
  8         8470  
  8         66  
27             require JSON::MaybeXS;
28 8     8   4169 use File::Spec ();
  8         19  
  8         111  
29 8     8   3487 use File::HomeDir ();
  8         35056  
  8         271  
30 8     8   623 use Hash::Util 0.06 qw{lock_keys unlock_keys};
  8         3084  
  8         61  
31 8     8   1202 use Carp::Assert::More;
  8         5076  
  8         1545  
32 8     8   596 use English '-no_match_vars';
  8         1807  
  8         67  
33 8     8   3753 use Params::Validate qw(:all);
  8         7156  
  8         8027  
34              
35             sub IRON_CONFIG_KEYS {
36             return (
37             # Iron.io standard:
38 12     12 1 59 'project_id', # The ID of the project to use for requests.
39             'token', # The OAuth token that should be used to authenticate requests. Can be found in the HUD.
40             'host', # The domain name the API can be located at. Defaults to a product-specific value, but always using Amazon's cloud.
41             'protocol'
42             , # The protocol that will be used to communicate with the API. Defaults to "https", which should be sufficient for 99% of users.
43             'port', # The port to connect to the API through. Defaults to 443, which should be sufficient for 99% of users.
44             'api_version'
45             , # The version of the API to connect through. Defaults to the version supported by the client. End-users should probably never change this. Except: IronMQ service upgraded from v2 to v3 in 2015!
46             # IO::Iron additions:
47             'timeout'
48             , # REST client timeout (for REST calls accessing IronMQ). N.B. This is not a IronMQ config option! It only configures client this client.
49             'policies', # Filename of JSON file containing policies.
50             );
51             }
52              
53             sub IRON_CLIENT_PARAMETERS {
54             return (
55 3     3 1 10 IRON_CONFIG_KEYS(),
56             'config', # The config file name.
57             'connector', # Reference to a preinitiated connector object.
58              
59             # 'policy', # Reference to a preinitiated policy hash.
60             );
61             }
62              
63             sub get_config { ## no critic (Subroutines::RequireArgUnpacking)
64             my %params = validate(
65             @_,
66             {
67 3     3 1 19 map { $_ => { type => SCALAR, optional => 1 }, } IRON_CONFIG_KEYS(), ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements)
  30         168  
68             'config' => { type => SCALAR, optional => 1, },
69             }
70             );
71 3         35 $log->tracef( 'Entering get_config(%s)', \%params );
72 3         505 my %config = ( map { $_ => undef } IRON_CONFIG_KEYS() ); ## preset config keys.
  24         82  
73 3         11 lock_keys( %config, IRON_CONFIG_KEYS() );
74 3         315 _read_iron_config_file( \%config, File::Spec->catfile( File::HomeDir->my_home, '.iron.json' ) ); # Homedir
75 3         26 _read_iron_config_env_vars( \%config ); # Global envs
76 3         68 _read_iron_config_file( \%config, File::Spec->catfile( File::Spec->curdir(), 'iron.json' ) ); # current dir
77 3 100       15 if ( defined $params{'config'} ) { # config file specified when creating the class, if given.
78             _read_iron_config_file( \%config,
79             File::Spec->file_name_is_absolute( $params{'config'} )
80             ? $params{'config'}
81 1 50       20 : File::Spec->catfile( File::Spec->curdir(), $params{'config'} ) );
82             }
83              
84             # The parameters given when the object was created, except 'config'
85 3         10 my @copy_param_keys = grep { !/^config$/msx } keys %params;
  5         20  
86 3         11 @config{@copy_param_keys} = @params{@copy_param_keys};
87              
88 3         12 $log->tracef( 'Exiting get_config: %s', \%config );
89 3         532 return \%config;
90             }
91              
92             # Replace the existing values in $config if new environment variables found.
93             # Vars:
94             # $config->{'project_id'} = $ENV{'IRON_PROJECT_ID'}
95             # $config->{'token'} = $ENV{'IRON_TOKEN'}
96             # $config->{'host'} = $ENV{'IRON_HOST'}
97             # $config->{'protocol'} = $ENV{'IRON_PROTOCOL'}
98             # $config->{'port'} = $ENV{'IRON_PORT'}
99             # $config->{'api_version'} = $ENV{'IRON_API_VERSION'}
100             # $config->{'timeout'} = $ENV{'IRON_TIMEOUT'}
101             sub _read_iron_config_env_vars {
102 3     3   8 my ($config) = @_;
103 3         10 $log->tracef( 'Entering _read_iron_config_env_vars(%s)', $config );
104 3         489 foreach my $config_key ( keys %{$config} ) {
  3         13  
105 24 100       81 if ( defined $ENV{ 'IRON_' . uc $config_key } ) {
106 6         12 $config->{$config_key} = $ENV{ 'IRON_' . uc $config_key };
107             }
108             }
109 3         13 $log->tracef( 'Exiting _read_iron_config_env_vars: %s', $config );
110 3         466 return $config;
111             }
112              
113             # Try to read the file given as second parameter. (if undef, fail).
114             # If fails, gracefully return 0; if succeed, change configuration (first parameter) and return 1.
115             sub _read_iron_config_file {
116 7     7   195 my ( $config, $full_path_name ) = @_;
117 7         27 $log->tracef( 'Entering _read_iron_config_file(%s, %s)', $full_path_name, $config );
118              
119 7         1149 assert_nonblank( $full_path_name, 'full_path_name is not defined or is blank.' );
120              
121 7         84 my $read_config;
122             my $rval;
123 7         25 my $file = path($full_path_name);
124 7 100       315 if ( $file->is_file ) {
125 2         46 $log->tracef( 'File %s exists', $full_path_name );
126 2         6 my $file_contents;
127 2     2   13 try { $file_contents = $file->slurp_utf8 };
  2         57  
128 2 50       1556 if ($file_contents) {
129 2         9 $log->tracef( 'Slurped file %s', $full_path_name );
130 2         29 my $json = JSON::MaybeXS->new( utf8 => 1, pretty => 1 );
131 2         54 $read_config = $json->decode($file_contents);
132 2         4 foreach my $config_key ( keys %{$config} ) {
  2         7  
133 16 100       35 if ( defined $read_config->{$config_key} ) {
134 8         19 $config->{$config_key} = $read_config->{$config_key};
135             }
136             }
137 2         14 $rval = 1;
138             }
139             else {
140 0         0 $log->debugf( 'Could not read file %s', $full_path_name );
141 0         0 $rval = 0;
142             }
143             }
144             else {
145 5         235 $log->tracef( 'File %s does not exist', $full_path_name );
146 5         326 $rval = 0;
147             }
148 7         28 $log->tracef( 'Exiting _read_iron_config_file: %s', $config );
149 7         1042 return $rval;
150             }
151              
152             #my $GEN_DELIMS = q{!} . q{$} . q{&} . q{'} . q{(} . q{)}
153             # . q{*} . q{+} . q{,} . q{;} . q{=};
154             #my $SUB_DELIMS = q{:} . q{/} . q{?} . q{#} . q{[} . q{]} . q{@};
155             #my $RESERVED_CHARACTERS = $GEN_DELIMS . $SUB_DELIMS;
156             #my $RFC_3986_RESERVED_CHARACTERS =~ s/(.{1})/\\$1/sg; # Escape every character.
157             sub contains_rfc_3986_res_chars {
158 11     11 1 1217 my @params = validate_pos( @_, { type => SCALAR } );
159             ## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars)
160 11         39 my $rfc_3986_reserved_characters = q{\!\$\&\'\(\)\*\+\,\;\=\:\/\?\#\[\]\@};
161             ## critic (ValuesAndExpressions::RequireInterpolationOfMetachars)
162 11 100       177 return ( $params[0] =~ m/[$rfc_3986_reserved_characters]{1,}/msx ) ? 1 : 0;
163             }
164              
165             1;
166              
167             __END__
168              
169             =pod
170              
171             =encoding UTF-8
172              
173             =head1 NAME
174              
175             IO::Iron::Common - Common routines for Client Libraries to Iron services IronCache, IronMQ and IronWorker.
176              
177             =head1 VERSION
178              
179             version 0.14
180              
181             =for stopwords IronCache IronMQ IronWorker config json Mikko Koivunalho
182              
183             =head1 REQUIREMENTS
184              
185             =head1 FUNCTIONS
186              
187             Internal functions for use in the Client objects.
188              
189             =head2 IRON_CONFIG_KEYS
190              
191             =head2 IRON_CLIENT_PARAMETERS
192              
193             =head2 get_config
194              
195             Get the config from file or from system environmental variables.
196             Follows the global configuration scheme as explained in http://dev.iron.io/mq/reference/configuration/.
197              
198             The configuration is constructed as follows:
199              
200             =over 8
201              
202             =item 1. The global configuration file sets the defaults according to the file hierarchy. (F<.iron.json> in home folder)
203              
204             =item 2. The global environment variables overwrite the global configuration file's values.
205              
206             =item 3. The product-specific environment variables overwrite everything before them.
207              
208             =item 4. The local configuration file overwrites everything before it according to the file hierarchy. (F<iron.json> in the same directory as the script being run)
209              
210             =item 5. The configuration file specified when instantiating the client library overwrites everything before it according to the file hierarchy.
211              
212             =item 6. The arguments passed when instantiating the client library overwrite everything before them.
213              
214             =back
215              
216             Return: ref to %config.
217              
218             =head2 contains_rfc_3986_res_chars
219              
220             Check that the string does not contain any RFC 3986 Reserved Characters:
221              
222             !$&'()*+,;=:/?#[]@
223              
224             Return True (1) if contains. Otherwise False (0).
225              
226             =head1 AUTHOR
227              
228             Mikko Koivunalho <mikko.koivunalho@iki.fi>
229              
230             =head1 BUGS
231              
232             Please report any bugs or feature requests to bug-io-iron@rt.cpan.org or through the web interface at:
233             http://rt.cpan.org/Public/Dist/Display.html?Name=IO-Iron
234              
235             =head1 COPYRIGHT AND LICENSE
236              
237             This software is copyright (c) 2023 by Mikko Koivunalho.
238              
239             This is free software; you can redistribute it and/or modify it under
240             the same terms as the Perl 5 programming language system itself.
241              
242             The full text of the license can be found in the
243             F<LICENSE> file included with this distribution.
244              
245             =cut