Skip to content

vixcpp/websocket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

107 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vix WebSocket Module

High-Performance β€’ Async β€’ Typed Protocol β€’ Rooms β€’ Persistent Storage β€’ Prometheus Metrics
Part of the Vix.cpp Runtime β€” offline-first, real-time, P2P-friendly.

The Vix WebSocket module provides a modern, production-ready WebSocket stack for C++20.
It is built for high-performance backend runtimes, chat systems, IoT, dashboards, and offline-first applications such as Softadastra Chat.


✨ Features

πŸ”Œ High-Performance WebSocket Server (Asio + Beast)

  • Fully asynchronous server
  • Uses the Vix ThreadPool executor
  • Optimized dispatch loop
  • Tunable message limits, ping interval, idle timeout
  • Transparent backpressure handling

πŸš€ 1. Quick Start – Minimal WebSocket Server

File: simple_server.cpp

#include <vix/websocket.hpp>

using vix::websocket::Server;

int main() {
    Server ws;

    ws.on_open([](auto& session) {
        session.send_json("chat.system", {"text", "Welcome πŸ‘‹"});
    });

    ws.on_typed_message([](auto& session,
                           const std::string& type,
                           const vix::json::kvs& payload)
    {
        if (type == "chat.message")
            session.broadcast_json("chat.message", payload);
    });

    ws.listen_blocking();
}

Build:

vix run server.cpp

πŸ’¬ 2. Minimal WebSocket Client

File: simple_client.cpp

auto client = Client::create("localhost", "9090", "/");

client->on_open([] {
    std::cout << "Connected!" << std::endl;
});

client->send("chat.message", {"text", "Hello world!"});

Run:

vix run client.cpp

🏠 Room-Based Messaging (join/leave/broadcast)

  • join_room(session, "room")
  • leave_room(session, "room")
  • broadcast_room_json(room, type, payload)
  • Automatic membership tracking
  • Supports millions of messages per channel

πŸ’Ύ Persistent Storage (SQLite + WAL)

Abstract API

struct MessageStore {
    virtual ~MessageStore() = default;

    virtual std::string append(
        const std::string& kind,
        const std::string& room,
        const std::string& type,
        const nlohmann::json& payload) = 0;

    virtual std::vector<StoredMessage> list_by_room(
        const std::string& room,
        size_t limit,
        const std::string& before_id) = 0;

    virtual std::vector<StoredMessage> replay_from(
        const std::string& id) = 0;
};

SQLite Implementation

  • WAL journaling for crash-safe durability
  • Ordered message IDs
  • Fast replay after reconnect
  • Chat history persistence
vix::websocket::SqliteMessageStore store{"chat_messages.db"};
store.append(message);
auto history = store.list_by_room("africa", 50, std::nullopt);

πŸ“Š Prometheus Metrics

Built-in /metrics endpoint:

  • Active WebSocket sessions
  • Total connections
  • Messages in/out
  • Errors

Example:

WebSocketMetrics metrics;

std::thread([&]{
    run_metrics_server(metrics, "0.0.0.0", 9100);
}).detach();

Then scrape:

GET /metrics

πŸ”§ Typed JSON Protocol

Every frame uses:

{
  "type": "chat.message",
  "payload": {
    "user": "Gaspard",
    "room": "africa",
    "text": "Hello!"
  }
}

Helpers:

  • JsonMessage::serialize(type, kvs)
  • ws_kvs_to_nlohmann() for KVS β†’ JSON
  • Consistent server/client protocol

πŸ“¦ Installation

This module is included inside the Vix umbrella:

vix/modules/websocket/

Enable it in CMake:

add_subdirectory(modules/websocket websocket_build)
target_link_libraries(vix INTERFACE vix::websocket)

Include in code:

#include <vix/websocket.hpp>

πŸš€ Basic Usage

1) Start the WebSocket server

vix::websocket::Server ws(cfg, executor);
ws.listen_blocking();

2) Handle connection open

ws.on_open([](Session &s) {
    s.send_text("Welcome!");
});

3) Handle typed events

ws.on_typed_message([](Session&, const std::string &type, const kvs &payload) {
    if (type == "chat.message") {
        // process
    }
});

4) Join a room

ws.join_room(session, "africa");

5) Broadcast JSON frame

