diff options
| author | Lex Neva <lexelby@users.noreply.github.com> | 2020-04-28 12:34:05 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-28 18:34:05 +0200 |
| commit | cb2b4e3522cb7f426ba5ad3e68deb9e6ccc581ec (patch) | |
| tree | 2a2f38823c3c9f0b5439ce2aa7c9040299109292 /lib/api/server.py | |
| parent | eb526927e16954390d06929535d6f5c3766b5f6c (diff) | |
electron simulator (#531)
Diffstat (limited to 'lib/api/server.py')
| -rw-r--r-- | lib/api/server.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/api/server.py b/lib/api/server.py new file mode 100644 index 00000000..c57a1785 --- /dev/null +++ b/lib/api/server.py @@ -0,0 +1,110 @@ +import errno +import logging +import socket +from threading import Thread +import time + +from flask import Flask, request, g +import requests + +from ..utils.json import InkStitchJSONEncoder +from .simulator import simulator +from .stitch_plan import stitch_plan + + +class APIServer(Thread): + def __init__(self, *args, **kwargs): + self.extension = args[0] + Thread.__init__(self, *args[1:], **kwargs) + self.daemon = True + self.shutting_down = False + self.app = None + self.host = None + self.port = None + self.ready = False + + self.__setup_app() + + def __setup_app(self): # noqa: C901 + self.app = Flask(__name__) + self.app.json_encoder = InkStitchJSONEncoder + + self.app.register_blueprint(simulator, url_prefix="/simulator") + self.app.register_blueprint(stitch_plan, url_prefix="/stitch_plan") + + @self.app.before_request + def store_extension(): + # make the InkstitchExtension object available to the view handling + # this request + g.extension = self.extension + + @self.app.route('/shutdown', methods=['POST']) + def shutdown(): + self.shutting_down = True + request.environ.get('werkzeug.server.shutdown')() + return "shutting down" + + @self.app.route('/ping') + def ping(): + return "pong" + + def stop(self): + # for whatever reason, shutting down only seems possible in + # the context of a flask request, so we'll just make one + requests.post("http://%s:%s/shutdown" % (self.host, self.port)) + + def disable_logging(self): + logging.getLogger('werkzeug').setLevel(logging.ERROR) + + def run(self): + self.disable_logging() + + self.host = "127.0.0.1" + self.port = 5000 + + while True: + try: + self.app.run(self.host, self.port, threaded=True) + except socket.error as e: + if e.errno == errno.EADDRINUSE: + self.port += 1 + continue + else: + raise + else: + break + + def ready_checker(self): + """Wait until the server is started. + + Annoyingly, there's no way to get a callback to be run when the Flask + server starts. Instead, we'll have to poll. + """ + + while True: + if self.port: + try: + response = requests.get("http://%s:%s/ping" % (self.host, self.port)) + if response.status_code == 200: + break + except socket.error, e: + if e.errno == errno.ECONNREFUSED: + pass + else: + raise + + time.sleep(0.1) + + def start_server(self): + """Start the API server. + + returns: port (int) -- the port that the server is listening on + (on localhost) + """ + + checker = Thread(target=self.ready_checker) + checker.start() + self.start() + checker.join() + + return self.port |
