source: trunk/gui/scripts/filexfer.tcl @ 742

Last change on this file since 742 was 683, checked in by mmc, 17 years ago

Fixed filexfer so that it tries to find the exportfile/importfile
commands if they're not on the user's path. Also, it creates the
spool directory automatically if it doesn't exist.

File size: 8.3 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: filexfer - support for file transfer with user's desktop
3#
4#  Supports interactions with the filexfer middleware, enabling
5#  Rappture to transfer files to and from the user's desktop.
6#  Files are downloaded by invoking "exportfile", and uploaded by
7#  invoking "importfile".  The middleware handles the rest.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2007  Purdue Research Foundation
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require BLT
16
17namespace eval Rappture { # forward declaration }
18namespace eval Rappture::filexfer {
19    variable enabled 0   ;# set to 1 when middleware is in place
20    variable commands    ;# complete path to exportfile/importfile
21    variable job         ;# used to manage bgexec jobs
22}
23
24# ----------------------------------------------------------------------
25# USAGE: Rappture::filexfer::init
26#
27# Called in the main application to see if the filexfer middleware
28# is installed.  Returns 1 if the middleware is installed, and 0
29# otherwise.
30# ----------------------------------------------------------------------
31proc Rappture::filexfer::init {} {
32    variable enabled
33    variable commands
34
35    #
36    # Look for the exportfile/importfile commands and see if
37    # they appear to be working.  If we have both, then this
38    # is "enabled".
39    #
40    foreach op {export import} {
41        set prog "${op}file"
42        set path [auto_execok $prog]
43        if {"" == $path} {
44            foreach dir {/apps/filexfer/bin /apps/bin} {
45                set p [file join $dir $prog]
46                if {[file executable $p]} {
47                    set path $p
48                    break
49                }
50            }
51        }
52        if {[file executable $path]} {
53            set commands($op) $path
54        } else {
55            return 0
56        }
57    }
58
59    return [set enabled 1]
60}
61
62# ----------------------------------------------------------------------
63# USAGE: Rappture::filexfer::enabled
64#
65# Clients use this to see if the filexfer stuff is up and running.
66# If so, then the GUI will provide "Download..." and other filexfer
67# options.  If not, then Rappture must be running within an
68# environment that doesn't support it.
69# ----------------------------------------------------------------------
70proc Rappture::filexfer::enabled {} {
71    variable enabled
72    return $enabled
73}
74
75# ----------------------------------------------------------------------
76# USAGE: Rappture::filexfer::upload <toolName> <controlList> <callback>
77#
78# Clients use this to prompt the user to upload a file.  The string
79# <toolName> is used to identify the application within the web form.
80# The <controlList> is a list of controls that could be uploaded:
81#
82#   { <id1> <label1> <desc1>  <id2> <label2> <desc2> ... }
83#
84# The user is prompted for each of the controls in <controlList>.
85# If successful, the <callback> is invoked to handle the uploaded
86# information.  If anything goes wrong, the same callback is used
87# to post errors near the widget that invoked this operation.
88# ----------------------------------------------------------------------
89proc Rappture::filexfer::upload {tool controlList callback} {
90    global env
91    variable enabled
92    variable commands
93    variable job
94
95    if {$enabled} {
96        set cmd $commands(import)
97        if {"" != $tool} {
98            lappend cmd --for "for $tool"
99        }
100
101        set dir ~/data/sessions/$env(SESSION)/spool
102        if {![file exists $dir]} {
103            catch {file mkdir $dir}
104        }
105
106        set i 0
107        foreach {path label desc} $controlList {
108            set file [file join $dir upload[pid]-[incr i]]
109            set file2path($file) $path
110            set file2label($file) $label
111            lappend cmd --label $label $file
112        }
113
114        uplevel #0 [list $callback error "Upload starting...\nA web browser page should pop up on your desktop.  Use that form to handle the upload operation.\n\nIf the upload form doesn't pop up, make sure that you're allowing pop ups from this site.  If it still doesn't pop up, you may be having trouble with the version of Java installed for your browser.  See our Support area for details.\n\nClick anywhere to dismiss this message."]
115
116        set job(output) ""
117        set job(error) ""
118
119        set status [catch {eval \
120            blt::bgexec ::Rappture::filexfer::job(control) \
121              -output ::Rappture::filexfer::job(output) \
122              -error ::Rappture::filexfer::job(error) \
123              $cmd
124        } result]
125
126        if {$status == 0} {
127            set changed ""
128            set errs ""
129            foreach file $job(output) {
130                # load the uploaded for this control
131                set status [catch {
132                    set fid [open $file r]
133                    fconfigure $fid -translation binary -encoding binary
134                    set info [read $fid]
135                    close $fid
136                    file delete -force $file
137                } result]
138
139                if {$status != 0} {
140                    append errs "Error loading data for \"$file2label($file)\":\n$result\n"
141                } else {
142                    lappend changed $file2path($file)
143                    uplevel #0 [list $callback path $file2path($file) data $info]
144                }
145            }
146            if {[llength $changed] == 0} {
147                set errs "The form was empty, so none of your controls were changed.  In order to upload a file, you must select the file name--or enter text into the copy/paste area--before pushing the Upload button."
148            }
149            if {[string length $errs] > 0} {
150                uplevel #0 [list $callback error $errs]
151            }
152        } else {
153            uplevel #0 [list $callback error $job(error)]
154        }
155    }
156}
157
158# ----------------------------------------------------------------------
159# USAGE: Rappture::filexfer::download <string> ?<filename>?
160#
161# Clients use this to send a file off to the user.  The <string>
162# is stored in a file called <filename> in the user's spool directory.
163# If there is already a file by that name, then the name is modified
164# to make it unique.  Once the string has been stored in the file,
165# a message is sent to all clients listening, letting them know
166# that the file is available.
167#
168# If anything goes wrong, this function returns a string that should
169# be displayed to the user to explain the problem.
170# ----------------------------------------------------------------------
171proc Rappture::filexfer::download {string {filename "output.txt"}} {
172    global env
173    variable enabled
174    variable commands
175    variable job
176
177    if {$enabled} {
178        # make a spool directory, if we don't have one already
179        set dir ~/data/sessions/$env(SESSION)/spool
180        if {![file exists $dir]} {
181            catch {file mkdir $dir}
182        }
183
184        if {[file exists [file join $dir $filename]]} {
185            #
186            # Find a similar file name that doesn't conflict
187            # with an existing file:  e.g., output2.txt
188            #
189            set root [file rootname $filename]
190            set ext [file extension $filename]
191            set counter 2
192            while {1} {
193                set filename "$root$counter$ext"
194                if {![file exists [file join $dir $filename]]} {
195                    break
196                }
197                incr counter
198            }
199        }
200
201        #
202        # Save the file in the spool directory, then have it
203        # exported.
204        #
205        if {[catch {
206            set file [file join $dir $filename]
207            set fid [open $file w]
208            fconfigure $fid -encoding binary -translation binary
209            puts -nonewline $fid $string
210            close $fid
211        } result]} {
212            return $result
213        }
214
215        set job(output) ""
216        set job(error) ""
217
218        set status [catch {blt::bgexec ::Rappture::filexfer::job(control) \
219            -output ::Rappture::filexfer::job(output) \
220            -error ::Rappture::filexfer::job(error) \
221            $commands(export) --timeout 300 --delete $file} result]
222
223        if {$status != 0} {
224            return $Rappture::filexfer::job(error)
225        }
226    }
227    return ""
228}
Note: See TracBrowser for help on using the repository browser.