v0.1 · Go Framework

Build Real-Time Apps
Blazingly Fast.

Mana is a batteries-included Go framework for WebSocket messaging, WebRTC signaling, rooms, E2EE, and plug-and-play SQL persistence. Ship your chat app in hours, not weeks.

Get Started
go get github.com/Aswanidev-vs/mana
3DB Drivers
6Chat Offers
~25Packages
100%Pure Go

Getting Started

Mana is a Go framework for building real-time communication applications — chat, video calling, collaboration tools, and more. It provides WebSocket management, room orchestration, WebRTC signaling, E2EE key exchange, and plug-and-play SQL persistence out of the box.

Installation

go get github.com/Aswanidev-vs/mana

Requirements

  • Go 1.21 or later
  • No CGo required (pure Go SQLite via modernc.org/sqlite)

Quick Start

The simplest Mana server — a fully functional WebSocket messaging backend in 15 lines:

package main

import (
    "log"
    mana "github.com/Aswanidev-vs/mana"
    "github.com/Aswanidev-vs/mana/core"
)

func main() {
    app := mana.New(core.Config{
        Port:           8080,
        AllowedOrigins: []string{"*"},
        EnableRTC:      true,
        EnableE2EE:     true,
    })

    app.OnMessage(func(msg core.Message) {
        log.Printf("[%s] %s → %s", msg.RoomID, msg.SenderID, string(msg.Payload))
    })

    log.Fatal(app.Start())
}

Run it: go run main.go. Connect any WebSocket client to ws://localhost:8080/ws.

Architecture

Mana's architecture is modular — each concern lives in its own package, orchestrated by the central App struct in app.go.

core/Shared types, config, and interfaces
ws/WebSocket handler and transport
signaling/Signal hub and message router
room/Room and session management
rtc/WebRTC manager, SFU, simulcast
e2ee/X3DH key exchange and crypto
auth/JWT, RBAC, rate limiting, accounts
storage/Message persistence (JSON + SQL)
storage/db/Plug-and-play database drivers
social/Profiles, contacts, blocking
settings/User preferences store
notification/User-targeted push alerts
cluster/Redis/NATS pub-sub fanout
observ/Logging, metrics, health, tracing
product/Conversations, devices, attachments

Configuration

All settings are defined in core.Config. Use core.DefaultConfig() for sensible defaults then override what you need.

