예제 #1
0
class FakeNode(metaclass=WAMPInitMeta):
    """A fake Node class that emulates the interesting API of
    r.r.node.node.WAMPNode, just to test the wamp stuff"""

    on_node_register = Signal()
    on_node_registration_success = Signal()
    on_node_registration_failure = Signal()
    on_node_unregister = Signal()

    node_registered = False

    def __init__(self, context, path):
        self.node_context = context
        self.node_path = path
        self.loop = context.loop

    async def node_register(self):
        self.node_registered = True
        await self.on_node_register.notify(node=self,
                                           context=self.node_context)

    async def node_unregister(self):
        self.node_registered = False
        await self.on_node_unregister.notify(node=self,
                                             context=self.node_context)
예제 #2
0
async def test_04_signal_with_methods(events):
    asignal = Signal()

    class A(object):
        def __init__(self, name):
            self.ev = events[name]

        called = False

        async def handler(self, arg, kw):
            self.called = (arg, kw)
            self.ev.set()

    a1 = A('a1')
    a2 = A('a2')

    asignal.connect(a1.handler)
    asignal.connect(a2.handler)

    assert len(asignal.subscribers) == 2

    await asignal.notify(1, kw='a')
    await events.wait()

    assert a1.called == (1, 'a')
    assert a2.called == (1, 'a')
예제 #3
0
def test_13_disconnect_wrapper():

    c = dict(called=0, disconnect_handler=None)

    asignal = Signal()

    @asignal.on_disconnect
    def asignal(handler, subscribers, disconnect, notify):
        c['called'] += 1
        c['disconnect_handler'] = handler
        assert len(subscribers) == 1
        disconnect(handler)
        return 'foo'

    def handler(*args, **kwargs):
        pass

    asignal.connect(handler)
    res = asignal.disconnect(handler)

    assert res == 'foo'
    assert c['called'] == 1
    assert c['disconnect_handler'] == handler
    assert len(asignal.subscribers) == 0

    c = dict(called=0, disconnect_handler=None)

    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        @click.on_disconnect
        def click(self, handler, subscribers, disconnect, notify):
            c['called'] += 1
            c['disconnect_handler'] = handler
            assert len(subscribers) == 1
            disconnect(handler)
            return 'foo'

        @handler('click')
        def handler(self, *args, **kwargs):
            pass

    a = A()

    def handler2(*args, **kwargs):
        pass

    a.click.connect(handler2)
    res = a.click.disconnect(handler2)
    assert res == 'foo'
    assert c['called'] == 1
    assert c['disconnect_handler'] == handler2
    # class-level handlers are excluded
    assert len(a.click.subscribers) == 0
예제 #4
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal(Signal.FLAGS.SORT_TOPDOWN)

        @handler('click')
        def z(self):
            called.append('z')
예제 #5
0
    class A(metaclass=MySignalMeta):

        click = Signal()

        @handler('click')
        def handler1(self, *args, **kwargs):
            c['handler_called'] = True
예제 #6
0
async def test_10_external_signaller_async(events):

    from metapensiero.signal import ExternalSignaller

    c = dict(publish_called=False, register_called=False)

    class MyExternalSignaller(object):
        async def publish_signal(self, signal, instance, loop, args, kwargs):
            c['publish_called'] = (signal, instance, loop, args, kwargs)
            events.publish.set()

        def register_signal(self, signal, name):
            c['register_called'] = (signal, name)

    ExternalSignaller.register(MyExternalSignaller)

    assert c['register_called'] is False
    assert c['publish_called'] is False

    signaller = MyExternalSignaller()
    asignal = Signal(name='foo', external=signaller)

    assert c['register_called'] == (asignal, 'foo')
    assert c['publish_called'] is False

    await asignal.notify('foo', zoo='bar')
    await events.publish.wait()

    assert c['publish_called'] == (asignal, None, asyncio.get_event_loop(),
                                   ('foo', ), {
                                       'zoo': 'bar'
                                   })
    assert c['register_called'] == (asignal, 'foo')
