Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • ec325a8
  • /
  • byceps
  • /
  • app_dispatcher.py
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge
swh:1:cnt:9dbd05e6c48d4890fd35011f28d6045ac1d760f9
directory badge
swh:1:dir:0cc25ae1c5c63c0c5307d6fc98bbfae6f96e3656

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
app_dispatcher.py
"""
byceps.app_dispatcher
~~~~~~~~~~~~~~~~~~~~~

Serve multiple apps together.

:Copyright: 2014-2025 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from threading import Lock
from wsgiref.types import WSGIApplication

from flask import Flask
import structlog
from werkzeug.exceptions import InternalServerError, NotFound

from byceps.application import create_admin_app, create_api_app, create_site_app
from byceps.config.models import (
    AdminAppConfig,
    ApiAppConfig,
    BycepsConfig,
    SiteAppConfig,
    WebAppConfig,
)
from byceps.config.util import iterate_app_configs

from byceps.util.result import Err, Ok, Result

from .byceps_app import BycepsApp


log = structlog.get_logger()


def create_dispatcher_app(byceps_config: BycepsConfig) -> Flask:
    app = Flask('dispatcher')
    app.wsgi_app = AppDispatcher(byceps_config)
    return app


class AppDispatcher:
    def __init__(self, byceps_config: BycepsConfig) -> None:
        self.lock = Lock()
        self.app_configs_by_host: dict[str, WebAppConfig] = {
            app_config.server_name: app_config
            for app_config in iterate_app_configs(byceps_config.apps)
        }
        self.byceps_config = byceps_config
        self.apps_by_host: dict[str, WSGIApplication] = {}

    def __call__(self, environ, start_response):
        app = self.get_application(environ['HTTP_HOST'])
        return app(environ, start_response)

    def get_application(self, host_and_port) -> WSGIApplication:
        host = host_and_port.split(':')[0]

        log_ctx = log.bind(host=host)

        with self.lock:
            app = self.apps_by_host.get(host)

            if app:
                return app

            app_config = self.app_configs_by_host.get(host)
            if not app_config:
                log_ctx.debug('No application configured for host')
                return NotFound()

            match _create_app(app_config, self.byceps_config):
                case Ok(app):
                    self.apps_by_host[host] = app
                    mode = app.byceps_app_mode
                    if mode.is_site():
                        log_ctx = log_ctx.bind(site_id=app_config.site_id)
                    log_ctx.info('Application mounted', mode=mode.name)
                    return app
                case Err(e):
                    log_ctx.error('Application creation failed', error=e)
                    return InternalServerError(e)
                case _:
                    error_message = 'Unknown error'
                    log_ctx.error(
                        'Application creation failed', error=error_message
                    )
                    return InternalServerError(error_message)


def _create_app(
    app_config: WebAppConfig, byceps_config: BycepsConfig
) -> Result[BycepsApp, str]:
    match app_config:
        case AdminAppConfig():
            return Ok(create_admin_app(byceps_config, app_config))
        case ApiAppConfig():
            return Ok(create_api_app(byceps_config, app_config))
        case SiteAppConfig():
            site_id = app_config.site_id
            if not site_id:
                return Err(f'Unknown site ID "{site_id}"')

            app = create_site_app(byceps_config, app_config)
            return Ok(app)
        case _:
            return Err('Unknown or unsupported app configuration type')

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API