diff --git a/ofm_config_full.json b/ofm_config_full.json index 16a211fb..53ca2587 100644 --- a/ofm_config_full.json +++ b/ofm_config_full.json @@ -26,6 +26,7 @@ "bg_channel_deviations_luv": "openflexure_microscope_server.things.background_detect:ChannelDeviationLUV" }, "settings_folder": "/var/openflexure/settings/", + "api_prefix": "/api/v3", "application_config": { "log_folder": "/var/openflexure/logs/", "data_folder": "/var/openflexure/data/" diff --git a/ofm_config_manual.json b/ofm_config_manual.json index 4498cf81..e9b0c092 100644 --- a/ofm_config_manual.json +++ b/ofm_config_manual.json @@ -4,6 +4,7 @@ "system": "openflexure_microscope_server.things.system:OpenFlexureSystem" }, "settings_folder": "./openflexure/settings/", + "api_prefix": "/api/v3", "application_config": { "log_folder": "./openflexure/logs/", "data_folder": "./openflexure/data/" diff --git a/ofm_config_simulation.json b/ofm_config_simulation.json index b52ce4d7..076d7243 100644 --- a/ofm_config_simulation.json +++ b/ofm_config_simulation.json @@ -20,6 +20,7 @@ "bg_channel_deviations_luv": "openflexure_microscope_server.things.background_detect:ChannelDeviationLUV" }, "settings_folder": "./openflexure/settings/", + "api_prefix": "/api/v3", "application_config": { "log_folder": "./openflexure/logs/", "data_folder": "./openflexure/data/" diff --git a/pyproject.toml b/pyproject.toml index 17d55fe1..81e84e83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ "Operating System :: OS Independent", ] dependencies = [ - "labthings-fastapi==0.1.0", + "labthings-fastapi==0.2.0rc1", "sangaboard~=0.4.0", "camera-stage-mapping ~= 0.1.10", "opencv-python-headless ~= 4.13.0", diff --git a/src/openflexure_microscope_server/server/__init__.py b/src/openflexure_microscope_server/server/__init__.py index 754a7799..52ee182f 100644 --- a/src/openflexure_microscope_server/server/__init__.py +++ b/src/openflexure_microscope_server/server/__init__.py @@ -86,7 +86,7 @@ def customise_server( ) add_v2_endpoints(server) - add_static_files(server.app, application_config.data_folder) + add_static_files(server, application_config.data_folder) # Configure logging to DEBUG if requested in CLI args. if debug: diff --git a/src/openflexure_microscope_server/server/serve_static_files.py b/src/openflexure_microscope_server/server/serve_static_files.py index 81338cc8..0d360a73 100644 --- a/src/openflexure_microscope_server/server/serve_static_files.py +++ b/src/openflexure_microscope_server/server/serve_static_files.py @@ -6,6 +6,8 @@ from fastapi import FastAPI from fastapi.responses import FileResponse, RedirectResponse from fastapi.staticfiles import StaticFiles +import labthings_fastapi as lt + THIS_DIR = os.path.dirname(os.path.abspath(__file__)) STATIC_PATH = os.path.normpath(os.path.join(THIS_DIR, "..", "static")) @@ -35,7 +37,7 @@ def add_static_file(app: FastAPI, fname: str, folder: str) -> None: ) -def add_static_files(app: FastAPI, data_folder: str) -> None: +def add_static_files(server: lt.ThingServer, data_folder: str) -> None: """Add the static files responsible for the webapp app to the FastAPI app. Note that any file in the root of the static dir will not be cached. However, the @@ -43,9 +45,10 @@ def add_static_files(app: FastAPI, data_folder: str) -> None: The Vue CSS and JS are hashed, so if updated their filename will update. The most important file not to cache is "index.html". - :param app: The FastAPI app to add to, in this case the OpenFlexure server + :param server: The LabThings server. :param data_folder: The directory for any data. """ + app = server.app check_static_dir() @app.get("/", response_class=RedirectResponse) @@ -71,7 +74,7 @@ def add_static_files(app: FastAPI, data_folder: str) -> None: if not os.path.isdir(data_folder): os.makedirs(data_folder) app.mount( - "/data/", + server._api_prefix.rstrip("/") + "/data/", StaticFiles(directory=data_folder), name="data", ) diff --git a/src/openflexure_microscope_server/things/__init__.py b/src/openflexure_microscope_server/things/__init__.py index b35f1fdf..c497209f 100644 --- a/src/openflexure_microscope_server/things/__init__.py +++ b/src/openflexure_microscope_server/things/__init__.py @@ -31,7 +31,7 @@ class OFMThing(lt.Thing): raise ValueError("No application configuration was supplied.") app_data_dir = application_config["data_folder"] self._data_dir = os.path.join( - os.path.normpath(str(app_data_dir)), os.path.normpath(self.path.strip("/")) + os.path.normpath(str(app_data_dir)), os.path.normpath(self.name) ) return self diff --git a/tests/lifecycle_test/testfile.py b/tests/lifecycle_test/testfile.py index 2278c6e2..48b41f69 100755 --- a/tests/lifecycle_test/testfile.py +++ b/tests/lifecycle_test/testfile.py @@ -74,7 +74,7 @@ def main() -> None: def test_client_connection() -> None: """Check a ThingClient can interact with the simulation microscope camera.""" print("Connecting Python client to microscope, and capturing image") - cam_client = lt.ThingClient.from_url("http://localhost:5000/camera/") + cam_client = lt.ThingClient.from_url("http://localhost:5000/api/v3/camera/") img = Image.open(cam_client.grab_jpeg().open()) print(f"Successfully grabbed image of size {img.size}") assert img.size == (820, 616) @@ -95,7 +95,7 @@ def subscribe_to_mjpeg_stream() -> subprocess.Popen: "nohup", "curl", "-s", - "http://localhost:5000/camera/mjpeg_stream", + "http://localhost:5000/api/v3/camera/mjpeg_stream", ">", "/dev/null", "2>&1", diff --git a/tests/unit_tests/test_serve_static_files.py b/tests/unit_tests/test_serve_static_files.py index ba5fb693..62a741d0 100644 --- a/tests/unit_tests/test_serve_static_files.py +++ b/tests/unit_tests/test_serve_static_files.py @@ -124,10 +124,13 @@ def test_add_static_files(mock_static_dir, mocker): "openflexure_microscope_server.server.serve_static_files.STATIC_PATH", mock_static_dir, ) + mock_server = mocker.Mock() + mock_server.app = mock_app + mock_server._api_prefix = "/api/v3" # Get the wrapper function from the mocked decorator wrapper = mock_app.get.return_value with tempfile.TemporaryDirectory() as datadir: - serve_static_files.add_static_files(mock_app, data_folder=datadir) + serve_static_files.add_static_files(mock_server, data_folder=datadir) # Get should have been called twice to create a route for index assert mock_app.get.call_count == 2 @@ -158,5 +161,5 @@ def test_add_static_files(mock_static_dir, mocker): assert "/assets/" in mounted_path assert os.path.join(mock_static_dir, "assets") in mounted_dir - assert mock_app.mount.call_args_list[1].args[0] == "/data/" + assert mock_app.mount.call_args_list[1].args[0] == "/api/v3/data/" assert mock_app.mount.call_args_list[1].args[1].directory == datadir diff --git a/webapp/src/stores/settings.js b/webapp/src/stores/settings.js index 4870f258..2477dbc3 100644 --- a/webapp/src/stores/settings.js +++ b/webapp/src/stores/settings.js @@ -10,7 +10,7 @@ function getOriginFromLocation() { if (origin) { return origin; } else { - return url.origin; + return `${url.origin}/api/v3`; } } @@ -32,7 +32,7 @@ export const useSettingsStore = defineStore( const appTheme = ref("system"); const disableStream = ref(false); // The origin to use if overriding with dev tools - const overrideOrigin = ref("http://microscope.local:5000"); + const overrideOrigin = ref("http://microscope.local:5000/api/v3"); // The step sizes for navigation via control pane/keys presses const navigationStepSize = ref({ x: 200, diff --git a/webapp/vite.config.mjs b/webapp/vite.config.mjs index 1be459b9..61e1d6e4 100644 --- a/webapp/vite.config.mjs +++ b/webapp/vite.config.mjs @@ -42,7 +42,7 @@ export default defineConfig({ host: true, // Set the development server port to 8080. // OFM uses port 5000, so we avoid conflicts. run, and override by using the address: - // http://microscope.local:8080/?overrideOrigin=http://microscope.local:5000# + // http://microscope.local:8080/?overrideOrigin=http://microscope.local:5000/api/v3# port: 8080, strictPort: true, },