예제 #7
0
    class RPCTest(WAMPNode):

        foo = Signal()

        @handler('foo')
        def local_bar(self, **_):
            nonlocal counter
            counter += 1
예제 #8
0
    class Service(BaseService):

        ping = Signal()
        pong = Signal()

        @handler('@service2.pong')
        def on_pong(self, details):
            events.pong.set()

        @handler('@service1.ping')
        def on_ping(self, details):
            events.ping.set()
            self.pong.notify()

        @handler('on_start')
        def _set_started_event(self):
            events[self.node_name].set()
예제 #9
0
async def test_01_signal_with_functions(events):
    asignal = Signal()
    c = dict(called1=False, called2=False)

    def handler1(arg, kw):
        # let python get the outer var here without using PY3 "nonlocal"
        c['called1'] = (arg, kw)

    def handler2(arg, kw):
        c['called2'] = (arg, kw)

    asignal.connect(handler1)
    asignal.connect(handler2)

    assert len(asignal.subscribers) == 2

    await asignal.notify(1, kw='a')
    assert c['called1'] == (1, 'a')
    assert c['called2'] == (1, 'a')
예제 #10
0
    class RPCTest(WAMPNode):

        foo = Signal()
        foo.name = '.'

        @call('.')
        def me(self, **_):
            nonlocal counter
            counter += 1
            return counter
예제 #11
0
class Session(ClientSession, metaclass=SignalAndHandlerInitMeta):
    "A client session, enriched with some signals."

    on_join = Signal()
    "Signal emitted when the session is joined."

    on_leave = Signal()
    "Signal emitted when the session is detached."

    def onJoin(self, details):
        "Emit the :attr:`on_join` signal."
        loop = self.config.extra['joined']._loop
        self.on_join.notify(details, loop=loop)
        super().onJoin(details)

    def onLeave(self, details):
        "Emit the :attr:`on_leave` signal."
        loop = self.config.extra['joined']._loop
        self.on_leave.notify(details, loop=loop)
        super().onLeave(details)
예제 #12
0
        class A(metaclass=SignalAndHandlerInitMeta):

            click = Signal()

            @click.on_notify
            def click(self, subscribers, notify, *args, **kwargs):
                notify('foo', k=2)

            @handler('dblclick')
            def handler(self, *args, **kwargs):
                pass
예제 #13
0
    class A(metaclass=MySignalMeta):

        click = Signal()

        @handler('click')
        def handler1(self, *args, **kwargs):
            pass

        @handler('myext.dbclick')
        def handler2(self, *args, **kwargs):
            pass
예제 #14
0
    class A(metaclass=SignalAndHandlerInitMeta):

        me = Signal()
        me.name = '.'

        def __init__(self):
            self.called = False

        @handler('.')
        def onme(self, arg, kw):
            self.called = (arg, kw)
예제 #15
0
async def test_03_signal_with_mixed_functions(events):
    asignal = Signal()
    c = dict(called1=False, called2=False)
    events.define('h1')

    async def handler1(arg, kw):
        c['called1'] = (arg, kw)
        events.h1.set()

    def handler2(arg, kw):
        c['called2'] = (arg, kw)

    asignal.connect(handler1)
    asignal.connect(handler2)

    assert len(asignal.subscribers) == 2

    await asignal.notify(1, kw='a')
    assert c['called2'] == (1, 'a')
    await events.wait()
    assert c['called1'] == (1, 'a')
예제 #16
0
    class RPCTest(WAMPNode):

        asignal = Signal()

        @call
        def callee(self):
            return self

        @handler('asignal')
        def store_incoming(self, node):
            events.asignal.set()
            self.node = node
예제 #17
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        def __init__(self, name):
            self.called = False
            self.a_ev = events['a_' + name]

        @handler('click')
        async def onclick(self, arg, kw):
            self.called = (arg, kw)
            self.a_ev.set()
            return 1
