2 use strict; use warnings;
6 use OpenSRF::Utils::Logger qw/$logger/;
7 use OpenILS::Application::AppUtils;
9 use OpenSRF::EX qw/:try/;
12 use OpenILS::Utils::Fieldmapper;
13 use Digest::MD5 qw/md5_hex/;
14 use OpenSRF::Utils qw/:daemon/;
15 use OpenILS::Utils::OfflineStore;
18 my $U = "OpenILS::Application::AppUtils";
19 my $DB = "OpenILS::Utils::OfflineStore";
20 my $SES = "${DB}::Session";
21 my $SCRIPT = "OpenILS::Utils::OfflineStore::Script";
25 # --------------------------------------------------------------------
27 # --------------------------------------------------------------------
28 #do '##CONFIG##/upload-server.pl';
29 do 'offline-config.pl';
33 my $basedir = $config{base_dir};
34 my $wsname = $cgi->param('ws');
35 my $org = $cgi->param('org');
36 my $authtoken = $cgi->param('ses') || "";
37 my $seskey = $cgi->param('seskey');
38 my $action = $cgi->param('action'); # - create, load, execute, status
50 # --------------------------------------------------------------------
52 # This function should behave as a child_init might behave in case
53 # this is moved to mod_perl
54 # --------------------------------------------------------------------
58 $s .= "$_=" . $cgi->param($_) . "\n" for $cgi->param;
59 warn '-'x60 ."\n$s\n" . '-'x60 ."\n";
61 $DB->DBFile($config{db});
62 OpenSRF::System->bootstrap_client(config_file => $config{bootstrap} );
66 # --------------------------------------------------------------------
67 # Finds the requestor and other info specific to this request
68 # --------------------------------------------------------------------
71 # fetch the requestor object
72 ($requestor, $evt) = $U->checkses($authtoken);
73 ol_handle_result($evt) if $evt;
76 # try the param, the workstation, and finally the user's ws org
78 $wsobj = ol_fetch_workstation($wsname);
79 $org = $wsobj->owning_lib if $wsobj;
80 $org = $requestor->ws_ou unless $org;
81 ol_handle_result(OpenILS::Event->new('OFFLINE_NO_ORG')) unless $org;
86 # --------------------------------------------------------------------
87 # Runs the requested action
88 # --------------------------------------------------------------------
93 if( $action eq 'create' ) {
95 $evt = $U->check_perms($requestor->id, $org, 'OFFLINE_UPLOAD');
96 ol_handle_result($evt) if $evt;
97 $payload = ol_create_session();
99 } elsif( $action eq 'load' ) {
101 $evt = $U->check_perms($requestor->id, $org, 'OFFLINE_UPLOAD');
102 ol_handle_result($evt) if $evt;
103 $payload = ol_load();
105 } elsif( $action eq 'execute' ) {
107 $evt = $U->check_perms($requestor->id, $org, 'OFFLINE_EXECUTE');
108 ol_handle_result($evt) if $evt;
109 $payload = ol_execute();
111 } elsif( $action eq 'status' ) {
113 $evt = $U->check_perms($requestor->id, $org, 'OFFLINE_VIEW');
114 ol_handle_result($evt) if $evt;
115 $payload = ol_status();
118 ol_handle_event('SUCCESS', payload => $payload );
122 # --------------------------------------------------------------------
123 # Creates a new session
124 # --------------------------------------------------------------------
125 sub ol_create_session {
127 my $desc = $cgi->param('desc') || "";
128 $seskey ||= time . "_${$}_" . int(rand() * 100);
130 $logger->debug("offline: user ".$requestor->id.
131 " creating new session with key $seskey and description $desc");
137 description => $desc,
138 creator => $requestor->id,
139 create_time => CORE::time(),
147 # --------------------------------------------------------------------
148 # Holds the meta-info for a script file
149 # --------------------------------------------------------------------
150 sub ol_create_script {
153 my $session = ol_find_session($seskey);
154 my $delta = $cgi->param('delta') || 0;
156 my $script = $session->add_to_scripts(
158 requestor => $requestor->id,
159 create_time => CORE::time,
160 workstation => $wsname,
161 logfile => "$basedir/pending/$org/$seskey/$wsname.log",
162 time_delta => $delta,
168 # --------------------------------------------------------------------
169 # Finds the current session in the db
170 # --------------------------------------------------------------------
171 sub ol_find_session {
172 my $ses = $SES->retrieve($seskey);
173 ol_handle_event('OFFLINE_INVALID_SESSION', payload => $seskey) unless $ses;
177 # --------------------------------------------------------------------
178 # Finds a script object in the DB based on workstation and seskey
179 # --------------------------------------------------------------------
181 my $ws = shift || $wsname;
182 my $sk = shift || $seskey;
183 my ($script) = $SCRIPT->search( session => $seskey, workstation => $ws );
187 # --------------------------------------------------------------------
188 # Creates a new script in the database and loads the new script file
189 # --------------------------------------------------------------------
191 my $session = ol_find_session;
192 my $handle = $cgi->upload('file');
193 my $outdir = "$basedir/pending/$org/$seskey";
194 my $outfile = "$outdir/$wsname.log";
196 ol_handl_event('OFFLINE_SESSION_FILE_EXISTS') if ol_find_script();
197 ol_handle_event('OFFLINE_SESSION_ACTIVE') if $session->in_process;
199 qx/mkdir -p $outdir/;
201 open(FILE, ">>$outfile") or ol_handle_event('OFFLINE_FILE_ERROR');
202 while( <$handle> ) { print FILE; $x++;}
205 ol_create_script($x);
211 # --------------------------------------------------------------------
212 sub ol_handle_result {
214 my $json = JSON->perl2JSON($obj);
216 if( $cgi->param('html')) {
217 my $html = "<html><body onload='xulG.handle_event($json)></body></html>";
218 print "content-type: text/html\n\n";
223 print "content-type: text/plain\n\n";
230 # --------------------------------------------------------------------
231 sub ol_handle_event {
232 my( $evt, @args ) = @_;
233 ol_handle_result(OpenILS::Event->new($evt, @args));
237 # --------------------------------------------------------------------
238 sub ol_flesh_session {
242 map { $data{$_} = $session->$_ } $session->columns;
245 for my $script ($session->scripts) {
247 map { $sdata{$_} = $script->$_ } $script->columns;
249 # the client doesn't need this info
250 delete $sdata{session};
252 delete $sdata{logfile};
254 push( @{$data{scripts}}, \%sdata );
261 # --------------------------------------------------------------------
262 # Returns various information on the sessions and scripts
263 # --------------------------------------------------------------------
266 my $type = $cgi->param('status_type') || "scripts";
268 if( $type eq 'scripts' ) {
269 my $session = ol_find_session();
270 ol_handle_result(ol_flesh_session($session));
272 } elsif( $type eq 'sessions' ) {
273 my @sessions = $SES->search( org => $org );
275 # can I do this in the DB without raw SQL?
276 @sessions = sort { $a->create_time <=> $b->create_time } @sessions;
278 push( @data, ol_flesh_session($_) ) for @sessions;
279 ol_handle_result(\@data);
284 sub ol_fetch_workstation {
286 $logger->debug("offline: Fetching workstation $name");
287 my $ws = $U->storagereq(
288 'open-ils.storage.direct.actor.workstation.search.name', $name);
289 ol_handle_result(OpenILS::Event->new('WORKSTATION_NOT_FOUND')) unless $ws;
296 # --------------------------------------------------------------------
297 # Sorts the script commands then forks a child to executes them.
298 # --------------------------------------------------------------------
301 my $commands = ol_collect_commands();
303 # --------------------------------------------------------------------
304 # Note that we must disconnect from opensrf before forking or the
305 # connection will be borked...
306 # --------------------------------------------------------------------
307 my $con = OpenSRF::Transport::PeerHandle->retrieve;
308 $con->disconnect if $con;
313 # --------------------------------------------------------------------
314 # Tell the client all is well
315 # --------------------------------------------------------------------
316 ol_handle_event('SUCCESS'); # - this exits
320 # --------------------------------------------------------------------
321 # close stdout/stderr or apache will wait on the child to finish
322 # --------------------------------------------------------------------
326 $logger->debug("offline: child $$ processing data...");
328 # --------------------------------------------------------------------
329 # The child re-connects to the opensrf network and processes
330 # the script requests
331 # --------------------------------------------------------------------
332 OpenSRF::System->bootstrap_client(config_file => $config{bootstrap});
335 ol_process_commands( $commands );
340 $logger->error("offline: child process error $e");
345 sub ol_file_to_perl {
347 open(F, "$fname") or ol_handle_event('OFFLINE_FILE_ERROR');
350 push(@p, JSON->JSON2perl($_)) for @d;
355 # collects the commands and sorts them on timestamp+delta
356 sub ol_collect_commands {
357 my $ses = ol_find_session();
360 # cycle through every script loaded to this session
361 for my $script ($ses->scripts) {
362 my $coms = ol_file_to_perl($script->logfile);
364 # cycle through all of the commands for this script
365 for my $com (@$coms) {
366 $$com{_worksation} = $script->workstation;
367 $$com{_realtime} = $script->time_delta + $com->{timestamp};
368 push( @commands, $com );
373 @commands = sort { $a->{_realtime} <=> $b->{_realtime} } @commands;
377 sub ol_process_commands {
378 my $commands = shift;
379 $logger->debug("offline: command = " . JSON->perl2JSON($_)) for @$commands;
382 sub ol_archive_files {