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 | |
| parent | eb526927e16954390d06929535d6f5c3766b5f6c (diff) | |
electron simulator (#531)
Diffstat (limited to 'lib/api')
| -rw-r--r-- | lib/api/__init__.py | 1 | ||||
| -rw-r--r-- | lib/api/server.py | 110 | ||||
| -rw-r--r-- | lib/api/simulator.py | 3 | ||||
| -rw-r--r-- | lib/api/stitch_plan.py | 17 |
4 files changed, 131 insertions, 0 deletions
diff --git a/lib/api/__init__.py b/lib/api/__init__.py new file mode 100644 index 00000000..f93e59a9 --- /dev/null +++ b/lib/api/__init__.py @@ -0,0 +1 @@ +from .server import APIServer
\ No newline at end of file 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 diff --git a/lib/api/simulator.py b/lib/api/simulator.py new file mode 100644 index 00000000..d11bd308 --- /dev/null +++ b/lib/api/simulator.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +simulator = Blueprint('simulator', __name__) diff --git a/lib/api/stitch_plan.py b/lib/api/stitch_plan.py new file mode 100644 index 00000000..fd6bf9c9 --- /dev/null +++ b/lib/api/stitch_plan.py @@ -0,0 +1,17 @@ +from flask import Blueprint, g, jsonify + +from ..stitch_plan import patches_to_stitch_plan + + +stitch_plan = Blueprint('stitch_plan', __name__) + + +@stitch_plan.route('') +def get_stitch_plan(): + if not g.extension.get_elements(): + return dict(colors=[], stitch_blocks=[], commands=[]) + + patches = g.extension.elements_to_patches(g.extension.elements) + stitch_plan = patches_to_stitch_plan(patches) + + return jsonify(stitch_plan) |
