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:
parent
b808d08eb3
commit
7e8ca842a2
4 changed files with 90 additions and 41 deletions
lbrynet
|
@ -155,13 +155,23 @@ class InvalidAuthenticationToken(Exception):
|
||||||
class NegotiationError(Exception):
|
class NegotiationError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidCurrencyError(Exception):
|
class InvalidCurrencyError(Exception):
|
||||||
def __init__(self, currency):
|
def __init__(self, currency):
|
||||||
self.currency = currency
|
self.currency = currency
|
||||||
Exception.__init__(
|
Exception.__init__(
|
||||||
self, 'Invalid currency: {} is not a supported currency.'.format(currency))
|
self, 'Invalid currency: {} is not a supported currency.'.format(currency))
|
||||||
|
|
||||||
|
|
||||||
class NoSuchDirectoryError(Exception):
|
class NoSuchDirectoryError(Exception):
|
||||||
def __init__(self, directory):
|
def __init__(self, directory):
|
||||||
self.directory = directory
|
self.directory = directory
|
||||||
Exception.__init__(self, 'No such directory {}'.format(directory))
|
Exception.__init__(self, 'No such directory {}'.format(directory))
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentStartConditionNotMet(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentsNotStarted(Exception):
|
||||||
|
pass
|
||||||
|
|
|
@ -9,7 +9,7 @@ class ComponentType(type):
|
||||||
def __new__(mcs, name, bases, newattrs):
|
def __new__(mcs, name, bases, newattrs):
|
||||||
klass = type.__new__(mcs, name, bases, newattrs)
|
klass = type.__new__(mcs, name, bases, newattrs)
|
||||||
if name != "Component":
|
if name != "Component":
|
||||||
ComponentManager.components.add(klass)
|
ComponentManager.default_component_classes[klass.component_name] = klass
|
||||||
return klass
|
return klass
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,34 +24,43 @@ class Component(object):
|
||||||
__metaclass__ = ComponentType
|
__metaclass__ = ComponentType
|
||||||
depends_on = []
|
depends_on = []
|
||||||
component_name = None
|
component_name = None
|
||||||
running = False
|
|
||||||
|
|
||||||
@classmethod
|
def __init__(self, component_manager):
|
||||||
def setup(cls):
|
self.component_manager = component_manager
|
||||||
raise NotImplementedError() # override
|
self._running = False
|
||||||
|
|
||||||
@classmethod
|
def __lt__(self, other):
|
||||||
def stop(cls):
|
return self.component_name < other.component_name
|
||||||
raise NotImplementedError() # override
|
|
||||||
|
@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
|
@defer.inlineCallbacks
|
||||||
def _setup(cls):
|
def _setup(self):
|
||||||
try:
|
try:
|
||||||
result = yield defer.maybeDeferred(cls.setup)
|
result = yield defer.maybeDeferred(self.start)
|
||||||
cls.running = True
|
self._running = True
|
||||||
defer.returnValue(result)
|
defer.returnValue(result)
|
||||||
except Exception as err:
|
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
|
raise err
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _stop(cls):
|
def _stop(self):
|
||||||
try:
|
try:
|
||||||
result = yield defer.maybeDeferred(cls.stop)
|
result = yield defer.maybeDeferred(self.stop)
|
||||||
cls.running = False
|
self._running = False
|
||||||
defer.returnValue(result)
|
defer.returnValue(result)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.exception("Error stopping %s", cls.__name__)
|
log.exception("Error stopping %s", self.__class__.__name__)
|
||||||
raise err
|
raise err
|
||||||
|
|
|
@ -1,20 +1,41 @@
|
||||||
import logging
|
import logging
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
from lbrynet.core.Error import ComponentStartConditionNotMet
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ComponentManager(object):
|
class ComponentManager(object):
|
||||||
components = set()
|
default_component_classes = {}
|
||||||
|
|
||||||
@classmethod
|
def __init__(self, reactor=None, analytics_manager=None, skip_components=None, **override_components):
|
||||||
def sort_components(cls, reverse=False):
|
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
|
Sort components by requirements
|
||||||
"""
|
"""
|
||||||
steps = []
|
steps = []
|
||||||
staged = set()
|
staged = set()
|
||||||
components = set(cls.components)
|
components = set(self.components)
|
||||||
|
|
||||||
# components with no requirements
|
# components with no requirements
|
||||||
step = []
|
step = []
|
||||||
|
@ -25,6 +46,7 @@ class ComponentManager(object):
|
||||||
components.remove(component)
|
components.remove(component)
|
||||||
|
|
||||||
if step:
|
if step:
|
||||||
|
step.sort()
|
||||||
steps.append(step)
|
steps.append(step)
|
||||||
|
|
||||||
while components:
|
while components:
|
||||||
|
@ -40,58 +62,58 @@ class ComponentManager(object):
|
||||||
to_stage.add(component.component_name)
|
to_stage.add(component.component_name)
|
||||||
components.remove(component)
|
components.remove(component)
|
||||||
if step:
|
if step:
|
||||||
|
step.sort()
|
||||||
staged.update(to_stage)
|
staged.update(to_stage)
|
||||||
steps.append(step)
|
steps.append(step)
|
||||||
elif components:
|
elif components:
|
||||||
raise SyntaxError("components cannot be started: %s" % components)
|
raise ComponentStartConditionNotMet("Unresolved dependencies for: %s" % components)
|
||||||
if reverse:
|
if reverse:
|
||||||
steps.reverse()
|
steps.reverse()
|
||||||
return steps
|
return steps
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def setup(cls, **callbacks):
|
def setup(self, **callbacks):
|
||||||
"""
|
"""
|
||||||
Start Components in sequence sorted by requirements
|
Start Components in sequence sorted by requirements
|
||||||
|
|
||||||
:return: (defer.Deferred)
|
:return: (defer.Deferred)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for component_name, cb in callbacks.iteritems():
|
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):
|
if not callable(cb):
|
||||||
raise ValueError("%s is not callable" % cb)
|
raise ValueError("%s is not callable" % cb)
|
||||||
cls.get_component(component_name)
|
|
||||||
|
|
||||||
def _setup(component):
|
def _setup(component):
|
||||||
if component.component_name in callbacks:
|
if component.component_name in callbacks:
|
||||||
d = component._setup()
|
d = component._setup()
|
||||||
d.addCallback(callbacks[component.component_name])
|
d.addCallback(callbacks[component.component_name])
|
||||||
return d
|
return d
|
||||||
return component.setup()
|
return component._setup()
|
||||||
|
|
||||||
stages = cls.sort_components()
|
stages = self.sort_components()
|
||||||
for stage in stages:
|
for stage in stages:
|
||||||
yield defer.DeferredList([_setup(component) for component in stage])
|
yield defer.DeferredList([_setup(component) for component in stage])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def stop(cls):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
Stop Components in reversed startup order
|
Stop Components in reversed startup order
|
||||||
|
|
||||||
:return: (defer.Deferred)
|
:return: (defer.Deferred)
|
||||||
"""
|
"""
|
||||||
stages = cls.sort_components(reverse=True)
|
stages = self.sort_components(reverse=True)
|
||||||
for stage in stages:
|
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(self, *component_names):
|
||||||
def all_components_running(cls, *component_names):
|
|
||||||
"""
|
"""
|
||||||
Check if components are running
|
Check if components are running
|
||||||
|
|
||||||
:return: (bool) True if all specified 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:
|
for component in component_names:
|
||||||
if component not in components:
|
if component not in components:
|
||||||
raise NameError("%s is not a known Component" % component)
|
raise NameError("%s is not a known Component" % component)
|
||||||
|
@ -99,9 +121,19 @@ class ComponentManager(object):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
def get_components_status(self):
|
||||||
def get_component(cls, component_name):
|
"""
|
||||||
for component in cls.components:
|
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:
|
if component.component_name == component_name:
|
||||||
return component
|
return component.component
|
||||||
raise NameError(component_name)
|
raise NameError(component_name)
|
||||||
|
|
|
@ -17,7 +17,6 @@ from lbrynet.core.Error import InvalidAuthenticationToken
|
||||||
from lbrynet.core import utils
|
from lbrynet.core import utils
|
||||||
from lbrynet.daemon.auth.util import APIKey, get_auth_message
|
from lbrynet.daemon.auth.util import APIKey, get_auth_message
|
||||||
from lbrynet.daemon.auth.client import LBRY_SECRET
|
from lbrynet.daemon.auth.client import LBRY_SECRET
|
||||||
from lbrynet.daemon.Component import ComponentManager
|
|
||||||
from lbrynet.undecorated import undecorated
|
from lbrynet.undecorated import undecorated
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -133,7 +132,6 @@ class JSONRPCServerType(type):
|
||||||
|
|
||||||
class AuthorizedBase(object):
|
class AuthorizedBase(object):
|
||||||
__metaclass__ = JSONRPCServerType
|
__metaclass__ = JSONRPCServerType
|
||||||
component_manager = ComponentManager
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def deprecated(new_command=None):
|
def deprecated(new_command=None):
|
||||||
|
|
Loading…
Add table
Reference in a new issue