diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5244cfe --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:alpine +ENV WORKERS=4 +RUN mkdir /app && adduser -D app +WORKDIR /app +COPY requirements.txt /app +RUN pip install -r requirements.txt +COPY app.py /app +USER app +ENTRYPOINT ["sh", "-c","exec gunicorn -w $WORKERS -b 0.0.0.0 app:app"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ab5e83 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# spaceapi + +Stupid implementation of [SpaceAPI](https://spaceapi.io/) for [Chaos-West TV](https://chaoswest.tv/). + +As we don't have a physical space, we look at the current Jitsi Lounge status, and use that as an indicator for the space being open or closed. + +## WTF. + +Could this have been a cronjob, writing some JSON file to disk? Yes. But we're paying for the whole CPU, so we're gonna use the whole CPU, damnit! diff --git a/src/app.py b/app.py similarity index 58% rename from src/app.py rename to app.py index 9bc93c1..f8e4928 100644 --- a/src/app.py +++ b/app.py @@ -1,11 +1,21 @@ +from functools import lru_cache import json +import time import urllib.request from flask import Flask, jsonify app = Flask(__name__) -def get_jitsi_status(): +@lru_cache(maxsize=1) +def get_jitsi_status(ttl_hash : int = 0) -> bool | None: + # ttl_hash is used to cache the result for a certain amount of time. + # This is done to rate-limit the outgoing requests to the jitsi server. + # Inspired by https://stackoverflow.com/a/55900800 + + # The jitsi server uses mod_census to provide a JSON representation of all + # currently active rooms. We can use this to check if the lounge is currently + # occupied. try: content = urllib.request.urlopen("https://talk.chaoswest.tv/room-census").read() census = json.loads(content) @@ -15,6 +25,12 @@ def get_jitsi_status(): print(e) return None + +def get_ttl_hash(seconds : int = 1) -> int: + # Generates a monotonically increasing "hash" as time progresses + return round(time.time() / seconds) + + @app.route("/spaceapi") def spaceapi(): result = { @@ -33,7 +49,7 @@ def spaceapi(): } } - status = get_jitsi_status() + status = get_jitsi_status(get_ttl_hash()) if status is not None: result["state"] = { diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 7708f3c..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3.8' - -services: - spaceapi: - image: spaceapi - build: - context: src - networks: - - ingress - - default - deploy: - labels: - - "shepherd.auto-update=true" - - "traefik.enable=true" - - "traefik.http.services.spaceapi.loadbalancer.server.port=5000" - - "traefik.http.routers.spaceapi.rule=Host(`api.montage2.de`)||Host(`api.chaoswest.tv`)" - - "traefik.http.routers.spaceapi.tls=true" - - "traefik.http.routers.spaceapi.tls.certresolver=default" - -networks: - ingress: - external: true - name: traefik - diff --git a/src/requirements.txt b/requirements.txt similarity index 59% rename from src/requirements.txt rename to requirements.txt index 5084a60..617a06a 100644 --- a/src/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Flask>=3.0.1 +gunicorn diff --git a/src/Dockerfile b/src/Dockerfile deleted file mode 100644 index bd244b1..0000000 --- a/src/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM python:alpine -RUN mkdir /app -WORKDIR /app -COPY . /app -RUN pip install -r requirements.txt -ENTRYPOINT ["flask", "--app", "app", "run", "--host=0.0.0.0"]