#+TITLE: Asteroid Radio Web Server Implementation Summary #+DATE: 2025-08-20 #+AUTHOR: Development Session Summary * Project Overview This document summarizes the implementation of a basic web server for the Asteroid Radio project, a Common Lisp-based streaming radio station for "asteroid music for hackers." ** Project Context - Fork of https://github.com/fade/asteroid - Goal: Create streaming radio station with web interface - Started with basic Common Lisp framework skeleton - Implemented web server as foundation for future streaming components * Initial State Analysis ** Original Dependencies (asteroid.asd) - :RADIANCE (web framework) - :MITO (database ORM) - :MITO-AUTH (authentication) - :STR (string utilities) - :PZMQ (ZeroMQ bindings) - :SPINNERET (HTML generation) ** Original Code Structure - =asteroid.lisp= - Main package with placeholder =-main= function - =app-utils.lisp= - Utility functions for debugger control and cross-platform quit - =design.org= - Comprehensive feature specification and MVP roadmap * Dependency Changes and Rationale ** Removed Dependencies | Dependency | Reason for Removal | |------------|-------------------| | :RADIANCE | Requires separate Shirakumo dist installation, switched to simpler Hunchentoot for MVP | | :MITO | Not available in default Quicklisp, not needed for basic web server | | :MITO-AUTH | Not available in default Quicklisp, authentication not needed for MVP | | :STR | Not used in current implementation | | :PZMQ | Not needed for basic web server functionality | ** Final Dependencies | Dependency | Purpose | Justification | |------------|---------|---------------| | :RADIANCE | Web framework | Modular web framework with subdomain routing and integrated module system | | :SPINNERET | HTML generation | Clean DSL for generating HTML, integrates well with Common Lisp | | :CL-JSON | JSON encoding/decoding | Standard library for API endpoints | ** Migration from Hunchentoot to RADIANCE - **Initial Choice**: Started with Hunchentoot for simpler MVP setup - **Discovery**: RADIANCE available via Shirakumo dist: `(ql-dist:install-dist "http://dist.shirakumo.org/shirakumo.txt")` - **Migration Completed**: Successfully migrated to RADIANCE framework - **Benefits**: RADIANCE provides modular architecture, subdomain routing, and integrated module system - **Result**: More scalable foundation for future radio station features * Implementation Details ** Web Server Architecture - Framework: RADIANCE modular web framework - Port: 8080 (default RADIANCE configuration) - Module: asteroid (domain: "asteroid") - Subdomain routing: asteroid.localhost:8080 - Server management: =radiance:startup= / =radiance:shutdown= ** Route Structure (RADIANCE) | Route | Handler | Purpose | URL | |-------|---------|---------|-----| | / | =index= | Main page with station status | http://asteroid.localhost:8080/ | | /admin | =admin= | Admin dashboard with controls | http://asteroid.localhost:8080/admin | | /player | =player= | Web player interface | http://asteroid.localhost:8080/player | | /api/status | =api/status= | JSON API endpoint | http://asteroid.localhost:8080/api/status | ** HTML Generation Strategy - Direct use of =spinneret:with-html-string= in each handler - Consistent hacker-themed styling (green text, black background) - Responsive design with CSS embedded in each page * Errors Encountered and Solutions ** Error 1: Missing MITO Dependency *** Problem #+BEGIN_EXAMPLE debugger invoked on a ASDF/FIND-COMPONENT:MISSING-DEPENDENCY Component :MITO not found, required by # #+END_EXAMPLE *** Root Cause MITO and related database dependencies not available in Quicklisp distribution. *** Solution Removed unused dependencies from =asteroid.asd=: - Removed :MITO, :MITO-AUTH, :STR, :PZMQ - Kept only essential dependencies: :HUNCHENTOOT, :SPINNERET, :CL-JSON ** Error 2: RADIANCE Framework Migration *** Problem Initially avoided RADIANCE due to perceived unavailability, implemented with Hunchentoot instead. *** Root Cause RADIANCE available via Shirakumo dist: `(ql-dist:install-dist "http://dist.shirakumo.org/shirakumo.txt")` but required additional setup step. *** Solution - Successfully migrated from Hunchentoot to RADIANCE - Installed Shirakumo distribution for RADIANCE access - Rewrote route handlers using =define-page= syntax - Added =define-module= declaration for proper RADIANCE integration - Updated server management to use =radiance:startup= / =radiance:shutdown= ** Error 3: HTML Generation Function Signature Mismatch *** Problem #+BEGIN_EXAMPLE The function GENERATE-PAGE-HTML is called with five arguments, but wants exactly two. #+END_EXAMPLE *** Root Cause Initial =generate-page-html= helper function designed for single body argument, but called with multiple arguments. *** Solution Attempted fix with =&rest= parameter, but Spinneret macro expansion issues persisted. ** Error 4: RADIANCE Route Syntax Issues *** Problem #+BEGIN_EXAMPLE Module # requested but while the package exists, it is not a module. The value #@"asteroid/api/status" is not of type LIST #+END_EXAMPLE *** Root Cause - Missing =define-module= declaration for RADIANCE integration - Incorrect route path syntax using =asteroid/= prefix instead of module-relative paths - Wrong API endpoint definition syntax *** Solution - Added =define-module= declaration with proper domain specification - Fixed route paths: =#@"asteroid/"= → =#@"/"=, =#@"asteroid/admin"= → =#@"/admin"= - Updated API endpoint to use =define-page= instead of =define-api= - Fixed parentheses syntax errors in HTML generation ** Error 5: Shell History Expansion Issues *** Problem #+BEGIN_EXAMPLE zsh: event not found: ~ zsh: event not found: \ #+END_EXAMPLE *** Root Cause Zsh history expansion interfering with command-line arguments containing special characters. *** Solution Used single quotes instead of double quotes for SBCL command-line arguments to prevent shell interpretation. * Current Project Status ** ✅ Completed Features - [X] Basic web server running on localhost:8080 - [X] Main page with station status display - [X] Admin dashboard with placeholder controls - [X] Web player interface (UI only) - [X] JSON API endpoint (/api/status) - [X] Hacker-themed consistent styling - [X] Proper error handling and server management - [X] Git upstream remote configuration ** 🎯 Current Capabilities - Web server starts/stops cleanly - All routes functional and accessible - HTML generation working correctly - JSON API returning structured data - Responsive web interface - Server management functions exported ** 🚀 Running the Server *** RADIANCE Setup (One-time) #+BEGIN_EXAMPLE sbcl --eval '(ql-dist:install-dist "http://dist.shirakumo.org/shirakumo.txt")' #+END_EXAMPLE *** Command Line (One-shot execution) #+BEGIN_EXAMPLE sbcl --eval '(ql:quickload (quote (:radiance :spinneret :cl-json)))' \ --eval '(load "asteroid.asd")' \ --eval '(asdf:load-system :asteroid)' \ --eval '(asteroid:start-server)' \ --eval '(format t "Server running at http://asteroid.localhost:8080/ - Press Ctrl+C to stop")' #+END_EXAMPLE *** Interactive REPL #+BEGIN_EXAMPLE sbcl (ql:quickload '(:radiance :spinneret :cl-json)) (load "asteroid.asd") (asdf:load-system :asteroid) (asteroid:start-server) ;; Server now running at http://asteroid.localhost:8080/ ;; To stop: (asteroid:stop-server) #+END_EXAMPLE *** Available Functions - =(asteroid:start-server)= - Start RADIANCE server (non-blocking) - =(asteroid:stop-server)= - Stop RADIANCE server cleanly - =(asteroid:run-server)= - Start server and keep running (blocking, with Ctrl+C handler) *** Access URLs - **Main page**: http://asteroid.localhost:8080/ - **Admin dashboard**: http://asteroid.localhost:8080/admin - **Web player**: http://asteroid.localhost:8080/player - **API endpoint**: http://asteroid.localhost:8080/api/status - **RADIANCE welcome**: http://localhost:8080/ ** 📋 Next Steps (Not Implemented) - Database integration (when MITO alternative chosen) - Audio streaming backend (Liquidsoap integration) - Icecast server integration - File upload functionality - Authentication system - Real-time now-playing updates - WebSocket integration for live updates - **Completed**: ✅ Successfully migrated to RADIANCE framework * Technical Lessons Learned ** Dependency Management - Always verify dependency availability in target package manager - Prefer widely-adopted, stable libraries over newer alternatives - Keep dependency list minimal for initial implementation ** Common Lisp Web Development - RADIANCE provides modular architecture with subdomain routing - Spinneret works best with direct macro usage, not through helper functions - HTML generation should be kept simple and direct - RADIANCE modules require proper =define-module= declarations - Route paths in RADIANCE are module-relative (use =#@"/"= not =#@"asteroid/"=) ** Error Handling Strategy - Compilation warnings often indicate runtime issues - Test each component incrementally - Use REPL for interactive debugging and testing ** Development Workflow - Start with minimal working version - Add complexity incrementally - Test each change immediately - Keep fallback options for critical dependencies * File Structure Summary #+BEGIN_EXAMPLE asteroid/ ├── asteroid.asd # System definition (minimal dependencies) ├── asteroid.lisp # Main web server implementation ├── app-utils.lisp # Utility functions ├── design.org # Original project specification ├── test-server.lisp # Server testing script ├── project-summary.org # This document ├── Makefile # Build configuration └── LICENSE # AGPL v3 license #+END_EXAMPLE * Conclusion Successfully implemented and migrated a functional web server foundation for the Asteroid Radio project using RADIANCE framework. The server provides a complete web interface with admin controls, player interface, and API endpoints accessible via subdomain routing at asteroid.localhost:8080. Key achievements: - **Framework Migration**: Successfully migrated from Hunchentoot to RADIANCE - **Modular Architecture**: Implemented proper RADIANCE module with subdomain routing - **Complete Web Interface**: Main page, admin dashboard, web player, and JSON API - **Scalable Foundation**: RADIANCE provides better architecture for future radio features The implementation demonstrates the value of exploring framework alternatives and provides a robust, modular foundation ready for the next development phase: integrating audio streaming components (Liquidsoap/Icecast) and database functionality.