ws.broadcast_room_json("africa", "chat.message", {"text", "Hello!"});

🧱 Architecture

modules/websocket/
β”‚
β”œβ”€ include/vix/websocket/
β”‚   β”œβ”€ server.hpp
β”‚   β”œβ”€ client.hpp
β”‚   β”œβ”€ session.hpp
β”‚   β”œβ”€ router.hpp
β”‚   β”œβ”€ protocol.hpp
β”‚   β”œβ”€ config.hpp
β”‚   β”œβ”€ MessageStore.hpp
β”‚   β”œβ”€ SqliteMessageStore.hpp
β”‚   └─ websocket.hpp     # aggregator
β”‚
└── src/
    β”œβ”€ server.cpp
    β”œβ”€ session.cpp
    β”œβ”€ router.cpp
    β”œβ”€ SqliteMessageStore.cpp
    └─ ...

πŸ“‘ Minimal Chat Example

#include <vix/websocket.hpp>
#include <vix/config/Config.hpp>
#include <nlohmann/json.hpp>

int main() {
    vix::config::Config cfg{"config/config.json"};
    auto exec = vix::experimental::make_threadpool_executor(4, 8, 0);

    vix::websocket::Server ws(cfg, exec);
    vix::websocket::SqliteMessageStore store{"chat_messages.db"};

    ws.on_open([](auto& session) {
        session.send_text(JsonMessage::serialize(
            "chat.system",
            {"user", "server", "text", "Welcome!"}
        ));
    });

    ws.on_typed_message([&](auto& session, auto& type, auto& kvs) {
        auto j = ws_kvs_to_nlohmann(kvs);

        if (type == "chat.join") {
            std::string room = j.value("room", "");
            ws.join_room(session, room);

            ws.broadcast_room_json(room, "chat.system",
                {"text", j["user"].get<std::string>() + " joined"});
        }
    });

    ws.listen_blocking();
}

πŸ§ͺ SQLite Inspection Cheatsheet

sqlite3 chat_messages.db
.tables
.schema ws_messages
SELECT id, room, type, substr(payload_json,1,80)
FROM ws_messages LIMIT 5;

βš™οΈ Configuration Example (config.json)

{
  "websocket": {
    "port": 9090,
    "maxMessageSize": 65536,
    "idleTimeout": 600,
    "pingInterval": 30
  }
}

πŸ“‚ Directory Layout Summary

modules/websocket/
β”‚
β”œβ”€ include/vix/websocket/
β”‚   β”œβ”€ client.hpp
β”‚   β”œβ”€ server.hpp
β”‚   β”œβ”€ session.hpp
β”‚   β”œβ”€ router.hpp
β”‚   β”œβ”€ protocol.hpp
β”‚   β”œβ”€ MessageStore.hpp
β”‚   β”œβ”€ SqliteMessageStore.hpp
β”‚   └─ websocket.hpp
β”‚
β”œβ”€ src/
β”‚   β”œβ”€ server.cpp
β”‚   β”œβ”€ session.cpp
β”‚   β”œβ”€ router.cpp
β”‚   β”œβ”€ SqliteMessageStore.cpp
β”‚
└─ examples/
    β”œβ”€ simple_server.cpp
    β”œβ”€ simple_client.cpp

πŸ›£ Roadmap

Feature Status
Dedicated WebSocket server βœ…
Typed JSON protocol βœ…
Rooms (join/leave/broadcast) βœ…
SQLite storage (WAL) βœ…
Replay by ID βœ…
Prometheus /metrics βœ…
Presence (online/offline) Planned
Auto-reconnect client βœ…
Binary frames Planned
Encrypted channels Planned
Batch messages Planned

πŸ“š Documentation

The WebSocket module ships with complete, structured documentation inside the docs/ folder:

Documentation directory:


πŸ“ License

MIT License
Included inside the Vix.cpp repository.


πŸ”₯ Summary

The Vix WebSocket Module is a modern, room-based, typed, persistent and metrics-aware WebSocket runtime for C++20, built for real-time backends, chat systems, IoT, and offline-first apps.

Fast β€’ Reliable β€’ Protocol-Driven β€’ Production-Ready
Part of Vix.cpp β€” the Offline-First, P2P-Ready C++ Backend Runtime.