From 54db11559794d1de05769e4288ba9fefae8063d8 Mon Sep 17 00:00:00 2001
From: sldesnoo-Delft <s.l.desnoo@tudelft.nl>
Date: Thu, 6 Mar 2025 16:07:53 +0100
Subject: [PATCH] Examples dataset webserver and remote command server

---
 core_tools/GUI/script_runner/web_server.py |   5 +-
 examples/demo_station/dataset_webclient.py |  16 ++++
 examples/demo_station/dataset_webserver.py | 105 +++++++++++++++++++++
 examples/demo_station/remote_script.py     |  32 +++++++
 4 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 examples/demo_station/dataset_webclient.py
 create mode 100644 examples/demo_station/dataset_webserver.py
 create mode 100644 examples/demo_station/remote_script.py

diff --git a/core_tools/GUI/script_runner/web_server.py b/core_tools/GUI/script_runner/web_server.py
index bfa70d4c..9fb95570 100644
--- a/core_tools/GUI/script_runner/web_server.py
+++ b/core_tools/GUI/script_runner/web_server.py
@@ -108,8 +108,9 @@ class WebRequestHandler(BaseHTTPRequestHandler):
         )
 
 
-def run_web_server(command_list: list[Command]):
-    server_address = ('127.0.0.1', 8001)
+def run_web_server(command_list: list[Command], server_address: tuple[str, int] | None = None):
+    if server_address is None:
+        server_address = ('0.0.0.0', 8001)
     httpd = HTTPServer(server_address, WebRequestHandler)
     httpd.commands = command_list
     try:
diff --git a/examples/demo_station/dataset_webclient.py b/examples/demo_station/dataset_webclient.py
new file mode 100644
index 00000000..e23c0c53
--- /dev/null
+++ b/examples/demo_station/dataset_webclient.py
@@ -0,0 +1,16 @@
+import json
+import requests
+from pprint import pprint
+
+
+base = "http://127.0.0.1:8002"
+
+
+# %%
+
+r = requests.get(base + "/latest",
+                 params={
+                     "start_time": "2025-03-06 15:30",
+                     })
+print(r.status_code)
+pprint(json.loads(r.content))
diff --git a/examples/demo_station/dataset_webserver.py b/examples/demo_station/dataset_webserver.py
new file mode 100644
index 00000000..ee2b8e45
--- /dev/null
+++ b/examples/demo_station/dataset_webserver.py
@@ -0,0 +1,105 @@
+import json
+from functools import cached_property
+from http.cookies import SimpleCookie
+from http.server import HTTPServer, BaseHTTPRequestHandler, HTTPStatus
+from urllib.parse import parse_qsl, urlparse
+
+import core_tools as ct
+from core_tools.data.ds.reader import load_by_uuid
+from core_tools.data.SQL.queries.dataset_gui_queries import query_for_measurement_results
+
+from core_tools.data.ds.ds2xarray import ds2xarray
+
+
+"""
+TIP:
+    Switch project name to 'Game', so all data is for Game
+"""
+
+
+class DatasetRequestHandler(BaseHTTPRequestHandler):
+
+    @cached_property
+    def url(self):
+        return urlparse(self.path)
+
+    @cached_property
+    def query_data(self):
+        return dict(parse_qsl(self.url.query))
+
+    @cached_property
+    def post_data(self):
+        content_length = int(self.headers.get("Content-Length", 0))
+        return self.rfile.read(content_length)
+
+    @cached_property
+    def form_data(self):
+        return dict(parse_qsl(self.post_data.decode("utf-8")))
+
+    @cached_property
+    def cookies(self):
+        return SimpleCookie(self.headers.get("Cookie"))
+
+    def log_request(self, code='-', size='-'):
+        pass
+
+    def do_GET(self):
+        if self.url.path != "/latest":
+            self.send_error(HTTPStatus.NOT_FOUND)
+        else:
+            start_time = self.query_data.get("start_time")
+            ds = self.get_last_ds(start_time)
+            if ds is None:
+                self.send_error(HTTPStatus.NO_CONTENT)
+            else:
+                response = self.get_ds_json(ds).encode("utf-8")
+                self.send_response(HTTPStatus.OK)
+                self.send_header("Content-Type", "application/json")
+                self.end_headers()
+                self.wfile.write(response)
+
+    def get_last_ds(self, start_time: str | None):
+        res = query_for_measurement_results.search_query(
+                start_time=start_time,  # optional
+                name=None,  # part of name optional
+                project=self.server.project_name,  # optional
+                keywords=None,  # optional
+                )
+        if len(res) == 0:
+            return None
+        uuid = res[-1].uuid
+        ds = load_by_uuid(uuid)
+        return ds
+
+    def get_ds_json(self, ds, variables: list[str] | None = None):
+        xds = ds2xarray(ds, snapshot=False)
+        for m_param in ds:
+            for name, descr in m_param:
+                var_name = descr.param_name
+                xds[var_name].attrs["written"] = descr.written()
+
+        if variables is not None:
+            xds = xds[variables]
+
+        d = xds.to_dict()
+        return json.dumps(d, indent=1)
+
+
+def run_web_server(project_name: str | None, server_address: tuple[str, int] | None = None):
+    if server_address is None:
+        server_address = ('0.0.0.0', 8002)
+    httpd = HTTPServer(server_address, DatasetRequestHandler)
+    httpd.project_name = project_name
+    try:
+        print(f"Server running at http://{server_address[0]}:{server_address[1]}")
+        print("Interrupt kernel to stop server")
+        httpd.serve_forever()
+    except KeyboardInterrupt:
+        httpd.shutdown()
+
+
+ # %%
+
+ct.configure('./setup_config/ct_config_laptop.yaml')
+
+run_web_server(None)
diff --git a/examples/demo_station/remote_script.py b/examples/demo_station/remote_script.py
new file mode 100644
index 00000000..3397caa9
--- /dev/null
+++ b/examples/demo_station/remote_script.py
@@ -0,0 +1,32 @@
+import json
+import requests
+from pprint import pprint
+
+
+base = "http://127.0.0.1:8001"
+
+# %%
+r = requests.get(base + "/functions")
+print(r.status_code)
+pprint(json.loads(r.content))
+
+
+# %%
+
+r = requests.post(base + "/run",
+                  data={
+                      "__name__": "sayHi",
+                      "name": "Oriol",
+                      "times": 2,
+                      })
+print(r.status_code)
+pprint(json.loads(r.content))
+
+r = requests.post(base + "/run",
+                  data={
+                      "__name__": "Fit it",
+                      "x": 13.0,
+                      "mode": "RIGHT",
+                      })
+print(r.status_code)
+pprint(json.loads(r.content))
-- 
GitLab