From a8cf9393e5d1c879574dcba4754ad31eea4bddc8 Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Tue, 27 Jul 2021 03:45:00 +0200 Subject: [PATCH] Client name optional and MAC address during connection. --- conf-machine.json | 4 +- controlpi_plugins/wsclient.py | 118 +++++++++++++++++++++------------- 2 files changed, 77 insertions(+), 45 deletions(-) diff --git a/conf-machine.json b/conf-machine.json index 26245ed..cba238d 100644 --- a/conf-machine.json +++ b/conf-machine.json @@ -10,14 +10,14 @@ "Controller": { "plugin": "WSClient", "url": "ws://localhost:8080", + "interface": "enp0s25", "client": "Machine", "up filter": [ { "sender": { "const": "Engine" } } ], "down filter": [ { "sender": { "const": "Engine Clearance" } } ] }, "Engine Clearance": { "plugin": "Alias", - "from": { "sender": { "const": "Controller" }, - "original sender": { "const": "Controller/Engine Clearance" } }, + "from": { "original sender": { "const": "Controller/Engine Clearance" } }, "to": { } }, "Engine Switch": { diff --git a/controlpi_plugins/wsclient.py b/controlpi_plugins/wsclient.py index e14be7b..5155e02 100644 --- a/controlpi_plugins/wsclient.py +++ b/controlpi_plugins/wsclient.py @@ -5,7 +5,10 @@ TODO: documentation, doctests """ import asyncio +import fcntl import json +import socket +import struct from websockets import ConnectionClosed, connect from controlpi import BasePlugin, Message, MessageTemplate @@ -18,53 +21,58 @@ class WSClient(BasePlugin): CONF_SCHEMA = {'properties': {'url': {'type': 'string'}, + 'interface': {'type': 'string'}, 'client': {'type': 'string'}, 'up filter': {'type': 'array', 'items': {'type': 'object'}}, 'down filter': {'type': 'array', 'items': {'type': 'object'}}}, - 'required': ['url', 'client', 'up filter', 'down filter']} + 'required': ['url', 'up filter', 'down filter']} async def _receive(self, message: Message) -> None: if not self._websocket: return assert isinstance(message['sender'], str) prefix = f"{self.name}/" - original_sender = self.conf['client'] + original_sender = self._client if 'original sender' in message: if message['original sender'].startswith(prefix): return original_sender += f"/{message['original sender']}" - else: + elif message['sender'] != '': original_sender += f"/{message['sender']}" message['original sender'] = original_sender del message['sender'] if 'target' in message: assert isinstance(message['target'], str) target = message['target'] - if target.startswith(prefix): + if target == '': + target = self._client + elif target.startswith(prefix): target = target[len(prefix):] else: - target = f"{self.conf['client']}/{target}" + target = f"{self._client}/{target}" message['target'] = target json_message = json.dumps(message) await self._websocket.send(json_message) async def _send(self, json_message: str) -> None: message = json.loads(json_message) - prefix = f"{self.conf['client']}/" + prefix = f"{self._client}/" original_sender = self.name if 'original sender' in message: if message['original sender'].startswith(prefix): return original_sender += f"/{message['original sender']}" - else: + elif message['sender'] != '': original_sender += f"/{message['sender']}" message['original sender'] = original_sender message['sender'] = self.name if 'target' in message: target = message['target'] - if target.startswith(prefix): + if target == '': + target = self.name + elif target.startswith(prefix): target = target[len(prefix):] else: target = f"{self.name}/{target}" @@ -74,6 +82,16 @@ class WSClient(BasePlugin): def process_conf(self) -> None: """Register plugin as bus client.""" self._websocket = None + if 'client' in self.conf: + self._client = self.conf['client'] + if 'interface' in self.conf: + # Get own MAC address: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + info = fcntl.ioctl(sock.fileno(), 0x8927, + struct.pack('256s', + bytes(self.conf['interface'], + 'utf-8')[:15])) + self._mac = ':'.join('%02x' % b for b in info[18:24]) sends = [] sends.append(MessageTemplate({'event': {'const': 'registered'}})) @@ -90,7 +108,7 @@ class WSClient(BasePlugin): 'const' in send_template['original sender']): const = send_template['original sender']['const'] original_sender += f"/{const}" - else: + elif send_template['sender']['const'] != '': const = send_template['sender']['const'] original_sender += f"/{const}" send_template['original sender'] = {'const': original_sender} @@ -98,9 +116,14 @@ class WSClient(BasePlugin): if ('target' in send_template and 'const' in send_template['target']): target = send_template['target']['const'] - prefix = f"{self.conf['client']}/" - if target.startswith(prefix): - target = target[len(prefix):] + if target == '': + target = self.name + elif 'client' in self.conf: + prefix = f"{self.conf['client']}/" + if target.startswith(prefix): + target = target[len(prefix):] + else: + target = f"{self.name}/{target}" else: target = f"{self.name}/{target}" send_template['target'] = {'const': target} @@ -110,40 +133,49 @@ class WSClient(BasePlugin): async def run(self) -> None: """Connect to wsserver and process messages from it.""" - up_filter = [] - for template in self.conf['up filter']: - up_template = MessageTemplate(template) - if ('sender' in up_template and - 'const' in up_template['sender']): - original_sender = self.conf['client'] - if ('original sender' in up_template and - 'const' in up_template['original sender']): - const = up_template['original sender']['const'] - original_sender += f"/{const}" - else: - const = up_template['sender']['const'] - original_sender += f"/{const}" - up_template['original sender'] = {'const': original_sender} - del up_template['sender'] - if ('target' in up_template and - 'const' in up_template['target']): - target = up_template['target']['const'] - prefix = f"{self.name}/" - if target.startswith(prefix): - target = target[len(prefix):] - else: - target = f"{self.conf['client']}/{target}" - up_template['target'] = {'const': target} - up_filter.append(up_template) - conf_command = {'command': 'configure websocket', - 'target': '', - 'name': self.conf['client'], - 'up filter': up_filter, - 'down filter': self.conf['down filter']} - json_command = json.dumps(conf_command) while True: try: async with connect(self.conf['url']) as websocket: + conf_command = {'command': 'configure websocket', + 'target': ''} + if 'client' in self.conf: + conf_command['name'] = self._client + else: + address = websocket.local_address[0] + port = websocket.local_address[1] + self._client = f"{address}:{port}" + if 'interface' in self.conf: + conf_command['mac'] = self._mac + up_filter = [] + for template in self.conf['up filter']: + up_template = MessageTemplate(template) + if ('sender' in up_template and + 'const' in up_template['sender']): + original_sender = self._client + if ('original sender' in up_template and + 'const' in up_template['original sender']): + const = up_template['original sender']['const'] + original_sender += f"/{const}" + elif up_template['sender']['const'] != '': + const = up_template['sender']['const'] + original_sender += f"/{const}" + up_template['original sender'] = {'const': original_sender} + del up_template['sender'] + if ('target' in up_template and + 'const' in up_template['target']): + target = up_template['target']['const'] + prefix = f"{self.name}/" + if target == '': + target = self._client + elif target.startswith(prefix): + target = target[len(prefix):] + else: + target = f"{self._client}/{target}" + up_template['target'] = {'const': target} + up_filter.append(up_template) + conf_command['up filter'] = up_filter + conf_command['down filter'] = self.conf['down filter'] + json_command = json.dumps(conf_command) await websocket.send(json_command) await self.bus.send(Message(self.name, {'event': -- 2.34.1