deb-python-autobahn/autobahn/wamp/types.py

572 lines
20 KiB
Python

###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Tavendo GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################
from __future__ import absolute_import
import six
__all__ = (
'ComponentConfig',
'HelloReturn',
'Accept',
'Deny',
'Challenge',
'HelloDetails',
'SessionDetails',
'CloseDetails',
'SubscribeOptions',
'EventDetails',
'PublishOptions',
'RegisterOptions',
'CallDetails',
'CallOptions',
'CallResult',
)
class ComponentConfig(object):
"""
WAMP application component configuration. An instance of this class is
provided to the constructor of :class:`autobahn.wamp.protocol.ApplicationSession`.
"""
def __init__(self, realm=None, extra=None):
"""
:param realm: The realm the session should join.
:type realm: unicode
:param extra: Optional user-supplied object with extra
configuration. This can be any object you like, and is
accessible in your `ApplicationSession` subclass via
`self.config.extra`. `dict` is a good default choice.
"""
if six.PY2 and type(realm) == str:
realm = six.u(realm)
self.realm = realm
self.extra = extra
def __str__(self):
return "ComponentConfig(realm = {0}, extra = {1})".format(self.realm, self.extra)
class HelloReturn(object):
"""
Base class for ``HELLO`` return information.
"""
class Accept(HelloReturn):
"""
Information to accept a ``HELLO``.
"""
def __init__(self, authid=None, authrole=None, authmethod=None, authprovider=None):
"""
:param authid: The authentication ID the client is assigned, e.g. ``"joe"`` or ``"joe@example.com"``.
:type authid: unicode
:param authrole: The authentication role the client is assigned, e.g. ``"anonymous"``, ``"user"`` or ``"com.myapp.user"``.
:type authrole: unicode
:param authmethod: The authentication method that was used to authenticate the client, e.g. ``"cookie"`` or ``"wampcra"``.
:type authmethod: unicode
:param authprovider: The authentication provider that was used to authenticate the client, e.g. ``"mozilla-persona"``.
:type authprovider: unicode
"""
if six.PY2:
if type(authid) == str:
authid = six.u(authid)
if type(authrole) == str:
authrole = six.u(authrole)
if type(authmethod) == str:
authmethod = six.u(authmethod)
if type(authprovider) == str:
authprovider = six.u(authprovider)
assert(authid is None or type(authid) == six.text_type)
assert(authrole is None or type(authrole) == six.text_type)
assert(authmethod is None or type(authmethod) == six.text_type)
assert(authprovider is None or type(authprovider) == six.text_type)
self.authid = authid
self.authrole = authrole
self.authmethod = authmethod
self.authprovider = authprovider
def __str__(self):
return "Accept(authid = {0}, authrole = {1}, authmethod = {2}, authprovider = {3})".format(self.authid, self.authrole, self.authmethod, self.authprovider)
class Deny(HelloReturn):
"""
Information to deny a ``HELLO``.
"""
def __init__(self, reason=u"wamp.error.not_authorized", message=None):
"""
:param reason: The reason of denying the authentication (an URI, e.g. ``wamp.error.not_authorized``)
:type reason: unicode
:param message: A human readable message (for logging purposes).
:type message: unicode
"""
if six.PY2:
if type(reason) == str:
reason = six.u(reason)
if type(message) == str:
message = six.u(message)
assert(type(reason) == six.text_type)
assert(message is None or type(message) == six.text_type)
self.reason = reason
self.message = message
def __str__(self):
return "Deny(reason = {0}, message = '{1}')".format(self.reason, self.message)
class Challenge(HelloReturn):
"""
Information to challenge the client upon ``HELLO``.
"""
def __init__(self, method, extra=None):
"""
:param method: The authentication method for the challenge (e.g. ``"wampcra"``).
:type method: unicode
:param extra: Any extra information for the authentication challenge. This is
specific to the authentication method.
:type extra: dict
"""
if six.PY2:
if type(method) == str:
method = six.u(method)
self.method = method
self.extra = extra or {}
def __str__(self):
return "Challenge(method = {0}, extra = {1})".format(self.method, self.extra)
class HelloDetails(object):
"""
Provides details of a WAMP session while still attaching.
"""
def __init__(self, roles=None, authmethods=None, authid=None, pending_session=None):
"""
:param roles: The WAMP roles and features supported by the attaching client.
:type roles: dict
:param authmethods: The authentication methods the client is willing to perform.
:type authmethods: list
:param authid: The authentication ID the client wants to authenticate as. Required for WAMP-CRA.
:type authid: str
:param pending_session: The session ID the session will get once successfully attached.
:type pending_session: int
"""
self.roles = roles
self.authmethods = authmethods
self.authid = authid
self.pending_session = pending_session
def __str__(self):
return "HelloDetails(roles = {0}, authmethods = {1}, authid = {2}, pending_session = {3})".format(self.roles, self.authmethods, self.authid, self.pending_session)
class SessionDetails(object):
"""
Provides details for a WAMP session upon open.
.. seealso:: :func:`autobahn.wamp.interfaces.ISession.onJoin`
"""
def __init__(self, realm, session, authid=None, authrole=None, authmethod=None, authprovider=None):
"""
Ctor.
:param realm: The realm this WAMP session is attached to.
:type realm: unicode
:param session: WAMP session ID of this session.
:type session: int
"""
self.realm = realm
self.session = session
self.authid = authid
self.authrole = authrole
self.authmethod = authmethod
self.authprovider = authprovider
def __str__(self):
return "SessionDetails(realm = {0}, session = {1}, authid = {2}, authrole = {3}, authmethod = {4})".format(self.realm, self.session, self.authid, self.authrole, self.authmethod)
class CloseDetails(object):
"""
Provides details for a WAMP session upon open.
.. seealso:: :func:`autobahn.wamp.interfaces.ISession.onLeave`
"""
REASON_DEFAULT = u"wamp.close.normal"
REASON_TRANSPORT_LOST = u"wamp.close.transport_lost"
def __init__(self, reason=None, message=None):
"""
:param reason: The close reason (an URI, e.g. ``wamp.close.normal``)
:type reason: unicode
:param message: Closing log message.
:type message: unicode
"""
self.reason = reason
self.message = message
def __str__(self):
return "CloseDetails(reason = {0}, message = '{1}'')".format(self.reason, self.message)
class SubscribeOptions(object):
"""
Used to provide options for subscribing in
:func:`autobahn.wamp.interfaces.ISubscriber.subscribe`.
"""
def __init__(self, match=None, details_arg=None):
"""
:param match: The topic matching method to be used for the subscription.
:type match: unicode
:param details_arg: When invoking the handler, provide event details
in this keyword argument to the callable.
:type details_arg: str
"""
assert(match is None or (type(match) == six.text_type and match in [u'exact', u'prefix', u'wildcard']))
assert(details_arg is None or type(details_arg) == str)
self.match = match
self.details_arg = details_arg
def message_attr(self):
# options dict as sent within WAMP message
return {
'match': self.match
}
def __str__(self):
return "SubscribeOptions(match = {0}, details_arg = {1})".format(self.match, self.details_arg)
class EventDetails(object):
"""
Provides details on an event when calling an event handler
previously registered.
"""
def __init__(self, publication, publisher=None, topic=None):
"""
Ctor.
:param publication: The publication ID of the event (always present).
:type publication: int
:param publisher: The WAMP session ID of the original publisher of this event.
:type publisher: int
:param topic: For pattern-based subscriptions, the actual topic URI being published to.
:type topic1: unicode or None
"""
self.publication = publication
self.publisher = publisher
self.topic = topic
def __str__(self):
return "EventDetails(publication = {0}, publisher = {1}, topic = {2})".format(self.publication, self.publisher, self.topic)
class PublishOptions(object):
"""
Used to provide options for subscribing in
:func:`autobahn.wamp.interfaces.IPublisher.publish`.
"""
def __init__(self,
acknowledge=None,
exclude_me=None,
exclude=None,
eligible=None,
disclose_me=None):
"""
:param acknowledge: If ``True``, acknowledge the publication with a success or
error response.
:type acknowledge: bool
:param exclude_me: If ``True``, exclude the publisher from receiving the event, even
if he is subscribed (and eligible).
:type exclude_me: bool
:param exclude: List of WAMP session IDs to exclude from receiving this event.
:type exclude: list of int
:param eligible: List of WAMP session IDs eligible to receive this event.
:type eligible: list of int
:param disclose_me: If ``True``, request to disclose the publisher of this event
to subscribers.
:type disclose_me: bool
"""
# filter out None entries from exclude list, so it's easier for callers
if type(exclude) == list:
exclude = [x for x in exclude if x is not None]
assert(acknowledge is None or type(acknowledge) == bool)
assert(exclude_me is None or type(exclude_me) == bool)
assert(exclude is None or (type(exclude) == list and all(type(x) in six.integer_types for x in exclude)))
assert(eligible is None or (type(eligible) == list and all(type(x) in six.integer_types for x in eligible)))
assert(disclose_me is None or type(disclose_me) == bool)
self.acknowledge = acknowledge
self.exclude_me = exclude_me
self.exclude = exclude
self.eligible = eligible
self.disclose_me = disclose_me
def message_attr(self):
# options dict as sent within WAMP message
return {
u'acknowledge': self.acknowledge,
u'exclude_me': self.exclude_me,
u'exclude': self.exclude,
u'eligible': self.eligible,
u'disclose_me': self.disclose_me
}
def __str__(self):
return "PublishOptions(acknowledge = {0}, exclude_me = {1}, exclude = {2}, eligible = {3}, disclose_me = {4})".format(self.acknowledge, self.exclude_me, self.exclude, self.eligible, self.disclose_me)
class RegisterOptions(object):
"""
Used to provide options for registering in
:func:`autobahn.wamp.interfaces.ICallee.register`.
"""
def __init__(self, match=None, invoke=None, details_arg=None):
"""
:param details_arg: When invoking the endpoint, provide call details
in this keyword argument to the callable.
:type details_arg: str
"""
assert(match is None or (type(match) == six.text_type and match in [u'exact', u'prefix', u'wildcard']))
assert(invoke is None or (type(invoke) == six.text_type and invoke in [u'single', u'first', u'last', u'roundrobin', u'random']))
assert(details_arg is None or type(details_arg) == str)
self.match = match
self.invoke = invoke
self.details_arg = details_arg
def message_attr(self):
# options dict as sent within WAMP message
return {
u'match': self.match,
u'invoke': self.invoke
}
def __str__(self):
return "RegisterOptions(match = {0}, invoke = {1}, details_arg = {2})".format(self.match, self.invoke, self.details_arg)
class CallDetails(object):
"""
Provides details on a call when an endpoint previously
registered is being called and opted to receive call details.
"""
def __init__(self, progress=None, caller=None, procedure=None):
"""
Ctor.
:param progress: A callable that will receive progressive call results.
:type progress: callable
:param caller: The WAMP session ID of the caller, if the latter is disclosed.
:type caller: int
:param procedure: For pattern-based registrations, the actual procedure URI being called.
:type procedure: unicode or None
"""
self.progress = progress
self.caller = caller
self.procedure = procedure
def __str__(self):
return "CallDetails(progress = {0}, caller = {1}, procedure = {2})".format(self.progress, self.caller, self.procedure)
class CallOptions(object):
"""
Used to provide options for calling with :func:`autobahn.wamp.interfaces.ICaller.call`.
"""
def __init__(self,
on_progress=None,
timeout=None,
disclose_me=None):
"""
:param on_progress: A callback that will be called when the remote endpoint
called yields interim call progress results.
:type on_progress: callable
:param timeout: Time in seconds after which the call should be automatically canceled.
:type timeout: float
:param disclose_me: Request to disclose the identity of the caller (it's WAMP session ID)
to Callees. Note that a Dealer, depending on Dealer configuration, might
reject the request, or might disclose the Callee's identity without
a request to do so.
:type disclose_me: bool
"""
assert(on_progress is None or callable(on_progress))
assert(timeout is None or (type(timeout) in list(six.integer_types) + [float] and timeout > 0))
assert(disclose_me is None or type(disclose_me) == bool)
self.on_progress = on_progress
self.timeout = timeout
self.disclose_me = disclose_me
def message_attr(self):
# options dict as sent within WAMP message
res = {
u'timeout': self.timeout,
u'disclose_me': self.disclose_me
}
if self.on_progress:
res['receive_progress'] = True
return res
def __str__(self):
return "CallOptions(on_progress = {0}, timeout = {1}, disclose_me = {2})".format(self.on_progress, self.timeout, self.disclose_me)
class CallResult(object):
"""
Wrapper for remote procedure call results that contain multiple positional
return values or keyword return values.
"""
def __init__(self, *results, **kwresults):
"""
Constructor.
:param results: The positional result values.
:type results: list
:param kwresults: The keyword result values.
:type kwresults: dict
"""
self.results = results
self.kwresults = kwresults
def __str__(self):
return "CallResult(results = {0}, kwresults = {1})".format(self.results, self.kwresults)
class IPublication(object):
"""
Represents a publication of an event. This is used with acknowledged publications.
"""
def id(self):
"""
The WAMP publication ID for this publication.
"""
class ISubscription(object):
"""
Represents a subscription to a topic.
"""
def id(self):
"""
The WAMP subscription ID for this subscription.
"""
def active(self):
"""
Flag indicating if subscription is active.
"""
def unsubscribe(self):
"""
Unsubscribe this subscription that was previously created from
:func:`autobahn.wamp.interfaces.ISubscriber.subscribe`.
After a subscription has been unsubscribed successfully, no events
will be routed to the event handler anymore.
Returns an instance of :tx:`twisted.internet.defer.Deferred` (when
running on **Twisted**) or an instance of :py:class:`asyncio.Future`
(when running on **asyncio**).
- If the unsubscription succeeds, the returned Deferred/Future will
*resolve* (with no return value).
- If the unsubscription fails, the returned Deferred/Future will *reject*
with an instance of :class:`autobahn.wamp.exception.ApplicationError`.
:returns: A Deferred/Future for the unsubscription
:rtype: instance(s) of :tx:`twisted.internet.defer.Deferred` / :py:class:`asyncio.Future`
"""
class IRegistration(object):
"""
Represents a registration of an endpoint.
"""
def id(self):
"""
The WAMP registration ID for this registration.
"""
def active(self):
"""
Flag indicating if registration is active.
"""
def unregister(self):
"""
Unregister this registration that was previously created from
:func:`autobahn.wamp.interfaces.ICallee.register`.
After a registration has been unregistered successfully, no calls
will be routed to the endpoint anymore.
Returns an instance of :tx:`twisted.internet.defer.Deferred` (when
running on **Twisted**) or an instance of :py:class:`asyncio.Future`
(when running on **asyncio**).
- If the unregistration succeeds, the returned Deferred/Future will
*resolve* (with no return value).
- If the unregistration fails, the returned Deferred/Future will be rejected
with an instance of :class:`autobahn.wamp.exception.ApplicationError`.
:returns: A Deferred/Future for the unregistration
:rtype: instance(s) of :tx:`twisted.internet.defer.Deferred` / :py:class:`asyncio.Future`
"""