Session Server Architecture Plan#
Current State (As of 2025-10-28)#
Overview#
Aesthetic Computer has transitioned away from Jamsocket (paid service discontinued) to a self-hosted session server architecture. This document outlines the current setup and what needs to be documented/updated.
Current Production Architecture#
Session Server#
- Production URL:
https://session-server.aesthetic.computer - Purpose: Handles both WebSocket connections AND UDP connections
- Location: Same server that previously only handled UDP (157.245.134.225)
- Previous UDP-only URL:
https://udp.aesthetic.computer(now deprecated/redundant)
Connection Flow#
- Client requests session info from Netlify function
/session/{slug} - Function returns URLs for WebSocket and UDP connections
- Both URLs now point to the same unified session server
Code Locations#
Frontend (disk.mjs)#
File: system/public/aesthetic.computer/lib/disk.mjs
Key Functions:
-
session(slug, forceProduction, service)(line ~3855)- Fetches session connection info from
/session/endpoint - Parses WebSocket and UDP URLs
- Currently still references Jamsocket EventSource for backend status (NEEDS UPDATE)
- Fetches session connection info from
-
startSocket()(line ~6320)- Establishes WebSocket connection via
socket.connect() - Sets up UDP connection via
send({ type: "udp:connect", ... })
- Establishes WebSocket connection via
Backend Session Function#
File: system/netlify/functions/session.js
Current Behavior:
- Development mode (
dev && !forceProd):- Returns
http://localhost:8889for both WebSocket and UDP
- Returns
- Production monolith mode (
service === "monolith"):- Returns
https://session-server.aesthetic.computerfor WebSocket - Returns
https://udp.aesthetic.computerfor UDP (REDUNDANT NOW)
- Returns
- Jamsocket mode (old, still in code):
- Attempts to spawn/check Jamsocket backends (NO LONGER FUNCTIONAL)
Issues to Fix#
1. ac-session Fish Function#
Problem: The Emacs detection in ac-session may be interfering with proper session server startup.
Current Code (.devcontainer/config.fish line ~1117):
if test -n "$INSIDE_EMACS"
echo "📋 Starting session server (non-blocking mode for Emacs)..."
# ... background startup logic
return
end
Analysis:
- The Emacs mode starts nodemon in background and immediately returns
- This may prevent proper monitoring/interaction with the session server
- The session server might not be getting proper stdio/logging visibility
Proposed Fix:
- Remove or simplify Emacs special handling
- Let nodemon run normally in all environments
- Use standard terminal output for monitoring
2. Jamsocket References (Obsolete)#
Problem: Code still references Jamsocket API and EventSource streams that no longer work.
Locations:
disk.mjsline ~3891: EventSource connection toapi.jamsocket.comdisk.mjsline ~3913-3927: State handling for Jamsocket backend states (Loading, Starting, Ready)session.jsline ~52-130: Jamsocket backend spawning/checking logic
Proposed Fix:
- Remove EventSource polling for backend status (session server is always ready in production)
- Simplify
session()function to just return URLs without state checking - Keep monolith mode as primary production path
- Remove all Jamsocket API calls and unused Redis backend tracking code
3. Redundant UDP URL#
Problem: The UDP connection URL still points to https://udp.aesthetic.computer but the session server now handles UDP on the same host.
Current (session.js line ~23):
const udpUrl = `https://udp.aesthetic.computer`;
Proposed Fix:
- In monolith mode, return the same base URL for both WebSocket and UDP
- Update to:
udp: "https://session-server.aesthetic.computer" - Or better: just return a single URL and have client use same host for both protocols
Proposed Changes#
Priority 1: Fix ac-session Fish Function#
function ac-session
echo "🎮 Starting session server..."
ac
cd session-server
echo "🔍 Cleaning up any stuck processes..."
pkill -f "nodemon.*session.mjs" 2>/dev/null
sleep 1
npx kill-port 8889 2>/dev/null
echo "🚀 Starting session server on port 8889..."
PORT=8889 NODE_ENV=development npx nodemon -I --watch session.mjs session.mjs
end
Priority 2: Simplify session.js Netlify Function#
async function fun(event, context) {
const forceProd = parseInt(event.queryStringParameters.forceProduction) === 1;
if (dev && !forceProd) {
// Local development
let host = event.headers.host.split(":")[0];
if (host === "local.aesthetic.computer") {
return {
statusCode: 200,
body: JSON.stringify({
url: `https://session.${host}`,
udp: `https://session.${host}`,
state: "Ready"
}),
headers: { "Access-Control-Allow-Origin": "*" },
};
} else {
return {
statusCode: 200,
body: JSON.stringify({
url: `http://${host}:8889`,
udp: `http://${host}:8889`,
state: "Ready"
}),
headers: { "Access-Control-Allow-Origin": "*" },
};
}
} else {
// Production - unified session server
return {
statusCode: 200,
body: JSON.stringify({
url: `https://session-server.aesthetic.computer`,
udp: `https://session-server.aesthetic.computer`,
state: "Ready"
}),
headers: { "Access-Control-Allow-Origin": "*" },
};
}
}
Priority 3: Simplify disk.mjs session() Function#
Remove EventSource logic and Jamsocket state polling since session server is always ready:
async function session(slug, forceProduction = false, service) {
let endPoint = "/session/" + slug;
const params = { service };
if (forceProduction) params.forceProduction = 1;
endPoint += "?" + new URLSearchParams(params);
const req = await fetch(endPoint);
if (req.status === 200 || req.status === 304) {
const session = await req.json();
return session; // Already includes url, udp, and state: "Ready"
} else {
const error = await req.text();
console.error("Session fetch error:", error);
return error;
}
}
Testing Plan#
-
Test ac-session locally:
- Run
ac-sessionin terminal - Verify nodemon starts properly
- Check logs appear in terminal
- Test hot reload by editing
session.mjs - Try Ctrl+C to stop
- Run
-
Test development WebSocket/UDP:
- Start local session server with
ac-session - Load aesthetic.computer locally
- Verify WebSocket connects to localhost:8889
- Verify UDP connects to localhost:8889
- Test piece with
socket()API
- Start local session server with
-
Test production connection:
- Deploy simplified
session.jsfunction - Load aesthetic.computer in production
- Verify WebSocket connects to
session-server.aesthetic.computer - Verify UDP connects to same host
- Test multiplayer piece functionality
- Deploy simplified
Migration Notes#
Breaking Changes: None - this is a cleanup/documentation update
Rollback Plan:
- Keep old session.js code commented out
- Can revert to Jamsocket mode if needed (though service is discontinued)
Post-Migration:
- Remove all Jamsocket-related code
- Remove Redis backend tracking code (unused)
- Update documentation to reflect unified session server architecture
Open Questions#
- Should we unify the WebSocket and UDP URLs into a single connection string?
- Do we need per-slug session isolation in production? (Current code doesn't use slug parameter)
- Should
session-server.aesthetic.computerhandle multiple pieces on different paths?
Status: Draft - Ready for review and implementation Created: 2025-10-28 Last Updated: 2025-10-28