예제 #18
0
    class A(object):

        # the name here is needed for classes that don't explicitly support
        # signals
        click = Signal(name='click')

        def __init__(self, name):
            self.called = False
            self.click.connect(self.onclick)
            self.on_click_ev = events[name]

        async def onclick(self, arg, kw):
            self.called = (arg, kw)
            self.on_click_ev.set()
예제 #19
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        @click.on_disconnect
        def click(self, handler, subscribers, disconnect, notify):
            c['called'] += 1
            c['disconnect_handler'] = handler
            assert len(subscribers) == 1
            disconnect(handler)
            return 'foo'

        @handler('click')
        def handler(self, *args, **kwargs):
            pass
예제 #20
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        def __init__(self):
            self.called = False
            self.called2 = False

        @handler('click')
        def onclick(self, arg, kw):
            self.called = (arg, kw)

        @handler('click')
        async def click2(self, arg, kw):
            self.called2 = (arg, kw)
예제 #21
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        @click.on_notify
        def click(self, subscribers, notify, *args, **kwargs):
            c['called'] += 1
            c['wrap_args'] = (args, kwargs)
            assert len(subscribers) == 2
            assert isinstance(self, A)
            notify('foo', k=2)
            return 'foo'

        @handler('click')
        def handler(self, *args, **kwargs):
            c['handler_called'] += 1
            c['handler_args'] = (args, kwargs)
예제 #22
0
async def test_12_connect_wrapper(events):

    c = dict(called=0,
             connect_handler=None,
             handler_called=0,
             handler_args=None)

    asignal = Signal()

    @asignal.on_connect
    def asignal(handler, subscribers, connect, notify):
        c['called'] += 1
        c['connect_handler'] = handler
        assert len(subscribers) == 0
        connect(handler)
        return 'foo'

    def handler(*args, **kwargs):
        c['handler_called'] += 1
        c['handler_args'] = (args, kwargs)

    res = asignal.connect(handler)
    res2 = await asignal.notify('bar', k=1)

    assert res == 'foo'
    assert c['called'] == 1
    assert c['connect_handler'] == handler
    assert c['handler_called'] == 1
    assert c['handler_args'] == (('bar', ), {'k': 1})

    c = dict(called=0,
             connect_handler=None,
             handler_called=0,
             handler_args=None,
             handler2_called=0,
             handler2_args=None)

    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        @click.on_connect
        def click(self, handler, subscribers, connect, notify):
            c['called'] += 1
            c['connect_handler'] = handler
            assert len(subscribers) == 0
            connect(handler)
            return 'foo'

        @handler('click')
        def handler(self, *args, **kwargs):
            c['handler_called'] += 1
            c['handler_args'] = (args, kwargs)

    a = A()

    def handler2(*args, **kwargs):
        c['handler2_called'] += 1
        c['handler2_args'] = (args, kwargs)

    res = a.click.connect(handler2)
    res2 = await a.click.notify('bar', k=1)

    assert res == 'foo'
    assert c['called'] == 1
    assert c['handler_called'] == 1
    assert c['connect_handler'] == handler2
    assert c['handler_args'] == (('bar', ), {'k': 1})
    assert c['handler2_called'] == 1
    assert c['handler2_args'] == (('bar', ), {'k': 1})
