Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ artifacts:
mounts:
- mount: tmpfs:/tmp
access: rw
- mount: persistent:/data
access: rw
devices:
- type: ttyTool
ingress:
Expand Down
52 changes: 46 additions & 6 deletions tool-comm-forwarder-backend/src/socat_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess
import json
import logging
import os
import sys

import flask
Expand All @@ -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__)

Expand All @@ -46,30 +48,37 @@ 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:
# wait 0.2 seconds for errors
_, 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"])
Expand All @@ -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)
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)
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ <h2 class="header" [textContent]="baseTranslationKey + '.socat-server.header' |
</ur-button>
</div>
<p *ngIf="canStopServer() && !canStartServer()" class="info-text" [textContent]="baseTranslationKey + '.socat-server.server-running-text' | translate"></p>
<p *ngIf="!canStopServer() && canStartServer()" class="info-text" [textContent]="baseTranslationKey + '.socat-server.server-stopped-text' | translate"></p>
</div>
</div>
5 changes: 3 additions & 2 deletions tool-comm-forwarder-frontend/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand All @@ -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."
}
}
}
Expand Down