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