예제 #23
0
class Connection(Client, metaclass=SignalAndHandlerInitMeta):
    "A client connection, enriched with some signals."

    on_connect = Signal()
    """Signal emitted when the connection is activated and the session has
    joined the realm.
    """
    def __init__(self, url, realm, loop=None, **kwargs):
        """:param str url: a :term:`WAMP` connection url
        :param str realm: a :term:`WAMP` realm to enter
        :param loop: an optional asyncio loop

        Every other keyword argument will be passed to the underlying
        autobahn client.
        """
        super().__init__(url, realm, loop=None, **kwargs)
        self.session = None
        self.session_details = None

    def _notify_disconnect(self):
        """NOTE: This is not a coroutine but returns one."""
        try:
            return self.on_disconnect.notify(loop=self.loop)
        finally:
            self.session = None
            self.session_details = None

    async def _on_session_leave(self, details):
        return self._notify_disconnect()

    async def connect(self, username=None, password=None):
        "Emits the :attr:`on_connect` signal."
        session, sess_details = await super().connect(username,
                                                      password,
                                                      session_class=Session)
        self.session = session
        self.session_details = sess_details
        await self.on_connect.notify(session=session,
                                     session_details=sess_details,
                                     loop=self.loop)
        session.on_leave.connect(self._on_session_leave)
        return session, sess_details

    @property
    def connected(self):
        """Returns ``True`` if this connection is attached to a session."""
        return self.session is not None and self.session.is_attached()

    async def disconnect(self):
        "Emits the :attr:`on_disconnect` signal."
        await self._notify_disconnect()
        await super().disconnect()

    def new_context(self):
        """
        Return a new :class:`~metapensiero.raccoon.node.node.WAMPNodeContext`
        instance tied to this connection.
        """
        return WAMPNodeContext(loop=self.loop, wamp_session=self.session)

    @on_connect.on_connect
    async def on_connect(self, handler, subscribers, connect):
        """Call handler immediately if the session is attached already."""
        if self.connected:
            res = connect.notify(handler,
                                 session=self.session,
                                 session_details=self.session_details)
        else:
            res = self.loop.create_future()
            res.set_result(None)
        connect(handler)
        return res

    on_disconnect = Signal()
    "Signal emitted when the connection is deactivated."

    @on_disconnect.on_connect
    async def on_disconnect(self, handler, subscribers, disconnect):
        """Call handler immediately if the session is already attached."""
        if not self.connected:
            res = disconnect.notify(handler, loop=self.loop)
        else:
            res = self.loop.create_future()
            res.set_result(None)
        disconnect(handler)
        return res

    def run(self):
        """Adds a ``SIGTERM`` handler and runs the loop until the connection
        ends or the process is killed.
        """
        try:
            self.loop.add_signal_handler(signal.SIGTERM, self.loop.stop)
        except NotImplementedError:
            # signals are not available on Windows
            pass

        try:
            self.loop.run_forever()
        except KeyboardInterrupt:
            # wait until we send Goodbye if user hit ctrl-c
            # (done outside this except so SIGTERM gets the same handling)
            pass

        # give Goodbye message a chance to go through, if we still
        # have an active session
        if self.protocol._session:
            self.loop.run_until_complete(self.protocol._session.leave())

        self.loop.close()
예제 #24
0
    class RPCTest(FakeNode):

        on_test_event = Signal()
