update
This commit is contained in:
@@ -19,17 +19,39 @@ NATSBridge is implemented in three languages, each providing the same API:
|
|||||||
| **JavaScript** | [`src/NATSBridge.js`](../src/NATSBridge.js) | JavaScript implementation for Node.js and browsers |
|
| **JavaScript** | [`src/NATSBridge.js`](../src/NATSBridge.js) | JavaScript implementation for Node.js and browsers |
|
||||||
| **Python/Micropython** | [`src/nats_bridge.py`](../src/nats_bridge.py) | Python implementation for desktop and microcontrollers |
|
| **Python/Micropython** | [`src/nats_bridge.py`](../src/nats_bridge.py) | Python implementation for desktop and microcontrollers |
|
||||||
|
|
||||||
### Multi-Payload Support
|
### File Server Handler Architecture
|
||||||
|
|
||||||
The implementation uses a **standardized list-of-tuples format** for all payload operations. **Even when sending a single payload, the user must wrap it in a list.**
|
The system uses **handler functions** to abstract file server operations, allowing support for different file server implementations (e.g., Plik, AWS S3, custom HTTP server).
|
||||||
|
|
||||||
|
**Handler Function Signatures:**
|
||||||
|
|
||||||
|
```julia
|
||||||
|
# Upload handler - uploads data to file server and returns URL
|
||||||
|
# The handler is passed to smartsend as fileserver_upload_handler parameter
|
||||||
|
# It receives: (file_server_url::String, dataname::String, data::Vector{UInt8})
|
||||||
|
# Returns: Dict{String, Any} with keys: "status", "uploadid", "fileid", "url"
|
||||||
|
fileserver_upload_handler(file_server_url::String, dataname::String, data::Vector{UInt8})::Dict{String, Any}
|
||||||
|
|
||||||
|
# Download handler - fetches data from file server URL with exponential backoff
|
||||||
|
# The handler is passed to smartreceive as fileserver_download_handler parameter
|
||||||
|
# It receives: (url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)
|
||||||
|
# Returns: Vector{UInt8} (the downloaded data)
|
||||||
|
fileserver_download_handler(url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)::Vector{UInt8}
|
||||||
|
```
|
||||||
|
|
||||||
|
This design allows the system to support multiple file server backends without changing the core messaging logic.
|
||||||
|
|
||||||
|
### Multi-Payload Support (Standard API)
|
||||||
|
|
||||||
|
The system uses a **standardized list-of-tuples format** for all payload operations. **Even when sending a single payload, the user must wrap it in a list.**
|
||||||
|
|
||||||
**API Standard:**
|
**API Standard:**
|
||||||
```julia
|
```julia
|
||||||
# Input format for smartsend (always a list of tuples with type info)
|
# Input format for smartsend (always a list of tuples with type info)
|
||||||
[(dataname1, data1, type1), (dataname2, data2, type2), ...]
|
[(dataname1, data1, type1), (dataname2, data2, type2), ...]
|
||||||
|
|
||||||
# Output format for smartreceive (returns envelope dictionary with payloads field)
|
# Output format for smartreceive (returns a dictionary with payloads field containing list of tuples)
|
||||||
# Returns: Dict with envelope metadata and payloads field containing list of tuples
|
# Returns: Dict with envelope metadata and payloads field containing Vector{Tuple{String, Any, String}}
|
||||||
# {
|
# {
|
||||||
# "correlation_id": "...",
|
# "correlation_id": "...",
|
||||||
# "msg_id": "...",
|
# "msg_id": "...",
|
||||||
@@ -48,20 +70,51 @@ The implementation uses a **standardized list-of-tuples format** for all payload
|
|||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
Where `type` can be: `"text"`, `"dictionary"`, `"table"`, `"image"`, `"audio"`, `"video"`, `"binary"`
|
**Supported Types:**
|
||||||
|
- `"text"` - Plain text
|
||||||
|
- `"dictionary"` - JSON-serializable dictionaries (Dict, NamedTuple)
|
||||||
|
- `"table"` - Tabular data (DataFrame, array of structs)
|
||||||
|
- `"image"` - Image data (Bitmap, PNG/JPG bytes)
|
||||||
|
- `"audio"` - Audio data (WAV, MP3 bytes)
|
||||||
|
- `"video"` - Video data (MP4, AVI bytes)
|
||||||
|
- `"binary"` - Generic binary data (Vector{UInt8})
|
||||||
|
|
||||||
|
This design allows per-payload type specification, enabling **mixed-content messages** where different payloads can use different serialization formats in a single message.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
```julia
|
```julia
|
||||||
# Single payload - still wrapped in a list (type is required as third element)
|
# Single payload - still wrapped in a list
|
||||||
smartsend("/test", [(dataname1, data1, "text")], broker_url="nats://localhost:4222")
|
smartsend(
|
||||||
|
"/test",
|
||||||
|
[("dataname1", data1, "dictionary")], # List with one tuple (data, type)
|
||||||
|
broker_url="nats://localhost:4222",
|
||||||
|
fileserver_upload_handler=plik_oneshot_upload
|
||||||
|
)
|
||||||
|
|
||||||
# Multiple payloads in one message (each payload has its own type)
|
# Multiple payloads in one message with different types
|
||||||
smartsend("/test", [(dataname1, data1, "dictionary"), (dataname2, data2, "table")], broker_url="nats://localhost:4222")
|
smartsend(
|
||||||
|
"/test",
|
||||||
|
[("dataname1", data1, "dictionary"), ("dataname2", data2, "table")],
|
||||||
|
broker_url="nats://localhost:4222",
|
||||||
|
fileserver_upload_handler=plik_oneshot_upload
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mixed content (e.g., chat with text, image, audio)
|
||||||
|
smartsend(
|
||||||
|
"/chat",
|
||||||
|
[
|
||||||
|
("message_text", "Hello!", "text"),
|
||||||
|
("user_image", image_data, "image"),
|
||||||
|
("audio_clip", audio_data, "audio")
|
||||||
|
],
|
||||||
|
broker_url="nats://localhost:4222"
|
||||||
|
)
|
||||||
|
|
||||||
# Receive returns a dictionary envelope with all metadata and deserialized payloads
|
# Receive returns a dictionary envelope with all metadata and deserialized payloads
|
||||||
env = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff, max_retries=5, base_delay=100, max_delay=5000)
|
env = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff, max_retries=5, base_delay=100, max_delay=5000)
|
||||||
# env["payloads"] = [(dataname1, data1, "text"), (dataname2, data2, "table"), ...]
|
# env["payloads"] = [("dataname1", data1, type1), ("dataname2", data2, type2), ...]
|
||||||
# env["correlation_id"], env["msg_id"], etc.
|
# env["correlation_id"], env["msg_id"], etc.
|
||||||
|
# env is a dictionary containing envelope metadata and payloads field
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cross-Platform Interoperability
|
## Cross-Platform Interoperability
|
||||||
@@ -263,7 +316,53 @@ node test/scenario3_julia_to_julia.js
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Scenario 0: Basic Multi-Payload Example
|
### Scenario 1: Command & Control (Small Dictionary)
|
||||||
|
|
||||||
|
**Focus:** Sending small dictionary configurations across platforms. This is the simplest use case for command and control scenarios.
|
||||||
|
|
||||||
|
**Julia (Sender/Receiver):**
|
||||||
|
```julia
|
||||||
|
using NATSBridge
|
||||||
|
|
||||||
|
# Subscribe to control subject
|
||||||
|
# Parse JSON envelope
|
||||||
|
# Execute simulation with parameters
|
||||||
|
# Send acknowledgment
|
||||||
|
```
|
||||||
|
|
||||||
|
**JavaScript (Sender/Receiver):**
|
||||||
|
```javascript
|
||||||
|
const { smartsend } = require('./src/NATSBridge');
|
||||||
|
|
||||||
|
// Create small dictionary config
|
||||||
|
// Send via smartsend with type="dictionary"
|
||||||
|
const config = {
|
||||||
|
step_size: 0.01,
|
||||||
|
iterations: 1000,
|
||||||
|
threshold: 0.5
|
||||||
|
};
|
||||||
|
|
||||||
|
await smartsend("control", [
|
||||||
|
{ dataname: "config", data: config, type: "dictionary" }
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Python/Micropython (Sender/Receiver):**
|
||||||
|
```python
|
||||||
|
from nats_bridge import smartsend
|
||||||
|
|
||||||
|
# Create small dictionary config
|
||||||
|
# Send via smartsend with type="dictionary"
|
||||||
|
config = {
|
||||||
|
"step_size": 0.01,
|
||||||
|
"iterations": 1000,
|
||||||
|
"threshold": 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
smartsend("control", [("config", config, "dictionary")])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Multi-Payload Example
|
||||||
|
|
||||||
#### Python/Micropython (Sender)
|
#### Python/Micropython (Sender)
|
||||||
```python
|
```python
|
||||||
|
|||||||
Reference in New Issue
Block a user