4.0 KiB
4.0 KiB
RadChat
A lightweight, self-hostable voice and text chat application using WebRTC for media and WebSockets for signaling. RadChat runs as a single binary with a static frontend.
- Backend: Go (Gorilla WebSocket), simple HTTP server with middleware
- Frontend: Single-page app (vanilla JS, HTML, CSS)
- Signaling: JSON messages over WebSocket
- Media: WebRTC peer connections with configurable STUN/TURN
Features
- Join a room and chat with others via audio and text
- Username validation and collision checks
- Emoji picker and message reactions (planned)
- File upload/download (ephemeral)
- Optional gzip and no-cache middlewares
- Configurable origin policy for WebSocket upgrades
Architecture Overview
- server/ package: Hub and Client primitives, websocket upgrader, HTTP middleware
- package main: wires routes, creates a Hub, starts the run loop, and serves static assets
- static/: SPA frontend (index.html, app.js, styles.css, SVG and sounds) handling UI, WebRTC, and signaling
Data flow (high level):
- Browser loads SPA from / (static/)
- Client connects to /ws for signaling
- Hub tracks Clients and broadcasts system/user messages
- WebRTC offers/answers/ICE are relayed via WS signaling
- Optional file uploads via /files and served via /files/{id}
Directory Layout
- main.go: entrypoint; flags and route wiring
- hub.go: HTTP handlers and hub run loop integration
- client.go: read/write pumps for websocket client
- message.go: message envelope used for signaling and system messages
- utils.go: file ops, ids, username validation, URL scheme helpers
- server/: Hub/Client structs, upgrader, middleware
- static/: frontend resources
Getting Started
Prerequisites: Go 1.20+ and a modern browser.
Build and run:
go build -o radchat
./radchat -ip 0.0.0.0 -port 8080 -gzip-enable
Open http://localhost:8080 in your browser.
Common flags:
- -ip: bind address (default localhost)
- -port: port (default 8080)
- -bufsize: channel buffer size for hub broadcast/register/unregister
- -gzip-enable: enable gzip middleware
- -cache-disable: disable caching headers
- -files: directory for uploads (default ./files)
- -files-timeout: seconds until an upload expires (default 3600)
- -origin: allowed Origin host for WS upgrades; leave empty to allow any
Configuration (STUN/TURN)
Edit static/app.js CONFIG.CONN.RTC_CONFIGURATION to set iceServers. By default, public Google STUN is enabled. For restrictive networks, configure your TURN server (e.g., Coturn) and optionally set iceTransportPolicy to "relay".
Development
- Backend hot reload: run using
go run .
- Frontend: static files are served as-is; just refresh the browser
- Lint/docs: prefer GoDoc-style comments for exported symbols (see server/doc.go)
Security Notes
- Set -origin in production to your domain to enforce Origin checks for WS upgrades
- Consider terminating TLS in front (reverse proxy) so GetScheme returns https
- Uploaded files are sanitized by name and stored under ./files; validate trust boundaries
Roadmap / Tasks
FIX/ADJUSTMENT NEEDED
- STYLE: MOBILE: Users list needs a rework
- APP: Emojis should have category picker buttons
- APP: File picker: Add an uploading spinner icon before the message is posted, currently it has a chat alert
- APP: File picker: Drag and drop
FEATURE ADDITIONS
- APP/STYLE: User settings should include a microphone selection, audio selection, and a test functionality for both
- APP/STYLE: Emoji message reactions
- APP/STYLE: Add webcam capability
- APP/STYLE: Add screen sharing
IN PROGRESS FEATURE ADDITIONS
- APP: Self-hosted STUN/TURN
BUG TRACKER [ Latest: #38 ]
- [#38] APP: STUN/TURN issues with browser ICE rejection of offer. Need TURN to function properly?
- Manifests in an inability to receive/send audio from a user.
- Need a way of reporting which STUN/TURN was agreed on.
- Set up my own STUN/TURN with Coturn.
FUTURE
- APP: Add pagination and message history
- APP: See who is in the room before you join
- META: Turn the app into a docker container
License
MIT (or your chosen license).