예제 #25
0
class WAMPNode(Node, serialize.Serializable, metaclass=WAMPInitMeta):
    """A Node subclass to deal with WAMP stuff. An instance gets
    local and WAMP pub/sub, WAMP RPC and automatic tree addressing.

    This is done by performing other two operations: *register* and
    *unregister* to be performed possibly at a different (later) time
    than the bind operation.

    This class is coded to run in tandem with the
    :class:`~.context.WAMPNodeContext` class that supplies the
    necessary informations about WAMP connection
    state. :meth:`node_register` should be called after the WAMP session
    has *joined* the Crossbar router.
    """

    node_registered = False
    """It's ``True`` if this mode's :meth:`node_register` has been called and
    that this node has successfully completed the registration process.
    """
    @signal
    def on_node_register(self, node, path, context, parent, points):
        """Signal emitted when the node's resources are registered.

        :param node: the bound node
        :type node: :class:`Node`
        :param path: the path where the node is bound, available also as
          `node.node_path`
        :type path: :class:`~.path.Path`
        :param context: the node_context of the node
        :type context: :class:`~.context.NodeContext`
        :param parent: this node's parent, if any
        :type parent: :class:`Node`
        :param points: a set containing the rpc points created by the
          registration
        """

    on_node_register = Signal()
    """Signal emitted when :meth:`node_register` is called. Its events have
    two keywords, ``node`` and ``context``.
    """

    on_node_registration_failure = Signal()
    """Signal emitted when registration fails. Its events have two keywords,
    ``node`` and ``context``.
    """

    on_node_registration_success = Signal()
    """Signal emitted when the registration is complete. Its events have two
    keywords, ``node`` and ``context``.
    """

    on_node_unregister = Signal()
    """Signal emitted when :meth:`node_unregister` is called. Its events have
    two keywords, ``node`` and ``context``.
    """

    async def _node_after_bind(self, path, context=None, parent=None):
        """Specialized to attach this node to the parent's
        :attr:`on_node_register` and :attr:`on_node_unbind` signals. It
        automatically calls :meth:`node_register`.
        """
        await super()._node_after_bind(path, context, parent)
        if parent is not None and isinstance(parent, WAMPNode):
            parent.on_node_register.connect(self._node_on_parent_register)
        await self.node_register()

    async def _node_on_parent_register(self, node, context):
        if self.node_context is None:
            self.node_context = context.new()
        await self.node_register()

    async def _node_unbind(self):
        """Specialized to call :meth:`node_unregister`."""
        await self.node_unregister()
        await super()._node_unbind()
        if self.node_registered:
            del self.node_registered

    def call(self, path, *args, **kwargs):
        """Call another rpc endpoint published via :term:`WAMP`.

        .. important::
          The ``disclose_me=True`` option (was the default in old
          ``raccoon.api`` framework) is now managed directly by
          crossbar in it's realm/role configuration.

        .. note::
          this isn't a coroutine but it returns one.
        """
        return self.__class__.manager.call(self, path, *args, **kwargs)

    @classmethod
    def node_deserialize(cls, value, endpoint_node):
        return endpoint_node.remote(value)

    async def node_register(self):
        """Register this node to the :term:`WAMP` session. It emits the
        `on_node_register` event."""
        if not self.node_registered and self.node_context is not None and \
           self.node_context.wamp_session is not None and \
           self.node_context.wamp_session.is_attached():
            await self.on_node_register.notify(node=self,
                                               context=self.node_context)

    @classmethod
    def node_serialize(cls, instance, srcpoint_node):
        if instance.node_path is None:
            raise serialize.SerializationError(
                "This instance cannot be serialized")
        return serialize.Serialized(str(instance.node_path))

    async def node_unregister(self):
        """Unregisters the node from the :term:`WAMP` session. It emits the
        `on_node_unregister` event."""
        if self.node_registered:
            await self.on_node_unregister.notify(node=self,
                                                 context=self.node_context)

    def remote(self, path):
        "Return a :class:`~.proxy.Proxy` instance on the given `path`."
        return Proxy(self, path)
