Add Execute plugin.
authorBenjamin Braatz <bb@bbraatz.eu>
Sat, 20 Mar 2021 23:38:55 +0000 (00:38 +0100)
committerBenjamin Braatz <bb@bbraatz.eu>
Sat, 20 Mar 2021 23:38:55 +0000 (00:38 +0100)
controlpi-plugins/util.py

index 284e15f2ab2625faa4a20dcdfa3fd7cdc49787f0..d3b42fd805ce91db7e8829375eba4b85e74df48e 100644 (file)
@@ -212,6 +212,79 @@ class Init(BasePlugin):
             await self.bus.send(Message(self.name, message))
 
 
+class Execute(BasePlugin):
+    """Send configurable list of messages on demand.
+
+    An Execute plugin instance receives two kinds of commands.
+    The "set messages" command has a "messages" key with a list of (partial)
+    messages, which are sent by the Execute instance in reaction to an
+    "execute" command.
+
+    In the example, the first command sent by the test sets two messages,
+    which are then sent in reaction to the second command sent by the test:
+    >>> import asyncio
+    >>> import controlpi
+    >>> asyncio.run(controlpi.test(
+    ...     {"Test Execute": {"plugin": "Execute"}},
+    ...     [{"target": "Test Execute", "command": "set messages",
+    ...       "messages": [{"id": 42, "content": "Test Message"},
+    ...                    {"id": 42.42, "content": "Second Message"}]},
+    ...      {"target": "Test Execute", "command": "execute"}]))
+    ... # doctest: +NORMALIZE_WHITESPACE
+    test(): {'sender': '', 'event': 'registered',
+             'client': 'Test Execute', 'plugin': 'Execute',
+             'sends': [{}],
+             'receives': [{'target': {'const': 'Test Execute'},
+                           'command': {'const': 'set messages'},
+                           'messages': {'type': 'array',
+                                        'items': {'type': 'object'}}},
+                          {'target': {'const': 'Test Execute'},
+                           'command': {'const': 'execute'}}]}
+    test(): {'sender': 'test()', 'target': 'Test Execute',
+             'command': 'set messages',
+             'messages': [{'id': 42, 'content': 'Test Message'},
+                          {'id': 42.42, 'content': 'Second Message'}]}
+    test(): {'sender': 'test()', 'target': 'Test Execute',
+             'command': 'execute'}
+    test(): {'sender': 'Test Execute', 'id': 42,
+             'content': 'Test Message'}
+    test(): {'sender': 'Test Execute', 'id': 42.42,
+             'content': 'Second Message'}
+    """
+
+    CONF_SCHEMA = True
+    """Schema for Execute plugin configuration.
+
+    There are no required or optional configuration keys.
+    """
+
+    async def execute(self, message: Message) -> None:
+        """Set or send configured messages."""
+        if message['command'] == 'set messages':
+            assert isinstance(message['messages'], list)
+            self.messages = list(message['messages'])
+        elif message['command'] == 'execute':
+            for message in self.messages:
+                await self.bus.send(Message(self.name, message))
+
+    def process_conf(self) -> None:
+        """Register plugin as bus client."""
+        self.messages = []
+        receives = [MessageTemplate({'target': {'const': self.name},
+                                     'command': {'const': 'set messages'},
+                                     'messages':
+                                     {'type': 'array',
+                                      'items': {'type': 'object'}}}),
+                    MessageTemplate({'target': {'const': self.name},
+                                     'command': {'const': 'execute'}})]
+        sends = [MessageTemplate()]
+        self.bus.register(self.name, 'Execute', sends, receives, self.execute)
+
+    async def run(self) -> None:
+        """Run no code proactively."""
+        pass
+
+
 class Alias(BasePlugin):
     """Translate messages to an alias.