diff --git a/manifest.yaml b/manifest.yaml index dace691..1c14cd3 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -26,6 +26,8 @@ artifacts: mounts: - mount: tmpfs:/tmp access: rw + - mount: persistent:/data + access: rw devices: - type: ttyTool ingress: diff --git a/tool-comm-forwarder-backend/src/socat_server.py b/tool-comm-forwarder-backend/src/socat_server.py index 03903b2..a5cad46 100644 --- a/tool-comm-forwarder-backend/src/socat_server.py +++ b/tool-comm-forwarder-backend/src/socat_server.py @@ -1,6 +1,7 @@ import subprocess import json import logging +import os import sys import flask @@ -20,6 +21,7 @@ SOCAT_COMMAND = ["socat", f"tcp-l:{PORT},reuseaddr,fork", "file:/dev/ur-ttylink/ttyTool,nonblock,raw,waitlock=/tmp/lock_tty"] STOP_SOCAT_COOMAND = "killall -9 socat 2> /dev/null" IS_SOCAT_SERVER_RUNNING_COMMAND = f"socat /dev/null TCP:127.0.0.1:{PORT}" +STATUS_FILENAME = "/data/socat_server_status.json" app = Flask(__name__) @@ -46,6 +48,7 @@ def socat_server(): flask.Response: A Flask response with a success key, telling whether the command was successful or not. """ action = request.get_json()["action"] + response = None if action == "start": result = subprocess.Popen(SOCAT_COMMAND, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: @@ -53,23 +56,29 @@ def socat_server(): _, stderr = result.communicate(timeout=0.2) if result.returncode != 0: logger.error(f"Failed to start socat server. Error message {stderr}") - return create_response({"success": False}) + + response = create_response({"success": False}) except subprocess.TimeoutExpired: # If timeout expired the server is running logger.info("Started socat server") - return create_response({"success": True}) + response = create_response({"success": True}) elif action == "stop": result = subprocess.run(STOP_SOCAT_COOMAND, capture_output=True, shell=True) if result.returncode == 0: logger.info("Stopped socat server") - return create_response({"success": True}) + response = create_response({"success": True}) else: logger.error(f"Failed to stop socat server. Error message {result.stderr}") - return create_response({"success": False}) + response = create_response({"success": False}) else: logger.error(f"Unknown action received! Action received {action}") - return create_response({"success": False}) + response = create_response({"success": False}) + + with open(STATUS_FILENAME, "wb") as status_file: + running_response = is_server_running() + status_file.write(running_response.data) + return response @app.route("/is_server_running", methods=["GET"]) @@ -85,5 +94,36 @@ def is_server_running(): # handle a message else: return create_response({"running": False}) +def recover_from_state(running: bool): + """Recovers the socat server to the given state + + Args: + running (bool): Whether the server should be running or not + """ + if running: + result = subprocess.Popen(SOCAT_COMMAND, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + try: + # wait 0.2 seconds for errors + _, stderr = result.communicate(timeout=0.2) + if result.returncode != 0: + logger.error(f"Failed to recover socat server. Error message {stderr}") + except subprocess.TimeoutExpired: # If timeout expired the server is running + logger.info("Recovered socat server to running state") + else: + result = subprocess.run(STOP_SOCAT_COOMAND, capture_output=True, shell=True) + if result.returncode == 0: + logger.info("Recovered socat server to stopped state") + else: + logger.error(f"Failed to stop socat server during recovery. Error message {result.stderr}") + if __name__ == '__main__': - serve(app, host='0.0.0.0', port=52762) \ No newline at end of file + if os.path.exists(STATUS_FILENAME): + logger.info("Loading socat state from file") + with open(STATUS_FILENAME, "rb") as status_file: + bytes_data = status_file.read() + try: + data = json.loads(bytes_data.decode("utf-8")) + recover_from_state(data["running"]) + except Exception as e: + logger.error(f"Failed to load socat server state from file. Error: {e}") + serve(app, host='0.0.0.0', port=52762) diff --git a/tool-comm-forwarder-frontend/src/app/components/tool-comm-forwarder-application/tool-comm-forwarder-application.component.html b/tool-comm-forwarder-frontend/src/app/components/tool-comm-forwarder-application/tool-comm-forwarder-application.component.html index 40c1dbc..8328432 100644 --- a/tool-comm-forwarder-frontend/src/app/components/tool-comm-forwarder-application/tool-comm-forwarder-application.component.html +++ b/tool-comm-forwarder-frontend/src/app/components/tool-comm-forwarder-application/tool-comm-forwarder-application.component.html @@ -22,5 +22,6 @@

+

diff --git a/tool-comm-forwarder-frontend/src/assets/i18n/en.json b/tool-comm-forwarder-frontend/src/assets/i18n/en.json index 9a5abbe..143e56e 100644 --- a/tool-comm-forwarder-frontend/src/assets/i18n/en.json +++ b/tool-comm-forwarder-frontend/src/assets/i18n/en.json @@ -3,7 +3,7 @@ "nodes": { "universal-robots-tool-comm-forwarder-tool-comm-forwarder-application": { "title": "Tool Communication Forwarder", - "supportiveText": "URCap to forward toool communication to the network", + "supportiveText": "URCap to forward tool communication to the network", "description": { "line1": "URCapX to support relaying the RS-485 communication device in a UR robot to a remote PC.", "line2": "It starts a socat server to relay the tool communication device to the network socket on port 54321." @@ -14,7 +14,8 @@ "start": "Start", "stop": "Stop" }, - "server-running-text": "Socat server is running on port 54321 forwarding tool communication to the network." + "server-running-text": "Socat server is running on port 54321 forwarding tool communication to the network. This state is persisted and remains unchanged after a restart.", + "server-stopped-text": "Socat server not running. This state is persisted and remains unchanged after a restart." } } }