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
32 changes: 32 additions & 0 deletions .github/workflows/python_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Ensure Python code is linted and formatted, matching the style guide
name: Python Linting

on: [push, pull_request]

jobs:
black-lint:
runs-on: ubuntu-latest
name: Python black Lint
steps:
- uses: actions/checkout@v4
- uses: psf/black@stable
flake8-lint:
runs-on: ubuntu-latest
name: Python flake8 Lint
steps:
- name: Check out source repository
uses: actions/checkout@v3

- name: Set up Python environment
uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: flake8 Lint
uses: py-actions/flake8@v2
with:
ignore: "E701,W503,E203"
exclude: "docs,.idea"
max-line-length: "88"
path: "."
plugins: "flake8-docstrings flake8-black"
31 changes: 22 additions & 9 deletions manager/comms/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
import websockets
from websockets.server import WebSocketServerProtocol

from manager.comms.consumer_message import ManagerConsumerMessage, ManagerConsumerMessageException
from manager.comms.consumer_message import (
ManagerConsumerMessage,
ManagerConsumerMessageException,
)
from manager.ram_logging.log_manager import LogManager

logger = LogManager.logger


class ManagerConsumer:
"""
Robotics Academy websocket consumer
Expand All @@ -19,7 +23,6 @@ class ManagerConsumer:
def __init__(self, host, port):
from manager.manager import Manager


"""
Initializes a new ManagerConsumer
@param host: host for connections, '0.0.0.0' to bind all interfaces
Expand All @@ -36,7 +39,9 @@ async def reject_connection(self, websocket: WebSocketServerProtocol):
Rejects a connection
@param websocket: websocket
"""
await websocket.close(1008, "This RADI server can't accept more than one connection")
await websocket.close(
1008, "This RADI server can't accept more than one connection"
)

async def handler(self, websocket: WebSocketServerProtocol):
"""
Expand All @@ -62,32 +67,40 @@ async def handler(self, websocket: WebSocketServerProtocol):
s = json.loads(websocket_message)
message = ManagerConsumerMessage(**s)
await self.manager.trigger(message.command, data=message.data or None)
response = {"message": f"Exercise state changed to {self.manager.state}"}
response = {
"message": f"Exercise state changed to {self.manager.state}"
}
await websocket.send(str(message.response(response)))
except ManagerConsumerMessageException as e:
await websocket.send(str(e))
except Exception as e:
if message is None:
ex = ManagerConsumerMessageException(message, str(e))
else:
ex = ManagerConsumerMessageException(id=str(uuid4()), message=str(e))
ex = ManagerConsumerMessageException(
id=str(uuid4()), message=str(e)
)
await websocket.send(str(ex))

async def send_message(self, message_data):
if self.client is not None and self.server is not None:
message = ManagerConsumerMessage(id=str(uuid4()), command="state-changed", data=message_data)
message = ManagerConsumerMessage(
id=str(uuid4()), command="state-changed", data=message_data
)
await self.client.send(str(message))

def start(self):
"""
Starts the consumer and listens for connections
"""
self.server = websockets.serve(self.handler, self.host, self.port)
LogManager.logger.debug(f"Websocket server listening in {self.host}:{self.port}")
LogManager.logger.debug(
f"Websocket server listening in {self.host}:{self.port}"
)
asyncio.get_event_loop().run_until_complete(self.server)
asyncio.get_event_loop().run_forever()


if __name__ == '__main__':
consumer = ManagerConsumer('0.0.0.0', 7163)
if __name__ == "__main__":
consumer = ManagerConsumer("0.0.0.0", 7163)
consumer.start()
15 changes: 11 additions & 4 deletions manager/comms/consumer_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ManagerConsumerMessage(BaseModel):
@param command: message command
@param data: message data (optional)
"""

id: str
command: str
data: Optional[Any] = None
Expand All @@ -24,7 +25,7 @@ def response(self, response: Any = None) -> ManagerConsumerMessage:
@param response: response data
@return: the response message as a ManagerConsumerMessage
"""
return ManagerConsumerMessage(id=self.id, command='ack', message=response)
return ManagerConsumerMessage(id=self.id, command="ack", message=response)

def __repr__(self):
return self.json()
Expand All @@ -37,11 +38,17 @@ class ManagerConsumerMessageException(BaseException):
def __init__(self, id: str, message: str = None):
super(ManagerConsumerMessageException, self).__init__(message)
self.id = id
self.command = 'error'
self.command = "error"
self.message = message

