change ComponentManager to use instance methods rather than class methods

-add get_component method to ComponentManager

-add override_components kwargs to ComponentManager

-add skip_components to ComponentManager

-change component_manager attribute to exist on the AuthJSONRPCServer instance instead of the class
This commit is contained in:
Jack Robison 2018-07-24 12:03:43 -04:00
parent b808d08eb3
commit 7e8ca842a2
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
4 changed files with 90 additions and 41 deletions

View file

@ -155,13 +155,23 @@ class InvalidAuthenticationToken(Exception):
class NegotiationError(Exception):
pass
class InvalidCurrencyError(Exception):
def __init__(self, currency):
self.currency = currency
Exception.__init__(
self, 'Invalid currency: {} is not a supported currency.'.format(currency))
class NoSuchDirectoryError(Exception):
def __init__(self, directory):
self.directory = directory
Exception.__init__(self, 'No such directory {}'.format(directory))
class ComponentStartConditionNotMet(Exception):
pass
class ComponentsNotStarted(Exception):
pass

View file

@ -9,7 +9,7 @@ class ComponentType(type):
def __new__(mcs, name, bases, newattrs):
klass = type.__new__(mcs, name, bases, newattrs)
if name != "Component":
ComponentManager.components.add(klass)
ComponentManager.default_component_classes[klass.component_name] = klass
return klass
@ -24,34 +24,43 @@ class Component(object):
__metaclass__ = ComponentType
depends_on = []
component_name = None
running = False
@classmethod
def setup(cls):
raise NotImplementedError() # override
def __init__(self, component_manager):
self.component_manager = component_manager
self._running = False
@classmethod
def stop(cls):
raise NotImplementedError() # override
def __lt__(self, other):
return self.component_name < other.component_name
@property
def running(self):
return self._running
def start(self):
raise NotImplementedError()
def stop(self):
raise NotImplementedError()
def component(self):
raise NotImplementedError()
@classmethod
@defer.inlineCallbacks
def _setup(cls):
def _setup(self):
try:
result = yield defer.maybeDeferred(cls.setup)
cls.running = True
result = yield defer.maybeDeferred(self.start)
self._running = True
defer.returnValue(result)
except Exception as err:
log.exception("Error setting up %s", cls.component_name or cls.__name__)
log.exception("Error setting up %s", self.component_name or self.__class__.__name__)
raise err
@classmethod
@defer.inlineCallbacks
def _stop(cls):
def _stop(self):
try:
result = yield defer.maybeDeferred(cls.stop)
cls.running = False
result = yield defer.maybeDeferred(self.stop)
self._running = False
defer.returnValue(result)
except Exception as err:
log.exception("Error stopping %s", cls.__name__)
log.exception("Error stopping %s", self.__class__.__name__)
raise err

View file

@ -1,20 +1,41 @@
import logging
from twisted.internet import defer
from lbrynet.core.Error import ComponentStartConditionNotMet
log = logging.getLogger(__name__)
class ComponentManager(object):
components = set()
default_component_classes = {}
@classmethod
def sort_components(cls, reverse=False):
def __init__(self, reactor=None, analytics_manager=None, skip_components=None, **override_components):
self.skip_components = skip_components or []
self.reactor = reactor
self.component_classes = {}
self.components = set()
self.analytics_manager = analytics_manager
for component_name, component_class in self.default_component_classes.iteritems():
if component_name in override_components:
component_class = override_components.pop(component_name)
if component_name not in self.skip_components:
self.component_classes[component_name] = component_class
if override_components:
raise SyntaxError("unexpected components: %s" % override_components)
for component_class in self.component_classes.itervalues():
self.components.add(component_class(self))
def sort_components(self, reverse=False):
"""
Sort components by requirements
"""
steps = []
staged = set()
components = set(cls.components)
components = set(self.components)
# components with no requirements
step = []
@ -25,6 +46,7 @@ class ComponentManager(object):
components.remove(component)
if step:
step.sort()
steps.append(step)
while components:
@ -40,58 +62,58 @@ class ComponentManager(object):
to_stage.add(component.component_name)
components.remove(component)
if step:
step.sort()
staged.update(to_stage)
steps.append(step)
elif components:
raise SyntaxError("components cannot be started: %s" % components)
raise ComponentStartConditionNotMet("Unresolved dependencies for: %s" % components)
if reverse:
steps.reverse()
return steps
@classmethod
@defer.inlineCallbacks
def setup(cls, **callbacks):
def setup(self, **callbacks):
"""
Start Components in sequence sorted by requirements
:return: (defer.Deferred)
"""
for component_name, cb in callbacks.iteritems():
if component_name not in self.component_classes:
raise NameError("unknown component: %s" % component_name)
if not callable(cb):
raise ValueError("%s is not callable" % cb)
cls.get_component(component_name)
def _setup(component):
if component.component_name in callbacks:
d = component._setup()
d.addCallback(callbacks[component.component_name])
return d
return component.setup()
return component._setup()
stages = cls.sort_components()
stages = self.sort_components()
for stage in stages:
yield defer.DeferredList([_setup(component) for component in stage])
@classmethod
@defer.inlineCallbacks
def stop(cls):
def stop(self):
"""
Stop Components in reversed startup order
:return: (defer.Deferred)
"""
stages = cls.sort_components(reverse=True)
stages = self.sort_components(reverse=True)
for stage in stages:
yield defer.DeferredList([component._stop() for component in stage])
yield defer.DeferredList([component._stop() for component in stage if component.running])
@classmethod
def all_components_running(cls, *component_names):
def all_components_running(self, *component_names):
"""
Check if components are running
:return: (bool) True if all specified components are running
"""
components = {component.component_name: component for component in cls.components}
components = {component.component_name: component for component in self.components}
for component in component_names:
if component not in components:
raise NameError("%s is not a known Component" % component)
@ -99,9 +121,19 @@ class ComponentManager(object):
return False
return True
@classmethod
def get_component(cls, component_name):
for component in cls.components:
def get_components_status(self):
"""
List status of all the components, whether they are running or not
:return: (dict) {(str) component_name: (bool) True is running else False}
"""
return {
component.component_name: component.running
for component in self.components
}
def get_component(self, component_name):
for component in self.components:
if component.component_name == component_name:
return component
return component.component
raise NameError(component_name)

View file

@ -17,7 +17,6 @@ from lbrynet.core.Error import InvalidAuthenticationToken
from lbrynet.core import utils
from lbrynet.daemon.auth.util import APIKey, get_auth_message
from lbrynet.daemon.auth.client import LBRY_SECRET
from lbrynet.daemon.Component import ComponentManager
from lbrynet.undecorated import undecorated
log = logging.getLogger(__name__)
@ -133,7 +132,6 @@ class JSONRPCServerType(type):
class AuthorizedBase(object):
__metaclass__ = JSONRPCServerType
component_manager = ComponentManager
@staticmethod
def deprecated(new_command=None):