from threading import Lock import sqlalchemy as sa import werkzeug.exceptions from werkzeug import wsgi import ereuse_devicehub.config from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources.inventory import Inventory class PathDispatcher: NOT_FOUND = werkzeug.exceptions.NotFound() INV = Inventory def __init__(self, config_cls=ereuse_devicehub.config.DevicehubConfig) -> None: self.lock = Lock() self.instances = {} self.CONFIG = config_cls self.engine = sa.create_engine(self.CONFIG.SQLALCHEMY_DATABASE_URI) with self.lock: self.instantiate() if not self.instances: raise ValueError('There are no Devicehub instances! Please, execute `dh init-db`.') self.one_app = next(iter(self.instances.values())) def __call__(self, environ, start_response): if wsgi.get_path_info(environ).startswith('/users'): # Not nice solution but it works well for now # Return any app, as all apps can handle login return self.call(self.one_app, environ, start_response) inventory = wsgi.pop_path_info(environ) with self.lock: if inventory not in self.instances: self.instantiate() app = self.instances.get(inventory, self.NOT_FOUND) return self.call(app, environ, start_response) @staticmethod def call(app, environ, start_response): return app(environ, start_response) def instantiate(self): sel = sa.select([self.INV.id]).where(self.INV.id.notin_(self.instances.keys())) for row in self.engine.execute(sel): self.instances[row.id] = Devicehub(inventory=row.id)