OddSockets C++ SDK
Modern C++ SDK for embedded systems and IoT devices - JavaScript Pattern Compliant
Overview & Features
The OddSockets C++ SDK provides a powerful, resource-efficient interface for real-time messaging specifically designed for embedded systems and IoT devices while maintaining full compatibility with the JavaScript SDK pattern.
Embedded Optimized
Minimal memory footprint, configurable resource limits, and custom allocator support for embedded systems.
Modern C++17
Clean, type-safe API with RAII principles, smart pointers, and modern async programming.
JS Pattern Compliant
100% architectural compliance with JavaScript SDK - same API patterns and behavior.
High Performance
Optimized for low latency with efficient WebSocket connections and minimal overhead.
Cross-Platform
Works on Linux, Windows, macOS, and embedded platforms with consistent behavior.
Production Ready
Thread-safe, automatic failover, and comprehensive error handling for mission-critical applications.
Installation
# CMakeLists.txt
find_package(OddSockets REQUIRED)
target_link_libraries(your_target OddSockets::oddsockets)
vcpkg install oddsockets-cpp-sdk
# conanfile.txt
[requires]
oddsockets-cpp-sdk/1.0.0
[generators]
cmake
git clone https://github.com/oddsockets/cpp-sdk.git
cd cpp-sdk
mkdir build && cd build
cmake ..
make install
Quick Start
Basic Usage
#include
#include
int main() {
// Create configuration
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.userId = "user123";
// Create client
auto client = std::make_unique(config);
// Connect to platform
auto connectFuture = client->connect();
bool connected = connectFuture.get();
if (connected) {
// Get a channel
auto channel = client->channel("my-channel");
// Subscribe to messages
channel->subscribe([](const std::string& message) {
std::cout << "Received: " << message << std::endl;
});
// Publish a message
auto publishFuture = channel->publish("Hello from C++!");
auto result = publishFuture.get();
if (result.success) {
std::cout << "Message published successfully!" << std::endl;
}
}
return 0;
}
Embedded System Usage
#include
// Custom allocator for embedded systems
class EmbeddedAllocator {
public:
static void* allocate(size_t size) {
return malloc(size);
}
static void deallocate(void* ptr) {
free(ptr);
}
};
int main() {
// Set custom allocator
oddsockets::setCustomAllocator();
// Minimal configuration for embedded systems
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.maxChannels = 4; // Limit channels
config.maxMessageSize = 1024; // Smaller messages
config.enableLogging = false; // Disable logging
config.enableSSL = false; // Disable SSL if not needed
config.enableThreading = false; // Single-threaded mode
auto client = std::make_unique(config);
// Connect and use...
auto connectFuture = client->connect();
bool connected = connectFuture.get();
if (connected) {
auto channel = client->channel("iot-data");
// Process events manually in single-threaded mode
while (client->isConnected()) {
client->processEvents();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
return 0;
}
Async/Await Style (C++20)
#include
#include
// C++20 coroutine support (optional)
oddsockets::task chatExample() {
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
auto client = std::make_unique(config);
// Await connection
bool connected = co_await client->connect();
if (connected) {
auto channel = client->channel("chat");
// Await subscription
bool subscribed = co_await channel->subscribe([](const std::string& msg) {
std::cout << "Message: " << msg << std::endl;
});
if (subscribed) {
// Await publish
auto result = co_await channel->publish("Hello from C++20!");
std::cout << "Published: " << result.success << std::endl;
}
}
}
Configuration
Client Configuration
oddsockets::Config config;
// Required
config.apiKey = "ak_live_1234567890abcdef";
// Optional
config.userId = "user123";
config.managerUrl = "https://manager.oddsockets.com";
// Connection Options
config.autoConnect = true;
config.reconnectAttempts = 5;
config.reconnectDelayMs = 1000;
config.connectionTimeoutMs = 10000;
config.messageTimeoutMs = 5000;
// Resource Limits (for embedded systems)
config.maxChannels = 32;
config.maxMessageSize = 32768; // 32KB
// SSL/TLS Options
config.enableSsl = true;
config.sslVerifyPeer = true;
config.caCertPath = "/path/to/ca-cert.pem";
// Logging
config.logLevel = oddsockets::LogLevel::Info;
config.logCallback = [](oddsockets::LogLevel level, const std::string& message) {
std::cout << "[" << oddsockets::logLevelToString(level) << "] " << message << std::endl;
};
// Callbacks
config.connectionCallback = [](oddsockets::ConnectionState state) {
std::cout << "Connection: " << oddsockets::connectionStateToString(state) << std::endl;
};
config.errorCallback = [](oddsockets::ErrorCode error, const std::string& message) {
std::cout << "Error: " << message << std::endl;
};
Channel Options
// Subscribe options
oddsockets::SubscribeOptions subscribeOpts;
subscribeOpts.maxHistory = 100;
subscribeOpts.retainHistory = true;
subscribeOpts.enablePresence = true;
channel->subscribe(callback, subscribeOpts);
// Publish options
oddsockets::PublishOptions publishOpts;
publishOpts.ttlSeconds = 3600;
publishOpts.metadata = R"({"priority": "high"})";
publishOpts.storeInHistory = true;
channel->publish("Hello, World!", publishOpts);
// History options
oddsockets::HistoryOptions historyOpts;
historyOpts.count = 50;
historyOpts.startTime = "2024-01-01T00:00:00Z";
historyOpts.endTime = "2024-01-02T00:00:00Z";
auto historyFuture = channel->getHistory(historyOpts);
Embedded Systems & IoT
The C++ SDK is specifically optimized for embedded systems and IoT devices with minimal resource requirements:
Memory Management
Custom allocators, memory tracking, and configurable limits for resource-constrained environments.
Single-Threaded Mode
Optional single-threaded operation for systems without threading support.
No-Exception Mode
Error code-based error handling for systems that don't support exceptions.
Configurable Features
Disable SSL, logging, or other features to reduce binary size and memory usage.
Memory Optimization
// Custom memory allocator
class PoolAllocator {
static constexpr size_t POOL_SIZE = 64 * 1024; // 64KB pool
static uint8_t pool[POOL_SIZE];
static size_t offset;
public:
static void* allocate(size_t size) {
if (offset + size > POOL_SIZE) return nullptr;
void* ptr = pool + offset;
offset += size;
return ptr;
}
static void deallocate(void* ptr) {
// Pool allocator - no individual deallocation
}
static void reset() {
offset = 0;
}
};
// Set custom allocator
oddsockets::setCustomAllocator();
// Monitor memory usage
size_t allocated, peak;
oddsockets::getMemoryStats(&allocated, &peak);
std::cout << "Memory: " << allocated << " bytes (peak: " << peak << ")" << std::endl;
Minimal Configuration
// Minimal embedded configuration
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
// Resource limits
config.maxChannels = 2; // Only 2 channels
config.maxMessageSize = 512; // 512 byte messages
config.connectionTimeoutMs = 5000; // 5 second timeout
// Disable features
config.enableLogging = false; // No logging
config.enableSSL = false; // No SSL (if not needed)
config.enableThreading = false; // Single-threaded
config.enableExceptions = false; // No exceptions
// Minimal callbacks
config.errorCallback = [](oddsockets::ErrorCode error, const std::string&) {
// Handle error codes instead of exceptions
if (error != oddsockets::ErrorCode::Success) {
// Handle error...
}
};
Platform Support
Supported Platforms
- Linux (ARM, x86, x64)
- FreeRTOS
- Zephyr RTOS
- Arduino (ESP32, ESP8266)
- Raspberry Pi
- STM32
- Nordic nRF
- Windows IoT
Requirements
- C++17 compiler
- 32KB+ RAM (configurable)
- TCP/IP stack
- Optional: SSL/TLS support
- Optional: Threading support
Examples
Explore comprehensive examples demonstrating the OddSockets C++ SDK in action:
Performance & Compatibility
OddSockets C++ SDK delivers superior performance optimized for embedded systems:
Compiler Support
- GCC 7+ (C++17)
- Clang 6+ (C++17)
- MSVC 2019+ (C++17)
- ARM GCC (embedded)
Build Systems
- CMake 3.12+
- vcpkg
- Conan
- Arduino IDE
Platform Integrations
The OddSockets C++ SDK works seamlessly across multiple platforms and environments:
Arduino (ESP32)
#include
#include
const char* ssid = "your-wifi-ssid";
const char* password = "your-wifi-password";
std::unique_ptr client;
void setup() {
Serial.begin(115200);
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
// Configure OddSockets for ESP32
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.maxChannels = 2;
config.maxMessageSize = 1024;
config.enableLogging = false;
client = std::make_unique(config);
// Connect and subscribe
auto connectFuture = client->connect();
if (connectFuture.get()) {
auto channel = client->channel("sensor-data");
channel->subscribe([](const std::string& message) {
Serial.println(("Received: " + message).c_str());
});
}
}
void loop() {
// Process events
client->processEvents();
// Send sensor data every 10 seconds
static unsigned long lastSend = 0;
if (millis() - lastSend > 10000) {
auto channel = client->channel("sensor-data");
String sensorData = "{\"temperature\": " + String(random(20, 30)) +
", \"humidity\": " + String(random(40, 60)) + "}";
channel->publish(sensorData.c_str());
lastSend = millis();
}
delay(10);
}
Raspberry Pi
#include
#include
#include
#include
const int LED_PIN = 18;
const int BUTTON_PIN = 24;
int main() {
// Initialize WiringPi
wiringPiSetupGpio();
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
pullUpDnControl(BUTTON_PIN, PUD_UP);
// Configure OddSockets
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.userId = "raspberry-pi-001";
auto client = std::make_unique(config);
// Connect
auto connectFuture = client->connect();
if (!connectFuture.get()) {
std::cerr << "Failed to connect!" << std::endl;
return 1;
}
auto controlChannel = client->channel("device-control");
auto statusChannel = client->channel("device-status");
// Subscribe to control commands
controlChannel->subscribe([](const std::string& message) {
std::cout << "Control command: " << message << std::endl;
if (message == "LED_ON") {
digitalWrite(LED_PIN, HIGH);
} else if (message == "LED_OFF") {
digitalWrite(LED_PIN, LOW);
}
});
// Monitor button and send status
bool lastButtonState = HIGH;
while (client->isConnected()) {
client->processEvents();
// Check button state
bool buttonState = digitalRead(BUTTON_PIN);
if (buttonState != lastButtonState && buttonState == LOW) {
statusChannel->publish("BUTTON_PRESSED");
std::cout << "Button pressed!" << std::endl;
}
lastButtonState = buttonState;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
return 0;
}
FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include
// FreeRTOS allocator
class FreeRTOSAllocator {
public:
static void* allocate(size_t size) {
return pvPortMalloc(size);
}
static void deallocate(void* ptr) {
vPortFree(ptr);
}
};
std::unique_ptr client;
QueueHandle_t messageQueue;
void oddSocketsTask(void* parameters) {
// Set FreeRTOS allocator
oddsockets::setCustomAllocator();
// Configure for FreeRTOS
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.maxChannels = 1;
config.maxMessageSize = 256;
config.enableLogging = false;
config.enableThreading = false; // Use FreeRTOS tasks instead
client = std::make_unique(config);
// Connect
auto connectFuture = client->connect();
if (connectFuture.get()) {
auto channel = client->channel("freertos-device");
channel->subscribe([](const std::string& message) {
// Send message to queue for processing by other tasks
const char* msg = message.c_str();
xQueueSend(messageQueue, &msg, portMAX_DELAY);
});
// Main event loop
while (1) {
client->processEvents();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
vTaskDelete(NULL);
}
void sensorTask(void* parameters) {
while (1) {
// Read sensor data
float temperature = readTemperatureSensor();
float humidity = readHumiditySensor();
// Create JSON message
char buffer[128];
snprintf(buffer, sizeof(buffer),
"{\"temp\": %.2f, \"humidity\": %.2f}",
temperature, humidity);
// Publish sensor data
if (client && client->isConnected()) {
auto channel = client->channel("freertos-device");
channel->publish(std::string(buffer));
}
vTaskDelay(pdMS_TO_TICKS(30000)); // 30 seconds
}
}
int main() {
// Create message queue
messageQueue = xQueueCreate(10, sizeof(char*));
// Create tasks
xTaskCreate(oddSocketsTask, "OddSockets", 4096, NULL, 2, NULL);
xTaskCreate(sensorTask, "Sensor", 2048, NULL, 1, NULL);
// Start scheduler
vTaskStartScheduler();
return 0;
}
Cross-Platform Desktop
#include
#include
#include
#include
#ifdef _WIN32
#include
#else
#include
#endif
class CrossPlatformApp {
private:
std::unique_ptr client;
std::atomic running{true};
public:
void run() {
// Configure client
oddsockets::Config config;
config.apiKey = "ak_live_1234567890abcdef";
config.userId = getSystemId();
// Platform-specific optimizations
#ifdef __EMBEDDED__
config.maxChannels = 2;
config.enableLogging = false;
#else
config.maxChannels = 10;
config.enableLogging = true;
#endif
client = std::make_unique(config);
// Connect
auto connectFuture = client->connect();
if (!connectFuture.get()) {
std::cerr << "Failed to connect!" << std::endl;
return;
}
std::cout << "Connected to OddSockets!" << std::endl;
// Setup channels
auto chatChannel = client->channel("cross-platform-chat");
auto statusChannel = client->channel("system-status");
// Subscribe to chat
chatChannel->subscribe([this](const std::string& message) {
std::cout << "Chat: " << message << std::endl;
});
// Send periodic status updates
std::thread statusThread([this, statusChannel]() {
while (running) {
std::string status = getSystemStatus();
statusChannel->publish(status);
std::this_thread::sleep_for(std::chrono::seconds(60));
}
});
// Main loop
std::string input;
while (running && std::getline(std::cin, input)) {
if (input == "/quit") {
running = false;
break;
}
chatChannel->publish(input);
}
statusThread.join();
client->disconnect();
}
private:
std::string getSystemId() {
#ifdef _WIN32
char computerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = sizeof(computerName);
GetComputerNameA(computerName, &size);
return std::string(computerName);
#else
char hostname[256];
gethostname(hostname, sizeof(hostname));
return std::string(hostname);
#endif
}
std::string getSystemStatus() {
// Platform-specific system info
return R"({"platform": ")" + getPlatformName() + R"(", "uptime": )" +
std::to_string(getUptime()) + "}";
}
std::string getPlatformName() {
#ifdef _WIN32
return "Windows";
#elif __linux__
return "Linux";
#elif __APPLE__
return "macOS";
#else
return "Unknown";
#endif
}
long getUptime() {
#ifdef _WIN32
return GetTickCount64() / 1000;
#else
return time(nullptr);
#endif
}
};
int main() {
CrossPlatformApp app;
app.run();
return 0;
}