diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..2d5cd0e --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,46 @@ +name: Build Docker +run-name: Build Docker Images +on: + push: + +jobs: + BuildImage: + runs-on: [ubuntu-latest, amd] + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Docker + run : | + apt-get install ca-certificates curl gnupg + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + apt-get update + apt-get install docker-ce-cli -y + - name: Build Docker image + run : | + echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin + echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" + tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + tag=${tag//\//-} + tag_num=${GITHUB_RUN_NUMBER} + echo "tag_num=$tag_num" + + if [[ "$tag" == "main" ]]; then + tag="latest" + else + tag_num="${tag}-${tag_num}" + fi + + repo=$GITHUB_REPOSITORY + repo=${repo#*/} + repo=$(echo $repo | tr '[:upper:]' '[:lower:]') + echo "container=$repo" + + + docker build -t $repo:$tag_num . + docker tag $repo:$tag_num git.woodburn.au/nathanwoodburn/$repo:$tag_num + docker push git.woodburn.au/nathanwoodburn/$repo:$tag_num + docker tag $repo:$tag_num git.woodburn.au/nathanwoodburn/$repo:$tag + docker push git.woodburn.au/nathanwoodburn/$repo:$tag \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2723ddd --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +__pycache__/ + +.env +.vs/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8bccc44 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder + +WORKDIR /app + +COPY requirements.txt /app +RUN --mount=type=cache,target=/root/.cache/pip \ + python3 -m pip install -r requirements.txt + +COPY . /app + +# Optionally mount /data to store the data +# VOLUME /data + +ENTRYPOINT ["python3"] +CMD ["main.py"] + +FROM builder as dev-envs \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..376fcd5 --- /dev/null +++ b/main.py @@ -0,0 +1,42 @@ +from flask import Flask +from server import app +import server +from gunicorn.app.base import BaseApplication +import os +import dotenv + + +class GunicornApp(BaseApplication): + def __init__(self, app, options=None): + self.options = options or {} + self.application = app + super().__init__() + + def load_config(self): + for key, value in self.options.items(): + if key in self.cfg.settings and value is not None: + self.cfg.set(key.lower(), value) + + def load(self): + return self.application + + + + +if __name__ == '__main__': + dotenv.load_dotenv() + + workers = os.getenv('WORKERS', 1) + threads = os.getenv('THREADS', 2) + workers = int(workers) + threads = int(threads) + + options = { + 'bind': '0.0.0.0:5000', + 'workers': workers, + 'threads': threads, + } + + gunicorn_app = GunicornApp(server.app, options) + print(f'Starting server with {workers} workers and {threads} threads', flush=True) + gunicorn_app.run() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8cf7fcb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +flask +gunicorn +requests +python-dotenv \ No newline at end of file diff --git a/server.py b/server.py new file mode 100644 index 0000000..240a1a8 --- /dev/null +++ b/server.py @@ -0,0 +1,114 @@ +from functools import cache +import json +from flask import ( + Flask, + make_response, + redirect, + request, + jsonify, + render_template, + send_from_directory, + send_file, +) +import os +import json +import requests +from datetime import datetime +import dotenv + +dotenv.load_dotenv() + +app = Flask(__name__) + + +def find(name, path): + for root, dirs, files in os.walk(path): + if name in files: + return os.path.join(root, name) + +# Assets routes +@app.route("/assets/") +def send_assets(path): + if path.endswith(".json"): + return send_from_directory( + "templates/assets", path, mimetype="application/json" + ) + + if os.path.isfile("templates/assets/" + path): + return send_from_directory("templates/assets", path) + + # Try looking in one of the directories + filename: str = path.split("/")[-1] + if ( + filename.endswith(".png") + or filename.endswith(".jpg") + or filename.endswith(".jpeg") + or filename.endswith(".svg") + ): + if os.path.isfile("templates/assets/img/" + filename): + return send_from_directory("templates/assets/img", filename) + if os.path.isfile("templates/assets/img/favicon/" + filename): + return send_from_directory("templates/assets/img/favicon", filename) + + return render_template("404.html"), 404 + + +# region Special routes +@app.route("/favicon.png") +def faviconPNG(): + return send_from_directory("templates/assets/img", "favicon.png") + + +@app.route("/.well-known/") +def wellknown(path): + # Try to proxy to https://nathan.woodburn.au/.well-known/ + req = requests.get(f"https://nathan.woodburn.au/.well-known/{path}") + return make_response( + req.content, 200, {"Content-Type": req.headers["Content-Type"]} + ) + + +# endregion + + +# region Main routes +@app.route("/") +def index(): + return render_template("index.html") + + +@app.route("/") +def catch_all(path: str): + if os.path.isfile("templates/" + path): + return render_template(path) + + # Try with .html + if os.path.isfile("templates/" + path + ".html"): + return render_template(path + ".html") + + if os.path.isfile("templates/" + path.strip("/") + ".html"): + return render_template(path.strip("/") + ".html") + + # Try to find a file matching + if path.count("/") < 1: + # Try to find a file matching + filename = find(path, "templates") + if filename: + return send_file(filename) + + return render_template("404.html"), 404 + + +# endregion + + +# region Error Catching +# 404 catch all +@app.errorhandler(404) +def not_found(e): + return render_template("404.html"), 404 + + +# endregion +if __name__ == "__main__": + app.run(debug=True, port=5000, host="0.0.0.0") diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..acea536 --- /dev/null +++ b/templates/404.html @@ -0,0 +1,21 @@ + + + + + + + Nathan.Woodburn/ + + + + + +
+
+

404 | Page not found

+

Sorry, the page you are looking for does not exist.

+

Go back to the homepage

+
+ + + \ No newline at end of file diff --git a/templates/assets/css/404.css b/templates/assets/css/404.css new file mode 100644 index 0000000..9635f9c --- /dev/null +++ b/templates/assets/css/404.css @@ -0,0 +1,20 @@ +body { + background-color: #000000; + color: #ffffff; +} +h1 { + font-size: 50px; + margin: 0; + padding: 0; +} +.centre { + margin-top: 10%; + text-align: center; +} +a { + color: #ffffff; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/templates/assets/css/index.css b/templates/assets/css/index.css new file mode 100644 index 0000000..9635f9c --- /dev/null +++ b/templates/assets/css/index.css @@ -0,0 +1,20 @@ +body { + background-color: #000000; + color: #ffffff; +} +h1 { + font-size: 50px; + margin: 0; + padding: 0; +} +.centre { + margin-top: 10%; + text-align: center; +} +a { + color: #ffffff; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/templates/assets/img/favicon.png b/templates/assets/img/favicon.png new file mode 100644 index 0000000..b325464 Binary files /dev/null and b/templates/assets/img/favicon.png differ diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..bb349f8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,19 @@ + + + + + + + Nathan.Woodburn/ + + + + + +
+
+

Nathan.Woodburn/

+
+ + + \ No newline at end of file