feat: Add initial code
All checks were successful
Build Docker / BuildImage (push) Successful in 1m2s
All checks were successful
Build Docker / BuildImage (push) Successful in 1m2s
This commit is contained in:
parent
e6eb62021e
commit
579539ccb8
46
.gitea/workflows/build.yml
Normal file
46
.gitea/workflows/build.yml
Normal file
@ -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
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
.env
|
||||||
|
.vs/
|
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@ -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
|
42
main.py
Normal file
42
main.py
Normal file
@ -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()
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
flask
|
||||||
|
gunicorn
|
||||||
|
requests
|
||||||
|
python-dotenv
|
114
server.py
Normal file
114
server.py
Normal file
@ -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/<path:path>")
|
||||||
|
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/<path:path>")
|
||||||
|
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("/<path:path>")
|
||||||
|
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")
|
21
templates/404.html
Normal file
21
templates/404.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Nathan.Woodburn/</title>
|
||||||
|
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
||||||
|
<link rel="stylesheet" href="/assets/css/404.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="centre">
|
||||||
|
<h1>404 | Page not found</h1>
|
||||||
|
<p>Sorry, the page you are looking for does not exist.</p>
|
||||||
|
<p><a href="/">Go back to the homepage</a></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
20
templates/assets/css/404.css
Normal file
20
templates/assets/css/404.css
Normal file
@ -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;
|
||||||
|
}
|
20
templates/assets/css/index.css
Normal file
20
templates/assets/css/index.css
Normal file
@ -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;
|
||||||
|
}
|
BIN
templates/assets/img/favicon.png
Normal file
BIN
templates/assets/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
19
templates/index.html
Normal file
19
templates/index.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Nathan.Woodburn/</title>
|
||||||
|
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
||||||
|
<link rel="stylesheet" href="/assets/css/index.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="centre">
|
||||||
|
<h1>Nathan.Woodburn/</h1>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user