47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
|
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)
|