diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..cd66469 --- /dev/null +++ b/TODO.md @@ -0,0 +1,9 @@ +# To do list + +* [x] Add `serve` mode, which starts up a web server to serve results. +* [ ] Incorporate server into main anybadge module (allowing `anybadge serve`) +* [ ] Create a Docker image to run server +* [ ] Add CI test for Docker image +* [ ] Add CI to push server to Docker hub +* [ ] Allow thresholds dictionary to be passed through URL +* [ ] Support common badge server URL structure diff --git a/anybadge_server.py b/anybadge_server.py new file mode 100755 index 0000000..383a72a --- /dev/null +++ b/anybadge_server.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +""" +Anybadge Server + +This package provides a server for anybadge. +""" +from __future__ import print_function +from os import environ +import logging +import argparse +from anybadge import Badge + +# Import the correct version of HTTP server +try: + from http.server import HTTPServer, BaseHTTPRequestHandler +except ImportError: + from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler + +# Import the correct version of urlparse, depending on which version +# of Python we are using +try: + import urlparse +except ImportError: + import urllib.parse as urlparse + + +logger = logging.getLogger(__name__) + +DEFAULT_SERVER_PORT = 8000 +DEFAULT_SERVER_LISTEN_ADDRESS = 'localhost' + +SERVER_PORT = DEFAULT_SERVER_PORT +SERVER_LISTEN_ADDRESS = DEFAULT_SERVER_LISTEN_ADDRESS + + +class AnybadgeHTTPRequestHandler(BaseHTTPRequestHandler): + """Request handler for Anybadge HTTP server.""" + + def do_HEAD(self): + logging.debug('Sending head.') + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + + def do_GET(self): + logging.debug('Handling get request.') + self.do_HEAD() + + # Ignore request for favicon + if self.path == '/favicon.ico': + logging.debug('Ignoring favicon request.') + return + + # Parse the URL query string + parsed = urlparse.urlparse(self.path) + url_query = urlparse.parse_qs(parsed.query) + + label = '' + value = '' + color = 'green' + + # Extract the label and value portions + if 'label' in url_query: + label = url_query['label'][0] + + if 'value' in url_query: + value = url_query['value'][0] + + logging.debug('Label: %s Value: %s', label, value) + + if label and value and color: + logging.debug('All parameters present.') + badge = Badge(label=label, value=value, default_color=color) + for line in badge.badge_svg_text: + self.wfile.write(str.encode(line)) + + else: + logging.debug('Not all parameters present.') + + self.wfile.write(b"Anybadge Web Server.") + self.wfile.write(b"") + + help_text = """ +

Welcome to the Anybadge Web Server.

+ + You are seeing this message because you haven't passed all the query parameters + to display a badge. + + You need to pass at least a label and value parameter. + + Here is an example: + + \ + http://localhost:{port}/?label=Project%20Awesomeness&value=110% + """.format(port=SERVER_PORT) + + for line in help_text.splitlines(): + self.wfile.write(str.encode('

%s

' % line)) + self.wfile.write(b"") + + +def run(listen_address=DEFAULT_SERVER_LISTEN_ADDRESS, port=DEFAULT_SERVER_PORT): + server_address = (listen_address, port) + + global SERVER_PORT, SERVER_LISTEN_ADDRESS + + SERVER_PORT = port + SERVER_LISTEN_ADDRESS = listen_address + + httpd = HTTPServer(server_address, AnybadgeHTTPRequestHandler) + logging.info('Serving at: http://%s:%s' % server_address) + httpd.serve_forever() + + +def parse_args(): + logger.debug('Parsing command line arguments.') + parser = argparse.ArgumentParser(description="Run an anybadge server.") + parser.add_argument('-p', '--port', type=int, default=DEFAULT_SERVER_PORT, + help="Server port number. Default is %s. This can also be set via an environment " + "variable called ``ANYBADGE_PORT``." % DEFAULT_SERVER_PORT) + parser.add_argument('-l', '--listen-address', type=str, default=DEFAULT_SERVER_LISTEN_ADDRESS, + help="Server listen address. Default is %s. This can also be set via an environment " + "variable called ``ANYBADGE_LISTEN_ADDRESS``." % DEFAULT_SERVER_LISTEN_ADDRESS) + return parser.parse_args() + + +if __name__ == '__main__': + logging.basicConfig(format='%(asctime)-15s %(levelname)s:%(filename)s(%(lineno)d):%(funcName)s: %(message)s', + level=logging.DEBUG) + logger.info('Starting up anybadge server.') + + if 'ANYBADGE_PORT' in environ: + DEFAULT_SERVER_PORT = environ['ANYBADGE_PORT'] + + if 'ANYBADGE_LISTEN_ADDRESS' in environ: + DEFAULT_SERVER_LISTEN_ADDRESS = environ['ANYBADGE_LISTEN_ADDRESS'] + + args = parse_args() + run(listen_address=args.listen_address, port=args.port) diff --git a/setup.py b/setup.py index 8960128..a179ce0 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( version=bump(), author='Jon Grace-Cox', author_email='jongracecox@gmail.com', - py_modules=['anybadge'], + py_modules=['anybadge', 'anybadge_server'], setup_requires=['setuptools', 'wheel'], tests_require=[], install_requires=[], @@ -33,6 +33,7 @@ setup( }, url='https://github.com/jongracecox/anybadge', entry_points={ - 'console_scripts': ['anybadge=anybadge:main'], + 'console_scripts': ['anybadge=anybadge:main', + 'anybadge-server=anybadge_server:main'], } )