diff --git a/README.md b/README.md
index be3f1ce..be22435 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# NATSBridge
+# NATSBridge - Cross-Platform Bi-Directional Data Bridge
-A high-performance, bi-directional data bridge for **Julia** applications using NATS (Core & JetStream), implementing the Claim-Check pattern for large payloads.
+A high-performance, bi-directional data bridge for **Julia, JavaScript, Python, and MicroPython** applications using NATS (Core & JetStream), implementing the Claim-Check pattern for large payloads.
[](https://opensource.org/licenses/MIT)
[](https://nats.io)
@@ -10,6 +10,7 @@ A high-performance, bi-directional data bridge for **Julia** applications using
## Table of Contents
- [Overview](#overview)
+- [Cross-Platform Support](#cross-platform-support)
- [Features](#features)
- [Architecture](#architecture)
- [Installation](#installation)
@@ -17,7 +18,7 @@ A high-performance, bi-directional data bridge for **Julia** applications using
- [API Reference](#api-reference)
- [Payload Types](#payload-types)
- [Transport Strategies](#transport-strategies)
-- [Examples](#examples)
+- [Cross-Platform Examples](#cross-platform-examples)
- [Testing](#testing)
- [License](#license)
@@ -25,7 +26,7 @@ A high-performance, bi-directional data bridge for **Julia** applications using
## Overview
-NATSBridge enables seamless communication for Julia applications through NATS, with intelligent transport selection based on payload size:
+NATSBridge enables seamless communication across multiple platforms through NATS, with intelligent transport selection based on payload size:
| Transport | Payload Size | Method |
|-----------|--------------|--------|
@@ -36,14 +37,40 @@ NATSBridge enables seamless communication for Julia applications through NATS, w
- **Chat Applications**: Text, images, audio, video in a single message
- **File Transfer**: Efficient transfer of large files using claim-check pattern
-- **Streaming Data**: Sensor data, telemetry, and analytics pipelines
+- **IoT/Embedded**: Sensor data, telemetry, and analytics pipelines (MicroPython)
+- **Cross-Platform Communication**: Interoperability between Julia, JavaScript, Python, and MicroPython systems
+---
+
+## Cross-Platform Support
+
+| Platform | Implementation | Features |
+|----------|----------------|----------|
+| **Julia** | [`src/NATSBridge.jl`](src/NATSBridge.jl) | Full feature set, Arrow IPC, multiple dispatch |
+| **JavaScript** | [`src/natbridge.js`](src/natbridge.js) | Node.js & browser, async/await |
+| **Python** | [`src/natbridge.py`](src/natbridge.py) | Desktop Python, asyncio, type hints |
+| **MicroPython** | [`src/natbridge_mpy.py`](src/natbridge_mpy.py) | Memory-constrained, synchronous API |
+
+### Platform Comparison
+
+| Feature | Julia | JavaScript | Python | MicroPython |
+|---------|-------|------------|--------|-------------|
+| Multiple Dispatch | ✅ Native | ❌ | ❌ | ❌ |
+| Async/Await | ❌ | ✅ Native | ✅ Native | ⚠️ (uasyncio) |
+| Type Safety | ✅ Strong | ⚠️ (TypeScript) | ✅ (Type hints) | ❌ |
+| Memory Management | ✅ GC | ✅ GC | ✅ GC | ⚠️ (Manual) |
+| Arrow IPC | ✅ Native | ✅ | ✅ | ❌ |
+| Direct Transport | ✅ | ✅ | ✅ | ✅ |
+| Link Transport | ✅ | ✅ | ✅ | ⚠️ (Limited) |
+| Handler Functions | ✅ | ✅ | ✅ | ✅ |
+| Cross-Platform API | ✅ | ✅ | ✅ | ✅ |
---
## Features
-- ✅ **Bi-directional messaging** for Julia applications
+- ✅ **Cross-platform messaging** for Julia, JavaScript, Python, and MicroPython applications
+- ✅ **Bi-directional messaging** with request-reply patterns
- ✅ **Multi-payload support** - send multiple payloads with different types in one message
- ✅ **Automatic transport selection** - direct vs link based on payload size
- ✅ **Claim-Check pattern** for payloads > 1MB
@@ -51,8 +78,7 @@ NATSBridge enables seamless communication for Julia applications through NATS, w
- ✅ **Exponential backoff** for reliable file server downloads
- ✅ **Correlation ID tracking** for message tracing
- ✅ **Reply-to support** for request-response patterns
-- ✅ **JetStream support** for message replay and durability
-
+- ✅ **Handler function abstraction** - pluggable file server implementations (Plik, AWS S3, custom)
---
@@ -62,13 +88,13 @@ NATSBridge enables seamless communication for Julia applications through NATS, w
```mermaid
flowchart TB
- subgraph Sender["Julia Application (Sender)"]
+ subgraph Sender["Application (Sender)"]
SenderApp[App Code]
NATSBridge_Send[NATSBridge]
NATS_Client[NATS.jl]
end
- subgraph Receiver["Julia Application (Receiver)"]
+ subgraph Receiver["Application (Receiver)"]
ReceiverApp[App Code]
NATSBridge_Recv[NATSBridge]
NATS_Client_Recv[NATS.jl]
@@ -96,14 +122,6 @@ flowchart TB
style FileServer fill:#f3e5f5
```
-### Key Components
-
-| Component | Description |
-|-----------|-------------|
-| **Julia Application** | Sender and receiver applications using the NATSBridge module |
-| **NATS Server** | Message broker for transporting message envelopes |
-| **HTTP File Server** | Independent HTTP server for large payload storage (e.g., Plik) |
-
### Message Flow
1. **Sender** creates a message envelope with payloads using `smartsend()`
@@ -124,11 +142,53 @@ The system uses handler functions to abstract file server operations:
| Handler | Purpose |
|---------|---------|
-| `plik_oneshot_upload()` | Uploads payload bytes to file server, returns URL |
-| `_fetch_with_backoff()` | Downloads data from URL with exponential backoff retry |
+| `plik_oneshot_upload()` / `plikOneshotUpload()` | Uploads payload bytes to file server, returns URL |
+| `_fetch_with_backoff()` / `fetchWithBackoff()` | Downloads data from URL with exponential backoff retry |
This abstraction allows support for different file server implementations (Plik, AWS S3, custom HTTP server).
+### Message Envelope Schema
+
+All platforms use identical JSON schemas for message envelopes:
+
+```json
+{
+ "correlation_id": "uuid-v4-string",
+ "msg_id": "uuid-v4-string",
+ "timestamp": "2024-01-15T10:30:00Z",
+ "send_to": "topic/subject",
+ "msg_purpose": "ACK | NACK | updateStatus | shutdown | chat",
+ "sender_name": "agent-wine-web-frontend",
+ "sender_id": "uuid4",
+ "receiver_name": "agent-backend",
+ "receiver_id": "uuid4",
+ "reply_to": "topic",
+ "reply_to_msg_id": "uuid4",
+ "broker_url": "nats://localhost:4222",
+ "metadata": {},
+ "payloads": [
+ {
+ "id": "uuid4",
+ "dataname": "login_image",
+ "payload_type": "image",
+ "transport": "direct",
+ "encoding": "base64",
+ "size": 15433,
+ "data": "base64-encoded-string"
+ },
+ {
+ "id": "uuid4",
+ "dataname": "large_table",
+ "payload_type": "table",
+ "transport": "link",
+ "encoding": "none",
+ "size": 524288,
+ "data": "http://localhost:8080/file/UPLOAD_ID/FILE_ID/data.arrow"
+ }
+ ]
+}
+```
+
---
## Installation
@@ -138,14 +198,53 @@ This abstraction allows support for different file server implementations (Plik,
- **NATS Server** (v2.10+ recommended)
- **HTTP File Server** (optional, for payloads > 1MB)
-### Julia
+### Platform-Specific Dependencies
+
+#### Julia
```julia
using Pkg
Pkg.add("NATS")
-Pkg.add("https://git.yiem.cc/ton/NATSBridge")
+Pkg.add("Arrow")
+Pkg.add("JSON3")
+Pkg.add("HTTP")
+Pkg.add("UUIDs")
+Pkg.add("Dates")
```
+#### JavaScript (Node.js)
+
+```bash
+npm install nats uuid apache-arrow node-fetch
+# or
+yarn add nats uuid apache-arrow node-fetch
+```
+
+#### JavaScript (Browser)
+
+```bash
+npm install nats uuid apache-arrow
+# or use CDN:
+# https://unpkg.com/nats-js/dist/bundle/nats.min.js
+# https://unpkg.com/apache-arrow/arrow.min.js
+```
+
+#### Python (Desktop)
+
+```bash
+pip install nats-py aiohttp pyarrow pandas python-dateutil
+```
+
+#### MicroPython
+
+MicroPython uses built-in modules:
+- `network` - NATS connection (custom implementation)
+- `time` - Timestamps
+- `uos` - File operations
+- `base64` - Base64 encoding
+- `json` - JSON parsing
+- `struct` - Binary data handling
+
---
## Quick Start
@@ -166,61 +265,39 @@ mkdir -p /tmp/fileserver
python3 -m http.server 8080 --directory /tmp/fileserver
```
-### Step 3: Send Your First Message
-
-#### Julia
-
-```julia
-using NATSBridge
-
-# Send a text message
-data = [("message", "Hello World", "text")]
-env, env_json_str = NATSBridge.smartsend("/chat/room1", data; broker_url="nats://localhost:4222")
-println("Message sent!")
-```
-
-### Step 4: Receive Messages
-
-#### Julia
-
-```julia
-using NATS, NATSBridge
-
-# Configuration
-const SUBJECT = "/chat/room1"
-const NATS_URL = "nats://localhost:4222"
-
-# Helper: Log with correlation ID
-function log_trace(message)
- timestamp = Dates.now()
- println("[$timestamp] $message")
-end
-
-# Receiver: Listen for messages - msg comes from the callback
-function test_receive()
- conn = NATS.connect(NATS_URL)
- NATS.subscribe(conn, SUBJECT) do msg
- log_trace("Received message on $(msg.subject)")
-
- # Receive and process message
- env, env_json_str = NATSBridge.smartreceive(msg, fileserverDownloadHandler)
- for (dataname, data, type) in env["payloads"]
- println("Received $dataname: $data")
- end
- end
-
- # Keep listening for 120 seconds
- sleep(120)
- NATS.drain(conn)
-end
-
-test_receive()
-```
-
---
## API Reference
+### Unified API Standard
+
+All platforms use the same input/output format for payloads:
+
+**Input format for smartsend:**
+```
+[(dataname1, data1, type1), (dataname2, data2, type2), ...]
+```
+
+**Output format for smartreceive:**
+```
+{
+ "correlation_id": "...",
+ "msg_id": "...",
+ "timestamp": "...",
+ "send_to": "...",
+ "msg_purpose": "...",
+ "sender_name": "...",
+ "sender_id": "...",
+ "receiver_name": "...",
+ "receiver_id": "...",
+ "reply_to": "...",
+ "reply_to_msg_id": "...",
+ "broker_url": "...",
+ "metadata": {...},
+ "payloads": [(dataname1, data1, type1), (dataname2, data2, type2), ...]
+}
+```
+
### smartsend
Sends data either directly via NATS or via a fileserver URL, depending on payload size.
@@ -231,27 +308,96 @@ Sends data either directly via NATS or via a fileserver URL, depending on payloa
using NATSBridge
env, env_json_str = NATSBridge.smartsend(
- subject, # NATS subject
+ subject::String, # NATS subject
data::AbstractArray{Tuple{String, Any, String}}; # List of (dataname, data, type)
broker_url::String = "nats://localhost:4222",
fileserver_url = "http://localhost:8080",
fileserver_upload_handler::Function = plik_oneshot_upload,
size_threshold::Int = 1_000_000,
- correlation_id::String = string(uuid4()), # Correlation ID for tracing (auto-generated UUID)
+ correlation_id::String = string(uuid4()),
msg_purpose::String = "chat",
sender_name::String = "NATSBridge",
receiver_name::String = "",
receiver_id::String = "",
reply_to::String = "",
reply_to_msg_id::String = "",
- is_publish::Bool = true, # Whether to automatically publish to NATS
- NATS_connection::Union{NATS.Connection, Nothing} = nothing, # Pre-existing NATS connection (optional, saves connection overhead)
- msg_id::String = string(uuid4()), # Message ID (auto-generated UUID)
- sender_id::String = string(uuid4()) # Sender ID (auto-generated UUID)
+ is_publish::Bool = true,
+ NATS_connection::Union{NATS.Connection, Nothing} = nothing,
+ msg_id::String = string(uuid4()),
+ sender_id::String = string(uuid4())
)
# Returns: ::Tuple{msg_envelope_v1, String}
-# - env: msg_envelope_v1 object with all envelope metadata and payloads
-# - env_json_str: JSON string representation of the envelope for publishing
+```
+
+#### JavaScript
+
+```javascript
+const NATSBridge = require('natbridge');
+
+const [env, env_json_str] = await NATSBridge.smartsend(
+ subject,
+ data, // Array of [dataname, data, type] tuples
+ {
+ broker_url: 'nats://localhost:4222',
+ fileserver_url: 'http://localhost:8080',
+ fileserver_upload_handler: NATSBridge.plikOneshotUpload,
+ size_threshold: 1_000_000,
+ correlation_id: uuidv4(),
+ msg_purpose: 'chat',
+ sender_name: 'NATSBridge',
+ receiver_name: '',
+ receiver_id: '',
+ reply_to: '',
+ reply_to_msg_id: '',
+ is_publish: true,
+ nats_connection: null,
+ msg_id: uuidv4(),
+ sender_id: uuidv4()
+ }
+);
+// Returns: Promise<[env, env_json_str]>
+```
+
+#### Python
+
+```python
+from natbridge import NATSBridge
+
+env, env_json_str = await NATSBridge.smartsend(
+ subject: str,
+ data: List[Tuple[str, Any, str]],
+ broker_url: str = "nats://localhost:4222",
+ fileserver_url: str = "http://localhost:8080",
+ fileserver_upload_handler: Callable = plik_oneshot_upload,
+ size_threshold: int = 1_000_000,
+ correlation_id: str = None,
+ msg_purpose: str = "chat",
+ sender_name: str = "NATSBridge",
+ receiver_name: str = "",
+ receiver_id: str = "",
+ reply_to: str = "",
+ reply_to_msg_id: str = "",
+ is_publish: bool = True,
+ nats_connection: Any = None,
+ msg_id: str = None,
+ sender_id: str = None
+)
+# Returns: Tuple[Dict, str]
+```
+
+#### MicroPython
+
+```python
+from natbridge import NATSBridge
+
+# Limited to direct transport (< 100KB threshold)
+env, env_json_str = NATSBridge.smartsend(
+ subject,
+ data, # List of (dataname, data, type) tuples
+ broker_url="nats://localhost:4222",
+ size_threshold=100000 # Lower threshold for memory constraints
+)
+# Returns: Tuple[Dict, str]
```
### smartreceive
@@ -263,7 +409,6 @@ Receives and processes messages from NATS, handling both direct and link transpo
```julia
using NATSBridge
-# Note: msg is a NATS.Msg object passed from the subscription callback
env = NATSBridge.smartreceive(
msg::NATS.Msg;
fileserver_download_handler::Function = _fetch_with_backoff,
@@ -271,51 +416,63 @@ env = NATSBridge.smartreceive(
base_delay::Int = 100,
max_delay::Int = 5000
)
-# Returns: ::JSON.Object{String, Any} - key-value structure resemble msg_envelope_v1
+# Returns: ::JSON.Object{String, Any}
```
-### publish_message
+#### JavaScript
-Publish a message to a NATS subject. This function is available in Julia with two overloads:
+```javascript
+const env = await NATSBridge.smartreceive(
+ msg,
+ {
+ fileserver_download_handler: NATSBridge.fetchWithBackoff,
+ max_retries: 5,
+ base_delay: 100,
+ max_delay: 5000
+ }
+);
+// Returns: Promise
+```
-#### Julia
+#### Python
-**Using broker URL (creates new connection):**
-```julia
-using NATSBridge, NATS
-
-# Publish with URL - creates a new connection
-NATSBridge.publish_message(
- "nats://localhost:4222", # broker_url
- "/chat/room1", # subject
- "{\"correlation_id\":\"abc123\"}", # message
- "abc123" # correlation_id
+```python
+env = await NATSBridge.smartreceive(
+ msg,
+ fileserver_download_handler=fetch_with_backoff,
+ max_retries=5,
+ base_delay=100,
+ max_delay=5000
)
+# Returns: Dict with "payloads" key
```
-**Using pre-existing connection (saves connection overhead):**
-```julia
-using NATSBridge, NATS
+#### MicroPython
-# Create connection once and reuse
-conn = NATS.connect("nats://localhost:4222")
-NATSBridge.publish_message(conn, "/chat/room1", "{\"correlation_id\":\"abc123\"}", "abc123")
-# Connection is automatically drained after publish
+```python
+env = NATSBridge.smartreceive(
+ msg,
+ fileserver_download_handler=_sync_fileserver_download,
+ max_retries=3,
+ base_delay=100,
+ max_delay=1000
+)
+# Returns: Dict with "payloads" key
```
---
## Payload Types
-| Type | Description | Serialization |
-|------|-------------|---------------|
-| `text` | Plain text strings | UTF-8 bytes |
-| `dictionary` | JSON-serializable dictionaries | JSON |
-| `table` | Tabular data (DataFrames, arrays) | Apache Arrow IPC |
-| `image` | Image data (PNG, JPG) | Raw bytes |
-| `audio` | Audio data (WAV, MP3) | Raw bytes |
-| `video` | Video data (MP4, AVI) | Raw bytes |
-| `binary` | Generic binary data | Raw bytes |
+| Type | Julia | JavaScript | Python | MicroPython | Description |
+|------|-------|------------|--------|-------------|-------------|
+| `text` | `String` | `string` | `str` | `str` | Plain text strings |
+| `dictionary` | `Dict`, `NamedTuple` | `Object`, `Array` | `dict`, `list` | `dict` | JSON-serializable dictionaries |
+| `table` | `DataFrame`, `Arrow.Table` | `Array