예제 #26
0
def test_11_notify_wrapper(events):

    c = dict(called=0, wrap_args=None, handler_called=0, handler_args=None)

    asignal = Signal()

    @asignal.on_notify
    def asignal(subscribers, notify, *args, **kwargs):
        c['called'] += 1
        c['wrap_args'] = (args, kwargs)
        assert len(subscribers) == 1
        notify('foo', k=2)
        return 'foo'

    def handler(*args, **kwargs):
        c['handler_called'] += 1
        c['handler_args'] = (args, kwargs)

    asignal.connect(handler)
    res = asignal.notify('bar', k=1)

    assert res == 'foo'
    assert c['called'] == 1
    assert c['wrap_args'] == (('bar', ), {'k': 1})
    assert c['handler_called'] == 1
    assert c['handler_args'] == (('foo', ), {'k': 2})

    c = dict(called=0,
             wrap_args=None,
             handler_called=0,
             handler_args=None,
             handler2_called=0,
             handler2_args=None)

    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()

        @click.on_notify
        def click(self, subscribers, notify, *args, **kwargs):
            c['called'] += 1
            c['wrap_args'] = (args, kwargs)
            assert len(subscribers) == 2
            assert isinstance(self, A)
            notify('foo', k=2)
            return 'foo'

        @handler('click')
        def handler(self, *args, **kwargs):
            c['handler_called'] += 1
            c['handler_args'] = (args, kwargs)

    a = A()

    def handler2(*args, **kwargs):
        c['handler2_called'] += 1
        c['handler2_args'] = (args, kwargs)

    a.click.connect(handler2)
    res = a.click.notify('bar', k=1)
    assert res == 'foo'
    assert c['called'] == 1
    assert c['wrap_args'] == (('bar', ), {'k': 1})
    assert c['handler_called'] == 1
    assert c['handler_args'] == (('foo', ), {'k': 2})
    assert c['handler2_called'] == 1
    assert c['handler2_args'] == (('foo', ), {'k': 2})
예제 #27
0
class ApplicationService(BaseService):
    """
    A service that publishes an API for the creation of long-running contexes.

    Each time a long-running session starts, it executes the supplied
    factory with a tailored context.

    :param factory: a class or method to execute per-session
    :param node_path: Path of the service :term:`WAMP` path
    :type node_path: an instance of :class:`~metapensiero.raccoon.node.path.Path`
    :param context: An optional parent context
    :type context: An instance of
      :class:`~metapensiero.raccoon.node.context.WAMPContext`
    :results: a dictionary containing initial session info.
    """

    SESSION_CLASS = SessionRoot
    """The type of the session to instantiate when `~.create_session` is
    called."""

    location_name = system.name

    on_session_stopped = Signal()
    """The `~metapensiero.signal.atom.Signal` that is fired each time a session is
    reached a ``stopped`` state."""

    def __init__(self, factory, node_path, node_context=None):
        super().__init__(node_path, node_context=node_context)
        self._next_session_num = 1
        self._sessions = {}
        self._factory = factory

    def _next_session_id(self):
        res = self._next_session_num
        self._next_session_num += 1
        return str(res)

    async def _create_session(self, session_id, from_location,
                              client_details=None):
        session_ctx = self.node_context.new(service=self,
                                            session_id=session_id)
        session_ctx.session_id = session_id
        session_path = Path(self.node_path + session_id)
        session_path.base = session_path
        sess = self.SESSION_CLASS(locations=[from_location, self.location_name],
                                  local_location_name=self.location_name,
                                  local_member_factory=self._factory,
                                  client_details=client_details)
        await sess.node_bind(session_path, session_ctx, self)
        return sess

    @call
    async def start_session(self, from_location, session_id=None,
                            details=None):
        """The entrypoint for this service. This should be called by the client to
        start a session that will establish and orchestrate further
        communication.
        """
        if (session_id and session_id not in self._sessions) or \
           not session_id:
            session_id = self._next_session_id()
            session_root = sr = await self._create_session(session_id,
                                                           from_location,
                                                           details)
            self._sessions[session_id] = session_root
        else:
            session_root = sr = self._sessions[session_id]
        return {
            'location': from_location,
            'base': str(sr.node_path),
            'id': sr.node_context.session_id
        }

    @handler('on_session_stopped')
    def _remove_session(self, session):
        del self._sessions[session.node_name]
