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.

189 lines
7.2 KiB

4 years ago
  1. import asyncio
  2. import logging
  3. import socket
  4. import sys
  5. from argparse import ArgumentParser
  6. from collections import Iterable
  7. from importlib import import_module
  8. from . import (helpers, web_app, web_exceptions, web_fileresponse,
  9. web_middlewares, web_protocol, web_request, web_response,
  10. web_routedef, web_runner, web_server, web_urldispatcher, web_ws)
  11. from .log import access_logger
  12. from .web_app import * # noqa
  13. from .web_exceptions import * # noqa
  14. from .web_fileresponse import * # noqa
  15. from .web_middlewares import * # noqa
  16. from .web_protocol import * # noqa
  17. from .web_request import * # noqa
  18. from .web_response import * # noqa
  19. from .web_routedef import * # noqa
  20. from .web_runner import * # noqa
  21. from .web_runner import AppRunner, GracefulExit, SockSite, TCPSite, UnixSite
  22. from .web_server import * # noqa
  23. from .web_urldispatcher import * # noqa
  24. from .web_ws import * # noqa
  25. __all__ = (web_protocol.__all__ +
  26. web_app.__all__ +
  27. web_fileresponse.__all__ +
  28. web_request.__all__ +
  29. web_response.__all__ +
  30. web_routedef.__all__ +
  31. web_exceptions.__all__ +
  32. web_urldispatcher.__all__ +
  33. web_ws.__all__ +
  34. web_server.__all__ +
  35. web_runner.__all__ +
  36. web_middlewares.__all__ +
  37. ('run_app',))
  38. def run_app(app, *, host=None, port=None, path=None, sock=None,
  39. shutdown_timeout=60.0, ssl_context=None,
  40. print=print, backlog=128, access_log_class=helpers.AccessLogger,
  41. access_log_format=helpers.AccessLogger.LOG_FORMAT,
  42. access_log=access_logger, handle_signals=True,
  43. reuse_address=None, reuse_port=None):
  44. """Run an app locally"""
  45. loop = asyncio.get_event_loop()
  46. if asyncio.iscoroutine(app):
  47. app = loop.run_until_complete(app)
  48. runner = AppRunner(app, handle_signals=handle_signals,
  49. access_log_class=access_log_class,
  50. access_log_format=access_log_format,
  51. access_log=access_log)
  52. loop.run_until_complete(runner.setup())
  53. sites = []
  54. try:
  55. if host is not None:
  56. if isinstance(host, (str, bytes, bytearray, memoryview)):
  57. sites.append(TCPSite(runner, host, port,
  58. shutdown_timeout=shutdown_timeout,
  59. ssl_context=ssl_context,
  60. backlog=backlog,
  61. reuse_address=reuse_address,
  62. reuse_port=reuse_port))
  63. else:
  64. for h in host:
  65. sites.append(TCPSite(runner, h, port,
  66. shutdown_timeout=shutdown_timeout,
  67. ssl_context=ssl_context,
  68. backlog=backlog,
  69. reuse_address=reuse_address,
  70. reuse_port=reuse_port))
  71. elif path is None and sock is None or port is not None:
  72. sites.append(TCPSite(runner, port=port,
  73. shutdown_timeout=shutdown_timeout,
  74. ssl_context=ssl_context, backlog=backlog,
  75. reuse_address=reuse_address,
  76. reuse_port=reuse_port))
  77. if path is not None:
  78. if isinstance(path, (str, bytes, bytearray, memoryview)):
  79. sites.append(UnixSite(runner, path,
  80. shutdown_timeout=shutdown_timeout,
  81. ssl_context=ssl_context,
  82. backlog=backlog))
  83. else:
  84. for p in path:
  85. sites.append(UnixSite(runner, p,
  86. shutdown_timeout=shutdown_timeout,
  87. ssl_context=ssl_context,
  88. backlog=backlog))
  89. if sock is not None:
  90. if not isinstance(sock, Iterable):
  91. sites.append(SockSite(runner, sock,
  92. shutdown_timeout=shutdown_timeout,
  93. ssl_context=ssl_context,
  94. backlog=backlog))
  95. else:
  96. for s in sock:
  97. sites.append(SockSite(runner, s,
  98. shutdown_timeout=shutdown_timeout,
  99. ssl_context=ssl_context,
  100. backlog=backlog))
  101. for site in sites:
  102. loop.run_until_complete(site.start())
  103. try:
  104. if print: # pragma: no branch
  105. names = sorted(str(s.name) for s in runner.sites)
  106. print("======== Running on {} ========\n"
  107. "(Press CTRL+C to quit)".format(', '.join(names)))
  108. loop.run_forever()
  109. except (GracefulExit, KeyboardInterrupt): # pragma: no cover
  110. pass
  111. finally:
  112. loop.run_until_complete(runner.cleanup())
  113. if hasattr(loop, 'shutdown_asyncgens'):
  114. loop.run_until_complete(loop.shutdown_asyncgens())
  115. loop.close()
  116. def main(argv):
  117. arg_parser = ArgumentParser(
  118. description="aiohttp.web Application server",
  119. prog="aiohttp.web"
  120. )
  121. arg_parser.add_argument(
  122. "entry_func",
  123. help=("Callable returning the `aiohttp.web.Application` instance to "
  124. "run. Should be specified in the 'module:function' syntax."),
  125. metavar="entry-func"
  126. )
  127. arg_parser.add_argument(
  128. "-H", "--hostname",
  129. help="TCP/IP hostname to serve on (default: %(default)r)",
  130. default="localhost"
  131. )
  132. arg_parser.add_argument(
  133. "-P", "--port",
  134. help="TCP/IP port to serve on (default: %(default)r)",
  135. type=int,
  136. default="8080"
  137. )
  138. arg_parser.add_argument(
  139. "-U", "--path",
  140. help="Unix file system path to serve on. Specifying a path will cause "
  141. "hostname and port arguments to be ignored.",
  142. )
  143. args, extra_argv = arg_parser.parse_known_args(argv)
  144. # Import logic
  145. mod_str, _, func_str = args.entry_func.partition(":")
  146. if not func_str or not mod_str:
  147. arg_parser.error(
  148. "'entry-func' not in 'module:function' syntax"
  149. )
  150. if mod_str.startswith("."):
  151. arg_parser.error("relative module names not supported")
  152. try:
  153. module = import_module(mod_str)
  154. except ImportError as ex:
  155. arg_parser.error("unable to import %s: %s" % (mod_str, ex))
  156. try:
  157. func = getattr(module, func_str)
  158. except AttributeError:
  159. arg_parser.error("module %r has no attribute %r" % (mod_str, func_str))
  160. # Compatibility logic
  161. if args.path is not None and not hasattr(socket, 'AF_UNIX'):
  162. arg_parser.error("file system paths not supported by your operating"
  163. " environment")
  164. logging.basicConfig(level=logging.DEBUG)
  165. app = func(extra_argv)
  166. run_app(app, host=args.hostname, port=args.port, path=args.path)
  167. arg_parser.exit(message="Stopped\n")
  168. if __name__ == "__main__": # pragma: no branch
  169. main(sys.argv[1:]) # pragma: no cover