From 0a9a33b87b90b2c94414fe837773efe9ecb68f9f Mon Sep 17 00:00:00 2001 From: NeilClack Date: Wed, 24 Jun 2026 14:17:06 -0500 Subject: [PATCH] Fix download URL mismatch --- README.md | 88 ---------------------------------- README.org | 90 +++++++++++++++++++++++++++++++++++ internal/download/Download.go | 43 +++++++++++++---- 3 files changed, 125 insertions(+), 96 deletions(-) delete mode 100644 README.md create mode 100644 README.org diff --git a/README.md b/README.md deleted file mode 100644 index 2a7fb76..0000000 --- a/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# RhemaWave - -A Go-based fullscreen SDL2/OpenGL application for Linux kiosk systems. Displays proclamations with audio playback and animated visual patterns. - -## Development - -Development uses Nix for a reproducible build environment. - -```bash -nix develop # enter dev shell -go build -o bin/rhemawave rhemawave.go # build -./bin/rhemawave # run -./dev_scripts/reset.sh # reset database (if needed) -``` - -### Prerequisites - -- Nix with flakes enabled -- A display server (X11/Wayland) and audio device for running the application - -## Architecture - -- **Page-based UI** — SDL2/OpenGL 3.3 fullscreen rendering with a page stack for navigation -- **Proclamation player** — scrolling text display with synchronized audio playback -- **Startup validation** — WiFi, TOS acceptance, email, license key checks -- **Singleton managers** — ShaderManager, FontManager, Logger (initialized once via `sync.Once`) - -### Key Directories - -``` -bin/ # build output (gitignored) -share/rhemawave/ # assets (fonts, shaders, proclamations, TOS) -internal/ # Go source packages -packaging/ # deployment configs (kiosk, updater, polkit) -dev_scripts/ # developer utilities -``` - -### Runtime Data - -Stored in `~/.local/share/rhemawave/`: - -- `data.db` — SQLite database (config, proclamations, logs) -- `log.txt` — application log -- `license_key` — license key file - -### Development Rules - -These rules must be followed during the development of RhemaWave to retain a -maintainable application. - -1. The Application package is soley responsible for managing the database handler, and the - configuration cache. Internal packages may update the configuration within the database, and - then signal the application to refresh the cache via a callback function `refreshCache()`. - -## Deployment - -Deployed to kiosk hardware via NixOS. - -## Notes - -### Deployment Pipeline - -A manual walkthough of deploying Radiant Wave updates. -For reference later when writing automated actions. - -1. Create a new branch for issue being worked on -2. Perform work -3. Merge to dev when done -4. Build dev with `nix build` to verify no errors -5. Checkout KioskConfig dev -6. Update rhemawave-dev with `nix flake update rhemawave-dev` -7. Build rhemawavekiosk-dev virtual machine -8. Test virtual machine for problems -9. Build dev-iso -10. Install dev-iso to a machine and check for problems -11. Checkout `main` -12. Merge `dev` -13. `nix flake update rhemawave` -14. Build virtual machine -15. Build iso image -16. Build commercial virtual machine -17. Build commercial iso image -18. Build Raspberry Pi img -19. Approve all virtual machines and iso images -20. Approve all machines update on their own -21. Rename all iso image to "radiantwavekiosk-iso-{system}-{MM-DD-YYYY}-{radiantwave-git-hash}.iso" -22. Upload iso images to file server -23. Move old iso images to `archives/` on the fileserver diff --git a/README.org b/README.org new file mode 100644 index 0000000..c2a383d --- /dev/null +++ b/README.org @@ -0,0 +1,90 @@ +#+TITLE: Radiantwave & KioskConfig Development & Release Pipeline +#+AUTHOR: Neil C. +#+DATE: 2026-06-23 +#+OPTIONS: toc:nil num:nil +#+TAGS: development nixos radiantwave kiosk automation + +* Radiant Wave + +* Full Pipeline Workflow (Detailed) + +** Development Phase +1. Create a new branch for the issue +2. Implement the changes for the issue + +** Integration to =dev= +3. Open a pull request to =dev= +4. CI: Run =nix build= to verify no errors +5. CI: Run linting and unit tests +6. CI: Auto-update =rhemawave-dev= flake input +7. CI: Build all =dev= VMs in parallel (Kiosk, Commercial, RPi) +8. Merge the pull request to =dev= after CI passes + +** Testing Phase +9. Run all VMs (Kiosk, Commercial, RPi) and test all functionality of the application on each VM +10. Install =dev-iso= to a test machine and verify installation and application functionality + +** Release to =main= +11. Open a pull request from =dev= to =main= +12. CI: Build all =main= VMs in parallel (Kiosk, Commercial, RPi) +13. CI: Build all ISO images in parallel +14. CI: Auto-rename ISO images to format =radiantwave-{system}-{YYYY-MM-DD}-{git-hash}.iso= +15. CI: Upload ISO images to file server +16. CI: Move old ISO images to =archives/= on file server +17. Merge the pull request to =main= after CI passes +18. Tag the release (optional, for traceability) + +* Automation Opportunities + +This section describes which parts of the workflow can be automated via CI/CD, and how. + +** Group 1: Development Validation (Steps 3-8) +- =What to automate=: PR triggering, =nix build=, linting, unit tests, flake updates, dev VM builds +- =How=: GitHub Actions workflow triggered on PR to =dev= +- =Why=: Catch integration errors before manual testing; ensure =dev= is always buildable + +** Group 2: Testing (Steps 9-10) +- =What to automate=: VM functionality testing, ISO installation verification +- =How=: Scripted test suites, automated ISO installation in VMs +- =Why=: Reduce manual toil; increase test coverage and consistency + +** Group 3: Release Pipeline (Steps 11-16) +- =What to automate=: Main VM/ISO builds, ISO renaming, file server uploads, archiving +- =How=: GitHub Actions workflow triggered on PR to =main= +- =Why=: Ensure consistent releases; eliminate human error in naming/uploading + +* Preflight Checklist + +- [ ] Create a new branch for the issue +- [ ] Implement the changes for the issue +- [ ] Open a pull request to =dev= +- [ ] Merge the pull request to =dev= after CI passes +- [ ] Run all VMs (Kiosk, Commercial, RPi) and test all functionality of the application on each VM +- [ ] Install =dev-iso= to a test machine and verify installation and application functionality +- [ ] Open a pull request from =dev= to =main= +- [ ] Merge the pull request to =main= after CI passes +- [ ] Tag the release (optional, for traceability) + +* Automation Task List + +** Group 1: Development Validation +- [ ] Set up GitHub Actions workflow for PRs to =dev= + - [ ] Configure =nix build= step + - [ ] Add linting and unit test steps + - [ ] Add flake auto-update step + - [ ] Configure parallel VM builds (Kiosk, Commercial, RPi) +- [ ] Verify workflow blocks PR merge on failure + +** Group 2: Testing +- [ ] Create automated test scripts for VM functionality +- [ ] Set up automated ISO installation testing +- [ ] Integrate with CI for optional automated testing + +** Group 3: Release Pipeline +- [ ] Set up GitHub Actions workflow for PRs to =main= + - [ ] Configure parallel VM builds + - [ ] Configure parallel ISO builds + - [ ] Add ISO auto-renaming step (using =git rev-parse HEAD= and =date +%Y-%m-%d=) + - [ ] Add file server upload step (=rsync= or similar) + - [ ] Add archive old ISOs step +- [ ] Verify workflow blocks PR merge on failure \ No newline at end of file diff --git a/internal/download/Download.go b/internal/download/Download.go index 5e704c6..144d55d 100644 --- a/internal/download/Download.go +++ b/internal/download/Download.go @@ -20,12 +20,44 @@ type DownloadStatus struct { Err error // Error, if any } +// ensureDir checks if a dire +func ensureDir(path string) error { + info, err := os.Stat(path) + if err == nil { + if !info.IsDir() { + return fmt.Errorf("path exists but is not a directory: %s", path) + } + fmt.Printf("Directory already exists: %s\n", path) + return nil + } + + if !os.IsNotExist(err) { + return fmt.Errorf("error checking path: %w", err) + } + + // 0760 = rwxrw---- (owner: rwx, group: rw-, others: ---) + if err := os.MkdirAll(path, 0760); err != nil { + return fmt.Errorf("failed to create directory: %w", err) + } + + logger.Info("Directory created: %s\n", path) + return nil +} + // DownloadAudioFiles downloads multiple audio files and sends progress updates // to the provided channel. The channel is closed when all downloads are complete. func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, destDir string) { defer close(progressChan) - urlBase := "https://files.rhemawavetech.com/audio/" + if err := ensureDir(destDir); err != nil { + logger.Error("failed to ensureDir %s %v", destDir, err) + progressChan <- DownloadStatus{ + Msg: fmt.Sprintf("Failed to ensure directory exists: %v", err), + Err: err, + } + } + + urlBase := "https://files.radiantwavetech.com/audio/" // First, calculate the total size of files that need to be downloaded totalSize := int64(0) @@ -87,6 +119,8 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, url := urlBase + filename destPath := filepath.Join(destDir, filename) + // Ensure the destination directory exists + // Create the destination file out, err := os.Create(destPath) if err != nil { @@ -158,13 +192,6 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, } out.Close() - - // Send completion for this file - progressChan <- DownloadStatus{ - Max: totalSize, - Cur: totalDownloaded, - Msg: "Finished Downloading", - } } // Send final status