Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

autobahn_endpoints.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. ###############################################################################
  2. #
  3. # The MIT License (MIT)
  4. #
  5. # Copyright (c) typedef int GmbH
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software"), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. ###############################################################################
  26. from zope.interface import implementer
  27. from twisted.plugin import IPlugin
  28. from twisted.internet.interfaces import IStreamServerEndpointStringParser, \
  29. IStreamServerEndpoint, \
  30. IStreamClientEndpoint
  31. try:
  32. from twisted.internet.interfaces import IStreamClientEndpointStringParserWithReactor
  33. _HAS_REACTOR_ARG = True
  34. except ImportError:
  35. _HAS_REACTOR_ARG = False
  36. from twisted.internet.interfaces import IStreamClientEndpointStringParser as \
  37. IStreamClientEndpointStringParserWithReactor
  38. from twisted.internet.endpoints import serverFromString, clientFromString
  39. from autobahn.twisted.websocket import WrappingWebSocketServerFactory, \
  40. WrappingWebSocketClientFactory
  41. def _parseOptions(options):
  42. opts = {}
  43. if 'url' not in options:
  44. raise Exception("URL needed")
  45. else:
  46. opts['url'] = options['url']
  47. if 'compression' in options:
  48. value = options['compression'].lower().strip()
  49. if value == 'true':
  50. opts['enableCompression'] = True
  51. elif value == 'false':
  52. opts['enableCompression'] = False
  53. else:
  54. raise Exception("invalid value '{0}' for compression".format(value))
  55. if 'autofrag' in options:
  56. try:
  57. value = int(options['autofrag'])
  58. except:
  59. raise Exception("invalid value '{0}' for autofrag".format(options['autofrag']))
  60. if value < 0:
  61. raise Exception("negative value '{0}' for autofrag".format(value))
  62. opts['autoFragmentSize'] = value
  63. if 'subprotocol' in options:
  64. value = options['subprotocol'].lower().strip()
  65. opts['subprotocol'] = value
  66. if 'debug' in options:
  67. value = options['debug'].lower().strip()
  68. if value == 'true':
  69. opts['debug'] = True
  70. elif value == 'false':
  71. opts['debug'] = False
  72. else:
  73. raise Exception("invalid value '{0}' for debug".format(value))
  74. return opts
  75. @implementer(IPlugin)
  76. @implementer(IStreamServerEndpointStringParser)
  77. class AutobahnServerParser(object):
  78. prefix = "autobahn"
  79. def parseStreamServer(self, reactor, description, **options):
  80. # The present endpoint plugin is intended to be used as in the
  81. # following for running a streaming protocol over WebSocket over
  82. # an underlying stream transport.
  83. #
  84. # endpoint = serverFromString(reactor,
  85. # "autobahn:tcp\:9000\:interface\=0.0.0.0:url=ws\://localhost\:9000:compress=false"
  86. #
  87. # This will result in `parseStreamServer` to be called will
  88. #
  89. # description == tcp:9000:interface=0.0.0.0
  90. #
  91. # and
  92. #
  93. # options == {'url': 'ws://localhost:9000', 'compress': 'false'}
  94. #
  95. # Essentially, we are using the `\:` escape to coerce the endpoint descriptor
  96. # of the underlying stream transport into one (first) positional argument.
  97. #
  98. # Note that the `\:` within "url" is another form of escaping!
  99. #
  100. opts = _parseOptions(options)
  101. endpoint = serverFromString(reactor, description)
  102. return AutobahnServerEndpoint(reactor, endpoint, opts)
  103. @implementer(IPlugin)
  104. @implementer(IStreamServerEndpoint)
  105. class AutobahnServerEndpoint(object):
  106. def __init__(self, reactor, endpoint, options):
  107. self._reactor = reactor
  108. self._endpoint = endpoint
  109. self._options = options
  110. def listen(self, protocolFactory):
  111. return self._endpoint.listen(WrappingWebSocketServerFactory(protocolFactory, reactor=self._reactor, **self._options))
  112. # note that for older Twisted before the WithReactor variant, we
  113. # import it under that name so we can share (most of) this
  114. # implementation...
  115. @implementer(IPlugin)
  116. @implementer(IStreamClientEndpointStringParserWithReactor)
  117. class AutobahnClientParser(object):
  118. prefix = "autobahn"
  119. def parseStreamClient(self, *args, **options):
  120. if _HAS_REACTOR_ARG:
  121. reactor = args[0]
  122. if len(args) != 2:
  123. raise RuntimeError("autobahn: client plugin takes exactly one positional argument")
  124. description = args[1]
  125. else:
  126. from twisted.internet import reactor
  127. if len(args) != 1:
  128. raise RuntimeError("autobahn: client plugin takes exactly one positional argument")
  129. description = args[0]
  130. opts = _parseOptions(options)
  131. endpoint = clientFromString(reactor, description)
  132. return AutobahnClientEndpoint(reactor, endpoint, opts)
  133. @implementer(IPlugin)
  134. @implementer(IStreamClientEndpoint)
  135. class AutobahnClientEndpoint(object):
  136. def __init__(self, reactor, endpoint, options):
  137. self._reactor = reactor
  138. self._endpoint = endpoint
  139. self._options = options
  140. def connect(self, protocolFactory):
  141. return self._endpoint.connect(WrappingWebSocketClientFactory(protocolFactory, reactor=self._reactor, **self._options))
  142. autobahnServerParser = AutobahnServerParser()
  143. autobahnClientParser = AutobahnClientParser()