Commit 09939d56 authored by Anael Beutot's avatar Anael Beutot
Browse files

Declarative API for RPC handlers

parent ecb4c7b4
Loading
Loading
Loading
Loading
+67 −1
Original line number Diff line number Diff line
"""Plugins helpers for Cloud Control clients."""

from inspect import getmembers

from cloudcontrol.common.client.tags import TagDB


def rpc_handler_decorator_factory(attr_name):
    """Can be used to create custom decorators for marking callable objects as
    RPC handlers

    """
    def rpc_handler(name_or_func=None):
        """RPC handler decorator

        Declares a callable as an RPC handler

        :param name_or_func: allow decorator to be used in two manners:
            # the first case is to export the handler using the same name as the
            # function
            @rpc_handler
            def plop():
                pass

            # the second case allow to specify the RPC handler exported name
            @rpc_handler('plop')
            def plop_handler():
                pass
        """

        def decorator(callable_):
            """Decorator for marking a callable as an RPC handler."""
            assert callable(callable_)
            setattr(callable_, attr_name, name)
            return callable_

        if callable(name_or_func):
            # we are in the first case
            name = True
            return decorator(name_or_func)

        # else, second case
        name = name_or_func
        return decorator
    return rpc_handler


def get_rpc_handlers(o, marker):
    """Get RPC handlers members of an object

    :param o: the object to instrospect
    :param str marker: the attribute to check to decide whether the member is an
        RPC handler
    """
    def get_marker(member):
        return getattr(member, marker, None)

    return dict((
        # return handler name to be the callable object name or the one defined
        # through the decorator
        get_marker(v) if isinstance(get_marker(v), basestring) else k,
        v,
    ) for k, v in getmembers(
        o, lambda m: callable(m) and get_marker(m) is not None))


#: basic decorator to declare RPC handlers
rpc_handler_marker = '_rpc_handler'
rpc_handler = rpc_handler_decorator_factory(rpc_handler_marker)


class Base(object):
    """Example skeleton plugin for clients.

@@ -22,7 +88,7 @@ class Base(object):

        # plugins may define handler functions that would be called by the
        # server
        self.rpc_handler = dict()
        self.rpc_handler = get_rpc_handlers(self, rpc_handler_marker)

        # tag_db and rpc_handler can be implemented as properties if more logic
        # is needed