572 lines
20 KiB
Python
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`
|
|
"""
|