예제 #28
0
class BaseService(ContextNode):
    """A simple class tailored to the needs of setting up some tree of
    endpoints immediately available as soon as the wamp connection is
    established.
    """

    on_start = Signal()
    """Signal emitted when the service starts. This happens when the
    connection has successfully joined the realm and the
    ``session.is_attached()`` is ``True`` rather than a simple TCP
    connection.
    """

    @on_start.on_connect
    async def on_start(self, handler, subscribers, connect):
        """Call handler immediately if the service is started already"""
        if self.started:
            await connect.notify(handler, self.node_path, self.node_context)
        connect(handler)

    def __init__(self, node_path, node_context=None):
        """
        :param node_path: Path of the service :term:`WAMP` path
        :type node_path: an instance of :class:`~metapensiero.raccoon.node.path.Path`
        :param node_context: An optional parent context
        :type node_context: An instance of
          :class:`~metapensiero.raccoon.node.context.WAMPContext`
        """
        super().__init__()
        self._connection = None
        self._tmp_path = node_path
        if node_context:
            context = node_context.new()
        else:
            context = WAMPNodeContext()
        context.chain(system.node_context)
        self._tmp_context = context
        self.started = False

    @property
    def connection(self):
        """
        :param connection: The associated connection
        :type connection: A :class:`~.wamp.connection.Connection`
        """
        return self._connection

    async def set_connection(self, connection):
        """Set the wamp connection."""
        self._connection = connection
        self._tmp_context.loop = connection.loop
        await connection.on_connect.connect(self._on_connection_connected)

    async def _on_connection_connected(self, session, session_details,
                                       **kwargs):
        path, context = self._tmp_path, self._tmp_context
        del self._tmp_path, self._tmp_context
        context.wamp_session = session
        context.wamp_details = session_details
        await self.node_bind(path, context)
        await self.start_service(path, context)
        self.started = True
        await self.on_start.notify(local_path=self.node_path,
                                   local_context=self.node_context)

    async def start_service(self, path, context):
        """Start this service. Execute the :py:meth:`~.node.Node.bind` on the
        passed in arguments and register the instance on the
        :term:`WAMP` network Called by the default ``on_start`` signal
        handler.

        :param path: Dotted string or sequence of the :term:`WAMP`  path.
        :param context: The execution context.
        :type context: A :py:class:`.context.GlobalContext`

        """
        logger.debug("Service at %r started", self.node_path)
예제 #29
0
class ServiceNode(metaclass=SignalAndHandlerInitMeta):
    """Base node for all the service stuff."""

    node_location = None
    """The location record."""

    on_node_primary_signal = Signal()
    """Signal used to receive *infrastructure* messages. The messages that
    implement the pairing protocol are of type 'pairing_request', 'peer_ready'
    and 'peer_start'.
    """

    on_node_primary_signal.name = '.'

    def _node_children(self):
        return {k: v for k, v in self.__dict__.items()
                if k != 'node_parent' and isinstance(v, node.Node)}

    def _node_remove_child(self, child):
        name = super()._node_remove_child(child)
        self.__delitem__(name)
        return name

    async def _node_unbind(self):
        from . import system
        await super()._node_unbind()
        system.unregister_node(self)

    async def _node_bind(self, path, context=None, parent=None):
        from . import system
        await super()._node_bind(path, context, parent)
        self.node_location = system.register_node(self)

    async def node_add(self, name, value):
        await super().node_add(name, value)
        self.__setitem__(name, value)

    def node_changed(self):
        self.node_location.changed()

    def node_depend(self):
        self.node_location.depend()

    def node_info(self):
        from . import system
        return {
            'uri': str(self.node_path),
            'type': self.__class__.__name__,
            'system': system.node_info()
        }

    async def node_remove(self, name):
        self.__delitem__(name)
        await super().node_remove(name)

    def node_resolve(self, uri):
        """Resolve a path to a Node.

        :param str uri: the uri to resolve.
        :returns: A `metapensiero.raccoon.node.node.Node` or ``None`` if the
          operation fails.

        """
        if isinstance(uri, node.Node):
            return uri
        from . import system
        if isinstance(uri, node.Path):
            uri = str(uri)
        else:
            uri = str(self.node_path.resolve(uri, self.node_context))
        return system.resolve(uri)
예제 #30
0
    class A(metaclass=SignalAndHandlerInitMeta):

        click = Signal()