# 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): 1. Browser loads SPA from / (static/) 2. Client connects to /ws for signaling 3. Hub tracks Clients and broadcasts system/user messages 4. WebRTC offers/answers/ICE are relayed via WS signaling 5. 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: ```bash 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).