Skip to content

Commit

Permalink
Plugins: replace running bool with PluginStatus enum
Browse files Browse the repository at this point in the history
This enables the plugin to read the status of the
four formal states a plugin can be in. Previously
even though the four states existed implicitly,
it could only be differentiated between the
STARTED/STOPPED state based on the `running`
bool.

This change also has the nice benefit that we
can make stronger assumptions about the status
inside `start()` and raise an exception if
`start()` was called on a plugin that isn't in
the correct status to call `start()`
  • Loading branch information
cburgdorf committed Oct 29, 2018
1 parent 58e4eaf commit 99f44ec
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 12 deletions.
10 changes: 9 additions & 1 deletion trinity/extensibility/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
class EventBusNotReady(BaseTrinityError):
"""
Raised when a plugin tried to access an :class:`~lahja.eventbus.EventBus` before the plugin
had received its :meth:`~trinity.extensibility.plugin.BasePlugin.ready` call.
had received its :meth:`~trinity.extensibility.plugin.BasePlugin.on_ready` call.
"""
pass


class InvalidPluginStatus(BaseTrinityError):
"""
Raised when it was attempted to perform an action while the current
:class:`~trinity.extensibility.plugin.PluginStatus` does not allow to perform such action.
"""
pass

Expand Down
50 changes: 43 additions & 7 deletions trinity/extensibility/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
_SubParsersAction,
)
import asyncio
from enum import (
auto,
Enum,
)
import logging
from multiprocessing import (
Process
Expand Down Expand Up @@ -38,6 +42,7 @@
)
from trinity.extensibility.exceptions import (
EventBusNotReady,
InvalidPluginStatus,
)
from trinity.utils.ipc import (
kill_process_gracefully
Expand All @@ -50,6 +55,16 @@
)


class PluginStatus(Enum):
NOT_READY = auto()
READY = auto()
STARTED = auto()
STOPPED = auto()


INVALID_START_STATUS = (PluginStatus.NOT_READY, PluginStatus.STARTED,)


class TrinityBootInfo(NamedTuple):
args: Namespace
trinity_config: TrinityConfig
Expand All @@ -65,7 +80,7 @@ class PluginContext:
The :class:`~trinity.extensibility.plugin.PluginContext` is set during startup and is
guaranteed to exist by the time that a plugin receives its
:meth:`~trinity.extensibility.plugin.BasePlugin.ready` call.
:meth:`~trinity.extensibility.plugin.BasePlugin.on_ready` call.
"""

def __init__(self, endpoint: Endpoint, boot_info: TrinityBootInfo) -> None:
Expand Down Expand Up @@ -112,7 +127,7 @@ def trinity_config(self) -> TrinityConfig:
class BasePlugin(ABC):

context: PluginContext = None
running: bool = False
status: PluginStatus = PluginStatus.NOT_READY

@property
@abstractmethod
Expand Down Expand Up @@ -140,13 +155,28 @@ def event_bus(self) -> Endpoint:

return self.context.event_bus

@property
def running(self) -> bool:
"""
Return ``True`` if the ``status`` is ``PluginStatus.STARTED``, otherwise return ``False``.
"""
return self.status is PluginStatus.STARTED

def set_context(self, context: PluginContext) -> None:
"""
Set the :class:`~trinity.extensibility.plugin.PluginContext` for this plugin.
"""
self.context = context

def ready(self) -> None:
"""
Set the ``status`` to ``PluginStatus.READY`` and delegate to
:meth:`~trinity.extensibility.plugin.BasePlugin.on_ready`
"""
self.status = PluginStatus.READY
self.on_ready()

def on_ready(self) -> None:
"""
Notify the plugin that it is ready to bootstrap itself. Plugins can rely
on the :class:`~trinity.extensibility.plugin.PluginContext` to be set
Expand All @@ -157,7 +187,7 @@ def ready(self) -> None:
def configure_parser(self, arg_parser: ArgumentParser, subparser: _SubParsersAction) -> None:
"""
Give the plugin a chance to amend the Trinity CLI argument parser. This hook is called
before :meth:`~trinity.extensibility.plugin.BasePlugin.ready`
before :meth:`~trinity.extensibility.plugin.BasePlugin.on_ready`
"""
pass

Expand All @@ -167,7 +197,13 @@ def start(self) -> None:
to ``True``. Broadcast a :class:`~trinity.extensibility.events.PluginStartedEvent` on the
:class:`~lahja.eventbus.EventBus` and hence allow other plugins to act accordingly.
"""
self.running = True

if self.status in INVALID_START_STATUS:
raise InvalidPluginStatus(
f"Can not start plugin when the plugin status is {self.status}"
)

self.status = PluginStatus.STARTED
self.do_start()
self.event_bus.broadcast(
PluginStartedEvent(type(self))
Expand Down Expand Up @@ -202,7 +238,7 @@ def stop(self) -> None:
plugin to stop and setting ``running`` to ``False``.
"""
self.do_stop()
self.running = False
self.status = PluginStatus.STOPPED


class BaseAsyncStopPlugin(BasePlugin):
Expand All @@ -223,7 +259,7 @@ async def stop(self) -> None:
plugin to stop asynchronously and setting ``running`` to ``False``.
"""
await self.do_stop()
self.running = False
self.status = PluginStatus.STOPPED


class BaseMainProcessPlugin(BasePlugin):
Expand Down Expand Up @@ -252,7 +288,7 @@ def start(self) -> None:
"""
Prepare the plugin to get started and eventually call ``do_start`` in a separate process.
"""
self.running = True
self.status = PluginStatus.STARTED
self._process = ctx.Process(
target=self._prepare_start,
)
Expand Down
2 changes: 1 addition & 1 deletion trinity/plugins/builtin/ethstats/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def configure_parser(self, arg_parser: ArgumentParser, subparser: _SubParsersAct
default=os.environ.get('ETHSTATS_NODE_CONTACT', ''),
)

def ready(self) -> None:
def on_ready(self) -> None:
args = self.context.args

if not args.ethstats:
Expand Down
2 changes: 1 addition & 1 deletion trinity/plugins/builtin/json_rpc/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class JsonRpcServerPlugin(BaseIsolatedPlugin):
def name(self) -> str:
return "JSON-RPC Server"

def ready(self) -> None:
def on_ready(self) -> None:
if not self.context.args.disable_rpc:
self.start()

Expand Down
2 changes: 1 addition & 1 deletion trinity/plugins/builtin/light_peer_chain_bridge/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class LightPeerChainBridgePlugin(BaseAsyncStopPlugin):
def name(self) -> str:
return "LightPeerChain Bridge"

def ready(self) -> None:
def on_ready(self) -> None:
if self.context.trinity_config.sync_mode != SYNC_LIGHT:
return

Expand Down
2 changes: 1 addition & 1 deletion trinity/plugins/builtin/tx_pool/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def configure_parser(self, arg_parser: ArgumentParser, subparser: _SubParsersAct
help="Enables the Transaction Pool (experimental)",
)

def ready(self) -> None:
def on_ready(self) -> None:

light_mode = self.context.args.sync_mode == SYNC_LIGHT
self.is_enabled = self.context.args.tx_pool and not light_mode
Expand Down

0 comments on commit 99f44ec

Please sign in to comment.