Skip to content

Commit

Permalink
Re-create data folder, change to importlib for static files (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin authored Dec 7, 2023
1 parent e94a359 commit f60314f
Show file tree
Hide file tree
Showing 5 changed files with 440 additions and 410 deletions.
5 changes: 3 additions & 2 deletions jbrowse_jupyter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# flake8: noqa
from .jbrowse_config import JBrowseConfig, create
from .util import launch, create_component
from .util import launch, create_component
from .dev_server import serve
__all__ = ['JBrowseConfig', 'create', 'launch', 'create_component', 'serve']

__all__ = ["JBrowseConfig", "create", "launch", "create_component", "serve"]
71 changes: 37 additions & 34 deletions jbrowse_jupyter/dev_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
import re
from http.server import HTTPServer, SimpleHTTPRequestHandler

'''
"""
This server takes inspiration from multiple solutions to provide:
* CORS enabled HTTPServer
- https://gist.github.com/acdha/925e9ffc3d74ad59c3ea
* Allowing Range Request Server
- https://github.com/danvk/RangeHTTPServer/blob/master/RangeHTTPServer
* Adding specific directory
- https://stackoverflow.com/a/46332163
'''
"""
# CREDIT FOR ENABLING RANGE REQUEST HTTP SERVER:
# lines 20-31, 34,37-52, 59-107
# https://github.com/danvk/RangeHTTPServer/blob/master/RangeHTTPServer


def copy_byte_range(infile, outfile, start=None, stop=None, bufsize=16*1024):
'''Like shutil.copyfileobj, but only copy a range of the streams.
def copy_byte_range(infile, outfile, start=None, stop=None, bufsize=16 * 1024):
"""Like shutil.copyfileobj, but only copy a range of the streams.
Both start and stop are inclusive.
'''
"""
if start is not None:
infile.seek(start)
while 1:
Expand All @@ -31,39 +31,40 @@ def copy_byte_range(infile, outfile, start=None, stop=None, bufsize=16*1024):
outfile.write(buf)


BYTE_RANGE_RE = re.compile(r'bytes=(\d+)-(\d+)?$')
BYTE_RANGE_RE = re.compile(r"bytes=(\d+)-(\d+)?$")


def parse_byte_range(byte_range):
"""
Returns the two numbers in 'bytes=123-456' or throws ValueError.
The last number or both numbers may be None.
"""
if byte_range.strip() == '':
if byte_range.strip() == "":
return None, None

m = BYTE_RANGE_RE.match(byte_range)
if not m:
raise ValueError('Invalid byte range %s' % byte_range)
raise ValueError("Invalid byte range %s" % byte_range)

first, last = [x and int(x) for x in m.groups()]
if last and last < first:
raise ValueError('Invalid byte range %s' % byte_range)
raise ValueError("Invalid byte range %s" % byte_range)
return first, last


class CustomRequestHandler (SimpleHTTPRequestHandler):
class CustomRequestHandler(SimpleHTTPRequestHandler):
"""
Creating a small HTTP request server
"""

def send_head(self):
if 'Range' not in self.headers:
if "Range" not in self.headers:
self.range = None
return SimpleHTTPRequestHandler.send_head(self)
try:
self.range = parse_byte_range(self.headers['Range'])
self.range = parse_byte_range(self.headers["Range"])
except ValueError:
self.send_error(400, 'Invalid byte range')
self.send_error(400, "Invalid byte range")
return None
first, last = self.range

Expand All @@ -72,28 +73,27 @@ def send_head(self):
f = None
ctype = self.guess_type(path)
try:
f = open(path, 'rb')
f = open(path, "rb")
except IOError:
self.send_error(404, 'File not found')
self.send_error(404, "File not found")
return None

fs = os.fstat(f.fileno())
file_len = fs[6]
if first >= file_len:
self.send_error(416, 'Requested Range Not Satisfiable')
self.send_error(416, "Requested Range Not Satisfiable")
return None

self.send_response(206)
self.send_header('Content-type', ctype)
self.send_header("Content-type", ctype)

if last is None or last >= file_len:
last = file_len - 1
response_length = last - first + 1

self.send_header('Content-Range',
'bytes %s-%s/%s' % (first, last, file_len))
self.send_header('Content-Length', str(response_length))
self.send_header('Last-Modified', self.date_time_string(fs.st_mtime))
self.send_header("Content-Range", "bytes %s-%s/%s" % (first, last, file_len))
self.send_header("Content-Length", str(response_length))
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
self.end_headers()
return f

Expand All @@ -107,11 +107,11 @@ def copyfile(self, source, outputfile):
copy_byte_range(source, outputfile, start, stop)

def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, OPTIONS')
self.send_header('Access-Control-Expose-Headers', '*')
self.send_header('Accept-Ranges', 'bytes')
self.send_header('Content-Type', 'application/octet-stream')
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
self.send_header("Access-Control-Expose-Headers", "*")
self.send_header("Accept-Ranges", "bytes")
self.send_header("Content-Type", "application/octet-stream")
SimpleHTTPRequestHandler.end_headers(self)

def translate_path(self, path):
Expand All @@ -122,8 +122,9 @@ def translate_path(self, path):


class DevServer(HTTPServer):
def __init__(self, base_path, server_address,
RequestHandlerClass=CustomRequestHandler):
def __init__(
self, base_path, server_address, RequestHandlerClass=CustomRequestHandler
):
self.base_path = base_path
HTTPServer.__init__(self, server_address, RequestHandlerClass)

Expand All @@ -144,19 +145,21 @@ def serve(data_path, **kwargs):
the dev server, default to localhost
"""
print("=============================================")
print("Warning: \n"
"This is a development environment.\n"
"This is not recommended for production.")
port = kwargs.get('port', 8080)
host = kwargs.get('host', "localhost")
print(
"Warning: \n"
"This is a development environment.\n"
"This is not recommended for production."
)
port = kwargs.get("port", 8080)
host = kwargs.get("host", "localhost")
# data_path = kwargs.get('path', ".")
# print('data', data_path)
# dir_path = os.path.join(os.path.dirname(__file__), data_path)
# print('dir path', dir_path)
# print('relative ', os.path.relpath(data_path, os.getcwd()))
# print('join', os.path.join(os.getcwd(), data_path))
httpd = DevServer(data_path, (host, port))
server = f'http://{host}:{port}'
server = f"http://{host}:{port}"
print("=============================================")
print(f'Server is now running at \n "{server}"')
httpd.serve_forever()
Loading

0 comments on commit f60314f

Please sign in to comment.