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.

routing.py 5.6KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import importlib
  2. from django.conf import settings
  3. from django.core.exceptions import ImproperlyConfigured
  4. from django.urls.exceptions import Resolver404
  5. from django.urls.resolvers import URLResolver
  6. """
  7. All Routing instances inside this file are also valid ASGI applications - with
  8. new Channels routing, whatever you end up with as the top level object is just
  9. served up as the "ASGI application".
  10. """
  11. def get_default_application():
  12. """
  13. Gets the default application, set in the ASGI_APPLICATION setting.
  14. """
  15. try:
  16. path, name = settings.ASGI_APPLICATION.rsplit(".", 1)
  17. except (ValueError, AttributeError):
  18. raise ImproperlyConfigured("Cannot find ASGI_APPLICATION setting.")
  19. try:
  20. module = importlib.import_module(path)
  21. except ImportError:
  22. raise ImproperlyConfigured("Cannot import ASGI_APPLICATION module %r" % path)
  23. try:
  24. value = getattr(module, name)
  25. except AttributeError:
  26. raise ImproperlyConfigured(
  27. "Cannot find %r in ASGI_APPLICATION module %s" % (name, path)
  28. )
  29. return value
  30. DEPRECATION_MSG = """
  31. Using ProtocolTypeRouter without an explicit "http" key is deprecated.
  32. Given that you have not passed the "http" you likely should use Django's
  33. get_asgi_application():
  34. from django.core.asgi import get_asgi_application
  35. application = ProtocolTypeRouter(
  36. "http": get_asgi_application()
  37. # Other protocols here.
  38. )
  39. """
  40. class ProtocolTypeRouter:
  41. """
  42. Takes a mapping of protocol type names to other Application instances,
  43. and dispatches to the right one based on protocol name (or raises an error)
  44. """
  45. def __init__(self, application_mapping):
  46. self.application_mapping = application_mapping
  47. async def __call__(self, scope, receive, send):
  48. if scope["type"] in self.application_mapping:
  49. application = self.application_mapping[scope["type"]]
  50. return await application(scope, receive, send)
  51. else:
  52. raise ValueError(
  53. "No application configured for scope type %r" % scope["type"]
  54. )
  55. class URLRouter:
  56. """
  57. Routes to different applications/consumers based on the URL path.
  58. Works with anything that has a ``path`` key, but intended for WebSocket
  59. and HTTP. Uses Django's django.urls objects for resolution -
  60. path() or re_path().
  61. """
  62. #: This router wants to do routing based on scope[path] or
  63. #: scope[path_remaining]. ``path()`` entries in URLRouter should not be
  64. #: treated as endpoints (ended with ``$``), but similar to ``include()``.
  65. _path_routing = True
  66. def __init__(self, routes):
  67. self.routes = routes
  68. for route in self.routes:
  69. # The inner ASGI app wants to do additional routing, route
  70. # must not be an endpoint
  71. if getattr(route.callback, "_path_routing", False) is True:
  72. route.pattern._is_endpoint = False
  73. if not route.callback and isinstance(route, URLResolver):
  74. raise ImproperlyConfigured(
  75. "%s: include() is not supported in URLRouter. Use nested"
  76. " URLRouter instances instead." % (route,)
  77. )
  78. async def __call__(self, scope, receive, send):
  79. # Get the path
  80. path = scope.get("path_remaining", scope.get("path", None))
  81. if path is None:
  82. raise ValueError("No 'path' key in connection scope, cannot route URLs")
  83. # Remove leading / to match Django's handling
  84. path = path.lstrip("/")
  85. # Run through the routes we have until one matches
  86. for route in self.routes:
  87. try:
  88. match = route.pattern.match(path)
  89. if match:
  90. new_path, args, kwargs = match
  91. # Add defaults to kwargs from the URL pattern.
  92. kwargs.update(route.default_args)
  93. # Add args or kwargs into the scope
  94. outer = scope.get("url_route", {})
  95. application = route.callback
  96. return await application(
  97. dict(
  98. scope,
  99. path_remaining=new_path,
  100. url_route={
  101. "args": outer.get("args", ()) + args,
  102. "kwargs": {**outer.get("kwargs", {}), **kwargs},
  103. },
  104. ),
  105. receive,
  106. send,
  107. )
  108. except Resolver404:
  109. pass
  110. else:
  111. if "path_remaining" in scope:
  112. raise Resolver404("No route found for path %r." % path)
  113. # We are the outermost URLRouter
  114. raise ValueError("No route found for path %r." % path)
  115. class ChannelNameRouter:
  116. """
  117. Maps to different applications based on a "channel" key in the scope
  118. (intended for the Channels worker mode)
  119. """
  120. def __init__(self, application_mapping):
  121. self.application_mapping = application_mapping
  122. async def __call__(self, scope, receive, send):
  123. if "channel" not in scope:
  124. raise ValueError(
  125. "ChannelNameRouter got a scope without a 'channel' key. "
  126. + "Did you make sure it's only being used for 'channel' type messages?"
  127. )
  128. if scope["channel"] in self.application_mapping:
  129. application = self.application_mapping[scope["channel"]]
  130. return await application(scope, receive, send)
  131. else:
  132. raise ValueError(
  133. "No application configured for channel name %r" % scope["channel"]
  134. )