File Coverage

blib/lib/Message/Passing/Role/Script.pm
Criterion Covered Total %
statement 27 63 42.8
branch 0 24 0.0
condition 0 2 0.0
subroutine 9 13 69.2
pod 4 4 100.0
total 40 106 37.7


line stmt bran cond sub pod time code
1             package Message::Passing::Role::Script;
2 3     3   4884 use Moo::Role;
  3         6  
  3         18  
3 3     3   776 use MooX::Options;
  3         4  
  3         19  
4 3     3   1712 use MooX::Types::MooseLike::Base qw/ Bool Str /;
  3         5  
  3         208  
5 3     3   15 use Getopt::Long qw(:config pass_through);
  3         4  
  3         25  
6 3     3   2215 use POSIX qw(setuid setgid);
  3         11798  
  3         20  
7 3     3   2704 use Message::Passing::DSL;
  3         5  
  3         300  
8 3     3   16 use Carp qw/ confess /;
  3         5  
  3         171  
9 3     3   16 use namespace::clean -except => 'meta';
  3         4  
  3         31  
10              
11             requires 'build_chain';
12              
13             option daemonize => (
14             is => 'ro',
15             isa => Bool,
16             default => sub { 0 },
17             doc => 'pass 1 to daemonize',
18             );
19              
20             option io_priority => (
21             isa => sub { $_[0] =~ /^(none|be|rt|idle)$/ },
22             coerce => sub { lc $_[0] },
23             is => 'ro',
24             predicate => "_has_io_priority",
25             format => 's',
26             doc => 'the IO priority to run the script at: none, be, rt, idle',
27             );
28              
29             option user => (
30             isa => Str,
31             is => 'ro',
32             predicate => "_has_user",
33             format => 's',
34             doc => 'changes the user the script is running as',
35             );
36              
37             option pid_file => (
38             isa => Str,
39             is => 'ro',
40             predicate => "_has_pid_file",
41             format => 's',
42             doc => 'the name of the pid file including the directory',
43             );
44              
45             sub daemonize_if_needed {
46 0     0 1   my ($self) = @_;
47 0           my $fh;
48 0 0         if ($self->_has_pid_file) {
49 0 0         open($fh, '>', $self->pid_file)
50             or confess("Could not open pid file '". $self->pid_file . "': $?");
51             }
52 0 0         if ($self->daemonize) {
53 0 0         fork && exit;
54 0           POSIX::setsid();
55 0 0         fork && exit;
56 0           chdir '/';
57 0           umask 0;
58             }
59 0 0         if ($fh) {
60 0           print $fh $$ . "\n";
61 0           close($fh);
62             }
63             }
64              
65             sub change_uid_if_needed {
66 0     0 1   my $self = shift;
67 0           my ($uid, $gid);
68 0 0         if ($self->_has_user) {
69 0           my $user = $self->user;
70 0   0       $uid = getpwnam($user) ||
71             die("User '$user' does not exist, cannot become that user!\n");
72 0           (undef, undef, undef, $gid ) = getpwuid($uid);
73             }
74 0 0         if ($gid) {
75 0 0         setgid($gid) || die("Could not setgid to '$gid' are you root? : $!\n");
76             }
77 0 0         if ($uid) {
78 0 0         setuid($uid) || die("Could not setuid to '$uid' are you root? : $!\n");
79             }
80             }
81              
82             sub set_io_priority_if_needed {
83 0     0 1   my $self = shift;
84 0 0         return unless $self->_has_io_priority;
85 0           require Linux::IO_Prio;
86 0           my $sym = do {
87 3     3   2369 no strict 'refs';
  3         5  
  3         497  
88 0           &{"Linux::IO_Prio::IOPRIO_CLASS_" . uc($self->io_priority)}();
  0            
89             };
90 0           Linux::IO_Prio::ioprio_set(Linux::IO_Prio::IOPRIO_WHO_PROCESS(), $$,
91             Linux::IO_Prio::IOPRIO_PRIO_VALUE($sym, 0)
92             );
93             }
94              
95             sub start {
96 0     0 1   my $class = shift;
97 0           my $instance = $class->new_with_options(@_);
98 0           $instance->set_io_priority_if_needed;
99 0           $instance->change_uid_if_needed;
100 0           $instance->daemonize_if_needed;
101 0           run_message_server $instance->build_chain;
102             }
103              
104             1;
105              
106             =head1 NAME
107              
108             Message::Passing:Role::Script - Handy role for building messaging scripts.
109              
110             =head1 SYNOPSIS
111              
112             # my_message_passer.pl
113             package My::Message::Passer;
114             use Moo;
115             use MooX::Options;
116             use MooX::Types::MooseLike::Base qw/ Bool /;
117             use Message::Passing::DSL;
118              
119             with 'Message::Passing::Role::Script';
120              
121             option foo => (
122             is => 'ro',
123             isa => Bool,
124             );
125              
126             sub build_chain {
127             my $self = shift;
128             message_chain {
129             input example => ( output_to => 'test_out', .... );
130             output test_out => ( foo => $self->foo, ... );
131             };
132             }
133              
134             __PACKAGE__->start unless caller;
135             1;
136              
137             =head1 DESCRIPTION
138              
139             This role can be used to make simple message passing scripts.
140              
141             The user implements a L type script class, with a
142             C method, that builds one or more
143             L chains and returns them.
144              
145             __PACKAGE__->start unless caller;
146              
147             is then used before the end of the script.
148              
149             This means that when the code is run as a script, it'll parse
150             the command line options, and start a message passing server..
151              
152             =head1 REQUIRED METHODS
153              
154             =head1 build_chain
155              
156             Return a chain of message processors, or an array reference with
157             multiple chains of message processors.
158              
159             =head1 ATTRIBUTES
160              
161             =head2 daemonize
162              
163             Do a double fork and lose controlling terminal.
164              
165             Used to run scripts in the background.
166              
167             =head2 io_priority
168              
169             The IO priority to run the script at..
170              
171             Valid values for the IO priority are:
172              
173             =over
174              
175             =item none
176              
177             =item be
178              
179             =item rt
180              
181             =item idle
182              
183             =back
184              
185             =head2 user
186              
187             Changes the user the script is running as. You probably need to run the script as root for this option to work.
188              
189             =head2 pid_file
190              
191             Write a pid file out. Useful for running Message::Passing scripts as daemons and/or from init.d scripts.
192              
193             =head1 METHODS
194              
195             =head2 start
196              
197             Called as a class method, it will build the current class as a
198             command line script (parsing ARGV), setup the daemonization options,
199             call the ->build_chain method supplied by the user to build the
200             chains needed for this application.
201              
202             Then enters the event loop and never returns.
203              
204             =head2 change_uid_if_needed
205              
206             Tries to change uid if the --user option has been supplied
207              
208             =head2 daemonize_if_needed
209              
210             Tires to daemonize if the --daemonize option has been supplied
211              
212             =head2 set_io_priority_if_needed
213              
214             Tries to set the process' IO priority if the --io_priority option
215             has been supplied.
216              
217             =head1 SPONSORSHIP
218              
219             This module exists due to the wonderful people at Suretec Systems Ltd.
220             who sponsored its development for its
221             VoIP division called SureVoIP for use with
222             the SureVoIP API -
223            
224              
225             =head1 AUTHOR, COPYRIGHT AND LICENSE
226              
227             See L.
228              
229             =cut