def consumer_message(self):
return ManagerConsumerMessage(id=self.id, command=self.command, data={'message': self.message})
return ManagerConsumerMessage(
id=self.id, command=self.command, data={"message": self.message}
)

def __str__(self):
return str(ManagerConsumerMessage(id=self.id, command=self.command, data={'message': self.message}))
return str(
ManagerConsumerMessage(
id=self.id, command=self.command, data={"message": self.message}
)
)
38 changes: 22 additions & 16 deletions manager/comms/new_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
from uuid import uuid4
from datetime import datetime

from manager.comms.consumer_message import ManagerConsumerMessageException, ManagerConsumerMessage
from manager.comms.consumer_message import (
ManagerConsumerMessageException,
ManagerConsumerMessage,
)
from manager.comms.websocker_server import WebsocketServer
from manager.ram_logging.log_manager import LogManager


class Client:
def __init__(self, **kwargs):
self.id = kwargs['id']
self.handler = kwargs['handler']
self.address = kwargs['address']
self.id = kwargs["id"]
self.handler = kwargs["handler"]
self.address = kwargs["address"]


class ManagerConsumer:
Expand All @@ -26,16 +29,17 @@ class ManagerConsumer:
def __init__(self, host, port, manager_queue: Queue):
self.host = host
self.port = port
self.server = WebsocketServer(
host=host, port=port, loglevel=logging.INFO)
self.server = WebsocketServer(host=host, port=port, loglevel=logging.INFO)

# Configurar el logger de websocket_server para salida a consola
ws_logger = logging.getLogger('websocket_server.websocket_server')
ws_logger = logging.getLogger("websocket_server.websocket_server")
ws_logger.propagate = False
ws_logger.setLevel(logging.INFO)
ws_logger.handlers.clear()
ws_formatter = logging.Formatter(
"%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] (%(name)s) %(message)s", "%H:%M:%S")
"%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] (%(name)s) %(message)s",
"%H:%M:%S",
)
ws_console_handler = logging.StreamHandler()
ws_console_handler.setFormatter(ws_formatter)
ws_logger.addHandler(ws_console_handler)
Expand All @@ -59,28 +63,29 @@ def handle_client_disconnect(self, client, server):
time_string = now.strftime("%H:%M:%S")
print(time_string)
message = ManagerConsumerMessage(
**{'id': str(uuid4()), 'command': 'disconnect'})
**{"id": str(uuid4()), "command": "disconnect"}
)
self.manager_queue.put(message)
self.client = None
self.server.allow_new_connections()

def handle_message_received(self, client, server, websocket_message):
LogManager.logger.info(
f"message received length: {len(websocket_message)} from client {client}")
f"message received length: {len(websocket_message)} from client {client}"
)
LogManager.logger.info(
f"message received: {websocket_message} from client {client}")
f"message received: {websocket_message} from client {client}"
)
message = None
try:
s = json.loads(websocket_message)
message = ManagerConsumerMessage(**s)
self.manager_queue.put(message)
except Exception as e:
if message is not None:
ex = ManagerConsumerMessageException(
id=message.id, message=str(e))
ex = ManagerConsumerMessageException(id=message.id, message=str(e))
else:
ex = ManagerConsumerMessageException(
id=str(uuid4()), message=str(e))
ex = ManagerConsumerMessageException(id=str(uuid4()), message=str(e))
self.server.send_message(client, str(ex))
raise e

Expand All @@ -92,7 +97,8 @@ def send_message(self, message_data, command=None):
message = message_data.consumer_message()
else:
message = ManagerConsumerMessage(
id=str(uuid4()), command=command, data=message_data)
id=str(uuid4()), command=command, data=message_data
)

self.server.send_message(self.client, str(message))

Expand Down
7 changes: 5 additions & 2 deletions manager/comms/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ThreadWithLoggedException(threading.Thread):
Exception is also reachable via <thread>.exception from the main thread.
"""

DIVIDER = "*"*80
DIVIDER = "*" * 80

def __init__(self, *args, **kwargs):
try:
Expand All @@ -31,11 +31,14 @@ def run(self):
except Exception as exception:
thread = threading.current_thread()
self.exception = exception
self.logger.exception(f"{self.DIVIDER}\nException in child thread {thread}: {exception}\n{self.DIVIDER}")
self.logger.exception(
f"{self.DIVIDER}\nException in child thread {thread}: {exception}\n{self.DIVIDER}"
)
finally:
del self._target, self._args, self._kwargs


class WebsocketServerThread(ThreadWithLoggedException):
"""Dummy wrapper to make debug messages a bit more readable"""

pass
Loading
Loading