Writing hooks ============= A :class:`.Hook` class accepts messages from all configured channels, and processes them however it likes. A common scenario is to forward or sync messages from one channel to another. The following methods are recognised: - :meth:`.Openable.start`: Perform any initial setup. - :meth:`.Openable.stop`: Perform any needed teardown. The following events can be implemented to collect, replace, or drop messages: - :meth:`.Hook.before_send`: Modify or suppress a message on its way out to a plug. - :meth:`.Hook.before_receive`: Modify or suppress a message received from a plug. - :meth:`.Hook.on_receive`: Handle a message received from a plug. Note that channel filtering is not provided out-of-the-box -- each hook will receive messages from all connected channels. Most likely you'll want to add a ``channels`` config entry which should take a list of channel names, and resolve them at initialisation. Host interaction ---------------- You can work with plugs, channels, groups, and other hooks by accessing them via the :class:`Host` instance at :attr:`.Hook.host`. Typically you should accept a list of objects in your config, then add config properties like :class:`.Plug.Property` to access them via an attribute. Plug & channel identifiers -------------------------- When working with plugs and channels, only refer to them by name when reading from user-provided config (e.g. to initially retrieve them). These names are liable to change if the user edits their setup, so if you were to store information about a channel or plug then it would become decoupled. Instead, use :attr:`.Plug.network_id` to identify plugs, and :attr:`.Channel.source` for channels, which should be based on constants from the underlying network (see :ref:`devs/plug-dev:Persistent identifiers`). Resource hooks -------------- In some cases, you may design a hook that acts as a single resource for other hooks, where only one such hook may be active, and other hooks retrieve it via the host. Rather than needing a setting to specify the hook name, as well as logic to ensure only one can be registered, you can subclass :class:`.ResourceHook` instead of :class:`.Hook`. Resources can be accessed via :attr:`.Host.resources`, keyed by the hook's class rather than its name, but is defined and added to a host in the same way as a regular hook.