Commit b7d419b8 authored by Sebastien Jourdain's avatar Sebastien Jourdain

Upgrade autobahn version to 0.8.9

Change-Id: I4f624490b3ca12977b74206f51ad20ba3f3fa2fc
parent 3814640a
Metadata-Version: 1.0
Name: autobahn
Version: 0.5.9
Version: 0.8.9
Summary: AutobahnPython - WebSocket/WAMP implementation for Python/Twisted.
Home-page: http://autobahn.ws/python
Author: Tavendo GmbH
......
###############################################################################
##
## Copyright 2011-2013 Tavendo GmbH
## Copyright (C) 2011-2014 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
......@@ -16,16 +16,5 @@
##
###############################################################################
from _version import __version__
__version__ = "0.8.9"
version = __version__ # backward compat.
import util
import useragent
import flashpolicy
import httpstatus
import utf8validator
import xormasker
import websocket
import resource
import prefixmap
import wamp
###############################################################################
##
## Copyright 2011-2013 Tavendo GmbH
## Copyright (C) 2013 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
......@@ -15,5 +15,3 @@
## limitations under the License.
##
###############################################################################
__version__ = "0.6.0"
###############################################################################
##
## Copyright (C) 2014 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
###############################################################################
from __future__ import absolute_import
__all__ = ['ApplicationSession',
'ApplicationSessionFactory',
'ApplicationRunner',
'RouterSession',
'RouterSessionFactory']
import sys
import asyncio
from asyncio.tasks import iscoroutine
from asyncio import Future
from autobahn.wamp import protocol
from autobahn.websocket.protocol import parseWsUrl
from autobahn.wamp.types import ComponentConfig
from autobahn.asyncio.websocket import WampWebSocketClientFactory
class FutureMixin:
"""
Mixin for Asyncio style Futures.
"""
def _create_future(self):
return Future()
def _as_future(self, fun, *args, **kwargs):
try:
res = fun(*args, **kwargs)
except Exception as e:
f = Future()
f.set_exception(e)
return f
else:
if isinstance(res, Future):
return res
elif iscoroutine(res):
return asyncio.Task(res)
else:
f = Future()
f.set_result(res)
return f
def _resolve_future(self, future, value):
future.set_result(value)
def _reject_future(self, future, value):
future.set_exception(value)
def _add_future_callbacks(self, future, callback, errback):
def done(f):
try:
res = f.result()
callback(res)
except Exception as e:
errback(e)
return future.add_done_callback(done)
def _gather_futures(self, futures, consume_exceptions = True):
return asyncio.gather(*futures, return_exceptions = consume_exceptions)
class ApplicationSession(FutureMixin, protocol.ApplicationSession):
"""
WAMP application session for asyncio-based applications.
"""
class ApplicationSessionFactory(FutureMixin, protocol.ApplicationSessionFactory):
"""
WAMP application session factory for asyncio-based applications.
"""
session = ApplicationSession
class RouterSession(FutureMixin, protocol.RouterSession):
"""
WAMP router session for asyncio-based applications.
"""
class RouterSessionFactory(FutureMixin, protocol.RouterSessionFactory):
"""
WAMP router session factory for asyncio-based applications.
"""
session = RouterSession
class ApplicationRunner:
"""
This class is a convenience tool mainly for development and quick hosting
of WAMP application components.
It can host a WAMP application component in a WAMP-over-WebSocket client
connecting to a WAMP router.
"""
def __init__(self, url, realm, extra = None,
debug = False, debug_wamp = False, debug_app = False):
"""
Constructor.
:param url: The WebSocket URL of the WAMP router to connect to (e.g. `ws://somehost.com:8090/somepath`)
:type url: str
:param realm: The WAMP realm to join the application session to.
:type realm: str
:param extra: Optional extra configuration to forward to the application component.
:type extra: dict
:param debug: Turn on low-level debugging.
:type debug: bool
:param debug_wamp: Turn on WAMP-level debugging.
:type debug_wamp: bool
:param debug_app: Turn on app-level debugging.
:type debug_app: bool
"""
self.url = url
self.realm = realm
self.extra = extra or dict()
self.debug = debug
self.debug_wamp = debug_wamp
self.debug_app = debug_app
self.make = None
def run(self, make):
"""
Run the application component.
:param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession`
when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`.
:type make: callable
"""
## 1) factory for use ApplicationSession
def create():
cfg = ComponentConfig(self.realm, self.extra)
try:
session = make(cfg)
except Exception:
## the app component could not be created .. fatal
print(traceback.format_exc())
asyncio.get_event_loop().stop()
session.debug_app = self.debug_app
return session
isSecure, host, port, resource, path, params = parseWsUrl(self.url)
## 2) create a WAMP-over-WebSocket transport client factory
transport_factory = WampWebSocketClientFactory(create, url = self.url,
debug = self.debug, debug_wamp = self.debug_wamp)
## 3) start the client
loop = asyncio.get_event_loop()
coro = loop.create_connection(transport_factory, host, port)
loop.run_until_complete(coro)
## 4) now enter the asyncio event loop
loop.run_forever()
loop.close()
###############################################################################
##
## Copyright (C) 2013 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
###############################################################################
__all__ = ['WebSocketServerProtocol',
'WebSocketServerFactory',
'WebSocketClientProtocol',
'WebSocketClientFactory']
from collections import deque
import asyncio
from asyncio.tasks import iscoroutine
from asyncio import Future
from autobahn.wamp import websocket
from autobahn.websocket import protocol
from autobahn.websocket import http
def yields(value):
"""
Return True iff the value yields.
See: http://stackoverflow.com/questions/20730248/maybedeferred-analog-with-asyncio
"""
return isinstance(value, Future) or iscoroutine(value)
class WebSocketAdapterProtocol(asyncio.Protocol):
"""
Adapter class for Asyncio WebSocket client and server protocols.
"""
def connection_made(self, transport):
self.transport = transport
self.receive_queue = deque()
self._consume()
peer = transport.get_extra_info('peername')
try:
self.peer = "%s:%d" % (peer[0], peer[1])
except:
## eg Unix Domain sockets don't have host/port
self.peer = str(peer)
self._connectionMade()
def connection_lost(self, exc):
self._connectionLost(exc)
self.transport = None
def _consume(self):
self.waiter = Future()
def process(_):
while len(self.receive_queue):
data = self.receive_queue.popleft()
if self.transport:
try:
self._dataReceived(data)
except Exception as e:
raise e
#print("WebSocketAdapterProtocol._consume: {}".format(e))
else:
print("WebSocketAdapterProtocol._consume: no transport")
self._consume()
self.waiter.add_done_callback(process)
def data_received(self, data):
self.receive_queue.append(data)
if not self.waiter.done():
self.waiter.set_result(None)
def _closeConnection(self, abort = False):
self.transport.close()
def _onOpen(self):
res = self.onOpen()
if yields(res):
asyncio.async(res)
def _onMessageBegin(self, isBinary):
res = self.onMessageBegin(isBinary)
if yields(res):
asyncio.async(res)
def _onMessageFrameBegin(self, length):
res = self.onMessageFrameBegin(length)
if yields(res):
asyncio.async(res)
def _onMessageFrameData(self, payload):
res = self.onMessageFrameData(payload)
if yields(res):
asyncio.async(res)
def _onMessageFrameEnd(self):
res = self.onMessageFrameEnd()
if yields(res):
asyncio.async(res)
def _onMessageFrame(self, payload):
res = self.onMessageFrame(payload)
if yields(res):
asyncio.async(res)
def _onMessageEnd(self):
res = self.onMessageEnd()
if yields(res):
asyncio.async(res)
def _onMessage(self, payload, isBinary):
res = self.onMessage(payload, isBinary)
if yields(res):
asyncio.async(res)
def _onPing(self, payload):
res = self.onPing(payload)
if yields(res):
asyncio.async(res)
def _onPong(self, payload):
res = self.onPong(payload)
if yields(res):
asyncio.async(res)
def _onClose(self, wasClean, code, reason):
res = self.onClose(wasClean, code, reason)
if yields(res):
asyncio.async(res)
def registerProducer(self, producer, streaming):
raise Exception("not implemented")
class WebSocketServerProtocol(WebSocketAdapterProtocol, protocol.WebSocketServerProtocol):
"""
Base class for Asyncio WebSocket server protocols.
"""
def _onConnect(self, request):
## onConnect() will return the selected subprotocol or None
## or a pair (protocol, headers) or raise an HttpException
##
try:
res = self.onConnect(request)
#if yields(res):
# res = yield from res
except http.HttpException as exc:
self.failHandshake(exc.reason, exc.code)
except Exception as exc:
self.failHandshake(http.INTERNAL_SERVER_ERROR[1], http.INTERNAL_SERVER_ERROR[0])
else:
self.succeedHandshake(res)
class WebSocketClientProtocol(WebSocketAdapterProtocol, protocol.WebSocketClientProtocol):
"""
Base class for Asyncio WebSocket client protocols.
"""
def _onConnect(self, response):
res = self.onConnect(response)
if yields(res):
asyncio.async(res)
class WebSocketAdapterFactory:
"""
Adapter class for Asyncio WebSocket client and server factories.
"""
def _log(self, msg):
print(msg)
def _callLater(self, delay, fun):
return self.loop.call_later(delay, fun)
def __call__(self):
proto = self.protocol()
proto.factory = self
return proto
class WebSocketServerFactory(WebSocketAdapterFactory, protocol.WebSocketServerFactory):
"""
Base class for Asyncio WebSocket server factories.
"""
def __init__(self, *args, **kwargs):
"""
In addition to all arguments to the constructor of
:class:`autobahn.websocket.protocol.WebSocketServerFactory`,
you can supply a `loop` keyword argument to specify the
Asyncio loop to be used.
"""
if 'loop' in kwargs:
if kwargs['loop']:
self.loop = kwargs['loop']
else:
self.loop = asyncio.get_event_loop()
del kwargs['loop']
else:
self.loop = asyncio.get_event_loop()
protocol.WebSocketServerFactory.__init__(self, *args, **kwargs)
class WebSocketClientFactory(WebSocketAdapterFactory, protocol.WebSocketClientFactory):
"""
Base class for Asyncio WebSocket client factories.
"""
def __init__(self, *args, **kwargs):
"""
In addition to all arguments to the constructor of
:class:`autobahn.websocket.protocol.WebSocketClientFactory`,
you can supply a `loop` keyword argument to specify the
Asyncio loop to be used.
"""
if 'loop' in kwargs:
if kwargs['loop']:
self.loop = kwargs['loop']
else:
self.loop = asyncio.get_event_loop()
del kwargs['loop']
else:
self.loop = asyncio.get_event_loop()
protocol.WebSocketClientFactory.__init__(self, *args, **kwargs)
class WampWebSocketServerProtocol(websocket.WampWebSocketServerProtocol, WebSocketServerProtocol):
pass
class WampWebSocketServerFactory(websocket.WampWebSocketServerFactory, WebSocketServerFactory):
protocol = WampWebSocketServerProtocol
def __init__(self, factory, *args, **kwargs):
if 'serializers' in kwargs:
serializers = kwargs['serializers']
del kwargs['serializers']
else:
serializers = None
if 'debug_wamp' in kwargs:
debug_wamp = kwargs['debug_wamp']
del kwargs['debug_wamp']
else:
debug_wamp = False
websocket.WampWebSocketServerFactory.__init__(self, factory, serializers, debug_wamp = debug_wamp)
kwargs['protocols'] = self._protocols
WebSocketServerFactory.__init__(self, *args, **kwargs)
class WampWebSocketClientProtocol(websocket.WampWebSocketClientProtocol, WebSocketClientProtocol):
pass
class WampWebSocketClientFactory(websocket.WampWebSocketClientFactory, WebSocketClientFactory):
protocol = WampWebSocketClientProtocol
def __init__(self, factory, *args, **kwargs):
if 'serializers' in kwargs:
serializers = kwargs['serializers']
del kwargs['serializers']
else:
serializers = None
if 'debug_wamp' in kwargs:
debug_wamp = kwargs['debug_wamp']
del kwargs['debug_wamp']
else:
debug_wamp = False
websocket.WampWebSocketClientFactory.__init__(self, factory, serializers, debug_wamp = debug_wamp)
kwargs['protocols'] = self._protocols
WebSocketClientFactory.__init__(self, *args, **kwargs)
This diff is collapsed.
###############################################################################
##
## Copyright (C) 2013 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
###############################################################################
###############################################################################
##
## Copyright (C) 2013 Tavendo GmbH
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
###############################################################################
__all__ = ['install_optimal_reactor','install_reactor']
def install_optimal_reactor():
"""
Try to install the optimal Twisted reactor for platform.
"""
import sys
if 'bsd' in sys.platform or sys.platform.startswith('darwin'):
try:
v = sys.version_info
if v[0] == 1 or (v[0] == 2 and v[1] < 6) or (v[0] == 2 and v[1] == 6 and v[2] < 5):
raise Exception("Python version too old (%s)" % sys.version)
from twisted.internet import kqreactor
kqreactor.install()
except Exception as e:
print("""
WARNING: Running on BSD or Darwin, but cannot use kqueue Twisted reactor.
=> %s
To use the kqueue Twisted reactor, you will need:
1. Python >= 2.6.5 or PyPy > 1.8
2. Twisted > 12.0
Note the use of >= and >.
Will let Twisted choose a default reactor (potential performance degradation).
""" % str(e))
pass
if sys.platform in ['win32']:
try:
from twisted.application.reactors import installReactor
installReactor("iocp")
except Exception as e:
print("""
WARNING: Running on Windows, but cannot use IOCP Twisted reactor.
=> %s
Will let Twisted choose a default reactor (potential performance degradation).
""" % str(e))
if sys.platform.startswith('linux'):
try:
from twisted.internet import epollreactor
epollreactor.install()
except Exception as e:
print("""
WARNING: Running on Linux, but cannot use Epoll Twisted reactor.
=> %s
Will let Twisted choose a default reactor (potential performance degradation).
""" % str(e))
def install_reactor(explicitReactor = None, verbose = False):
"""
Install Twisted reactor.
:param explicitReactor: If provided, install this reactor. Else, install optimal reactor.
:type explicitReactor: obj
:param verbose: If `True`, print what happens.
:type verbose: bool
"""
import sys
if explicitReactor:
## install explicitly given reactor
##
from twisted.application.reactors import installReactor
print("Trying to install explicitly specified Twisted reactor '%s'" % explicitReactor)
try:
installReactor(explicitReactor)
except Exception as e:
print("Could not install Twisted reactor %s%s" % (explicitReactor, ' ["%s"]' % e if verbose else ''))
sys.exit(1)
else:
## automatically choose optimal reactor