ggj26-comp
Extracted components from ggj26: build system, logging, and hub-and-spoke networking.
Components
Build System
Makefile-based build system for MoonScript/Lua projects:
- Compiles .moon files to .lua
- Embeds JavaScript files with jshint validation
- Runs tests with busted
Usage:
make # Build all sources
make test # Run tests
make clean # Clean build artifacts
Logging Utility
src/log.moon - Singleton logger with level-based and tag-based filtering.
Features: - Log levels: debug, info, warn, error, panic - Tag-based filtering for organizing logs - Observer pattern for real-time monitoring - Message stream with time tracking
Usage:
log = require "log"
-- Log with level and tags
log.info("User connected", {"network", "auth"})
log.error("Connection failed", {"network"})
-- Filter by level
log.of_level("error", function(msg)
print(msg.message)
end)
-- Filter by tags
log.of_tags({"network"}, function(msg)
print(msg.message)
end)
-- Listen to all messages
log.listen(function(msg)
if msg.level == "panic" then
-- handle critical error
end
end)
Networking - Hub and Spoke Model
Core (src/net.moon)
Low-level WebRTC peer connection abstraction using PeerJS: - Peer creation and connection management - Message validation and routing - JavaScript bridge for browser integration
Hub (src/hub.moon)
Server-side hub that manages client connections: - Maintains registry of connected clients - Routes messages between clients (unicast, multicast, broadcast) - Connection/disconnection event handling
Usage:
Hub = require("hub").Hub
hub = Hub()
hub:initialize()
-- Get hub ID to share with clients
hub_id = hub:get_peer_id()
-- Listen for client events
hub:on_connect(function(client_id)
print("Client connected:", client_id)
end)
hub:on_disconnect(function(client_id)
print("Client disconnected:", client_id)
end)
-- Update loop
function love.update(dt)
hub:pump()
end
Client (src/client.moon)
Client-side with router registration system: - Connect to hub - Register message handlers (routers) by message type - Send messages to specific clients or broadcast
Usage:
Client = require("client").Client
client = Client("player1")
-- Connect to hub
client:connect_to_hub(hub_id)
-- Register router for message type
client:register_router("chat", function(from_id, data)
print("Chat from", from_id, ":", data.message)
end)
client:register_router("game_state", function(from_id, data)
-- handle game state update
end)
-- Send messages
client:send_to(other_client_id, "chat", {message = "Hello!"})
client:broadcast("game_state", {position = {x=10, y=20}})
-- Update loop
function love.update(dt)
client:pump()
end
Testing Utilities (src/channel.moon)
Channel abstractions for testing:
- SimpleChannel - Basic in-memory channel
- FaultyChannel - Simulates network latency and packet loss
Utility Functions (src/util.lua)
Helper functions including:
- typecheck(tbl, ...) - Validate table fields and types
- peer_to_code(str) / code_to_peer(str) - Convert peer IDs to shareable codes
Architecture
Hub-and-Spoke Networking
[Client A]
|
v
[Hub] ←-→ [Client B]
|
v
[Client C]
- Hub: Single peer that accepts all client connections
- Clients: Connect to hub, register message handlers (routers)
- Message Flow: Client → Hub → Target Client(s)
- Routing: Hub handles unicast, multicast, and broadcast
This replaces the previous RAFT-based peer-to-peer model with a simpler, centralized approach suitable for game lobbies and small multiplayer sessions.
Requirements
- MoonScript compiler (
moonc) - Lua
- Busted (for unit testing)
- Node.js/npm (for jshint)
- Python 3.8+ (for integration testing)
- Chrome browser (for Selenium tests)
Installation
# Install Node.js dependencies
npm install
# Install Python test dependencies (for integration testing)
pip install -r requirements-test.txt
Testing
Run All Tests
Run both unit tests and integration tests:
make test1
Unit Tests (Lua/Busted)
Run Lua unit tests with busted:
make test
Integration Tests (Selenium)
Run browser-based integration tests:
# Using Make
make test-integration # Run with visible browser
make test-integration-headless # Run in headless mode
Or use the PowerShell script:
.\run-integration-tests.ps1 # Run all tests
.\run-integration-tests.ps1 -Headless # Headless mode
.\run-integration-tests.ps1 -Smoke # Smoke tests only
.\run-integration-tests.ps1 -UI # UI interaction tests
Or use pytest directly:
pytest # Run all integration tests
pytest -m smoke # Run smoke tests only
pytest -v # Verbose output
See tests/integration/README.md for more details on integration testing.
