root/t2-web/trunk/bin/web_t2_service.rb @ 142

Revision 142, 7.4 KB (checked in by kostas.karasavvas@…, 3 years ago)

Changed results page divs to frames!

Line 
1#!/usr/bin/env ruby
2
3require 'rubygems' if RUBY_VERSION < '1.9'
4require 'sinatra'
5require 'haml'
6require 'rest-open-uri'
7require 'rest-client'
8require 't2-server'
9require 'myexperiment-rest'
10#require "web-t2" TODO: move whole of WebT2App in lib
11
12
13class WebT2App < Sinatra::Base
14
15  WEB_APP_NAME = "t2web"
16  # TODO: const for TMP_UPLOAD_PATH ? - need to read from config file?
17
18  set :port, 9494
19  set :views, File.dirname(__FILE__) + '/../views'
20  set :public, File.dirname(__FILE__) + '/../public'
21
22  # can be used from routes and views (haml)
23  helpers do
24
25    # Used before we sent the workflow inputs to the taverna server. Just converts
26    # double quotations to single ones. That is because the t2-server library
27    # is confused with double quotes and apparently it is not easy to fix.
28    def t2_library_sanitize(string)
29      ex = string.gsub('"', "'")
30    end
31
32
33    # used by haml code to place default values in textareas, etc.
34    def html_sanitise(string)
35      # escape double quotes characters
36      ex = string.gsub('"', '&quot;')
37      # convert newlines to HTML newlines to display in textareas inputs
38      ex = ex.gsub(/[\n]/, '&#xA;')
39    end
40
41    #
42    # Deletes last new line of file if it exists! It is needed for t2 workflows that
43    # do not sanitize properly, i.e. via a user-provided beanshell script
44    #
45    def chomp_last_newline(file)
46
47      if File.file?(file) and File.size(file) > 1
48        f = open(file, "rb+")
49        f.seek(-1, File::SEEK_END)
50        f.truncate(File.size(file) - 1) if f.read(1) == "\n"
51        f.close
52      end
53
54    end
55   
56    # Construct the complete or partial URL as MyExperimentRest lib expects it
57    # TODO: Maybe update myExperimentRest lib to accept only wid and wkf_version
58    # Minor for now
59    def get_url_from_wid(wid, wkf_version)
60      if wkf_version == "default"
61        "/workflows/#{wid}"
62      else
63        "/workflows/#{wid}?version=#{wkf_version}"
64      end
65    end
66
67
68    # Generates the contents of the header frame
69    def generate_header_frame(my_exp_wkf)
70      "<html>" <<
71         "<head><link href='/css/results_header.css' rel='stylesheet'/></head>" <<
72         "<body>" <<
73           "<p><h2>Workflow: #{my_exp_wkf.title}</h2></p>" <<
74         "</body>" <<
75      "</html>"
76    end
77
78
79    # Generates the contents of the data-navigation frame
80    def generate_data_navigation_frame(my_exp_wkf, uuid, wid, wkf_version, t2_server, finished_execution)
81
82      data_navigation_frame = "<html><head><link href='/css/results_navigation.css' rel='stylesheet'/></head><body><table>"
83      if my_exp_wkf.outputs.size >=1
84        my_exp_wkf.outputs.each do |output|
85          data_navigation_frame << "<tr>"
86          if finished_execution
87            data_navigation_frame << "<a href='javascript:void(0);' onclick='parent.getSampleOutput(\\\"#{t2_server}\\\", \\\"#{uuid}\\\", " <<
88                                     "\\\"#{output.name}\\\", \\\"#{wid}\\\", \\\"#{wkf_version}\\\");'>#{output.name}</a>" <<
89                                     "<br>"
90          else
91            data_navigation_frame << "<td>#{output.name}</td><td><img src='/images/snake_transparent.gif' alt='Loading Content...'></td>"
92          end
93          data_navigation_frame << "</tr>"
94        end
95      end
96      data_navigation_frame << "</table></body></html>"
97    end
98
99
100    # Check type of data and generate appropriate html for that result!
101    def generate_html_result(data)
102      html = ""
103      #p data
104      if data.instance_of? Array
105        html = data.flatten.join('<br>')
106      elsif data.instance_of? String
107        html = data.gsub(/[\n]/, '<br>')
108      else
109        html = data
110      end
111      html
112    end
113
114  end
115
116
117
118  # Create the Web UI for that workflow
119  get "/#{WEB_APP_NAME}/workflow/:wid" do
120
121    # Get http request's parameters
122    # TODO: consider adding the following to a session
123    @wid = params[:wid]
124    @wkf_version = params[:wkf_version] || "default"
125    @t2_server = params[:server] || "http://test.mybiobank.org/taverna-server"
126
127    # Get myExperiment workflow object
128    @my_exp_wkf = MyExperimentREST::Workflows.new.read(get_url_from_wid(@wid, @wkf_version))
129
130    haml :form
131
132  end
133
134
135  # Enact the workflow with the submitted parameters and returns
136  # result display (involves checking run's status and getting results)
137  post "/#{WEB_APP_NAME}/enact" do
138    #p params
139
140    # Get http POST request's parameters
141    # TODO: consider adding the following to a session
142    @wid = params[:wid]
143    @wkf_version = params[:wkf_version]
144    @t2_server = params[:server]
145
146    # Get myExperiment workflow object (TODO: session!)
147    @my_exp_wkf = MyExperimentREST::Workflows.new.read(get_url_from_wid(@wid, @wkf_version))
148
149    # use the uri reference to download the workflow locally
150    wkf_file = URI.parse(@my_exp_wkf.xml_uri)
151    wkf = wkf_file.read
152
153    # create run
154    begin
155      run = T2Server::Run.create(@t2_server, wkf)
156    rescue T2Server::T2ServerError => e
157      return "404 Not Found: run could not be instantiated!"
158    end
159
160    # Get the run as instance member to make visible in views
161    @run_uuid = run.uuid
162
163    @my_exp_wkf.inputs.each do |input|
164      if params[:"upload-checkbox-#{input.name}"] == "yes"
165        filename = params[:"#{input.name}-file"]
166        tmp_filename = "/tmp/#{WEB_APP_NAME}/#{filename}"
167        chomp_last_newline(tmp_filename)
168        run.upload_input_file(input.name, tmp_filename)
169      else
170        run.set_input(input.name, t2_library_sanitize(params["#{input.name}-input".to_sym]) )
171      end
172    end
173
174    # start run and wait until it is finished
175    run.start
176
177    haml :results
178  end
179
180
181
182  # Proxy operation (to bypass cross-domain AJAX) to get T2 run's status
183  get '/runs/:uuid/status' do
184    uuid = params[:uuid]
185    t2_server = params[:server]
186
187    response = RestClient.get t2_server + "/rest/runs/" + uuid + "/status", :content_type => "text/plain"
188
189    response.to_str
190  end
191
192
193
194  # Get results for specified run and output - display it in data-display div
195  # Cross-domain AJAX to get result from T2
196  get "/#{WEB_APP_NAME}/run/:uuid/output/:out" do
197
198    # Get http request's parameters
199    # TODO: consider adding the following to a session
200    @wid = params[:wid]
201    @wkf_version = params[:wkf_version]
202
203    # Get myExperiment workflow object
204    # TODO: with sessions that would be remembered
205    @my_exp_wkf = MyExperimentREST::Workflows.new.read(get_url_from_wid(@wid, @wkf_version))
206
207    @run_uuid = params[:uuid]
208    @t2_server = params[:server]
209    t2_output = params[:out]
210
211    # Get t2 server and then the run using uuid
212    server = T2Server::Server.connect(@t2_server)
213    run = server.run(@run_uuid)
214
215    # Get output from t2 server
216    # TODO: that gets the whole output.. request client lib to support partial
217    # download! -- refs could then be used to download the full results!
218    begin
219      data_lists = run.get_output(t2_output, false)
220    rescue Exception => e
221      data_lists = run.get_output("#{t2_output}.error", false)
222    end
223   
224    # that should be a sample of the results -- not the complete results!
225    data = generate_html_result(data_lists)
226
227    data
228  end
229
230
231  # Used from input's upload-form to upload files without refresh (actually
232  # a hidden iframe is refreshed).
233  post "/#{WEB_APP_NAME}/upload" do
234    filename = params[:file][:filename]
235    tempfile = params[:file][:tempfile]
236    FileUtils.mkdir("/tmp/#{WEB_APP_NAME}") unless File.exist?("/tmp/#{WEB_APP_NAME}")
237    FileUtils.copy(tempfile.path, "/tmp/#{WEB_APP_NAME}/#{filename}")
238  end
239
240end
241
242
243# Start Web App
244WebT2App.run!
Note: See TracBrowser for help on using the browser.