Files
cellxgene-gateway/gateway.py
2019-08-27 16:14:10 -04:00

174 lines
5.2 KiB
Python

# Copyright 2019 Novartis Institutes for BioMedical Research Inc. Licensed
# under the Apache License, Version 2.0 (the "License"); you may not use
# this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless
# required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. See the License for
# the specific language governing permissions and limitations under the License.
# import BaseHTTPServer
import datetime
import os
from threading import Thread
from flask import Flask, redirect, render_template, request, send_from_directory
from flask_api import status
from werkzeug import secure_filename
import env
from backend_cache import BackendCache
from cellxgene_exception import CellxgeneException
from dir_util import create_dir, recurse_dir, render_entries
from extra_scripts import get_extra_scripts
from path_util import get_dataset, get_file_path
from process_exception import ProcessException
from prune_process_cache import PruneProcessCache
from util import current_time_stamp
app = Flask(__name__)
cache = BackendCache()
location = f"{env.gateway_protocol}://{env.gateway_host}"
@app.errorhandler(CellxgeneException)
def handle_invalid_usage(error):
message = f"{error.http_status} Error : {error.message}"
return (
render_template(
"cellxgene_error.html", extra_scripts=get_extra_scripts(), message=message
),
error.http_status,
)
@app.errorhandler(ProcessException)
def handle_invalid_process(error):
message = []
message.append(error.message)
message.append(f"{error.http_status} Error.")
message.append(f"Stdout: {error.stdout}")
message.append(f"Stderr: {error.stderr}")
return (
render_template(
"process_error.html", extra_scripts=get_extra_scripts(), message=message
),
error.http_status,
)
@app.route("/favicon.ico")
def favicon():
return send_from_directory(
os.path.join(app.root_path, "static"),
"nibr.ico",
mimetype="image/vnd.microsof.icon",
)
@app.route("/")
def index():
users = [
name
for name in os.listdir(env.cellxgene_data)
if os.path.isdir(os.path.join(env.cellxgene_data, name))
]
return render_template(
"index.html",
ip=env.ip,
cellxgene_data=env.cellxgene_data,
extra_scripts=get_extra_scripts(),
users=users,
)
@app.route("/make_user", methods=["POST"])
def make_user():
dir_name = request.form["directory"]
create_dir(env.cellxgene_data, dir_name)
return redirect(location, code=302)
@app.route("/make_subdir", methods=["POST"])
def make_subdir():
parent_path = os.path.join(env.cellxgene_data, request.form["usernames"])
dir_name = request.form["directory"]
create_dir(parent_path, dir_name)
return redirect(location, code=302)
@app.route("/upload_file", methods=["POST"])
def upload_file():
upload_dir = request.form["path"]
full_upload_path = env.cellxgene_data + "/" + upload_dir
if os.path.isdir(full_upload_path):
if request.method == "POST":
if "file" in request.files:
f = request.files["file"]
if f and f.filename.endswith(".h5ad"):
f.save(full_upload_path + "/" + secure_filename(f.filename))
return redirect("/filecrawl.html", code=302)
else:
raise CellxgeneException(
"Uploaded file must be in anndata (.h5ad) format.",
status.HTTP_400_BAD_REQUEST,
)
else:
raise CellxgeneException(
"A file must be chosen to upload.", status.HTTP_400_BAD_REQUEST
)
else:
raise CellxgeneException("Invalid directory.", status.HTTP_400_BAD_REQUEST)
return redirect(env.location, code=302)
@app.route("/filecrawl.html")
def filecrawl():
entries = recurse_dir(env.cellxgene_data)
rendered_html = render_entries(entries)
return render_template(
"filecrawl.html", extra_scripts=get_extra_scripts(), rendered_html=rendered_html
)
@app.route("/view/<path:path>")
def do_GET(path):
dataset = get_dataset(path)
file_path = get_file_path(dataset)
match = cache.check_entry(dataset)
if match is None:
uascripts = get_extra_scripts()
match = cache.create_entry(dataset, file_path, uascripts)
match.timestamp = current_time_stamp()
if match.status == "loaded":
return match.serve_content(path)
elif match.status == "loading":
launch_time = datetime.datetime.fromtimestamp(match.launchtime)
return render_template(
"loading.html", launchtime=launch_time, all_output=match.all_output
)
elif match.status == "error":
raise ProcessException.from_pid_object(match)
if __name__ == "__main__":
background_thread = Thread(target=PruneProcessCache(cache))
background_thread.start()
app.run(host="0.0.0.0", port=5005, debug=False)