__init__.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. # This file is part of Radicale - CalDAV and CardDAV server
  2. # Copyright © 2008 Nicolas Kandel
  3. # Copyright © 2008 Pascal Halter
  4. # Copyright © 2008-2017 Guillaume Ayoub
  5. # Copyright © 2017-2019 Unrud <unrud@outlook.com>
  6. #
  7. # This library is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This library is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  19. """
  20. Entry point for external WSGI servers (like uWSGI or Gunicorn).
  21. Configuration files can be specified in the environment variable
  22. ``RADICALE_CONFIG``.
  23. """
  24. import os
  25. import threading
  26. from typing import Iterable, Optional, cast
  27. from radicale import config, log, types, utils
  28. from radicale.app import Application
  29. from radicale.log import logger
  30. VERSION: str = utils.package_version("radicale")
  31. _application_instance: Optional[Application] = None
  32. _application_config_path: Optional[str] = None
  33. _application_lock = threading.Lock()
  34. def _get_application_instance(config_path: str, wsgi_errors: types.ErrorStream
  35. ) -> Application:
  36. global _application_instance, _application_config_path
  37. with _application_lock:
  38. if _application_instance is None:
  39. log.setup()
  40. with log.register_stream(wsgi_errors):
  41. _application_config_path = config_path
  42. configuration = config.load(config.parse_compound_paths(
  43. config.DEFAULT_CONFIG_PATH,
  44. config_path))
  45. log.set_level(cast(str, configuration.get("logging", "level")))
  46. # Log configuration after logger is configured
  47. for source, miss in configuration.sources():
  48. logger.info("%s %s", "Skipped missing" if miss
  49. else "Loaded", source)
  50. _application_instance = Application(configuration)
  51. if _application_config_path != config_path:
  52. raise ValueError("RADICALE_CONFIG must not change: %r != %r" %
  53. (config_path, _application_config_path))
  54. return _application_instance
  55. def application(environ: types.WSGIEnviron,
  56. start_response: types.WSGIStartResponse) -> Iterable[bytes]:
  57. """Entry point for external WSGI servers."""
  58. config_path = environ.get("RADICALE_CONFIG",
  59. os.environ.get("RADICALE_CONFIG"))
  60. app = _get_application_instance(config_path, environ["wsgi.errors"])
  61. return app(environ, start_response)