[LON-CAPA-cvs] cvs: loncom /lonnet/perl lonnet.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Wed, 31 Mar 2004 19:25:08 -0000


This is a MIME encoded message

--raeburn1080761108
Content-Type: text/plain

raeburn		Wed Mar 31 14:25:08 2004 EDT

  Modified files:              
    /loncom/lonnet/perl	lonnet.pm 
  Log:
  Changes to lonnet::getfile to support replication of uploaded files in /userfiles from course's home server to requesting server. Files are copied from /home/httpd/lonUsers/...../userfiles/  and stored in /home/httpd/html/userfiles/....
  If the requested file already exists on the requesting server, then its last modified time is compared with the last-modified information in a HEAD request to /raw/uploaded for the same file on the home server. If the file is stale a new copy is requested.
  
  
--raeburn1080761108
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20040331142508.txt"

Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.480 loncom/lonnet/perl/lonnet.pm:1.481
--- loncom/lonnet/perl/lonnet.pm:1.480	Tue Mar 30 15:46:24 2004
+++ loncom/lonnet/perl/lonnet.pm	Wed Mar 31 14:25:08 2004
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.480 2004/03/30 20:46:24 www Exp $
+# $Id: lonnet.pm,v 1.481 2004/03/31 19:25:08 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -32,6 +32,7 @@
 use strict;
 use LWP::UserAgent();
 use HTTP::Headers;
+use Date::Parse;
 use vars 
 qw(%perlvar %hostname %homecache %badServerCache %hostip %iphost %spareid %hostdom 
    %libserv %pr %prp %metacache %packagetab %titlecache %courseresversioncache %resversioncache
@@ -1200,6 +1201,12 @@
 #         and will then be copied to
 #          /home/httpd/lonUsers/$domain/1/2/3/$course/userfiles/$file in
 #         course's home server.
+# action = uploaddoc - /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
+#         will be retrived from $ENV{form.$source} via DOCS interface to
+#         /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
+#         and will then be copied to /home/httpd/lonUsers/1/2/3/$course/userfiles/$file
+#         in course's home server.
+
 
 sub process_coursefile {
     my ($action,$docuname,$docudom,$docuhome,$file,$source)=@_;
@@ -1207,7 +1214,7 @@
     if ($action eq 'propagate') {
         $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file
                             ,$docuhome);
-    } elsif ($action eq 'copy') {
+    } else {
         my $fetchresult = '';
         my $fpath = '';
         my $fname = $file;
@@ -1223,14 +1230,29 @@
                 }
             }
         }
-        if ($source eq '') {
-            $fetchresult = 'no source file';
-        } else {
-            my $destination = $filepath.'/'.$fname;
-            print STDERR "Getting ready to rename $source to $destination\n";
-            rename($source,$destination);
+        if ($action eq 'copy') {
+            if ($source eq '') {
+                $fetchresult = 'no source file';
+                return $fetchresult;
+            } else {
+                my $destination = $filepath.'/'.$fname;
+                rename($source,$destination);
+                $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
+                                 $docuhome);
+            }
+        } elsif ($action eq 'uploaddoc') {
+            open(my $fh,'>'.$filepath.'/'.$fname);
+            print $fh $ENV{'form.'.$source};
+            close($fh);
             $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
                                  $docuhome);
+            if ($fetchresult eq 'ok') {
+                return '/uploaded/'.$fpath.'/'.$fname;
+            } else {
+                &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.
+                        ' to host '.$docuhome.': '.$fetchresult);
+                return '/adm/notfound.html';
+            }
         }
     }
     unless ( ($fetchresult eq 'ok') || ($fetchresult eq 'no source file') ) {
@@ -1258,6 +1280,7 @@
 # See if there is anything left
     unless ($fname) { return 'error: no uploaded file'; }
     chop($ENV{'form.'.$formname});
+    my $url = '';
 # Create the directory if not present
     my $docuname='';
     my $docudom='';
@@ -1266,6 +1289,12 @@
 	$docuname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
 	$docudom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
 	$docuhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};
+        if ($ENV{'form.folder'} =~ m/^default/) {
+            $url = &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);
+        } else {
+            $fname=$ENV{'form.folder'}.'/'.$fname;
+            $url = &process_coursefile('uploaddoc',$docuname,$docudom,$docuhome,$fname,$formname);
+        }
     } else {
         $docuname=$ENV{'user.name'};
         $docudom=$ENV{'user.domain'};
@@ -4267,9 +4296,13 @@
     my %bighash;
     my $syval='';
     if (($ENV{'request.course.fn'}) && ($thisfn)) {
+        my $targetfn = $thisfn;
+        if ( ($thisfn =~ m/^uploaded\//) && ($thisfn !~ m/\.(page|sequence)$/) ) {
+            $targetfn = 'adm/wrapper/'.$thisfn;
+        }
         if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
                       &GDBM_READER(),0640)) {
-	    $syval=$hash{$thisfn};
+	    $syval=$hash{$targetfn};
             untie(%hash);
         }
 # ---------------------------------------------------------- There was an entry
@@ -4321,7 +4354,7 @@
                  }
 	      }
               untie(%bighash)
