Architecture
Solstice uses a unified single-process Go architecture. A single compiled native binary handles all Telegram Bot API interactions, command parsing, database persistence, queue management, voice chat streaming (via CGo libntgcalls), and the embedded Web Room server.
High-Level Overview
┌─────────────────────────────────────────────────────────────────┐
│ Telegram Cloud │
│ (Bot API + MTProto API) │
└──────────────┬──────────────────────────────────┬───────────────┘
│ Bot API (HTTPS) │ MTProto (TCP)
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ SolsticeIO (Single Go Process) │
│ │
│ ┌───────────────────────┐ ┌─────────────────────────┐ │
│ │ Bot Engine (telebot)│ │ MTProto Client (gogram) │ │
│ │ • Command routing │ │ • Assistant account │ │
│ │ • User permissions │ │ • Join group voice chat │ │
│ │ • i18n localization │ │ • Universal session │ │
│ └───────────┬───────────┘ └────────────┬────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────────────┐ ┌─────────────────────────┐ │
│ │ Action Dispatcher │ │ Voice Engine (CGo) │ │
│ │ • Play, Pause, Skip │◄───────►│ • libntgcalls bindings │ │
│ │ • Queue transitions │ │ • In-process WebRTC │ │
│ │ • Thread-safe locks │ │ • FFmpeg media stream │ │
│ └───────────┬───────────┘ └─────────────────────────┘ │
│ │ │
│ ├──────────────────────────────────┐ │
│ ▼ ▼ │
│ ┌───────────────────────┐ ┌─────────────────────────┐ │
│ │ Embedded Web Server │ │ Storage & Resolvers │ │
│ │ • HTTP & WebSockets │ │ • MongoDB persistence │ │
│ │ • Web Room Mini App │ │ • Upstash Redis cache │ │
│ │ • On-demand sync hub │ │ • InnerTube / yt-dlp │ │
│ └───────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘Why Pure Go with CGo?
| Area | Implementation | Advantage |
|---|---|---|
| Bot API Handling | telebot.v3 | High concurrency, typed handlers, clean middleware |
| Voice Chat Engine | CGo (libntgcalls) | In-process WebRTC streaming without external daemons |
| MTProto Assistant | gogram | Native Go MTProto client; supports Pyrogram, Telethon, & GoGram sessions |
| Web Room & Mini App | Native net/http + //go:embed | Zero CORS, 1 deployment URL, no Node.js runtime needed |
| Audio Extraction | InnerTube + yt-dlp fallback | Fast YouTube resolver with Upstash Redis stream caching |
| Database | go.mongodb.org/mongo-driver | Direct connection pooling with replica-set support |
By embedding libntgcalls directly into Go via CGo, Solstice eliminates the CPU overhead, memory consumption.
Centralized Action Dispatcher
All playback operations (whether triggered from Telegram commands, inline buttons, or the Web Room) funnel through internal/dispatcher/:
Telegram Chat Command ──┐
Telegram Inline Button ─┼──► [Action Dispatcher] ──► [QueueManager]
Web Room WebSocket ─────┘ │ │
▼ ▼
[Role Check & Lock] [CGo Voice Engine]- Per-Chat Mutex Serialization: Every chat has an isolated mutex preventing race conditions during concurrent skips, seeks, or queue additions.
- Role Verification: Actions enforce permission hierarchies (Owner > Sudoer > Group Admin > Song Requester > Member).
- Event Broadcasting: When a track starts or advances, the dispatcher updates both Telegram inline play cards and broadcasts the state change to all connected Web Room clients.
Embedded Web Room Architecture
The embedded web server (internal/web/) runs concurrently with the bot on :PORT (default 8080):
- Static Asset Serving: All frontend assets (
index.html,app.css,app.js) are compiled into the binary via Go 1.16+//go:embed static/*. - On-Demand WebSocket Hub:
- Starts a 1-second sync loop only when the first client connects to a voice chat room.
- Automatically terminates the ticker and deletes room memory when all clients leave (0% idle CPU).
- Interactive Controls: Users can play, pause, seek, adjust volume, reorder, remove, or search and queue new tracks directly from the web interface.
- Synced Lyrics Proxy: Calls LRCLIB with in-memory caching to synchronize lyrics with the voice stream.
Sequence: Playing a Song
User sends: /play Bohemian Rhapsody (or clicks Add in Web Room)
│
▼
┌─── Go Action Dispatcher ───────────────────────────────────┐
│ 1. Validate permissions (admin / requester / everyone) │
│ 2. Search YouTube (InnerTube → HTML scrape → yt-dlp) │
│ 3. Extract direct stream URL (checking Upstash Redis) │
│ 4. Atomic Enqueue in QueueManager │
│ 5. If stream is idle: │
│ a. Initialize VoiceSession via Assistant │
│ b. Join voice chat WebRTC via libntgcalls │
│ c. Start audio stream pipeline │
│ 6. Send Now Playing card to Telegram & broadcast to Web │
└────────────────────────────────────────────────────────────┘
│
│ Stream ends naturally
▼
┌─── CGo libntgcalls Callback ───────────────────────────────┐
│ 1. Engine fires OnStreamEnd │
│ 2. Dispatcher advances queue in-place │
│ 3. If next song exists, streams immediately │
│ 4. If queue empty + autoplay enabled: │
│ Fetches related YouTube Mix track and queues it │
│ 5. If queue empty + autoplay disabled: │
│ Leaves VC after alone timeout │
└────────────────────────────────────────────────────────────┘Concurrency Model
- Goroutines: YouTube searches, stream caching, broadcast messages, and WebSocket pump loops run non-blocking in lightweight goroutines.
- Thread Safety: All state managers (
QueueManager,ActionDispatcher,Hub) use strict read/write mutexes (sync.RWMutex) to guarantee safe concurrent access. - Graceful Shutdown: Intercepts
SIGINTandSIGTERM, cleanly closing WebRTC voice sessions, terminating the web server, and disconnecting MongoDB connections.
