diff --git a/.github/workflows/make_ipks.yml b/.github/workflows/make_ipks.yml new file mode 100644 index 0000000000..fd8d0adb3c --- /dev/null +++ b/.github/workflows/make_ipks.yml @@ -0,0 +1,28 @@ +name: Make IPKs + +on: + push: + branches: + - "*" + tags-ignore: + - "*" + pull_request: + release: + types: [published] + +jobs: + + build-system-viewer: + name: Build IPK for SystemViewer + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build IPK (SystemCore) + run: cd systemcore-apps/system-view && chmod +x build.sh && ./build.sh + - name: Upload development artifact (SystemCore) + uses: actions/upload-artifact@v4 + with: + name: pv-system-viewer.ipk + path: systemcore-apps/system-view/pv-system-viewer_*.ipk diff --git a/.gitignore b/.gitignore index dda0d4712f..4522bf02ea 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,5 @@ photon-server/src/main/resources/web/* node_modules dist components.d.ts + +*.ipk diff --git a/systemcore-apps/system-view/.gitignore b/systemcore-apps/system-view/.gitignore new file mode 100644 index 0000000000..83c41fb10f --- /dev/null +++ b/systemcore-apps/system-view/.gitignore @@ -0,0 +1,2 @@ +!overlay/ +!overlay/** diff --git a/systemcore-apps/system-view/build.sh b/systemcore-apps/system-view/build.sh new file mode 100755 index 0000000000..87b34a869d --- /dev/null +++ b/systemcore-apps/system-view/build.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +set -e + +# Extract package info from control/control file +if [ ! -f "control/control" ]; then + echo "Error: control/control not found!" + echo "Create a control/control file with package metadata" + exit 1 +fi + +PACKAGE_NAME=$(grep "^Package:" control/control | cut -d' ' -f2- | tr -d ' ') +PACKAGE_VERSION=$(grep "^Version:" control/control | cut -d' ' -f2- | tr -d ' ') + +# Validate required fields +if [ -z "$PACKAGE_NAME" ] || [ -z "$PACKAGE_VERSION" ]; then + echo "Err: Package and Version must be set in control/control" + echo "Package: my-package" + echo "Version: 1.0.0" + exit 1 +fi + +PACKAGE_DIR="${PACKAGE_NAME}_${PACKAGE_VERSION}" +BUILD_DIR="build" + +echo "Building IPK package from overlay structure..." +echo "Package: ${PACKAGE_NAME}_${PACKAGE_VERSION}.ipk" + +if [ ! -d "overlay" ]; then + echo "overlay/ directory not found" + exit 1 +fi + +if [ ! -d "control" ]; then + echo "Error: control/ directory not found!" + echo "Create control/ with control, postinst, prerm, postrm files" + exit 1 +fi + +echo "Cleaning previous build..." +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR/$PACKAGE_DIR" + +echo "Copying overlay structure..." +cp -r overlay/* "$BUILD_DIR/$PACKAGE_DIR/" + +echo "Copying CONTROL files..." +mkdir -p "$BUILD_DIR/$PACKAGE_DIR/CONTROL" +cp control/* "$BUILD_DIR/$PACKAGE_DIR/CONTROL/" + +echo "Setting file permissions..." + +# Make scripts executable +find "$BUILD_DIR/$PACKAGE_DIR" -name "*.py" -exec chmod +x {} \; + +if [ -d "$BUILD_DIR/$PACKAGE_DIR/CONTROL" ]; then + chmod +x "$BUILD_DIR/$PACKAGE_DIR/CONTROL"/* 2>/dev/null || true +fi + +find "$BUILD_DIR/$PACKAGE_DIR" -name "*.sh" -exec chmod +x {} \; + +echo "Building IPK dir structure" +cd "$BUILD_DIR" + +echo "Creating data.tar.gz" +tar --exclude='CONTROL' -czf data.tar.gz -C "$PACKAGE_DIR" . + +echo "Creating control.tar.gz" +tar -czf control.tar.gz -C "$PACKAGE_DIR/CONTROL" . + +echo "Creating IPK..." +ar r "../${PACKAGE_NAME}_${PACKAGE_VERSION}.ipk" control.tar.gz data.tar.gz + +cd .. + +echo "" +echo "IPK package created." +echo "Package: ${PACKAGE_NAME}_${PACKAGE_VERSION}.ipk" +echo "" +echo "Package structure:" +echo " CONTROL files:" +find control -type f | sort | sed 's/^/ /' +echo " Overlay files (will be installed):" +find overlay -type f | sort | sed 's/^overlay/ /' | head -15 + +if [ $(find overlay -type f | wc -l) -gt 15 ]; then + echo " ... and $(($(find overlay -type f | wc -l) - 15)) more files" +fi + +rm -rf "$BUILD_DIR" + +echo "" +echo "Build complete" diff --git a/systemcore-apps/system-view/control/control b/systemcore-apps/system-view/control/control new file mode 100644 index 0000000000..be143b6de8 --- /dev/null +++ b/systemcore-apps/system-view/control/control @@ -0,0 +1,13 @@ +Package: pv-system-viewer +Version: 0.1.0 +Description: PhotonVision System Viewer - A simple interface to see all PhotonVision cameras. +Section: development +Priority: optional +Maintainer: PhotonVision Team +Architecture: all +Source: local +X-Port: 5804 +X-Has-UI: true +X-Auto-Start: true +X-Icon-Path: /usr/share/pv-system-viewer.png +X-Display-Name: PhotonVision System Viewer diff --git a/systemcore-apps/system-view/control/postinst b/systemcore-apps/system-view/control/postinst new file mode 100644 index 0000000000..e719783f7c --- /dev/null +++ b/systemcore-apps/system-view/control/postinst @@ -0,0 +1,29 @@ +#!/bin/sh +PACKAGE_NAME="pv-system-viewer" + +echo "Configuring service for $PACKAGE_NAME" + +systemctl daemon-reload +sleep 1 + +echo "Enabling service for auto-start on boot..." +systemctl enable $PACKAGE_NAME.service + +echo "Starting service..." +if systemctl start $PACKAGE_NAME.service; then + echo "Service started successfully" + + sleep 2 + + if systemctl is-active $PACKAGE_NAME.service >/dev/null 2>&1; then + echo "Service is now running" + else + echo "Service may have an issue" + fi +else + echo "Failed to start service automatically" +fi + +echo "Package installation complete" + +exit 0 diff --git a/systemcore-apps/system-view/control/postrm b/systemcore-apps/system-view/control/postrm new file mode 100644 index 0000000000..6fe3eb6778 --- /dev/null +++ b/systemcore-apps/system-view/control/postrm @@ -0,0 +1,15 @@ +#!/bin/sh +PACKAGE_NAME="pv-system-viewer" + +systemctl daemon-reload +systemctl reset-failed $PACKAGE_NAME.service 2>/dev/null || true + +if systemctl list-unit-files | grep -q "$PACKAGE_NAME.service"; then + echo "Service still appears in systemd unit files (normal until next boot)" +else + echo "Service removed from systemd" +fi + +echo "Service cleanup complete." + +exit 0 diff --git a/systemcore-apps/system-view/control/prerm b/systemcore-apps/system-view/control/prerm new file mode 100644 index 0000000000..861055929d --- /dev/null +++ b/systemcore-apps/system-view/control/prerm @@ -0,0 +1,27 @@ +#!/bin/sh +PACKAGE_NAME="pv-system-viewer" + +echo "Stopping $PACKAGE_NAME service..." + +if systemctl is-active $PACKAGE_NAME.service >/dev/null 2>&1; then + echo "Service is running, stopping it..." + if systemctl stop $PACKAGE_NAME.service; then + echo "Service stopped successfully" + else + echo "Service stop may have failed, continuing anyway..." + fi +else + echo "Service was not running" +fi + +# Disable the service +echo "Disabling service auto-start..." +if systemctl disable $PACKAGE_NAME.service 2>/dev/null; then + echo "Service auto-start disabled" +else + echo "Service was not enabled or disable failed" +fi + +echo "Service stopped and disabled" + +exit 0 diff --git a/systemcore-apps/system-view/overlay/etc/systemd/system/pv-system-viewer.service b/systemcore-apps/system-view/overlay/etc/systemd/system/pv-system-viewer.service new file mode 100644 index 0000000000..7cbc05b587 --- /dev/null +++ b/systemcore-apps/system-view/overlay/etc/systemd/system/pv-system-viewer.service @@ -0,0 +1,23 @@ +[Unit] +Description=PhotonVision System Viewer - A simple interface to check all connected PhotonVision Coprocessor statuses +After=network.target +Wants=network.target + +[Service] +Type=simple +User=root +Group=root +ExecStart=/usr/local/bin/pv-system-viewer/pv-system-viewer.py +Restart=always +RestartSec=5 +TimeoutStartSec=3 +TimeoutStopSec=3 + +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/var/log + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/404.html b/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/404.html new file mode 100644 index 0000000000..e0b1f01921 --- /dev/null +++ b/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/404.html @@ -0,0 +1,5 @@ + + + +
404 error
+ \ No newline at end of file diff --git a/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/pv-system-viewer.py b/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/pv-system-viewer.py new file mode 100644 index 0000000000..5ab9b4d199 --- /dev/null +++ b/systemcore-apps/system-view/overlay/usr/local/bin/pv-system-viewer/pv-system-viewer.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +import http.server +import socketserver +import threading +import signal +import sys +import os +import json +from datetime import datetime + +import mimetypes +# Ensure mimetypes are set for common file types +mimetypes.add_type('application/javascript', '.js') + + +class PVSystemViewerHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + script_dir = os.path.dirname(os.path.abspath(__file__)) + www_dir = os.path.join(script_dir, 'www') # Path to the www folder + + if self.path == '/': + file_path = os.path.join(www_dir, 'systemViewer.html') + else: + # Serve the requested file + file_path = os.path.join(www_dir, self.path.lstrip('/')) + + # Check if the file exists and is within the www directory + if os.path.commonpath([www_dir, os.path.abspath(file_path)]) != www_dir or not os.path.isfile(file_path): + self.send_response(404) + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write(b'404 Not Found