diff --git a/src/SuperBeam/RequestHandlers.py b/src/SuperBeam/RequestHandlers.py index 72a01d7..34fc3c5 100644 --- a/src/SuperBeam/RequestHandlers.py +++ b/src/SuperBeam/RequestHandlers.py @@ -1,3 +1,17 @@ +# -*- coding: utf-8 -*- +"""SuperBeam Handlers + +SuperBeam Handlers define how to handle certain requests to the +:class:`SuperBeamServer`. Each handler needs to be registered in ThumbHandler +`SuperBeamServer.do_GET()` function within the ``paths`` variable and imported +in the top of the :module:`SuperBeam` module. + +The handlers itself are defined in this module. + +Each class handler method needs to be a ``staticmethod``. The callee will call +the `handle()` with the ``httpd`` instance of the :class:`SuperBeamServer`. +""" + import os import json diff --git a/src/SuperBeam/__init__.py b/src/SuperBeam/__init__.py index 03ec188..026131c 100644 --- a/src/SuperBeam/__init__.py +++ b/src/SuperBeam/__init__.py @@ -17,10 +17,21 @@ from SuperBeam.RequestHandlers import ( class SuperBeamServer(BaseHTTPRequestHandler): + """SuperBeam Server Request Handler + + Handle incoming requests to serve information to the client. + + Class inherited `BaseHTTPRequestHandler`. + """ + + def __init__(self, debug=False, *args, **kwargs): + self.debug = debug + super(SuperBeamServer, self).__init__() def do_GET(self): # TODO Add globbing - print(threading.current_thread()) + if self.debug: + print(threading.current_thread()) paths = { 'index': ChunkTemplateHandler, '/': ChunkTemplateHandler, @@ -40,19 +51,28 @@ class SuperBeamServer(BaseHTTPRequestHandler): self.respond(paths[self.path]) def respond(self, handler): - print('='*30 + ' DEBUG ' + '='*30) - print('CONNECTION:', self.connection) - print('HEADERS :', self.headers) - print('REQUEST :', self.request) - print('REQUEST* :', self.requestline) - print('PATH :', self.path) - print('COMMAND :', self.command) - print('HANDLER :', handler) - print('='*30 + ' DEBUG ' + '='*30) + if self.debug: + print('='*30 + ' DEBUG ' + '='*30) + print('CONNECTION:', self.connection) + print('HEADERS :', self.headers) + print('REQUEST :', self.request) + print('REQUEST* :', self.requestline) + print('PATH :', self.path) + print('COMMAND :', self.command) + print('HANDLER :', handler) + print('='*30 + ' DEBUG ' + '='*30) handler.handle(self) def get_primary_ip(): + """Get primary IP address. + + Obtain the primary interface IP address. If an error occurs, the default + loopback adddress '127.0.0.1' is returned. + + Returns: + str: IP Address + """ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # doesn't even have to be reachable @@ -67,21 +87,42 @@ def get_primary_ip(): def get_qrcode(): + """Generate QR Code to be scanned by the SuperBeam Client. + + Returns: + pyqrcode.QRCode: SuperBeam QR Code + """ primary_ip = get_primary_ip() octets = [1] octets.extend([int(_) for _ in primary_ip.split('.')[::-1]]) url = 'http://superbe.am/q?' + base64.b64encode( struct.pack('BBBBB', *octets) ).decode('utf-8') - return pyqrcode.create(url) + return pyqrcode.create(url), primary_ip def show_qrcode(): - qrcode = get_qrcode() + """Display QR Code with link for SuperBeam Client. + + The QR code is generated in function `get_code()`. The QR code is rendered + in the terminal window. + """ + qrcode, primary_ip = get_qrcode() print(qrcode.terminal()) + print(f'SuperBeam Server: http:://{primary_ip}:8080/\n') def build_filelist(paths, recursive=True): + """List of files or directories to be served to SuperBeam clients. + + Args: + paths (list(str)): list of directories to serve. + recursive (bool, optional): serve subdirectories of `paths`. Defaults + to True + + Returns: + list: list of files with fullpath to be served. + """ filelist = [] for path in paths: if os.path.isdir(path) and recursive: @@ -94,6 +135,16 @@ def build_filelist(paths, recursive=True): def serve_forever(files): + """Start the SuperBeam server and serve `files`. + + Infinite main loop serving `files` via SuperBeam server. + + The server tries to obtain the primary IP address of the system and binds + the server to TCP port 8080. + + Args: + files (list(str)): a list of files with fullpath information to serve. + """ Handler = SuperBeamServer Handler.files = files with socketserver.ThreadingTCPServer(('', 8080), Handler) as httpd: