From 0b2536a79bd453fa420cdb29815b305fc91c96df Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Wed, 20 Nov 2019 13:48:27 +0000 Subject: [PATCH] Reorganised stream resource --- openflexure_microscope/api/app.py | 4 +- .../api/v2/blueprints/__init__.py | 2 +- .../api/v2/blueprints/actions/__init__.py | 8 +- .../api/v2/blueprints/root.py | 4 +- .../api/v2/blueprints/stream.py | 58 --------- .../api/v2/blueprints/streams.py | 112 ++++++++++++++++++ 6 files changed, 122 insertions(+), 66 deletions(-) delete mode 100644 openflexure_microscope/api/v2/blueprints/stream.py create mode 100644 openflexure_microscope/api/v2/blueprints/streams.py diff --git a/openflexure_microscope/api/app.py b/openflexure_microscope/api/app.py index 83264dba..c3db5f89 100644 --- a/openflexure_microscope/api/app.py +++ b/openflexure_microscope/api/app.py @@ -148,8 +148,8 @@ app.register_blueprint(task_blueprint, url_prefix=uri("/task", "v1")) v2_root_blueprint = v2.blueprints.root.construct_blueprint(api_microscope) app.register_blueprint(v2_root_blueprint, url_prefix=uri("/", "v2")) -v2_stream_blueprint = v2.blueprints.stream.construct_blueprint(api_microscope) -app.register_blueprint(v2_stream_blueprint, url_prefix=uri("/", "v2")) +v2_streams_blueprint = v2.blueprints.streams.construct_blueprint(api_microscope) +app.register_blueprint(v2_streams_blueprint, url_prefix=uri("/streams", "v2")) # Captures routes v2_captures_blueprint = v2.blueprints.captures.construct_blueprint(api_microscope) diff --git a/openflexure_microscope/api/v2/blueprints/__init__.py b/openflexure_microscope/api/v2/blueprints/__init__.py index 473540f2..0ce1ebae 100644 --- a/openflexure_microscope/api/v2/blueprints/__init__.py +++ b/openflexure_microscope/api/v2/blueprints/__init__.py @@ -1 +1 @@ -from . import root, captures, settings, status, tasks, stream, plugins, actions +from . import root, captures, settings, status, tasks, streams, plugins, actions diff --git a/openflexure_microscope/api/v2/blueprints/actions/__init__.py b/openflexure_microscope/api/v2/blueprints/actions/__init__.py index 0f3faa19..e7cd7c67 100644 --- a/openflexure_microscope/api/v2/blueprints/actions/__init__.py +++ b/openflexure_microscope/api/v2/blueprints/actions/__init__.py @@ -11,6 +11,11 @@ from openflexure_microscope.api.views import MicroscopeView from . import camera, stage, system +class ActionsAPI(MicroscopeView): + def get(self): + return jsonify(actions_representation()) + + _actions = { "capture": { "rule": "/camera/capture/", @@ -67,9 +72,6 @@ def actions_representation(): return actions -class ActionsAPI(MicroscopeView): - def get(self): - return jsonify(actions_representation()) def construct_blueprint(microscope_obj): global _actions diff --git a/openflexure_microscope/api/v2/blueprints/root.py b/openflexure_microscope/api/v2/blueprints/root.py index 17b2773c..e005e7e7 100644 --- a/openflexure_microscope/api/v2/blueprints/root.py +++ b/openflexure_microscope/api/v2/blueprints/root.py @@ -4,10 +4,10 @@ from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.utilities import get_docstring, bottom_level_name from openflexure_microscope.api.utilities import blueprint_name_for_module -from openflexure_microscope.api.v2.blueprints import settings, status, plugins, captures, actions, stream +from openflexure_microscope.api.v2.blueprints import settings, status, plugins, captures, actions, streams # List of submodules containing create_blueprint methods using standard blueprint_for_module naming -_root_blueprint_modules = [settings, status, plugins, captures, actions, stream] +_root_blueprint_modules = [settings, status, plugins, captures, actions, streams] def root_representation(): """ diff --git a/openflexure_microscope/api/v2/blueprints/stream.py b/openflexure_microscope/api/v2/blueprints/stream.py deleted file mode 100644 index a79d2419..00000000 --- a/openflexure_microscope/api/v2/blueprints/stream.py +++ /dev/null @@ -1,58 +0,0 @@ -from openflexure_microscope.api.utilities import gen, JsonResponse -from openflexure_microscope.api.views import MicroscopeView -from openflexure_microscope.api.utilities import blueprint_for_module - -from flask import Response, Blueprint, jsonify, request - - -class StreamAPI(MicroscopeView): - def get(self): - """ - Real-time MJPEG stream from the microscope camera - - .. :quickref: Stream; Camera MJPEG stream - - :>header Accept: image/jpeg - :>header Content-Type: image/jpeg - :status 200: stream active - """ - # Restart stream worker thread - self.microscope.camera.start_worker() - - return Response( - gen(self.microscope.camera), - mimetype="multipart/x-mixed-replace; boundary=frame", - ) - - -class SnapshotAPI(MicroscopeView): - def get(self): - """ - Single snapshot from the camera stream - - .. :quickref: Stream; Camera snapshot - - :>header Accept: image/jpeg - :>header Content-Type: image/jpeg - :status 200: stream active - """ - # Restart stream worker thread - self.microscope.camera.start_worker() - - return Response(self.microscope.camera.get_frame(), mimetype="image/jpeg") - - -def construct_blueprint(microscope_obj): - - blueprint = blueprint_for_module(__name__) - - blueprint.add_url_rule( - "/stream", view_func=StreamAPI.as_view("stream", microscope=microscope_obj) - ) - - blueprint.add_url_rule( - "/snapshot", - view_func=SnapshotAPI.as_view("snapshot", microscope=microscope_obj), - ) - - return blueprint diff --git a/openflexure_microscope/api/v2/blueprints/streams.py b/openflexure_microscope/api/v2/blueprints/streams.py new file mode 100644 index 00000000..e727c6e3 --- /dev/null +++ b/openflexure_microscope/api/v2/blueprints/streams.py @@ -0,0 +1,112 @@ +""" +Top-level description of routes related to live camera stream data +""" + +from openflexure_microscope.api.utilities import gen, JsonResponse +from openflexure_microscope.api.views import MicroscopeView +from openflexure_microscope.api.utilities import blueprint_for_module, blueprint_name_for_module +from openflexure_microscope.utilities import description_from_view + +from flask import Response, Blueprint, jsonify, request, url_for + + +class StreamAPI(MicroscopeView): + def get(self): + return jsonify(streams_representation()) + + +class MjpegAPI(MicroscopeView): + """ + Real-time MJPEG stream from the microscope camera + """ + def get(self): + """ + Real-time MJPEG stream from the microscope camera + + .. :quickref: Stream; Camera MJPEG stream + + :>header Accept: image/jpeg + :>header Content-Type: image/jpeg + :status 200: stream active + """ + # Restart stream worker thread + self.microscope.camera.start_worker() + + return Response( + gen(self.microscope.camera), + mimetype="multipart/x-mixed-replace; boundary=frame", + ) + + +class SnapshotAPI(MicroscopeView): + """ + Single JPEG snapshot from the camera stream + """ + def get(self): + """ + Single snapshot from the camera stream + + .. :quickref: Stream; Camera snapshot + + :>header Accept: image/jpeg + :>header Content-Type: image/jpeg + :status 200: stream active + """ + # Restart stream worker thread + self.microscope.camera.start_worker() + + return Response(self.microscope.camera.get_frame(), mimetype="image/jpeg") + + +_streams = { + "mjpeg": { + "rule": "/mjpeg", + "view_class": MjpegAPI, + "conditions": True, + }, + "snapshot": { + "rule": "/snapshot", + "view_class": SnapshotAPI, + "conditions": True, + } +} + + +def enabled_streams(): + global _streams + return {k: v for k, v in _streams.items() if v["conditions"]} + + +def streams_representation(): + global _streams + + streams = {} + for name, stream in enabled_streams().items(): + d = { + "links": {"self": url_for(f".{name}")}, + } + + d.update(description_from_view(stream["view_class"])) + + streams[name] = d + + return streams + + +def construct_blueprint(microscope_obj): + + blueprint = blueprint_for_module(__name__) + + # For each enabled stream route defined in our dictionary above + for name, stream in enabled_streams().items(): + # Add the action to our blueprint + blueprint.add_url_rule( + stream["rule"], + view_func=stream["view_class"].as_view(name, microscope=microscope_obj), + ) + + blueprint.add_url_rule( + "/", view_func=StreamAPI.as_view("streams", microscope=microscope_obj) + ) + + return blueprint