diff --git a/.github/workflows/images.yml b/.github/workflows/images.yml new file mode 100644 index 000000000..2846562a9 --- /dev/null +++ b/.github/workflows/images.yml @@ -0,0 +1,70 @@ +# +name: Build & Publish Images + +# Configures this workflow to run every time a change is pushed to the branch called `release`. +on: + push: + branches: ['main'] + workflow_dispatch: + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ghcr.io/murraygroves/saferoute/frontend:latest + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ./saferoute + push: true + tags: ghcr.io/murraygroves/saferoute/frontend:latest + labels: ${{ steps.meta.outputs.labels }} + + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta-spring + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ghcr.io/spe-uob/saferoute/backend:dev + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ./backend + push: true + tags: ghcr.io/murraygroves/saferoute/backend:dev + labels: ${{ steps.meta-spring.outputs.labels }} + + # It doesn't really matter that this hook is exposed because all the server does is check for any changes, and only takes action if there are any. + - name: Tell server to pull new images and restart + uses: distributhor/workflow-webhook@v3 + with: + webhook_url: https://saferoutehook.murraygrov.es/webhook + + + \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 000000000..b460392fc --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.11 + +COPY ./ ./ + +RUN pip install -r requirements.txt + +CMD ["python", "safety.py"] \ No newline at end of file diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 000000000..2f55ee2a4 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,7 @@ +Flask==2.3.3 +Flask-Cors==4.0.0 +Flask-SocketIO==5.3.6 +osmnx=1.9.1 +networkx==3.2.1 +numpy=1.26.4 +scipy==1.12.0 \ No newline at end of file diff --git a/backend/safety.py b/backend/safety.py index 9a3576c2a..5c112e1dc 100644 --- a/backend/safety.py +++ b/backend/safety.py @@ -1,5 +1,4 @@ import csv -import math import os from flask_cors import CORS, cross_origin import osmnx as ox @@ -7,8 +6,6 @@ import osmnx.utils_graph as utils_graph import numpy as np from scipy.spatial import KDTree -import time -import matplotlib.pyplot as plt import flask @@ -127,13 +124,13 @@ def get_reference_points(G): app = flask.Flask(__name__) -cors = CORS(app, resources={r"/route": {"origins": "*"}}) +cors = CORS(app, resources={r"/api/route": {"origins": "*"}}) def myFunc(x, y, atts): print(x, y, atts) return atts.get("travel_time", 1) -@app.route("/route") +@app.route("/api/route") @cross_origin(origin='*',headers=['Content- Type','Authorization']) def get_route(): start = flask.request.args.get("start") diff --git a/continuous-development/docker-compose.yml b/continuous-development/docker-compose.yml new file mode 100644 index 000000000..d13e1cb45 --- /dev/null +++ b/continuous-development/docker-compose.yml @@ -0,0 +1,16 @@ +services: + backend: + container_name: saferoute-backend + image: ghcr.io/murraygroves/saferoute/backend:dev + ports: + - 8920:8080 + pull_policy: always + + frontend: + container_name: cityfarm-frontend + image: ghcr.io/murraygroves/saferoute/frontend:dev + environment: + - REACT_APP_HOSTPATH=https://saferoute.murraygrov.es + ports: + - 8921:3000 + pull_policy: always \ No newline at end of file diff --git a/continuous-development/saferoute-cd.service b/continuous-development/saferoute-cd.service new file mode 100644 index 000000000..7c3c6c2a6 --- /dev/null +++ b/continuous-development/saferoute-cd.service @@ -0,0 +1,8 @@ +[Unit] +Description=Start webhook listener for saferoute app + +[Service] +ExecStart=/home/mediaserver/configs/saferoute/saferoute/continuous-development/webhook_listener.py + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/continuous-development/webhook_listener.py b/continuous-development/webhook_listener.py new file mode 100644 index 000000000..b81f0bd39 --- /dev/null +++ b/continuous-development/webhook_listener.py @@ -0,0 +1,30 @@ +#!/bin/python3 + +from flask import Flask, request, Response +import os +import subprocess +from subprocess import Popen + +app = Flask(__name__) + +@app.route("/webhook", methods=["POST"]) +def update(): + output = subprocess.getoutput("git fetch --dry-run").strip() + if output == "": + print("No changes") + return Response(status=204) + + else: + print("Changes found") + # Update local git log + os.system("git fetch") + os.system("git pull") + + # Update and restart docker containers + os.system("docker compose down") + Popen(["docker", "compose", "up", "-d"]) + return Response(status=200) + + +if __name__ == '__main__': + app.run(host="localhost", port=1727, debug=True) \ No newline at end of file diff --git a/saferoute/src/App.tsx b/saferoute/src/App.tsx index bd7a0bf26..d4cc643c5 100644 --- a/saferoute/src/App.tsx +++ b/saferoute/src/App.tsx @@ -34,7 +34,7 @@ function App() { setNewRoute(undefined); return; } - fetch(`${process.env.REACT_APP_HOSTPATH}/route?start=${start}&end=${end}&weight=${weight ? 'combined_index': 'travel_time'}`).then( + fetch(`${process.env.REACT_APP_HOSTPATH}/api/route?start=${start}&end=${end}&weight=${weight ? 'combined_index': 'travel_time'}`).then( (response) => { response.json().then((data) => { let coordsList = data["route"];