-           } 
+           }
         }
         if ($syval) {
            return &symbclean($syval.'___'.$thisfn); 
@@ -4524,39 +4557,112 @@
 # ------------------------------------------------------------ Serves up a file
 # returns either the contents of the file or 
 # -1 if the file doesn't exist
-# -2 if an error occured when trying to aqcuire the file
+#
+# if the target is a file that was uploaded via DOCS, 
+# a check will be made to see if a current copy exists on the local server,
+# if it does this will be served, otherwise a copy will be retrieved from
+# the home server for the course and stored in /home/httpd/html/userfiles on
+# the local server.   
 
 sub getfile {
-    my $file=shift;
-    if ($file=~/^\/*uploaded\//) { # user file
-	my $ua=new LWP::UserAgent;
-	my $request=new HTTP::Request('GET',&tokenwrapper($file));
-	my $response=$ua->request($request);
-	if ($response->is_success()) {
-	    return $response->content;
-	} else { 
-	    #&logthis("Return Code is ".$response->code." for $file ".
-	    #         &tokenwrapper($file));
-	    # 500 for ISE when tokenwrapper can't figure out what server to
-            #  contact
-            # 503 when lonuploadacc can't contact the requested server
-	    if ($response->code eq 503 || $response->code eq 500) {
-		return -2;
-	    } else {
-		return -1;
-	    }
-	}
+    my ($file,$caller) = @_;
+    if ($file=~ m|^/*uploaded/(\w+)/(\w+)/(.+)$|) { # user file
+        my $info;
+        my $cdom = $1;
+        my $cnum = $2;
+        my $filename = $3;
+        my $path = $Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles';
+        my ($lwpresp,$rtncode);
+        my $localfile = $path.'/'.$cdom.'/'.$cnum.'/'.$filename;
+        if (-e "$localfile") {
+            my @fileinfo = stat($localfile);
+            $lwpresp = &getuploaded('HEAD',$file,$cdom,$cnum,\$info,\$rtncode);
+            if ($lwpresp eq 'ok') {
+                if ($info > $fileinfo[9]) {
+                    $info = '';
+                    $lwpresp = &getuploaded('GET',$file,$cdom,$cnum,\$info,\$rtncode);
+                    if ($lwpresp eq 'ok') {
+                        open (FILE,">$localfile");
+                        print FILE $info;
+                        close(FILE);
+                        if ($caller eq 'uploadrep') {
+                            return 'ok';
+                        } else {
+                            return $info;
+                        }
+                    } else {
+                        return -1;
+                    }
+	        } else {
+                    return &readfile($localfile);
+                }
+            } else {
+                if ($rtncode eq '404') {
+                    unlink($localfile);
+                }
+                return -1;
+            }
+	} else {
+            $lwpresp = &getuploaded('GET',$file,$cdom,$cnum,\$info,\$rtncode);
+            if ($lwpresp eq 'ok') {
+                my @parts = ($cdom,$cnum); 
+                if ($filename =~ m|^(.+)/[^/]+$|) {
+                    push @parts, split(/\//,$1);
+                }
+                foreach my $part (@parts) {
+                    $path .= '/'.$part;
+                    if (!-e $path) {
+                        mkdir($path,0770);
+                    }
+                }
+                open (FILE,">$localfile");
+                print FILE $info;
+                close(FILE);
+                if ($caller eq 'uploadrep') {
+                    return 'ok';
+                } else {
+                    return $info;
+                }
+            } else {
+                return -1;
+            }
+        }
     } else { # normal file from res space
 	&repcopy($file);
-	if (! -e $file ) { return -1; };
-	my $fh;
-	open($fh,"<$file");
-	my $a='';
-	while (<$fh>) { $a .=$_; }
-	return $a;
+        return &readfile($file);
     }
 }
 
+sub getuploaded {
+    my ($reqtype,$uri,$cdom,$cnum,$info,$rtncode) = @_;
+    $uri=~s/^\///;
+    $uri = 'http://'.$hostname{ &homeserver($cnum,$cdom)}.'/raw/'.$uri;
+    my $ua=new LWP::UserAgent;
+    my $request=new HTTP::Request($reqtype,$uri);
+    my $response=$ua->request($request);
+    $$rtncode = $response->code;
+    if ($response->is_success()) {
+        if ($reqtype eq 'HEAD') {
+            $$info = &Date::Parse::str2time( $response->header('Last-modified') );
+        } elsif ($reqtype eq 'GET') {
+            $$info = $response->content;
+        }
+        return 'ok';
+    } else {
+        return 'failed';
+    }
+}
+
+sub readfile {
+    my $file = shift;
+    if ( (! -e $file ) || ($file eq '') ) { return -1; };
+    my $fh;
+    open($fh,"<$file");
+    my $a='';
+    while (<$fh>) { $a .=$_; }
+    return $a;
+}
+
 sub filelocation {
   my ($dir,$file) = @_;
   my $location;
@@ -5560,8 +5666,29 @@
 
 =item *
 
-getfile($file) : returns the entire contents of a file or -1; it
-properly subscribes to and replicates the file if neccessary.
+getfile($file,$caller) : two cases - requests for files in /res or in /uploaded.
+(a) files in /uploaded
+  (i) If a local copy of the file exists - 
+      compares modification date of local copy with last-modified date for 
+      definitive version stored on home server for course. If local copy is 
+      stale, requests a new version from the home server and stores it. 
+      If the original has been removed from the home server, then local copy 
+      is unlinked.
+  (ii) If local copy does not exist -
+      requests the file from the home server and stores it. 
+  
+  If $caller is 'uploadrep':  
+    This indicates a call from lonuploadrep.pm (PerlHeaderParserHandler phase)
+    for request for files originally uploaded via DOCS. 
+     - returns 'ok' if fresh local copy now available, -1 otherwise.
+  
+  Otherwise:
+     This indicates a call from the content generation phase of the request.
+     -  returns the entire contents of the file or -1.
+     
+(b) files in /res
+   - returns the entire contents of a file or -1; 
+   it properly subscribes to and replicates the file if neccessary.
 
 =item *
 

--raeburn1080761108--