@@ -176,7 +176,7 @@ Every plugin needs to overwrite ``name`` so voilà, here's our first plugin!
176
176
177
177
.. literalinclude :: ../../../trinity/plugins/examples/peer_count_reporter/plugin.py
178
178
:language: python
179
- :start-after: --START CLASS--
179
+ :pyobject: PeerCountReporterPlugin
180
180
:end-before: def configure_parser
181
181
182
182
Of course that doesn't do anything useful yet, bear with us.
@@ -229,8 +229,30 @@ code in a loop or any other kind of action.
229
229
:class: `~trinity.extensibility.events.PluginStartedEvent ` and the plugin won't be properly shut
230
230
down with Trinity if the node closes.
231
231
232
- Causing a plugin to start
233
- -------------------------
232
+ Let's assume we want to create a plugin that simply periodically prints out the number of connected
233
+ peers.
234
+
235
+ While it is absolutely possible to put this logic right into the plugin, the preferred way is to
236
+ subclass :class: `~p2p.service.BaseService ` and implement the core logic in such a standalone
237
+ service.
238
+
239
+ .. literalinclude :: ../../../trinity/plugins/examples/peer_count_reporter/plugin.py
240
+ :language: python
241
+ :pyobject: PeerCountReporter
242
+
243
+ Then, the implementation of :meth: `~trinity.extensibility.plugin.BaseIsolatedPlugin.do_start ` is
244
+ only concerned about running the service on a fresh event loop.
245
+
246
+ .. literalinclude :: ../../../trinity/plugins/examples/peer_count_reporter/plugin.py
247
+ :language: python
248
+ :pyobject: PeerCountReporterPlugin.do_start
249
+
250
+ If the example may seem unnecessarily complex, it should be noted that plugins can be implemented
251
+ in many different ways, but this example follows a pattern that is considered best practice within
252
+ the Trinity Code Base.
253
+
254
+ Starting a plugin
255
+ -----------------
234
256
235
257
As we've read in the previous section not all plugins should run at any point in time. In fact, the
236
258
circumstances under which we want a plugin to begin its work may vary from plugin to plugin.
@@ -245,19 +267,69 @@ We may want a plugin to only start running if:
245
267
246
268
Hence, to actually start a plugin, the plugin needs to invoke the
247
269
:meth: `~trinity.extensibility.plugin.BasePlugin.start ` method at any moment when it is in its
248
- ``READY `` state.
270
+ ``READY `` state. Let's assume a simple case in which we simply want to start the plugin if Trinity
271
+ is started with the ``--report-peer-count `` flag.
272
+
273
+ .. literalinclude :: ../../../trinity/plugins/examples/peer_count_reporter/plugin.py
274
+ :language: python
275
+ :pyobject: PeerCountReporterPlugin.on_ready
276
+
277
+ In case of a :class: `~trinity.extensibility.plugin.BaseIsolatedProcessPlugin `, this will cause the
278
+ :meth: `~trinity.extensibility.plugin.BaseIsolatedPlugin.do_start ` method to run on an entirely
279
+ separated, new process. In other cases
280
+ :meth: `~trinity.extensibility.plugin.BaseIsolatedPlugin.do_start ` will simply run in the same
281
+ process as the plugin manager that the plugin is controlled by.
282
+
249
283
250
284
Communication pattern
251
285
~~~~~~~~~~~~~~~~~~~~~
252
286
253
- Coming soon: Spoiler: Plugins can communicate with other parts of the application or even other
254
- plugins via the central event bus.
287
+ For most plugins to be useful they need to be able to communicate with the rest of the application
288
+ as well as other plugins. In addition to that, this kind of communication needs to work across
289
+ process boundaries as plugins will often operate in independent processes.
255
290
256
- Making plugins discoverable
257
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291
+ To achieve this, Trinity uses the
292
+ `Lahja project <https://github.com/ethereum/lahja >`_, which enables us to operate
293
+ a lightweight event bus that works across processes. An event bus is a software dedicated to the
294
+ transmission of events from a broadcaster to interested parties.
258
295
259
- Coming soon.
296
+ This kind of architecture allows for efficient and decoupled communication between different parts
297
+ of Trinity including plugins.
260
298
261
- .. warning ::
262
- **Wait?! This is it? No! This is draft version of the plugin guide as small DEVCON IV gitft.
263
- This will turn into a much more detailed guide shortly after the devcon craze is over. **
299
+ For instance, a plugin may be interested to perform some action every time that a new peer connects
300
+ to our node. These kind of events get exposed on the EventBus and hence allow a wide range of
301
+ plugins to make use of them.
302
+
303
+ For an event to be usable across processes it needs to be pickable and in general should be a
304
+ shallow Data Transfer Object (`DTO <https://en.wikipedia.org/wiki/Data_transfer_object >`_)
305
+
306
+ Every plugin has access to the event bus via its
307
+ :meth: `~trinity.extensibility.plugin.BasePlugin.event_bus ` property and in fact we have already
308
+ used it in the above example to get the current number of connected peers.
309
+
310
+ .. note ::
311
+ This guide will soon cover communication through the event bus in more detail. For now, the
312
+ `Lahja documentation <https://github.com/ethereum/lahja/blob/master/README.md >`_ gives us some
313
+ more information about the available APIs and how to use them.
314
+
315
+ Distributing plugins
316
+ ~~~~~~~~~~~~~~~~~~~~
317
+
318
+ Of course, plugins are more fun if we can share them and anyone can simply install them through
319
+ ``pip ``. The good news is, it's not hard at all!
320
+
321
+ In this guide, we won't go into details about how to create Python packages as this is already
322
+ `covered in the official Python docs <https://packaging.python.org/tutorials/packaging-projects/ >`_
323
+ .
324
+
325
+ Once we have a ``setup.py `` file, all we have to do is to expose our plugin under
326
+ ``trinity.plugins `` via the ``entry_points `` section.
327
+
328
+ .. literalinclude :: ../../../tests/trinity/integration/trinity_test_plugin/setup.py
329
+ :language: python
330
+
331
+ Check out the `official documentation on entry points <https://packaging.python.org/guides/creating-and-discovering-plugins/#using-package-metadata >`_
332
+ for a deeper explanation.
333
+
334
+ A plugin where the ``setup.py `` file is configured as described can be installed by
335
+ ``pip install <package-name>` `` and is immediately available as a plugin in Trinity.
0 commit comments