Skip to content

Commit

Permalink
Merge db0fb78 into 432f2cc
Browse files Browse the repository at this point in the history
  • Loading branch information
squirrelo committed Jun 19, 2014
2 parents 432f2cc + db0fb78 commit 751a52e
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 55 deletions.
50 changes: 50 additions & 0 deletions qiita_pet/handlers/analysis_handlers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from os.path import basename

from tornado.web import authenticated
from collections import defaultdict

Expand All @@ -7,6 +9,7 @@
from qiita_db.study import Study
from qiita_db.data import ProcessedData
from qiita_db.metadata_template import SampleTemplate
from qiita_db.job import Job
# login code modified from https://gist.github.com/guillaumevincent/4771570


Expand Down Expand Up @@ -78,3 +81,50 @@ def post(self):
samples = [(processed_data[data_type], sid) for sid in
sample_ids]
analysis.add_samples(samples)


class AnalysisWaitHandler(BaseHandler):
@authenticated
def get(self, analysis_id):
analysis = Analysis(analysis_id)
commands = []
for job in analysis.jobs:
jobject = Job(job)
commands.append("%s:%s" % (jobject.datatype, jobject.command[0]))

self.render("analysis_waiting.html", user=self.get_current_user(),
aid=analysis_id, aname=analysis.name,
commands=commands)

@authenticated
def post(self, analysis_id):
command_args = self.get_arguments("commands")
split = [x.split("#") for x in command_args]
analysis = Analysis(analysis_id)

commands = []
for data_type, command in split:
print "INPUT: ", data_type, command
job = Job.create(data_type, command, {}, analysis)
print "INPUT2: ", data_type, command
print "JOB %s %s:%s" % (job.id, job.datatype, job.command[0])
commands.append("%s:%s" % (data_type, command))

self.render("analysis_waiting.html", user=self.get_current_user(),
aid=analysis_id, aname=analysis.name,
commands=commands)
# fire off analysis run here


class AnalysisResultsHandler(BaseHandler):
@authenticated
def get(self, aid):
analysis = Analysis(aid)
jobres = defaultdict(list)
for job in analysis.jobs:
jobject = Job(job)
jobres[jobject.datatype].append((jobject.command[0],
jobject.results))

self.render("analysis_results.html", user=self.get_current_user(),
jobres=jobres, aname=analysis.name)
40 changes: 13 additions & 27 deletions qiita_pet/handlers/websocket_handlers.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# adapted from
# https://github.com/leporo/tornado-redis/blob/master/demos/websockets
from time import sleep

from redis import Redis
from tornadoredis import Client
from tornado.websocket import WebSocketHandler
import tornado.gen
from tornado.gen import engine, Task
from json import loads

# all messages are in json format. They must have the following format:
# 'job': jobname
# 'analysis': analysis_id
# 'msg': message to print
# 'analysis': what analysis this is from in format datatype:analysis
# 'results': list of files created if any
# 'command': what command this is from in format datatype#command


class MessageHandler(WebSocketHandler):
def __init__(self, *args, **kwargs):
super(MessageHandler, self).__init__(*args, **kwargs)
self.r_server = Redis()
self.redis = Client()
self.redis.connect()
# self.redis = Client()
# self.redis.connect()

def get_current_user(self):
user = self.get_secure_cookie("user")
Expand All @@ -32,33 +29,22 @@ def on_message(self, msg):
msginfo = loads(msg)
# listens for handshake from page
if "user:" in msginfo['msg']:
self.channel = msginfo['msg'].split(':')[1]
self.aid = msginfo['msg'].split()[0]
self.channel = msginfo['msg'].split()[1].split(':')[1]
# need to split the rest off to new func so it can be asynchronous
self.listen()

# decorator turns the function into an asynchronous generator object
@tornado.gen.engine
@engine
def listen(self):
# runs task given, with the yield required to get returned value
# equivalent of callback/wait pairing from tornado.gen
yield tornado.gen.Task(self.redis.subscribe, self.channel)
if not self.redis.subscribed:
self.write_message('ERROR IN SUBSCRIPTION')
# listen from tornadoredis makes the listen object asynchronous
# if using standard redis lib, it blocks while listening
self.redis.listen(self.callback)
# fight race condition by loading from redis after listen started
# need to use std redis lib because tornadoredis is in subscribed state
oldmessages = self.r_server.lrange(self.channel + ':messages', 0, -1)
if oldmessages is not None:
for message in oldmessages:
self.write_message(message)
sleep(5)
self.write_message({"analysis": self.aid, "msg": "allcomplete"})

def callback(self, msg):
if msg.kind == 'message':
self.write_message(str(msg.body))

@tornado.gen.engine
@engine
def on_close(self):
yield tornado.gen.Task(self.redis.unsubscribe, self.channel)
yield Task(self.redis.unsubscribe, self.channel)
self.redis.disconnect()
1 change: 1 addition & 0 deletions qiita_pet/static/css/style.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#template-content{
padding: 20px;
height: 100%;
}

