#!/usr/bin/env ruby require 'rubygems' if RUBY_VERSION < '1.9' require 'sinatra' require 'haml' require 'open-uri' require 'rest-client' require 't2-server' require 'myexperiment-rest' require 'cgi' #require "web-t2" TODO: move whole of WebT2App in lib class WebT2App < Sinatra::Base WEB_APP_NAME = "t2web" # TODO: const for TMP_UPLOAD_PATH ? - need to read from config file? set :port, 9494 set :views, File.dirname(__FILE__) + '/../views' set :public, File.dirname(__FILE__) + '/../public' # can be used from routes and views (haml) helpers do # Used before we sent the workflow inputs to the taverna server. Just converts # double quotations to single ones. That is because the t2-server library # is confused with double quotes and apparently it is not easy to fix. def t2_library_sanitize(string) ex = string.gsub('"', "'") end # # Deletes last new line of file if it exists! It is needed for t2 workflows that # do not sanitize properly, i.e. via a user-provided beanshell script # def chomp_last_newline(file) if File.file?(file) and File.size(file) > 1 f = open(file, "rb+") f.seek(-1, File::SEEK_END) f.truncate(File.size(file) - 1) if f.read(1) == "\n" f.close end end # Construct the complete or partial URL as MyExperimentRest lib expects it # TODO: Maybe update myExperimentREST lib to accept only wid and wkf_version # Minor for now def get_url_from_wid(wid, wkf_version) if wkf_version == "default" "/workflows/#{wid}" else "/workflows/#{wid}?version=#{wkf_version}" end end # Generates the contents of the header frame def generate_header_frame(my_exp_wkf, my_exp_usr) < #{generate_header_table(my_exp_wkf, my_exp_usr)} END end # Generates the contents of the header frame def generate_header_table(my_exp_wkf, my_exp_usr) <
NBIC logo
Workflow: #{@my_exp_wkf.title}
workflow by #{@my_exp_usr.name}
LUMC logo
END end # Generates tooltip html text for descriptions def generate_label_tooltip(input) "Description: " << CGI::unescapeHTML(input.descriptions[0]) end # Generates tooltip html text for textarea example def generate_textarea_tooltip(input) "Example: " << CGI::unescapeHTML(input.examples[0]) end # Generates the contents of the data-navigation frame def generate_data_navigation_frame(my_exp_wkf, uuid, wid, wkf_version, t2_server, finished_execution) data_navigation_frame = "" if my_exp_wkf.outputs.size >=1 my_exp_wkf.outputs.each do |output| data_navigation_frame << "" if finished_execution data_navigation_frame << "" else data_navigation_frame << "" end data_navigation_frame << "" end end data_navigation_frame << "
#{output.name}#{output.name}Loading Content...
" end # Check type of data and generate appropriate html for that result! def generate_html_result(data) html = "" #p data if data.instance_of? Array html = data.flatten.join('
') elsif data.instance_of? String html = data.gsub(/[\n]/, '
') else html = data end html end end # Create the Web UI for that workflow get "/#{WEB_APP_NAME}/workflow/:wid" do # Get http request's parameters # TODO: consider adding the following to a session @wid = params[:wid] @wkf_version = params[:wkf_version] || nil @t2_server = params[:server] || "http://test.mybiobank.org/taverna-server" # Get myExperiment workflow object # TODO: catch exception -- make custom exceptions? @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version) # Get myExperiment user object # TODO: catch exception -- make custom exceptions? @my_exp_usr = MyExperimentREST::User.from_uri(@my_exp_wkf.uploader_uri) haml :form end # Enact the workflow with the submitted parameters and returns # result display (involves checking run's status and getting results) post "/#{WEB_APP_NAME}/enact" do #p params # Get http POST request's parameters # TODO: consider adding the following to a session @wid = params[:wid] @wkf_version = params[:wkf_version] @t2_server = params[:server] @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version) # Get myExperiment user object (TODO: session!, exceptions) @my_exp_usr = MyExperimentREST::User.from_uri(@my_exp_wkf.uploader_uri) # use the uri reference to download the workflow locally #wkf_file = URI.parse(@my_exp_wkf.content_uri) wkf = open(@my_exp_wkf.content_uri).read # create run begin run = T2Server::Run.create(@t2_server, wkf) rescue T2Server::T2ServerError => e return "404 Not Found: run could not be instantiated!" end # Get the run as instance member to make visible in views @run_uuid = run.uuid # Set workflow inputs @my_exp_wkf.inputs.each do |input| if params[:"upload-checkbox-#{input.name}"] == "yes" filename = params[:"#{input.name}-file"] tmp_filename = "/tmp/#{WEB_APP_NAME}/#{filename}" # make sure that the file is uploaded completely, i.e. all it's # connections are closed #while `lsof -c cp | grep /tmp/#{WEB_APP_NAME}/#{filename}` != "" # sleep 1 #end chomp_last_newline(tmp_filename) run.upload_input_file(input.name, tmp_filename) else run.set_input(input.name, t2_library_sanitize(params["#{input.name}-input".to_sym]) ) end end # start run and wait until it is finished run.start haml :results end # Proxy operation (to bypass cross-domain AJAX) to get T2 run's status get '/runs/:uuid/status' do uuid = params[:uuid] t2_server = params[:server] response = RestClient.get t2_server + "/rest/runs/" + uuid + "/status", :content_type => "text/plain" response.to_str end # Get results for specified run and output - display it in data-display div # Cross-domain AJAX to get result from T2 get "/#{WEB_APP_NAME}/run/:uuid/output/:out" do # Get http request's parameters # TODO: consider adding the following to a session @wid = params[:wid] @wkf_version = params[:wkf_version] # Get myExperiment workflow object # TODO: with sessions that would be remembered @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version) @run_uuid = params[:uuid] @t2_server = params[:server] t2_output = params[:out] # Get t2 server and then the run using uuid server = T2Server::Server.connect(@t2_server) run = server.run(@run_uuid) # Get output from t2 server # TODO: that gets the whole output.. request client lib to support partial # download! -- refs could then be used to download the full results! begin data_lists = run.get_output(t2_output, false) rescue Exception => e data_lists = run.get_output("#{t2_output}.error", false) end # that should be a sample of the results -- not the complete results! data = generate_html_result(data_lists) data end # Used from input's upload-form to upload files without refresh (actually # a hidden iframe is refreshed). post "/#{WEB_APP_NAME}/upload" do filename = params[:file][:filename] tempfile = params[:file][:tempfile] FileUtils.mkdir("/tmp/#{WEB_APP_NAME}") unless File.exist?("/tmp/#{WEB_APP_NAME}") FileUtils.copy(tempfile.path, "/tmp/#{WEB_APP_NAME}/#{filename}") "Successfully copied #{filename}!!" end end # Start Web App WebT2App.run!