-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #78 from astrofrog/load-fits
Added support for displaying FITS data
- Loading branch information
Showing
11 changed files
with
207 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import os | ||
import time | ||
import socket | ||
import logging | ||
from hashlib import md5 | ||
from threading import Thread | ||
|
||
__all__ = ['get_data_server'] | ||
|
||
|
||
def get_data_server(verbose=True): | ||
""" | ||
This starts up a flask server and returns a handle to a DataServer | ||
object which can be used to register files to serve. | ||
""" | ||
|
||
from flask import Flask | ||
from flask_cors import CORS | ||
|
||
class FlaskWrapper(Flask): | ||
|
||
port = None | ||
host = None | ||
|
||
def run(self, *args, **kwargs): | ||
self.host = kwargs.get('host', None) | ||
self.port = kwargs.get('port', None) | ||
try: | ||
super(FlaskWrapper, self).run(*args, **kwargs) | ||
finally: | ||
self.host = None | ||
self.port = None | ||
|
||
app = FlaskWrapper('DataServer') | ||
CORS(app) | ||
if verbose: | ||
log = logging.getLogger('werkzeug') | ||
log.setLevel(logging.ERROR) | ||
|
||
class DataServer(object): | ||
|
||
def __init__(self): | ||
self._files = {} | ||
self._thread = Thread(target=self.start_app) | ||
self._thread.daemon = True | ||
self._thread.start() | ||
self._app = app | ||
while self._app.host is None and self._app.port is None: | ||
time.sleep(0.1) | ||
|
||
@property | ||
def port(self): | ||
return self._app.port | ||
|
||
@property | ||
def host(self): | ||
return self._app.host | ||
|
||
def start_app(self): | ||
host = socket.gethostbyname('localhost') | ||
for port in range(8000, 9000): | ||
try: | ||
return app.run(host=host, port=port) | ||
except Exception: | ||
pass | ||
raise Exception("Could not start up data server") | ||
|
||
def serve_file(self, filename, real_name=True, extension=''): | ||
with open(filename, 'rb') as f: | ||
content = f.read() | ||
if real_name: | ||
hash = os.path.basename(filename) | ||
else: | ||
hash = md5(content).hexdigest() + extension | ||
self._files[hash] = os.path.abspath(filename) | ||
return 'http://' + self.host + ':' + str(self.port) + '/data/' + hash | ||
|
||
def get_file_contents(self, hash): | ||
with open(self._files[hash], 'rb') as f: | ||
return f.read() | ||
|
||
ds = DataServer() | ||
|
||
@app.route("/data/<hash>") | ||
def data(hash): | ||
return ds.get_file_contents(hash) | ||
|
||
return ds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,73 @@ | ||
import os | ||
import json | ||
from hashlib import md5 | ||
from tornado import web | ||
from notebook.utils import url_path_join | ||
from notebook.base.handlers import IPythonHandler | ||
|
||
__all__ = ['load_jupyter_server_extension'] | ||
|
||
|
||
STATIC_DIR = os.path.join(os.path.dirname(__file__), 'nbextension', 'static') | ||
CONFIG = os.path.expanduser('~/.pywwt') | ||
|
||
|
||
class WWTHTMLHandler(IPythonHandler): | ||
def get(self): | ||
with open(os.path.join(STATIC_DIR, 'wwt.html')) as f: | ||
content = f.read() | ||
self.finish(content) | ||
class WWTFileHandler(IPythonHandler): | ||
|
||
def get(self, filename): | ||
|
||
filename = os.path.basename(filename) | ||
|
||
# First we check if this is a standard file in the static directory | ||
if os.path.exists(os.path.join(STATIC_DIR, filename)): | ||
path = os.path.join(STATIC_DIR, filename) | ||
else: | ||
# If not, we open the config file which should contain a JSON | ||
# dictionary with filenames and paths. | ||
if not os.path.exists(CONFIG): | ||
raise web.HTTPError(404) | ||
with open(CONFIG) as f: | ||
config = json.load(f) | ||
if filename in config['paths']: | ||
path = config['paths'][filename] | ||
else: | ||
raise web.HTTPError(404) | ||
|
||
class WWTJSHandler(IPythonHandler): | ||
def get(self): | ||
with open(os.path.join(STATIC_DIR, 'wwt_json_api.js')) as f: | ||
with open(path, 'rb') as f: | ||
content = f.read() | ||
|
||
self.finish(content) | ||
|
||
|
||
def serve_file(path, extension=''): | ||
|
||
if not os.path.exists(path): | ||
raise ValueError("Path {0} does not exist".format(path)) | ||
|
||
hash = md5(path.encode('utf-8')).hexdigest() + extension | ||
|
||
with open(CONFIG) as f: | ||
config = json.load(f) | ||
|
||
if hash not in config['paths']: | ||
|
||
config['paths'][hash] = os.path.abspath(path) | ||
|
||
with open(CONFIG, 'w') as f: | ||
json.dump(config, f) | ||
|
||
return '/wwt/' + hash | ||
|
||
|
||
def load_jupyter_server_extension(nb_server_app): | ||
|
||
web_app = nb_server_app.web_app | ||
host_pattern = '.*$' | ||
|
||
route_pattern = url_path_join(web_app.settings['base_url'], '/wwt.html') | ||
web_app.add_handlers(host_pattern, [(route_pattern, WWTHTMLHandler)]) | ||
if not os.path.exists(CONFIG): | ||
config = {'paths': {}} | ||
with open(CONFIG, 'w') as f: | ||
json.dump(config, f) | ||
|
||
route_pattern = url_path_join(web_app.settings['base_url'], '/wwt_json_api.js') | ||
web_app.add_handlers(host_pattern, [(route_pattern, WWTJSHandler)]) | ||
route_pattern = url_path_join(web_app.settings['base_url'], '/wwt/(.*)') | ||
web_app.add_handlers(host_pattern, [(route_pattern, WWTFileHandler)]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.