diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..502dadd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,31 @@ +# Exclude everything +** + +# Project file +!pyproject.toml +!LICENSE + +# Migrations +!src/migrations/*.py +!src/migrations/versions +!src/alembic.ini + +# Python application +!src/traffcap/config +!src/traffcap/core +!src/traffcap/dto +!src/traffcap/model +!src/traffcap/repositories +!src/traffcap/routes +!src/traffcap/templates +!src/traffcap/*.py + +# SPA +!src/traffcap/spa/public +!src/traffcap/spa +!src/traffcap/spa/.npmrc +!src/traffcap/spa/index.html +!src/traffcap/spa/package.json +!src/traffcap/spa/postcss.config.cjs +!src/traffcap/spa/quasar.config.js +!src/traffcap/spa/tsconfig.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1cb39f5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM python:3.8.18-alpine AS base_image + +ENV PATH=/root/.local/bin:$PATH \ + TRAFFCAP_REQUESTS_PREFIX="r" \ + TRAFFCAP_DB_USER="" \ + TRAFFCAP_DB_PASSWORD="" \ + TRAFFCAP_DB_HOST="" \ + TRAFFCAP_DB_NAME="/data/traffcap.db" \ + TRAFFCAP_DB_DRIVER="sqlite" \ + TRAFFCAP_SERVER_URL="localhost:9669" \ + PYTHONPATH="src/traffcap" + +EXPOSE 9669 + +RUN apk --no-cache add curl nodejs npm && \ + mkdir /traffcap && \ + mkdir /data + +COPY . /traffcap + +WORKDIR /traffcap + +# Install Python dependencies +RUN curl -sSL https://pdm.fming.dev/install-pdm.py | python3 - && \ + pdm install --production + +# Build frontend +RUN cd src/traffcap/spa && \ + npm install && \ + npm run build + +WORKDIR /traffcap/src + +VOLUME /data + +CMD pdm run server diff --git a/pyproject.toml b/pyproject.toml index 68b8488..714a3dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,8 +19,10 @@ test = "pytest src" cover = "pytest --cov=src --cov-report term" cover_html = "pytest --cov=src --cov-report html" type_check = "mypy src" -server.cmd = "gunicorn traffcap.server:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:9669" +server.cmd = "gunicorn traffcap.server:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --preload --bind 0.0.0.0:9669" server.env = { "PYTHONPATH" = "src" } +docker_build = "docker build --no-cache --tag traffcap --progress plain ." +docker_shell = "docker run --entrypoint /bin/sh -p 9669:9669 -it traffcap" [tool.ruff] line-length=119 @@ -49,8 +51,8 @@ dependencies = [ "dpath>=2.1.6", ] requires-python = ">=3.8,<3.9" -readme = "README.md" -license = {text = "MIT"} +# readme = "README.md" +license = {file = "LICENSE"} [project.scripts] traffcap = "traffcap.server:cli" diff --git a/src/alembic.ini b/src/alembic.ini index 2d026a1..dc37095 100644 --- a/src/alembic.ini +++ b/src/alembic.ini @@ -2,7 +2,7 @@ # Seems like we can't get away with having no alembic.ini # So we set some variables here and then define the connection string # in our env.py -script_location = migrations +script_location = src/migrations prepend_sys_path = . version_path_separator = os diff --git a/src/traffcap/config/settings.py b/src/traffcap/config/settings.py index 00d0bd2..303f03a 100644 --- a/src/traffcap/config/settings.py +++ b/src/traffcap/config/settings.py @@ -9,6 +9,11 @@ class Settings(BaseSettings): server_url: str = "" websocket_protocol: str = "ws" http_protocol: str = "http" + db_user: str = "" + db_password: str = "" + db_host: str = "" + db_name: str = "" + db_driver: str = "" class Config: env_prefix: str = "traffcap_" diff --git a/src/traffcap/repositories/repository.py b/src/traffcap/repositories/repository.py index 6f043c5..768b0c7 100644 --- a/src/traffcap/repositories/repository.py +++ b/src/traffcap/repositories/repository.py @@ -49,7 +49,7 @@ def create_connection(cls) -> None: @classmethod def migrate_up(cls) -> None: # Migrate up the database - config = Config("alembic.ini") + config = Config("src/alembic.ini") command.upgrade(config, "head") @classmethod diff --git a/src/traffcap/routes/traffic.py b/src/traffcap/routes/traffic.py index f6f986d..1266b14 100644 --- a/src/traffcap/routes/traffic.py +++ b/src/traffcap/routes/traffic.py @@ -30,8 +30,9 @@ async def traffic_firehose(websocket: WebSocket): inbound_requests = await InboundRequestRepository.get_all_inbound_requests() # Send more data - response = DANJAResourceList.from_basemodel_list(inbound_requests) - await websocket.send_text(response.model_dump_json()) + if len(inbound_requests) > 0: + response = DANJAResourceList.from_basemodel_list(inbound_requests) + await websocket.send_text(response.model_dump_json()) # Wait for an event from the message broker await wait_for_notification()