FieldTypeDefaultDescription
Portint8080HTTP listen port
Hoststring"0.0.0.0"Bind address
EnableAuthboolfalseEnable JWT auth on WebSocket
JWTSecretstring""JWT signing secret (≥32 bytes for prod)
JWTExpiryDuration24hToken validity duration
EnableRTCboolfalseEnable WebRTC signaling
EnableE2EEboolfalseEnable E2EE key exchange
AllowedOrigins[]string[]WebSocket CORS origins
MaxMessageSizeint6464KBMax WS message bytes
RateLimitPerSecondint100Messages/sec per connection
DatabaseDriverstring"sqlite""sqlite", "postgres", or "mysql"
DatabaseDSNstring"mana.db"Connection string or file path
DatabaseTablePrefixstring""Table prefix (e.g. "mana_")
PubSubBackendstring"""memory", "redis", or "nats"
EnableTracingboolfalseOpenTelemetry tracing
EnableTLSboolfalseHTTPS/WSS mode

Event Hooks

Mana exposes lifecycle hooks so your application logic reacts to real-time events without touching framework internals.

app.OnMessage(func(msg core.Message) {
    // Fires after every message is routed and stored
})

app.OnUserJoin(func(roomID string, user core.User) {
    // Fires when a user joins a room
})

app.OnUserLeave(func(roomID string, user core.User) {
    // Fires when a user disconnects from a room
})

app.OnCallStart(func(event core.CallEvent) {
    // Fires when a WebRTC call begins
})

app.OnCallEnd(func(event core.CallEvent) {
    // Fires when a WebRTC call ends
})

app.OnSignal(core.SignalTyping, func(sig core.Signal) {
    // React to any signal type (typing, presence, etc.)
})

// Logic hooks (context-aware, for business logic)
app.OnAccountCreated(func(ctx context.Context, user core.User) { })
app.OnMessageStored(func(ctx context.Context, msg core.Message) { })

Types & Signals

Core types used throughout the framework:

// Message — the fundamental unit of communication
type Message struct {
    ID        string    `json:"id"`
    Sequence  uint64    `json:"sequence,omitempty"`
    Type      string    `json:"type"`
    RoomID    string    `json:"room_id,omitempty"`
    SenderID  string    `json:"sender_id"`
    TargetID  string    `json:"target_id,omitempty"`
    Payload   []byte    `json:"payload"`
    Timestamp time.Time `json:"timestamp"`
    AckID     string    `json:"ack_id,omitempty"`
}

// Signal — WebRTC and signaling events
type Signal struct {
    Type      SignalType  `json:"type"`
    From      string      `json:"from"`
    To        string      `json:"to,omitempty"`
    RoomID    string      `json:"room_id,omitempty"`
    Payload   []byte      `json:"payload,omitempty"`
    SDP       string      `json:"sdp,omitempty"`
    Candidate interface{} `json:"candidate,omitempty"`
}

Signal Types

offeranswercandidate joinleavemessage typingkey_exchangecall_start call_endmutecamera_toggle screen_share_startscreen_share_stop message_syncsync_request ice_restartnetwork_change active_speakertrack_added

Features

💬

Messaging

1:1 and group messaging with acknowledgments, sequence tracking, cursor-based offline sync, and delivery receipts.

Advanced E2EE

Full X3DH + Double Ratchet implementation. Forward secrecy and self-healing handshakes out of the box. Learn More →

🔐

Authentication

JWT auth with RBAC, rate limiting, origin controls, and a built-in SQL account store with bcrypt hashing.

🗄️

Plug-and-Play DB

Point at SQLite, PostgreSQL, or MySQL — Mana auto-creates tables for messaging, identity, social, and settings.

📹

WebRTC

SFU-based architecture with offer/answer negotiation, ICE management, simulcast, congestion control, and jitter buffering.

🔒

E2EE

X3DH-style key exchange, Curve25519 key pairs, HKDF derivation, and AES-256-GCM encryption primitives.

🌐

Clustering

Stateless horizontal scaling via Redis or NATS pub-sub backends for multi-node signal fanout.

🏠

Rooms

Dynamic room creation, member tracking, and multi-device session management with per-device cursor sync.

📊

Observability

Structured logging, Prometheus-style metrics, health endpoints, and OpenTelemetry tracing with in-memory inspection.

Messaging

Messages are automatically persisted, sequenced, and synced across devices. The framework handles offline delivery and cursor-based reconnect replay.

Store Interface

type MessageStore interface {
    SaveMessage(ctx context.Context, msg Message, recipients []string) (Message, error)
    MarkDelivered(ctx context.Context, messageID, userID string) error
    PendingForUser(ctx context.Context, userID string) []Message
    SyncForUserSince(ctx context.Context, userID string, since time.Time) []Message
    SyncForUserAfterSequence(ctx context.Context, userID string, after uint64, limit int) ([]Message, bool)
    LatestSequenceForUser(ctx context.Context, userID string) uint64
}

Client Sync Protocol

Reconnecting clients send a sync_request with their last-known cursor. Mana responds with a DeviceSyncBatch containing any new messages and a pagination cursor.

// Client → Server
{"type": "sync_request", "cursor": 42, "limit": 50}

// Server → Client
{"type": "message_sync", "cursor": 87, "has_more": false, "messages": [...]}

Rooms

The room package manages room lifecycle, member tracking, and multi-device sessions.

// Access the room manager
rm := app.RoomManager()

// Rooms are automatically created when users join via signaling
// You can also access rooms programmatically:
rooms := rm.List()        // all active rooms
room, err := rm.Get(id)   // get a specific room
members := room.Members() // list members

Authentication

Enable auth with EnableAuth: true. Mana provides JWT token generation/validation, RBAC, rate limiting, and a built-in SQL account store.

cfg := core.DefaultConfig()
cfg.EnableAuth = true
cfg.JWTSecret = "your-secret-key-at-least-32-bytes"
cfg.JWTIssuer = "my-app"

app := mana.New(cfg)

// Generate tokens
token, _ := app.JWTAuth().GenerateToken(userID, username, auth.RoleUser)

// Validate tokens
claims, err := app.JWTAuth().ValidateToken(token)

// Account Store (auto-created with DatabaseDSN)
app.AccountStore().CreateUser(ctx, "alice", "password123")
userID, err := app.AccountStore().Authenticate(ctx, "alice", "password123")

RBAC Roles

adminmoderatoruserguest

Database — Plug-and-Play Batteries

Mana's database layer uses standard database/sql with driver packages for SQLite, PostgreSQL, and MySQL. Point it at a DSN and the framework auto-creates all tables.

Option A: Framework-Managed DSN

cfg := core.DefaultConfig()
cfg.DatabaseDriver = db.SQLite        // or db.Postgres, db.MySQL
cfg.DatabaseDSN    = "data/app.db"    // or your connection string
cfg.DatabaseTablePrefix = "mana_"     // optional: prefix all tables

app := mana.New(cfg)
// AccountStore, MessageStore, ProfileStore, ContactStore, PreferenceStore
// are all automatically wired and ready.

Option B: Bring Your Own *sql.DB

// Connect with your own driver
db, _ := sql.Open("pgx", "postgres://user:pass@localhost/mydb")

app := mana.New(cfg)
app.WithDatabase(db, manadb.Postgres)
// Mana uses YOUR connection pool — shared transactions are possible!

Auto-Created Stores

StoreInterfaceTables Created
AccountStorecore.AccountStoreaccounts
MessageStorecore.MessageStoremessages, delivery
ProfileStorecore.ProfileStoreprofiles
ContactStorecore.ContactStorecontacts, blocks
PreferenceStorecore.PreferenceStorepreferences

Supported Drivers

SQLite

Pure Go via modernc.org/sqlite. No CGo. WAL mode enabled by default.

cfg.DatabaseDriver = db.SQLite

PostgreSQL

High-performance via pgx/v5. Production-ready connection pooling.

cfg.DatabaseDriver = db.Postgres

MySQL

Via go-sql-driver/mysql. Full UPSERT and transaction support.

cfg.DatabaseDriver = db.MySQL

WebRTC

Mana includes a full SFU-oriented WebRTC stack with offer/answer signaling, ICE candidate exchange, simulcast layer selection, congestion control, and jitter buffering.

cfg.EnableRTC = true
cfg.STUNServers = []string{"stun:stun.l.google.com:19302"}
cfg.TURNServers = []core.ICEServerConfig{{
    URLs:       []string{"turn:turn.example.com:3478"},
    Username:   "user",
    Credential: "pass",
}}
cfg.ICETransportPolicy = "all" // or "relay"

app := mana.New(cfg)

app.OnCallStart(func(e core.CallEvent) {
    log.Printf("Call started: %s → %s", e.Caller, e.Callee)
})
app.OnCallEnd(func(e core.CallEvent) {
    log.Printf("Call ended in room %s", e.RoomID)
})

E2EE — End-to-End Encryption

The e2ee package provides X3DH-style key exchange, Curve25519 key generation, HKDF key derivation, and AES-256-GCM authenticated encryption.

cfg.EnableE2EE = true
app := mana.New(cfg)

// Key exchange is managed automatically via signaling
// Clients register their public keys:
app.KeyExchange().StorePublicKey("alice", alicePublicKey)
pub, ok := app.KeyExchange().GetPublicKey("alice")

Notifications

The notification hub delivers targeted alerts to specific users across all their connected devices.

app.NotificationHub().Send("user-123", core.Notification{
    Title: "New Message",
    Body:  "You have a new message from Alice",
    Data:  map[string]interface{}{"room_id": "chat-room"},
})

Clustering

Scale horizontally with Redis or NATS for multi-node signal fan-out. Each node broadcasts signals to the pub-sub backend, and all subscribed nodes forward them to local peers.

// Redis
cfg.PubSubBackend = "redis"
cfg.RedisAddr     = "localhost:6379"
cfg.RedisChannel  = "mana.cluster"

// NATS
cfg.PubSubBackend = "nats"
cfg.NATSURL       = "nats://127.0.0.1:4222"
cfg.NATSSubject   = "mana.cluster"

cfg.ClusterNodeID = "node-1" // unique per instance

Observability

Built-in structured logging, metrics, health checks, and OpenTelemetry tracing.

Endpoints

PathDescription
GET /healthHealth check with room/peer/session counts
GET /metricsPrometheus-style metrics (connections, messages, bytes)
GET /debug/tracesIn-memory OpenTelemetry trace inspection
cfg.EnableTracing    = true
cfg.TraceSampleRatio = 1.0
cfg.ServiceName      = "my-chat-app"
cfg.ServiceVersion   = "1.0.0"

Dependency Injection

Override any store with your own implementation using the With* setters:

app.WithMessageStore(myCustomStore)
app.WithAccountStore(myCustomAuth)
app.WithProfileStore(myCustomProfiles)
app.WithContactStore(myCustomContacts)
app.WithDeviceStore(myCustomDevices)
app.WithPreferenceStore(myCustomPrefs)

Shared Transactions

Because Mana can share your *sql.DB, you can run your own business logic and Mana operations inside a single ACID transaction.

tx, _ := myDB.BeginTx(ctx, nil)

// 1. Your business logic
tx.ExecContext(ctx, "UPDATE users SET coins = coins - 10 WHERE id = $1", userID)

// 2. Inject the tx into context so Mana uses it
txCtx := manadb.WithTx(ctx, tx)

// 3. Mana's insert runs inside YOUR transaction
app.MessageStore().SaveMessage(txCtx, core.Message{
    Type:    "receipt",
    Payload: []byte("You spent 10 coins!"),
}, []string{userID})

// 4. Commit or rollback — both operations are atomic
tx.Commit()

Working Examples

Explore production-grade implementations. Each example opens in a dedicated page for deep study.

Component Accessors

Access any framework component via the App instance:

MethodReturnsDescription
app.Mux()*http.ServeMuxHTTP router — add your own endpoints
app.JWTAuth()*auth.JWTAuthToken generation and validation
app.RoomManager()*room.ManagerRoom lifecycle management
app.SignalHub()*signaling.HubWebSocket signal routing
app.RTCManager()*rtc.ManagerWebRTC peer connection management
app.KeyExchange()*e2ee.HandshakeManagerE2EE public key store
app.MessageStore()core.MessageStoreMessage persistence
app.AccountStore()core.AccountStoreUser accounts and auth
app.ProfileStore()core.ProfileStoreUser profiles
app.ContactStore()core.ContactStoreContacts and blocking
app.DBBackend()*db.BackendRaw database backend access
app.NotificationHub()*notification.HubPush notification delivery
app.Metrics()*observ.MetricsRuntime metrics counters