37 changes: 37 additions & 0 deletions qiita_pet/templates/analysis_results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% extends sitebase.html%}

{%block head%}


{%end%}

{%block content%}
<div class="container">
<div class="row">
<h1>Analysis {{aname}}</h1>
</div>
<div class="row">
<div class="col-md-2">
<div class="panel-group" id="accordion">
{% for data_type, jobs in jobres.items() %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#{{data_type}}">{{data_type}}</a></h3>
</div>
<div id="{{data_type}}" class="panel-collapse collapse">
{% for job, result in jobs%}
<div class="panel-body">
<a href="/results/{{result}}" target="resframe">{{job}}</a>
</div>
{% end %}
</div>
</div>
{% end %}
</div>
</div>
<div class="col-md-10">
<iframe id="resframe" name="resframe" width="100%" height="900" frameBorder=0></iframe>
</div>
</div>
</div>
{%end%}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
noerror = true;

websocket.onopen = function() {
websocket.send(JSON.stringify({'msg': 'user:{{user}}'}));
console.log(JSON.stringify({'msg': 'user:{{user}}'}));
websocket.send(JSON.stringify({'msg': '{{aid}} user:{{user}}'}));
console.log(JSON.stringify({'msg':'{{aid}} user:{{user}}'}));
};
websocket.onmessage = function(evt) {
console.log(evt.data);
message = JSON.parse(evt.data);
if(message.job == '{{job}}') {
if(message.analysis == '{{aid}}') {
if(noerror && message.msg == 'allcomplete') {
window.location.replace("/completed/{{job}}");
window.location.replace("/analysis/results/{{aid}}");
}
list = document.getElementById(message.analysis);
if(message.msg.indexOf("ERROR") != -1) {
Expand All @@ -30,11 +30,7 @@
else {
list.style.color="Blue";
}
list.innerHTML = message.msg + '<br />';
for(var i=0; i<message.results.length; i++) {
list.innerHTML += '<a class="link" target="_blank" href="../' +
message.results[i] + '">Plot ' + (i+1) + '</a><br />';
}
list.innerHTML = message.msg;
}
};
websocket.onerror = function(evt) { };
Expand All @@ -52,24 +48,12 @@
{% end %}

{% block content %}
<table width='100%'>
<tr>
<td width=180 valign='top'>
1) Choose studies<br />
2) Select analyses<br />
3) Set analysis options<br />
4) Review analysis<br />
<b>5) Running analysis</b><br />
6) Analysis results<br />
</td>
<td>
<h1>Analysis {{job}}</h1>
{% for analysis in analyses %}
<h1>Analysis {{aname}}</h1>
{% for command in commands%}
<p>
{{analysis}}: <span id='{{analysis}}'>Queued</span>
{{command}}: <span id='{{command}}'>Queued</span>
</p>
{% end %}
</td></tr></table>
<div id='error'></div>

{% end %}
3 changes: 1 addition & 2 deletions qiita_pet/templates/select_commands.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ <h1>Select Commands</h1>
{% end %}
</ul>

<form role="form" action="/analysis/wait/" method="post">
<input type="hidden" name="analysis-id" value="{{aid}}">
<form role="form" action="/analysis/wait/{{aid}}" method="post">
<div class="tab-content" style="height:300px">
{% for data_type in data_types %}
<div class="tab-pane" id="{{ data_type }}">
Expand Down
2 changes: 1 addition & 1 deletion qiita_pet/templates/sitebase.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

{% block head %}{% end %}
</head>
<body style="padding-top: 65px;">
<body style="padding-top: 65px; height: 100%">
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
Expand Down
7 changes: 6 additions & 1 deletion qiita_pet/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
from qiita_pet.handlers.auth_handlers import (
AuthCreateHandler, AuthLoginHandler, AuthLogoutHandler, AuthVerifyHandler)
from qiita_pet.handlers.analysis_handlers import (
CreateAnalysisHandler, SelectStudiesHandler, SelectCommandsHandler)
CreateAnalysisHandler, SelectStudiesHandler, SelectCommandsHandler,
AnalysisWaitHandler, AnalysisResultsHandler)
from qiita_pet.handlers.websocket_handlers import MessageHandler

define("port", default=8888, help="run on the given port", type=int)

Expand All @@ -43,6 +45,9 @@ def __init__(self):
(r"/analysis/1", CreateAnalysisHandler),
(r"/analysis/2", SelectStudiesHandler),
(r"/analysis/3", SelectCommandsHandler),
(r"/analysis/wait/(.*)", AnalysisWaitHandler),
(r"/analysis/results/(.*)", AnalysisResultsHandler),
(r"/consumer/", MessageHandler),
(r"/mockup/", MockupHandler),
# 404 PAGE MUST BE LAST IN THIS LIST!
(r".*", NoPageHandler)
Expand Down

0 comments on commit 751a52e

Please sign in to comment.