Skip to content

Latest commit

 

History

History
359 lines (257 loc) · 8.38 KB

File metadata and controls

359 lines (257 loc) · 8.38 KB

Bindings Guide

mtwRequest's core is written in Rust for maximum performance. Language bindings make it accessible from Node.js, Python, PHP, and the browser (WASM). This guide covers using mtwRequest from each language.


Architecture

+-------------------+
| mtwRequest Core   |  (Rust)
| (crates/*)        |
+---+---+---+---+---+
    |   |   |   |
    v   v   v   v
 NAPI  PyO3 FFI WASM
  |     |    |    |
Node  Python PHP Browser

Source: bindings/node/, bindings/python/, bindings/php/, bindings/wasm/


Using mtwRequest from Node.js

The Node.js binding uses NAPI-RS for native performance without the overhead of a separate process.

Installation

npm install mtw-request

Creating a Server

import { MtwServer, MtwConfig } from 'mtw-request';

const server = new MtwServer({
  host: '127.0.0.1',
  port: 8080,
  transport: {
    websocket: { path: '/ws', pingInterval: 30 },
  },
});

// Register event handlers
server.onConnect((connId, metadata) => {
  console.log(`Connected: ${connId} from ${metadata.remoteAddr}`);
});

server.onDisconnect((connId, reason) => {
  console.log(`Disconnected: ${connId} (${reason})`);
});

server.onMessage((connId, message) => {
  console.log(`Message from ${connId}:`, message.type, message.payload);

  // Echo back
  if (message.type === 'request') {
    server.send(connId, {
      type: 'response',
      refId: message.id,
      payload: message.payload,
    });
  }
});

// Start
await server.start();
console.log('Server running on ws://127.0.0.1:8080/ws');

Using Channels

// Create channels
server.createChannel('chat.general', { maxMembers: 100, history: 50 });
server.createChannel('notifications', { history: 10 });

// Subscribe/publish
server.subscribe('chat.general', connId);
server.publish('chat.general', { user: 'alice', text: 'Hello!' });

Loading Config from TOML

const server = await MtwServer.fromConfig('./mtw.toml');
await server.start();

Using mtwRequest from Python

The Python binding uses PyO3 to expose Rust functionality as a native Python module.

Installation

pip install mtw-request

Creating a Server

import mtw_request
import asyncio

async def main():
    server = mtw_request.Server(
        host="127.0.0.1",
        port=8080,
    )

    @server.on_connect
    async def handle_connect(conn_id, metadata):
        print(f"Connected: {conn_id} from {metadata.remote_addr}")

    @server.on_disconnect
    async def handle_disconnect(conn_id, reason):
        print(f"Disconnected: {conn_id} ({reason})")

    @server.on_message
    async def handle_message(conn_id, message):
        print(f"Message from {conn_id}: {message.type}")

        if message.type == "request":
            await server.send(conn_id, {
                "type": "response",
                "ref_id": message.id,
                "payload": message.payload,
            })

    # Create channels
    server.create_channel("chat.general", max_members=100, history=50)

    await server.start()
    print("Server running on ws://127.0.0.1:8080/ws")

    # Run until interrupted
    await server.run_forever()

asyncio.run(main())

Client Usage

import mtw_request
import asyncio

async def main():
    conn = mtw_request.Connection("ws://localhost:8080/ws")
    await conn.connect()

    # Subscribe
    await conn.subscribe("chat.general")

    # Publish
    await conn.publish("chat.general", {"text": "Hello from Python!"})

    # Request/response
    response = await conn.request({"action": "get_users"}, timeout=30)
    print(f"Users: {response.payload}")

    # Listen for messages
    @conn.on_message
    def handle(msg):
        print(f"Received: {msg}")

    # AI agent
    async for chunk in conn.agent_stream("assistant", "What is mtwRequest?"):
        print(chunk.text, end="", flush=True)
    print()

    await conn.close()

asyncio.run(main())

Loading Config

server = mtw_request.Server.from_config("mtw.toml")

Using mtwRequest from PHP

The PHP binding uses FFI (Foreign Function Interface) to call Rust functions directly.

Installation

composer require mtw/request

Creating a Server

<?php
use Mtw\Request\Server;
use Mtw\Request\Channel;

$server = new Server([
    'host' => '127.0.0.1',
    'port' => 8080,
]);

$server->onConnect(function (string $connId, array $metadata) {
    echo "Connected: {$connId}\n";
});

$server->onMessage(function (string $connId, array $message) use ($server) {
    echo "Message from {$connId}: {$message['type']}\n";

    if ($message['type'] === 'request') {
        $server->send($connId, [
            'type' => 'response',
            'ref_id' => $message['id'],
            'payload' => $message['payload'],
        ]);
    }
});

// Create channels
$server->createChannel('chat.general', ['maxMembers' => 100, 'history' => 50]);

$server->start();
echo "Server running on ws://127.0.0.1:8080/ws\n";
$server->run();

Client Usage

<?php
use Mtw\Request\Connection;

$conn = new Connection('ws://localhost:8080/ws');
$conn->connect();

$conn->subscribe('chat.general');
$conn->publish('chat.general', ['text' => 'Hello from PHP!']);

$response = $conn->request(['action' => 'get_users'], timeout: 30);
var_dump($response);

$conn->close();

Using mtwRequest in the Browser (WASM)

The WASM binding compiles the Rust core to WebAssembly, enabling high-performance message processing directly in the browser.

Installation

npm install @mtw/wasm

Usage

import init, { WasmMtwConnection } from '@mtw/wasm';

// Initialize the WASM module
await init();

// Create a connection (uses the browser's native WebSocket)
const conn = new WasmMtwConnection('ws://localhost:8080/ws');

conn.onConnected((meta) => {
  console.log('Connected via WASM:', meta.connId);
});

conn.onMessage((msg) => {
  // Message is already decoded in WASM (faster than JS JSON.parse for large payloads)
  console.log('Message:', msg);
});

await conn.connect();

// Encode/decode with WASM performance
conn.subscribe('chat.general');
conn.publish('chat.general', { text: 'Hello from WASM!' });

When to Use WASM vs. Pure JS

Scenario Recommendation
Simple chat/messaging Use @mtw/client (pure JS)
High-frequency binary data (3D, audio) Use @mtw/wasm
Large JSON payloads Use @mtw/wasm (faster parsing)
Bundle size sensitive Use @mtw/client (smaller)
Server-side Node.js Use mtw-request (native binding)

Performance Comparison

The Rust core provides significant performance advantages over pure JavaScript implementations, particularly for WebSocket-heavy workloads.

WebSocket Message Throughput

Implementation Messages/sec Latency (p99)
Rust (native server) ~500,000 <1ms
Node.js (NAPI binding) ~200,000 <2ms
Python (PyO3 binding) ~100,000 <5ms
Pure Node.js (ws) ~50,000 <10ms
WASM (browser) ~150,000 <3ms

JSON Encoding/Decoding

Implementation Operations/sec
Rust (serde_json) ~2,000,000
WASM (serde_json) ~800,000
Node.js (native) ~500,000
Python (json) ~200,000

Binary Frame Processing

Implementation Frames/sec
Rust (native) ~5,000,000
WASM ~2,000,000
Node.js (Buffer) ~1,000,000

These numbers demonstrate why using the Rust bindings rather than reimplementing protocol logic in each language provides both performance and correctness benefits.


Binding Status

Binding Source Status
Node.js (NAPI-RS) bindings/node/ Planned (Phase 4)
Python (PyO3) bindings/python/ Planned (Phase 4)
PHP (FFI) bindings/php/ Planned (Phase 4)
WASM (wasm-bindgen) bindings/wasm/ Planned (Phase 4)

The binding directories contain scaffold files. Full implementations are coming in Phase 4 of the project roadmap. In the meantime, you can use the @mtw/client TypeScript package (pure JS) for browser and Node.js connectivity.


Next Steps