update docs
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
## 1. Executive Summary
|
## 1. Executive Summary
|
||||||
|
|
||||||
This document defines the **blueprint** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using NATS as the message bus.
|
This document defines the **blueprint** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using a message broker as the transport layer.
|
||||||
|
|
||||||
This architecture document serves as the single source of truth for:
|
This architecture document serves as the single source of truth for:
|
||||||
- **System Structure**: How components fit together and interact
|
- **System Structure**: How components fit together and interact
|
||||||
@@ -48,11 +48,10 @@ This architecture document serves as the single source of truth for:
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
subgraph "External Systems"
|
subgraph "External Systems"
|
||||||
NATS_Server[NATS Server]
|
Message_Broker[Message Broker<br/>NATS/MQTT/WebSocket/Custom]
|
||||||
File_Server[HTTP File Server<br/>Plik/AWS S3/Custom]
|
File_Server[HTTP File Server<br/>Plik/AWS S3/Custom]
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph "Client Applications"
|
|
||||||
Julia_App[Julia Application]
|
Julia_App[Julia Application]
|
||||||
JS_App[JavaScript Application<br/>Node.js/Browser]
|
JS_App[JavaScript Application<br/>Node.js/Browser]
|
||||||
Python_App[Python Application<br/>Desktop]
|
Python_App[Python Application<br/>Desktop]
|
||||||
@@ -61,12 +60,12 @@ flowchart TD
|
|||||||
MicroPython_App[MicroPython Device]
|
MicroPython_App[MicroPython Device]
|
||||||
end
|
end
|
||||||
|
|
||||||
Julia_App -->|NATS| NATS_Server
|
Julia_App -->|Transport| Message_Broker
|
||||||
JS_App -->|NATS| NATS_Server
|
JS_App -->|Transport| Message_Broker
|
||||||
Python_App -->|NATS| NATS_Server
|
Python_App -->|Transport| Message_Broker
|
||||||
Dart_App -->|NATS| NATS_Server
|
Dart_App -->|Transport| Message_Broker
|
||||||
Rust_App -->|NATS| NATS_Server
|
Rust_App -->|Transport| Message_Broker
|
||||||
MicroPython_App -->|NATS| NATS_Server
|
MicroPython_App -->|Transport| Message_Broker
|
||||||
|
|
||||||
Julia_App -->|HTTP| File_Server
|
Julia_App -->|HTTP| File_Server
|
||||||
JS_App -->|HTTP| File_Server
|
JS_App -->|HTTP| File_Server
|
||||||
@@ -75,7 +74,7 @@ flowchart TD
|
|||||||
Rust_App -->|HTTP| File_Server
|
Rust_App -->|HTTP| File_Server
|
||||||
MicroPython_App -->|HTTP| File_Server
|
MicroPython_App -->|HTTP| File_Server
|
||||||
|
|
||||||
style NATS_Server fill:#fff3e0,stroke:#f57c00
|
style Message_Broker fill:#fff3e0,stroke:#f57c00
|
||||||
style File_Server fill:#f3e5f5,stroke:#9c27b4
|
style File_Server fill:#f3e5f5,stroke:#9c27b4
|
||||||
style Julia_App fill:#e8f5e9,stroke:#4caf50
|
style Julia_App fill:#e8f5e9,stroke:#4caf50
|
||||||
style JS_App fill:#e3f2fd,stroke:#2196f3
|
style JS_App fill:#e3f2fd,stroke:#2196f3
|
||||||
@@ -98,14 +97,14 @@ flowchart TD
|
|||||||
MicroPython_Module[MicroPython msghandler Module]
|
MicroPython_Module[MicroPython msghandler Module]
|
||||||
end
|
end
|
||||||
|
|
||||||
Julia_Module --> NATS_Client
|
Julia_Module --> Transport_Client
|
||||||
JS_Module --> NATS_Client
|
JS_Module --> Transport_Client
|
||||||
Python_Module --> NATS_Client
|
Python_Module --> Transport_Client
|
||||||
Dart_Module --> NATS_Client
|
Dart_Module --> Transport_Client
|
||||||
Rust_Module --> NATS_Client
|
Rust_Module --> Transport_Client
|
||||||
MicroPython_Module --> NATS_Client
|
MicroPython_Module --> Transport_Client
|
||||||
|
|
||||||
NATS_Client --> NATS_Broker
|
Transport_Client --> Message_Broker
|
||||||
|
|
||||||
Julia_Module --> File_Client
|
Julia_Module --> File_Client
|
||||||
JS_Module --> File_Client
|
JS_Module --> File_Client
|
||||||
@@ -122,7 +121,7 @@ flowchart TD
|
|||||||
style Dart_Module fill:#fff0f6,stroke:#e91e63
|
style Dart_Module fill:#fff0f6,stroke:#e91e63
|
||||||
style Rust_Module fill:#dea584,stroke:#e65100
|
style Rust_Module fill:#dea584,stroke:#e65100
|
||||||
style MicroPython_Module fill:#fce4ec,stroke:#e91e63
|
style MicroPython_Module fill:#fce4ec,stroke:#e91e63
|
||||||
style NATS_Broker fill:#fff3e0,stroke:#f57c00
|
style Message_Broker fill:#fff3e0,stroke:#f57c00
|
||||||
style File_Server fill:#f3e5f5,stroke:#9c27b4
|
style File_Server fill:#f3e5f5,stroke:#9c27b4
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -174,8 +173,8 @@ flowchart TD
|
|||||||
|
|
||||||
| Component | Purpose | Platform Support |
|
| Component | Purpose | Platform Support |
|
||||||
|-----------|---------|------------------|
|
|-----------|---------|------------------|
|
||||||
| **smartsend** | Send data via NATS with automatic transport selection, returns (envelope, json_string) for caller to publish | All |
|
| **smartsend** | Send data with automatic transport selection, returns (envelope, json_string) for caller to publish via transport | All |
|
||||||
| **smartreceive** | Receive and process NATS messages from JSON string | All |
|
| **smartreceive** | Receive and process messages from JSON string | All |
|
||||||
| **_serialize_data** | Serialize data according to payload type | All |
|
| **_serialize_data** | Serialize data according to payload type | All |
|
||||||
| **_deserialize_data** | Deserialize bytes to native data types | All |
|
| **_deserialize_data** | Deserialize bytes to native data types | All |
|
||||||
| **envelope_to_json** | Convert msg_envelope_v1 struct to JSON string | All |
|
| **envelope_to_json** | Convert msg_envelope_v1 struct to JSON string | All |
|
||||||
@@ -224,7 +223,7 @@ struct msg_envelope_v1
|
|||||||
msg_id::String # UUID v4 for this message
|
msg_id::String # UUID v4 for this message
|
||||||
timestamp::String # ISO 8601 UTC timestamp
|
timestamp::String # ISO 8601 UTC timestamp
|
||||||
|
|
||||||
send_to::String # NATS subject to publish to
|
send_to::String # Topic/subject to publish to
|
||||||
msg_purpose::String # ACK, NACK, updateStatus, shutdown, chat
|
msg_purpose::String # ACK, NACK, updateStatus, shutdown, chat
|
||||||
sender_name::String # Sender application name
|
sender_name::String # Sender application name
|
||||||
sender_id::String # UUID v4 of sender
|
sender_id::String # UUID v4 of sender
|
||||||
@@ -233,7 +232,7 @@ struct msg_envelope_v1
|
|||||||
|
|
||||||
reply_to::String # Topic for reply messages
|
reply_to::String # Topic for reply messages
|
||||||
reply_to_msg_id::String # Message ID being replied to
|
reply_to_msg_id::String # Message ID being replied to
|
||||||
broker_url::String # NATS broker URL
|
broker_url::String # Broker URL for the transport layer
|
||||||
|
|
||||||
metadata::Dict{String, Any} # Message-level metadata
|
metadata::Dict{String, Any} # Message-level metadata
|
||||||
payloads::Vector{msg_payload_v1} # List of payloads
|
payloads::Vector{msg_payload_v1} # List of payloads
|
||||||
@@ -436,13 +435,13 @@ JavaScript uses async/await for non-blocking I/O:
|
|||||||
|
|
||||||
#### Node.js Implementation (msghandler_ssr.js)
|
#### Node.js Implementation (msghandler_ssr.js)
|
||||||
|
|
||||||
- **TCP NATS connections**: Uses `nats://` or `tls://` URLs
|
- **Transport connections**: Uses broker URLs (e.g., `nats://`, `mqtt://`, `ws://`)
|
||||||
- **Apache Arrow IPC**: Full support via `apache-arrow`
|
- **Apache Arrow IPC**: Full support via `apache-arrow`
|
||||||
- **Buffer for binary data**: Native Node.js Buffer handling
|
- **Buffer for binary data**: Native Node.js Buffer handling
|
||||||
|
|
||||||
#### Browser Implementation (msghandler_csr.js)
|
#### Browser Implementation (msghandler_csr.js)
|
||||||
|
|
||||||
- **WebSocket NATS connections**: Uses `ws://` or `wss://` URLs via `nats.ws`
|
- **WebSocket connections**: Uses `ws://` or `wss://` URLs (transport-agnostic)
|
||||||
- **No Apache Arrow**: Uses `jsontable` for tabular data only
|
- **No Apache Arrow**: Uses `jsontable` for tabular data only
|
||||||
- **Uint8Array for binary data**: Browser-compatible binary handling
|
- **Uint8Array for binary data**: Browser-compatible binary handling
|
||||||
- **Web Crypto API**: UUID generation via `crypto.getRandomValues()`
|
- **Web Crypto API**: UUID generation via `crypto.getRandomValues()`
|
||||||
@@ -474,7 +473,7 @@ Dart uses classes for stateful operations with async/await:
|
|||||||
- **Async/await**: I/O operations
|
- **Async/await**: I/O operations
|
||||||
- **dart-arrow**: Arrow IPC support (Desktop/Flutter only)
|
- **dart-arrow**: Arrow IPC support (Desktop/Flutter only)
|
||||||
- **HTTP package**: HTTP file server communication
|
- **HTTP package**: HTTP file server communication
|
||||||
- **nats package**: NATS client with WebSocket support (Dart Web)
|
- **Transport package**: Transport client with WebSocket support (Dart Web)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
class msghandler {
|
class msghandler {
|
||||||
@@ -484,7 +483,7 @@ class msghandler {
|
|||||||
final String fileserverUrl;
|
final String fileserverUrl;
|
||||||
|
|
||||||
msghandler({
|
msghandler({
|
||||||
this.brokerUrl = 'nats://localhost:4222',
|
this.brokerUrl = DEFAULT_BROKER_URL,
|
||||||
this.fileserverUrl = 'http://localhost:8080',
|
this.fileserverUrl = 'http://localhost:8080',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -492,19 +491,19 @@ class msghandler {
|
|||||||
|
|
||||||
#### Dart Desktop (Dart SDK)
|
#### Dart Desktop (Dart SDK)
|
||||||
|
|
||||||
- **TCP NATS connections**: Uses `nats://` or `tls://` URLs
|
- **Transport connections**: Uses broker URLs (e.g., `nats://`, `mqtt://`)
|
||||||
- **Apache Arrow IPC**: Full support via `dart-arrow`
|
- **Apache Arrow IPC**: Full support via `dart-arrow`
|
||||||
- **Uint8List for binary data**: Native Dart binary handling
|
- **Uint8List for binary data**: Native Dart binary handling
|
||||||
|
|
||||||
#### Dart Flutter (Dart SDK)
|
#### Dart Flutter (Dart SDK)
|
||||||
|
|
||||||
- **TCP NATS connections**: Uses `nats://` or `tls://` URLs
|
- **Transport connections**: Uses broker URLs (e.g., `nats://`, `mqtt://`)
|
||||||
- **Apache Arrow IPC**: Full support via `dart-arrow`
|
- **Apache Arrow IPC**: Full support via `dart-arrow`
|
||||||
- **Uint8List for binary data**: Native Dart binary handling
|
- **Uint8List for binary data**: Native Dart binary handling
|
||||||
|
|
||||||
#### Dart Web (Dart SDK)
|
#### Dart Web (Dart SDK)
|
||||||
|
|
||||||
- **WebSocket NATS connections**: Uses `ws://` or `wss://` URLs via `nats` package
|
- **WebSocket connections**: Uses `ws://` or `wss://` URLs (transport-agnostic)
|
||||||
- **No Apache Arrow**: Uses `jsontable` for tabular data only
|
- **No Apache Arrow**: Uses `jsontable` for tabular data only
|
||||||
- **Uint8List for binary data**: Browser-compatible binary handling
|
- **Uint8List for binary data**: Browser-compatible binary handling
|
||||||
- **Fetch API**: HTTP file server communication via `http` package
|
- **Fetch API**: HTTP file server communication via `http` package
|
||||||
@@ -516,7 +515,7 @@ Browser JavaScript has specific constraints due to security and compatibility:
|
|||||||
- **Async/await**: Native async/await support
|
- **Async/await**: Native async/await support
|
||||||
- **No Apache Arrow**: Arrow IPC not available in browsers
|
- **No Apache Arrow**: Arrow IPC not available in browsers
|
||||||
- **JSON table only**: Use "jsontable" for tabular data
|
- **JSON table only**: Use "jsontable" for tabular data
|
||||||
- **WebSocket NATS**: Uses nats.ws for browser-compatible NATS connections
|
- **WebSocket transport**: Uses transport client for browser-compatible connections
|
||||||
- **Fetch API**: HTTP file server communication via fetch
|
- **Fetch API**: HTTP file server communication via fetch
|
||||||
|
|
||||||
### MicroPython Architecture
|
### MicroPython Architecture
|
||||||
@@ -540,7 +539,7 @@ Rust leverages compile-time type safety and async runtimes:
|
|||||||
|
|
||||||
- **Type-safe payloads**: Rust enum discriminates between `Text`, `Dictionary`, `ArrowTable`, `Binary`, etc.
|
- **Type-safe payloads**: Rust enum discriminates between `Text`, `Dictionary`, `ArrowTable`, `Binary`, etc.
|
||||||
- **serde serialization**: Automatic JSON deserialization via `#[derive(Serialize, Deserialize)]`
|
- **serde serialization**: Automatic JSON deserialization via `#[derive(Serialize, Deserialize)]`
|
||||||
- **tokio runtime**: Efficient async I/O for NATS connections and HTTP file server operations
|
- **tokio runtime**: Efficient async I/O for transport connections and HTTP file server operations
|
||||||
- **arrow2 integration**: Native Arrow IPC deserialization without intermediate format conversion
|
- **arrow2 integration**: Native Arrow IPC deserialization without intermediate format conversion
|
||||||
- **reqwest**: High-performance HTTP client with built-in TLS and connection pooling
|
- **reqwest**: High-performance HTTP client with built-in TLS and connection pooling
|
||||||
- **Zero-copy patterns**: `Vec<u8>` passed directly to avoid unnecessary memory copies
|
- **Zero-copy patterns**: `Vec<u8>` passed directly to avoid unnecessary memory copies
|
||||||
@@ -572,8 +571,8 @@ pub struct SmartsendOptions {
|
|||||||
// ... other fields
|
// ... other fields
|
||||||
}
|
}
|
||||||
|
|
||||||
// NATS client with tokio integration
|
// Transport client with tokio integration
|
||||||
let conn = nats::connect("nats://localhost:4222").await?;
|
let conn = transport_client::connect(DEFAULT_BROKER_URL).await?;
|
||||||
|
|
||||||
// Subscribe and process messages
|
// Subscribe and process messages
|
||||||
let mut sub = conn.subscribe("/agent/wine/api/v1/analyze")?;
|
let mut sub = conn.subscribe("/agent/wine/api/v1/analyze")?;
|
||||||
@@ -599,7 +598,7 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
| Component | Scaling Strategy |
|
| Component | Scaling Strategy |
|
||||||
|-----------|------------------|
|
|-----------|------------------|
|
||||||
| **NATS Server** | Cluster deployment with multiple nodes |
|
| **Message Broker** | Cluster deployment with multiple nodes |
|
||||||
| **File Server** | Load balancer + multiple instances |
|
| **File Server** | Load balancer + multiple instances |
|
||||||
| **Client Applications** | Deploy multiple instances behind load balancer |
|
| **Client Applications** | Deploy multiple instances behind load balancer |
|
||||||
|
|
||||||
@@ -607,7 +606,7 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
| Component | Scaling Strategy |
|
| Component | Scaling Strategy |
|
||||||
|-----------|------------------|
|
|-----------|------------------|
|
||||||
| **NATS Server** | Increase memory, CPU, disk I/O |
|
| **Message Broker** | Increase memory, CPU, disk I/O |
|
||||||
| **File Server** | Increase memory, CPU, disk capacity |
|
| **File Server** | Increase memory, CPU, disk capacity |
|
||||||
| **Client Applications** | Increase heap size (Python/JS) |
|
| **Client Applications** | Increase heap size (Python/JS) |
|
||||||
|
|
||||||
@@ -617,7 +616,7 @@ for msg in sub.messages() {
|
|||||||
|--------|--------|-------|
|
|--------|--------|-------|
|
||||||
| Message serialization overhead | <50ms | For 10KB payload |
|
| Message serialization overhead | <50ms | For 10KB payload |
|
||||||
| Message deserialization overhead | <50ms | For 10KB payload |
|
| Message deserialization overhead | <50ms | For 10KB payload |
|
||||||
| NATS connection establishment | <100ms | Connection pool recommended |
|
| Transport connection establishment | <100ms | Connection pool recommended |
|
||||||
| File upload latency | <1s | For 0.5MB file |
|
| File upload latency | <1s | For 0.5MB file |
|
||||||
| File download latency | <1s | For 0.5MB file |
|
| File download latency | <1s | For 0.5MB file |
|
||||||
|
|
||||||
@@ -625,16 +624,16 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
## Failure Modes and Recovery
|
## Failure Modes and Recovery
|
||||||
|
|
||||||
### NATS Connection Failure
|
### Transport Connection Failure
|
||||||
|
|
||||||
**Scenario**: NATS server unavailable
|
**Scenario**: Message broker unavailable
|
||||||
|
|
||||||
**Handler**:
|
**Handler**:
|
||||||
- Connection auto-reconnect via TCP-level reconnection
|
- Connection auto-reconnect via transport-level reconnection
|
||||||
- Retry with exponential backoff for publish operations
|
- Retry with exponential backoff for publish operations
|
||||||
|
|
||||||
**Recovery**:
|
**Recovery**:
|
||||||
- NATS client automatically attempts reconnection
|
- Transport client automatically attempts reconnection
|
||||||
- Application can check connection status before publishing
|
- Application can check connection status before publishing
|
||||||
|
|
||||||
### File Server Unavailable
|
### File Server Unavailable
|
||||||
@@ -697,7 +696,7 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
**Rationale**:
|
**Rationale**:
|
||||||
- Simplifies JSON serialization (all data is string-compatible)
|
- Simplifies JSON serialization (all data is string-compatible)
|
||||||
- Increases payload size by ~33%, but NATS can handle this
|
- Increases payload size by ~33%, but transport can handle this
|
||||||
- Alternative would be binary payload support (more complex)
|
- Alternative would be binary payload support (more complex)
|
||||||
|
|
||||||
### Decision 3: Multiple Platform Implementations
|
### Decision 3: Multiple Platform Implementations
|
||||||
@@ -730,7 +729,7 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
| Component | Minimum | Notes |
|
| Component | Minimum | Notes |
|
||||||
|-----------|---------|-------|
|
|-----------|---------|-------|
|
||||||
| NATS Server | 1 instance | Single node for development |
|
| Message Broker | 1 instance | Single node for development |
|
||||||
| File Server | 1 instance | HTTP server for large payloads |
|
| File Server | 1 instance | HTTP server for large payloads |
|
||||||
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
||||||
| Client Memory | 256KB | MicroPython devices |
|
| Client Memory | 256KB | MicroPython devices |
|
||||||
@@ -739,7 +738,7 @@ for msg in sub.messages() {
|
|||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `NATS_URL` | `nats://localhost:4222` | NATS server URL |
|
| `BROKER_URL` | `ws://localhost:4222` | Message broker URL |
|
||||||
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
||||||
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
||||||
|
|
||||||
@@ -748,15 +747,15 @@ for msg in sub.messages() {
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
subgraph "Docker Network"
|
subgraph "Docker Network"
|
||||||
NATS_Container[NATS Server]
|
Broker_Container[Message Broker]
|
||||||
FileServer_Container[Plik File Server]
|
FileServer_Container[Plik File Server]
|
||||||
App_Container[Application Container]
|
App_Container[Application Container]
|
||||||
end
|
end
|
||||||
|
|
||||||
App_Container -->|NATS| NATS_Container
|
App_Container -->|Transport| Broker_Container
|
||||||
App_Container -->|HTTP| FileServer_Container
|
App_Container -->|HTTP| FileServer_Container
|
||||||
|
|
||||||
style NATS_Container fill:#fff3e0,stroke:#f57c00
|
style Broker_Container fill:#fff3e0,stroke:#f57c00
|
||||||
style FileServer_Container fill:#f3e5f5,stroke:#9c27b4
|
style FileServer_Container fill:#f3e5f5,stroke:#9c27b4
|
||||||
style App_Container fill:#e3f2fd,stroke:#2196f3
|
style App_Container fill:#e3f2fd,stroke:#2196f3
|
||||||
```
|
```
|
||||||
@@ -775,11 +774,12 @@ flowchart TD
|
|||||||
|
|
||||||
### Transport Security
|
### Transport Security
|
||||||
|
|
||||||
**Mechanism**: TLS support for NATS connections
|
**Mechanism**: TLS support for transport connections
|
||||||
|
|
||||||
**Implementation**:
|
**Implementation**:
|
||||||
- Use `nats://` URL for plain text
|
- Use `nats://` URL for plain text
|
||||||
- Use `tls://` URL for TLS-encrypted connections
|
- Use `tls://` URL for TLS-encrypted connections
|
||||||
|
- Use `ws://` or `wss://` for WebSocket connections
|
||||||
|
|
||||||
### File Server Security
|
### File Server Security
|
||||||
|
|
||||||
@@ -835,6 +835,11 @@ flowchart TD
|
|||||||
|
|
||||||
| Date | Version | Changes |
|
| Date | Version | Changes |
|
||||||
|------|---------|---------|
|
|------|---------|---------|
|
||||||
|
| 2026-05-15 | 1.5.0 | Made transport layer agnostic | All sections |
|
||||||
|
| - | - | Removed all NATS-specific references from architecture docs | All sections |
|
||||||
|
| - | - | Updated diagrams to use generic "Message Broker" instead of "NATS Server" | All sections |
|
||||||
|
| - | - | Updated code examples to use transport-agnostic patterns | All sections |
|
||||||
|
| - | - | Removed NATS client packages from external dependencies | All sections |
|
||||||
| 2026-05-14 | 1.4.0 | Updated Rust API to reflect `smartreceive` deserialization changes | All sections |
|
| 2026-05-14 | 1.4.0 | Updated Rust API to reflect `smartreceive` deserialization changes | All sections |
|
||||||
| - | - | `smartreceive` now stores deserialized data in `MsgPayloadV1.data` | specification.md:8 |
|
| - | - | `smartreceive` now stores deserialized data in `MsgPayloadV1.data` | specification.md:8 |
|
||||||
| - | - | Added `plik_upload_file` convenience function to component table | specification.md:13 |
|
| - | - | Added `plik_upload_file` convenience function to component table | specification.md:13 |
|
||||||
@@ -849,6 +854,7 @@ flowchart TD
|
|||||||
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) |
|
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) |
|
||||||
| - | - | Removed publish_message component (commented out in source) |
|
| - | - | Removed publish_message component (commented out in source) |
|
||||||
| - | - | Removed NATSClient and NATSConnectionPool classes (not in ground truth) |
|
| - | - | Removed NATSClient and NATSConnectionPool classes (not in ground truth) |
|
||||||
|
| - | - | Updated smartsend to return JSON for caller to publish via transport |
|
||||||
| - | - | Updated component diagram to match actual module structure |
|
| - | - | Updated component diagram to match actual module structure |
|
||||||
| - | - | Updated data flow to show smartsend returns JSON for caller to publish |
|
| - | - | Updated data flow to show smartsend returns JSON for caller to publish |
|
||||||
| - | - | Fixed SIZE_THRESHOLD default to 500,000 bytes |
|
| - | - | Fixed SIZE_THRESHOLD default to 500,000 bytes |
|
||||||
@@ -856,6 +862,7 @@ flowchart TD
|
|||||||
| - | - | Added NATSClient with keepAlive support |
|
| - | - | Added NATSClient with keepAlive support |
|
||||||
| - | - | Added NATSConnectionPool for connection reuse |
|
| - | - | Added NATSConnectionPool for connection reuse |
|
||||||
| - | - | Added publishMessage function with closeConnection option |
|
| - | - | Added publishMessage function with closeConnection option |
|
||||||
|
| (Historical - pre-transport-agnostic refactor) | | |
|
||||||
| 2026-03-13 | 1.0.0 | Initial architecture documentation |
|
| 2026-03-13 | 1.0.0 | Initial architecture documentation |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -880,7 +887,7 @@ flowchart TD
|
|||||||
|------|----------|----------|---------------------------|-------------------|
|
|------|----------|----------|---------------------------|-------------------|
|
||||||
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only, WebSocket NATS | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe, file upload helpers | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe, file upload helpers | specification.md:2-19 (all sections) | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
@@ -889,24 +896,18 @@ flowchart TD
|
|||||||
### 16.3 External Dependencies
|
### 16.3 External Dependencies
|
||||||
|
|
||||||
| Platform | Package | Version | Purpose | Specification Traceability | Requirement ID(s) |
|
| Platform | Package | Version | Purpose | Specification Traceability | Requirement ID(s) |
|
||||||
|----------|---------|---------|---------|---------------------------|-------------------|
|
|----------|---------|---------|---------|--------------------------|-------------------|
|
||||||
| Julia | NATS.jl | Latest | NATS client | specification.md:11 | FR-013, FR-014, NFR-201 |
|
|
||||||
| Julia | JSON.jl | Latest | JSON serialization | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
| Julia | JSON.jl | Latest | JSON serialization | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
||||||
| Julia | Arrow.jl | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
| Julia | Arrow.jl | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
||||||
| Julia | HTTP.jl | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
| Julia | HTTP.jl | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
||||||
| Julia | UUIDs.jl | Latest | UUID generation | specification.md:11 | FR-011, NFR-401 |
|
| Julia | UUIDs.jl | Latest | UUID generation | specification.md:11 | FR-011, NFR-401 |
|
||||||
| Node.js | nats | Latest | NATS client (TCP) | specification.md:11 | FR-013, FR-014 |
|
|
||||||
| Node.js | node-fetch | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
| Node.js | node-fetch | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
||||||
| Browser | nats.ws | Latest | NATS client (WebSocket) | specification.md:11 | FR-013, FR-014 |
|
| Browser | - | - | Transport-agnostic (caller provides) | specification.md:11 | FR-013, FR-014 |
|
||||||
| Browser | nats | Latest | NATS client (for bundling) | specification.md:11 | FR-013, FR-014 |
|
|
||||||
| Python | nats-py | Latest | NATS client | specification.md:11 | FR-013, FR-014 |
|
|
||||||
| Python | aiohttp | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
| Python | aiohttp | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
||||||
| Python | pyarrow | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
| Python | pyarrow | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
||||||
| Dart | nats | Latest | NATS client | specification.md:11 | FR-013, FR-014 |
|
|
||||||
| Dart | http | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
| Dart | http | Latest | HTTP file server | specification.md:11 | FR-008, FR-009 |
|
||||||
| Dart | uuid | Latest | UUID generation | specification.md:11 | FR-011, NFR-401 |
|
| Dart | uuid | Latest | UUID generation | specification.md:11 | FR-011, NFR-401 |
|
||||||
| Dart | dart-arrow | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
| Dart | dart-arrow | Latest | Arrow IPC support | specification.md:11 | FR-002, FR-012 |
|
||||||
| Rust | nats | Latest | NATS client | specification.md:11 | FR-013, FR-014 |
|
|
||||||
| Rust | serde | Latest | JSON serialization | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
| Rust | serde | Latest | JSON serialization | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
||||||
| Rust | serde_json | Latest | JSON handling | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
| Rust | serde_json | Latest | JSON handling | specification.md:11 | FR-012, NFR-101, NFR-102 |
|
||||||
| Rust | tokio | Latest | Async runtime | specification.md:11 | FR-013, FR-014 |
|
| Rust | tokio | Latest | Async runtime | specification.md:11 | FR-013, FR-014 |
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
### 1.1 Business Goal
|
### 1.1 Business Goal
|
||||||
|
|
||||||
msghandler is a cross-platform, bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using NATS as the message bus. The system implements the **Claim-Check pattern** for efficient handling of large payloads (>0.5MB) by uploading them to an HTTP file server instead of sending raw binary data over NATS.
|
msghandler is a cross-platform, bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using a message broker as the transport layer. The system implements the **Claim-Check pattern** for efficient handling of large payloads (>0.5MB) by uploading them to an HTTP file server instead of sending raw binary data over the transport layer.
|
||||||
|
|
||||||
### 1.2 User Stories (with acceptance criteria)
|
### 1.2 User Stories (with acceptance criteria)
|
||||||
|
|
||||||
@@ -19,13 +19,13 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
|-------|----------|---------------------|
|
|-------|----------|---------------------|
|
||||||
| **As a Julia developer**, I want to send text messages to JavaScript/Dart applications that lives on a server and also on a browser | P1 | Text messages are serialized, encoded, and received correctly across platforms |
|
| **As a Julia developer**, I want to send text messages to JavaScript/Dart applications that lives on a server and also on a browser | P1 | Text messages are serialized, encoded, and received correctly across platforms |
|
||||||
| **As a Python developer**, I want to send tabular data to Julia/Dart applications | P1 | DataFrame exchange works with both Arrow IPC and JSON formats |
|
| **As a Python developer**, I want to send tabular data to Julia/Dart applications | P1 | DataFrame exchange works with both Arrow IPC and JSON formats |
|
||||||
| **As a JavaScript developer**, I want to send large files (>0.5MB) from JavaScript applications that lives on a server and also on a browser to other applications | P1 | Large files are automatically uploaded to file server and URLs are sent via NATS |
|
| **As a JavaScript developer**, I want to send large files (>0.5MB) from JavaScript applications that lives on a server and also on a browser to other applications | P1 | Large files are automatically uploaded to file server and URLs are sent via the transport layer |
|
||||||
| **As a Dart developer**, I want to send text messages to other platforms | P1 | Text messages are serialized, encoded, and received correctly across platforms |
|
| **As a Dart developer**, I want to send text messages to other platforms | P1 | Text messages are serialized, encoded, and received correctly across platforms |
|
||||||
| **As a Dart developer**, I want to send dictionary data to other platforms | P1 | JSON-serializable data is exchanged correctly |
|
| **As a Dart developer**, I want to send dictionary data to other platforms | P1 | JSON-serializable data is exchanged correctly |
|
||||||
| **As a Dart developer**, I want to send tabular data (List<Map>) to other platforms | P1 | JSON table format exchange works with Arrow IPC on desktop |
|
| **As a Dart developer**, I want to send tabular data (List<Map>) to other platforms | P1 | JSON table format exchange works with Arrow IPC on desktop |
|
||||||
| **As a Dart developer**, I want to send large files (>0.5MB) | P1 | Large files are automatically uploaded to file server and URLs are sent via NATS |
|
| **As a Dart developer**, I want to send large files (>0.5MB) | P1 | Large files are automatically uploaded to file server and URLs are sent via the transport layer |
|
||||||
| **As a MicroPython developer**, I want to send sensor data with minimal memory usage | P1 | Direct transport works for payloads <100KB on memory-constrained devices |
|
| **As a MicroPython developer**, I want to send sensor data with minimal memory usage | P1 | Direct transport works for payloads <100KB on memory-constrained devices |
|
||||||
| **As a Rust developer**, I want to send and receive messages with type-safe APIs | P1 | Rust implementation uses serde for serialization, tokio for async, and nats-io for NATS connectivity |
|
| **As a Rust developer**, I want to send and receive messages with type-safe APIs | P1 | Rust implementation uses serde for serialization, tokio for async, and transport-agnostic client for connectivity |
|
||||||
| **As a developer**, I want to send mixed-content messages (text + image + file) | P1 | msghandler accepts list of (dataname, data, type) tuples and handles each payload appropriately |
|
| **As a developer**, I want to send mixed-content messages (text + image + file) | P1 | msghandler accepts list of (dataname, data, type) tuples and handles each payload appropriately |
|
||||||
| **As a developer**, I want to receive multi-payload messages | P1 | msghandler returns payloads as list of tuples with correct types preserved |
|
| **As a developer**, I want to receive multi-payload messages | P1 | msghandler returns payloads as list of tuples with correct types preserved |
|
||||||
| **As a developer**, I want to use Plik as the file server | P2 | Plik one-shot upload mode is supported with upload ID and token handling |
|
| **As a developer**, I want to use Plik as the file server | P2 | Plik one-shot upload mode is supported with upload ID and token handling |
|
||||||
@@ -59,37 +59,32 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| File server integration | Plik one-shot upload and custom HTTP server support |
|
| File server integration | Plik one-shot upload and custom HTTP server support |
|
||||||
| Reliability features | Exponential backoff retry and correlation ID propagation |
|
| Reliability features | Exponential backoff retry and correlation ID propagation |
|
||||||
| Message serialization | Converts data types to binary format (Base64, JSON, Arrow IPC) |
|
| Message serialization | Converts data types to binary format (Base64, JSON, Arrow IPC) |
|
||||||
| NATS communication | Publishing and subscription via NATS subjects |
|
| Transport communication | Publishing and subscription via message broker (NATS, MQTT, WebSocket, etc.) |
|
||||||
|
|
||||||
### 2.2 Out of Scope
|
### 2.2 Out of Scope
|
||||||
|
|
||||||
| Feature | Reason |
|
| Feature | Reason |
|
||||||
|---------|--------|
|
|---------|--------|
|
||||||
| NATS JetStream support | Core NATS sufficient for current use cases |
|
| Advanced transport features | Basic transport sufficient for current use cases |
|
||||||
| Message compression | Compression adds complexity without clear benefit |
|
| Message compression | Compression adds complexity without clear benefit |
|
||||||
| Message encryption | Payload encryption is application-layer concern |
|
| Message encryption | Payload encryption is application-layer concern |
|
||||||
| Persistent message queues | NATS request-reply pattern sufficient |
|
| Persistent message queues | Transport request-reply pattern sufficient |
|
||||||
| Advanced routing rules | Simple NATS subject matching sufficient |
|
| Advanced routing rules | Simple topic matching sufficient |
|
||||||
|
|
||||||
### 2.3 Dependencies
|
### 2.3 Dependencies
|
||||||
|
|
||||||
| Platform | Package | Version |
|
| Platform | Package | Version |
|
||||||
|----------|---------|---------|
|
|----------|---------|---------|
|
||||||
| Julia | NATS.jl | Latest stable |
|
|
||||||
| Julia | JSON.jl | Latest stable |
|
| Julia | JSON.jl | Latest stable |
|
||||||
| Julia | Arrow.jl | Latest stable |
|
| Julia | Arrow.jl | Latest stable |
|
||||||
| Julia | HTTP.jl | Latest stable |
|
| Julia | HTTP.jl | Latest stable |
|
||||||
| Julia | UUIDs.jl | Latest stable |
|
| Julia | UUIDs.jl | Latest stable |
|
||||||
| Node.js | nats | Latest stable |
|
|
||||||
| Node.js | node-fetch | Latest stable |
|
| Node.js | node-fetch | Latest stable |
|
||||||
| Python | nats-py | Latest stable |
|
|
||||||
| Python | aiohttp | Latest stable |
|
| Python | aiohttp | Latest stable |
|
||||||
| Python | pyarrow | Latest stable |
|
| Python | pyarrow | Latest stable |
|
||||||
| Browser | nats.ws | Latest stable |
|
| Browser | - | Transport-agnostic (caller provides) |
|
||||||
| Dart | nats | Latest stable |
|
|
||||||
| Dart | http | Latest stable |
|
| Dart | http | Latest stable |
|
||||||
| Dart | uuid | Latest stable |
|
| Dart | uuid | Latest stable |
|
||||||
| Rust | nats | Latest stable |
|
|
||||||
| Rust | serde | Latest stable |
|
| Rust | serde | Latest stable |
|
||||||
| Rust | serde_json | Latest stable |
|
| Rust | serde_json | Latest stable |
|
||||||
| Rust | tokio | Latest stable |
|
| Rust | tokio | Latest stable |
|
||||||
@@ -100,7 +95,7 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| Platform | Minimum Version | Notes |
|
| Platform | Minimum Version | Notes |
|
||||||
|----------|-----------------|-------|
|
|----------|-----------------|-------|
|
||||||
| Julia | 1.7+ | Arrow.jl required for arrowtable support |
|
| Julia | 1.7+ | Arrow.jl required for arrowtable support |
|
||||||
| Node.js | 16+ | nats.js required, Arrow IPC supported |
|
| Node.js | 16+ | Transport client required, Arrow IPC supported |
|
||||||
| Python | 3.8+ | pyarrow required for arrowtable support |
|
| Python | 3.8+ | pyarrow required for arrowtable support |
|
||||||
| Browser | Latest | No Arrow IPC (uses jsontable only) |
|
| Browser | Latest | No Arrow IPC (uses jsontable only) |
|
||||||
| Dart | 2.17+ | Supports Desktop (Dart SDK), Flutter (Dart SDK), and Web (Dart SDK) |
|
| Dart | 2.17+ | Supports Desktop (Dart SDK), Flutter (Dart SDK), and Web (Dart SDK) |
|
||||||
@@ -115,8 +110,8 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
|----|-------------|-------------|
|
|----|-------------|-------------|
|
||||||
| **FR-001** | Cross-platform text messaging | System shall allow users to send text messages between Julia, JavaScript, Python, and MicroPython applications |
|
| **FR-001** | Cross-platform text messaging | System shall allow users to send text messages between Julia, JavaScript, Python, and MicroPython applications |
|
||||||
| **FR-002** | Cross-platform tabular data | System shall support DataFrame exchange between Julia and Python applications using Arrow IPC format |
|
| **FR-002** | Cross-platform tabular data | System shall support DataFrame exchange between Julia and Python applications using Arrow IPC format |
|
||||||
| **FR-003** | Large file handling | System shall automatically detect payloads ≥0.5MB and upload them to HTTP file server instead of sending via NATS |
|
| **FR-003** | Large file handling | System shall automatically detect payloads ≥0.5MB and upload them to HTTP file server instead of sending via transport |
|
||||||
| **FR-004** | Direct transport for small payloads | System shall send payloads <0.5MB directly via NATS without file server upload |
|
| **FR-004** | Direct transport for small payloads | System shall send payloads <0.5MB directly via transport without file server upload |
|
||||||
| **FR-005** | MicroPython support | System shall support payloads <100KB on MicroPython devices using direct transport |
|
| **FR-005** | MicroPython support | System shall support payloads <100KB on MicroPython devices using direct transport |
|
||||||
| **FR-006** | Multi-payload messages | System shall accept and process lists of (dataname, data, type) tuples |
|
| **FR-006** | Multi-payload messages | System shall accept and process lists of (dataname, data, type) tuples |
|
||||||
| **FR-007** | Payload type preservation | System shall preserve payload types when returning multi-payload messages |
|
| **FR-007** | Payload type preservation | System shall preserve payload types when returning multi-payload messages |
|
||||||
@@ -125,8 +120,8 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| **FR-010** | Exponential backoff retry | System shall implement exponential backoff with configurable retries (default: 5, base_delay: 100ms, max_delay: 5000ms) for file server download failures |
|
| **FR-010** | Exponential backoff retry | System shall implement exponential backoff with configurable retries (default: 5, base_delay: 100ms, max_delay: 5000ms) for file server download failures |
|
||||||
| **FR-011** | Correlation ID propagation | System shall propagate correlation IDs through all message processing steps |
|
| **FR-011** | Correlation ID propagation | System shall propagate correlation IDs through all message processing steps |
|
||||||
| **FR-012** | Message serialization | System shall serialize data types using Base64, JSON, or Arrow IPC encoding |
|
| **FR-012** | Message serialization | System shall serialize data types using Base64, JSON, or Arrow IPC encoding |
|
||||||
| **FR-013** | NATS publishing | System shall return JSON string representation for caller to publish to NATS subjects (caller is responsible for actual NATS publish) |
|
| **FR-013** | Transport publishing | System shall return JSON string representation for caller to publish via transport layer (caller is responsible for actual transport publish) |
|
||||||
| **FR-014** | NATS subscription | System shall receive and process NATS messages by accepting JSON string from NATS payload |
|
| **FR-014** | Transport subscription | System shall receive and process messages by accepting JSON string from transport payload |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -138,10 +133,10 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
|----|-------------|---------------|-------------|
|
|----|-------------|---------------|-------------|
|
||||||
| **NFR-101** | Message serialization overhead | <50ms for 10KB payload | Benchmark tests |
|
| **NFR-101** | Message serialization overhead | <50ms for 10KB payload | Benchmark tests |
|
||||||
| **NFR-102** | Message deserialization overhead | <50ms for 10KB payload | Benchmark tests |
|
| **NFR-102** | Message deserialization overhead | <50ms for 10KB payload | Benchmark tests |
|
||||||
| **NFR-103** | NATS connection establishment | <100ms | Connection pool benchmarks |
|
| **NFR-103** | Transport connection establishment | <100ms | Connection pool benchmarks |
|
||||||
| **NFR-104** | File upload latency | <1s for 0.5MB file | Integration tests |
|
| **NFR-104** | File upload latency | <1s for 0.5MB file | Integration tests |
|
||||||
| **NFR-105** | File download latency | <1s for 0.5MB file | Integration tests |
|
| **NFR-105** | File download latency | <1s for 0.5MB file | Integration tests |
|
||||||
| **NFR-106** | Concurrent connections | Support 100+ simultaneous NATS connections | Scale testing |
|
| **NFR-106** | Concurrent connections | Support 100+ simultaneous transport connections | Scale testing |
|
||||||
| **NFR-107** | Message throughput | Handle 1000+ messages/second per instance | Load testing |
|
| **NFR-107** | Message throughput | Handle 1000+ messages/second per instance | Load testing |
|
||||||
| **NFR-108** | File server scalability | Support horizontal scaling of file server backend | Architecture review |
|
| **NFR-108** | File server scalability | Support horizontal scaling of file server backend | Architecture review |
|
||||||
|
|
||||||
@@ -149,16 +144,16 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
|
|
||||||
| ID | Requirement | Specification |
|
| ID | Requirement | Specification |
|
||||||
|----|-------------|---------------|
|
|----|-------------|---------------|
|
||||||
| **NFR-201** | Message delivery | At-least-once delivery semantics via NATS |
|
| **NFR-201** | Message delivery | At-least-once delivery semantics via transport |
|
||||||
| **NFR-202** | File server availability | Graceful degradation when file server is unavailable |
|
| **NFR-202** | File server availability | Graceful degradation when file server is unavailable |
|
||||||
| **NFR-203** | Connection recovery | Auto-reconnect on NATS connection failure |
|
| **NFR-203** | Connection recovery | Auto-reconnect on transport connection failure |
|
||||||
|
|
||||||
### 4.3 Privacy & Security
|
### 4.3 Privacy & Security
|
||||||
|
|
||||||
| ID | Requirement | Specification |
|
| ID | Requirement | Specification |
|
||||||
|----|-------------|---------------|
|
|----|-------------|---------------|
|
||||||
| **NFR-301** | Payload integrity | SHA-256 checksum support via metadata |
|
| **NFR-301** | Payload integrity | SHA-256 checksum support via metadata |
|
||||||
| **NFR-302** | Transport security | TLS support for NATS connections |
|
| **NFR-302** | Transport security | TLS support for transport connections |
|
||||||
| **NFR-303** | File server security | Authentication token for file uploads |
|
| **NFR-303** | File server security | Authentication token for file uploads |
|
||||||
|
|
||||||
### 4.4 Observability & Telemetry
|
### 4.4 Observability & Telemetry
|
||||||
@@ -234,11 +229,11 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
|
|
||||||
| Platform | Maximum | Notes |
|
| Platform | Maximum | Notes |
|
||||||
|----------|---------|-------|
|
|----------|---------|-------|
|
||||||
| Desktop | Unlimited | Limited by NATS server configuration |
|
| Desktop | Unlimited | Limited by transport server configuration |
|
||||||
| Dart Desktop | Unlimited | Limited by NATS server configuration |
|
| Dart Desktop | Unlimited | Limited by transport server configuration |
|
||||||
| Dart Flutter | Unlimited | Limited by NATS server configuration |
|
| Dart Flutter | Unlimited | Limited by transport server configuration |
|
||||||
| Dart Web | Unlimited | Limited by NATS server configuration |
|
| Dart Web | Unlimited | Limited by transport server configuration |
|
||||||
| Rust | Unlimited | Limited by NATS server configuration |
|
| Rust | Unlimited | Limited by transport server configuration |
|
||||||
| MicroPython | 50KB | Hard limit due to 256KB-1MB memory |
|
| MicroPython | 50KB | Hard limit due to 256KB-1MB memory |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -252,7 +247,7 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| `correlation_id` | String (UUID) | Track message flow across systems |
|
| `correlation_id` | String (UUID) | Track message flow across systems |
|
||||||
| `msg_id` | String (UUID) | Unique message identifier |
|
| `msg_id` | String (UUID) | Unique message identifier |
|
||||||
| `timestamp` | String (ISO 8601) | Message publication timestamp |
|
| `timestamp` | String (ISO 8601) | Message publication timestamp |
|
||||||
| `send_to` | String | NATS subject to publish to |
|
| `send_to` | String | Topic/subject to publish to |
|
||||||
| `msg_purpose` | String | ACK, NACK, updateStatus, shutdown, chat |
|
| `msg_purpose` | String | ACK, NACK, updateStatus, shutdown, chat |
|
||||||
| `sender_name` | String | Sender application name |
|
| `sender_name` | String | Sender application name |
|
||||||
| `sender_id` | String (UUID) | Sender unique identifier |
|
| `sender_id` | String (UUID) | Sender unique identifier |
|
||||||
@@ -260,7 +255,7 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| `receiver_id` | String (UUID) | Receiver unique identifier (empty = broadcast) |
|
| `receiver_id` | String (UUID) | Receiver unique identifier (empty = broadcast) |
|
||||||
| `reply_to` | String | Topic for reply messages |
|
| `reply_to` | String | Topic for reply messages |
|
||||||
| `reply_to_msg_id` | String | Message ID being replied to |
|
| `reply_to_msg_id` | String | Message ID being replied to |
|
||||||
| `broker_url` | String | NATS server URL |
|
| `broker_url` | String | Broker URL for the transport layer |
|
||||||
| `metadata` | Dict | Message-level metadata |
|
| `metadata` | Dict | Message-level metadata |
|
||||||
| `payloads` | Array | List of payload objects |
|
| `payloads` | Array | List of payload objects |
|
||||||
|
|
||||||
@@ -289,14 +284,14 @@ msghandler is a cross-platform, bi-directional data bridge that enables seamless
|
|||||||
| `Failed to upload` | File server error | Throw error |
|
| `Failed to upload` | File server error | Throw error |
|
||||||
| `Failed to fetch` | File server unavailable | Retry with exponential backoff |
|
| `Failed to fetch` | File server unavailable | Retry with exponential backoff |
|
||||||
| `Unknown transport` | Invalid transport type | Throw error |
|
| `Unknown transport` | Invalid transport type | Throw error |
|
||||||
| `NATS connection failed` | NATS unavailable | Throw error |
|
| `Transport connection failed` | Transport/broker unavailable | Throw error |
|
||||||
|
|
||||||
### 9.2 Exception Handling
|
### 9.2 Exception Handling
|
||||||
|
|
||||||
| Scenario | Handler |
|
| Scenario | Handler |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| File server unavailable | Retry up to 5 times with exponential backoff |
|
| File server unavailable | Retry up to 5 times with exponential backoff |
|
||||||
| NATS publish failure | Connection auto-reconnect |
|
| Transport publish failure | Handled by caller |
|
||||||
| Deserialization error | Log correlation ID and throw error |
|
| Deserialization error | Log correlation ID and throw error |
|
||||||
| Memory overflow (MicroPython) | Reject payloads >50KB |
|
| Memory overflow (MicroPython) | Reject payloads >50KB |
|
||||||
|
|
||||||
@@ -350,7 +345,7 @@ function smartsend(
|
|||||||
)::Tuple{msg_envelope_v1, String} where {T1<:Any}
|
)::Tuple{msg_envelope_v1, String} where {T1<:Any}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility. `smartsend` returns `(env::msg_envelope_v1, env_json_str::String)`.
|
**Note**: Publishing via the transport layer is the caller's responsibility. `smartsend` returns `(env::msg_envelope_v1, env_json_str::String)`.
|
||||||
|
|
||||||
### 11.2 smartreceive Signature
|
### 11.2 smartreceive Signature
|
||||||
|
|
||||||
@@ -364,7 +359,9 @@ function smartreceive(
|
|||||||
)::JSON.Object{String, Any}
|
)::JSON.Object{String, Any}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Pass `String(nats_msg.payload)` from NATS subscription to `smartreceive`.
|
**Note**: Pass the payload string from the transport subscription to `smartreceive`. The input is the JSON string payload from the transport message, not the transport message object directly.
|
||||||
|
|
||||||
|
**Note**: Pass the payload from the transport subscription to `smartreceive`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -374,7 +371,7 @@ function smartreceive(
|
|||||||
|
|
||||||
| Component | Minimum | Notes |
|
| Component | Minimum | Notes |
|
||||||
|-----------|---------|-------|
|
|-----------|---------|-------|
|
||||||
| NATS Server | 1 instance | Single node for development |
|
| Message Broker | 1 instance | Single node for development |
|
||||||
| File Server | 1 instance | HTTP server for large payloads |
|
| File Server | 1 instance | HTTP server for large payloads |
|
||||||
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
||||||
| Client Memory | 256KB | MicroPython devices |
|
| Client Memory | 256KB | MicroPython devices |
|
||||||
@@ -383,7 +380,7 @@ function smartreceive(
|
|||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `NATS_URL` | `nats://localhost:4222` | NATS server URL |
|
| `BROKER_URL` | `ws://localhost:4222` | Message broker URL |
|
||||||
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
||||||
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
||||||
|
|
||||||
@@ -409,6 +406,10 @@ function smartreceive(
|
|||||||
|
|
||||||
| Date | Version | Changes |
|
| Date | Version | Changes |
|
||||||
|------|---------|---------|
|
|------|---------|---------|
|
||||||
|
| 2026-05-15 | 1.3.0 | Made transport layer agnostic |
|
||||||
|
| - | - | Removed all NATS-specific dependencies and references |
|
||||||
|
| - | - | Updated all NATS references to generic "transport layer"/"message broker" |
|
||||||
|
| - | - | Removed NATS client packages from dependencies tables |
|
||||||
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) |
|
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) |
|
||||||
| - | - | Fixed smartsend signature: removed is_publish, NATS_connection; added sender_name |
|
| - | - | Fixed smartsend signature: removed is_publish, NATS_connection; added sender_name |
|
||||||
| - | - | Fixed smartreceive signature: takes msg_json_str::String instead of msg::NATS.Msg |
|
| - | - | Fixed smartreceive signature: takes msg_json_str::String instead of msg::NATS.Msg |
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
## 1. Technical Contract Overview
|
## 1. Technical Contract Overview
|
||||||
|
|
||||||
This document defines the **technical contract** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using NATS as the message bus.
|
This document defines the **technical contract** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using a message broker as the transport layer.
|
||||||
|
|
||||||
This specification serves as the single source of truth for:
|
This specification serves as the single source of truth for:
|
||||||
- **Inputs**: What data structures are accepted by `smartsend()`
|
- **Inputs**: What data structures are accepted by `smartsend()`
|
||||||
@@ -28,7 +28,7 @@ This specification serves as the single source of truth for:
|
|||||||
| Section 5 (Enumerations) | FR-003, FR-004, FR-006, NFR-101 | Enumerations for transport and encoding |
|
| Section 5 (Enumerations) | FR-003, FR-004, FR-006, NFR-101 | Enumerations for transport and encoding |
|
||||||
| Section 6 (Transport Protocols) | FR-003, FR-004, NFR-104, NFR-105 | Direct and link transport protocols |
|
| Section 6 (Transport Protocols) | FR-003, FR-004, NFR-104, NFR-105 | Direct and link transport protocols |
|
||||||
| Section 7 (Size Thresholds) | FR-004, FR-005, NFR-104, NFR-105 | Size thresholds for transport selection |
|
| Section 7 (Size Thresholds) | FR-004, FR-005, NFR-104, NFR-105 | Size thresholds for transport selection |
|
||||||
| Section 8 (NATS Subject Convention) | FR-013, FR-014 | NATS subject naming patterns |
|
| Section 8 (Topic Convention) | FR-013, FR-014 | Topic/subject naming patterns |
|
||||||
| Section 9 (Error Handling) | FR-010, FR-011, NFR-201, NFR-202, NFR-203 | Error codes and exception handling |
|
| Section 9 (Error Handling) | FR-010, FR-011, NFR-201, NFR-202, NFR-203 | Error codes and exception handling |
|
||||||
| Section 10 (Serialization Rules) | FR-001, FR-002, FR-003, FR-012, NFR-101, NFR-102 | Serialization and encoding rules |
|
| Section 10 (Serialization Rules) | FR-001, FR-002, FR-003, FR-012, NFR-101, NFR-102 | Serialization and encoding rules |
|
||||||
| Section 11 (API Contract) | FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 | Function signatures for all platforms |
|
| Section 11 (API Contract) | FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 | Function signatures for all platforms |
|
||||||
@@ -95,7 +95,7 @@ This specification serves as the single source of truth for:
|
|||||||
| `correlation_id` | `string` | Yes | UUID v4 format | Track message flow across distributed systems | FR-011, NFR-401 |
|
| `correlation_id` | `string` | Yes | UUID v4 format | Track message flow across distributed systems | FR-011, NFR-401 |
|
||||||
| `msg_id` | `string` | Yes | UUID v4 format | Unique identifier for this specific message | FR-012, NFR-401 |
|
| `msg_id` | `string` | Yes | UUID v4 format | Unique identifier for this specific message | FR-012, NFR-401 |
|
||||||
| `timestamp` | `string` | Yes | ISO 8601 UTC | Message publication timestamp | FR-012, NFR-401 |
|
| `timestamp` | `string` | Yes | ISO 8601 UTC | Message publication timestamp | FR-012, NFR-401 |
|
||||||
| `send_to` | `string` | Yes | Non-empty string | NATS subject/topic to publish the message to | FR-013 |
|
| `send_to` | `string` | Yes | Non-empty string | Topic/subject to publish the message to | FR-013 |
|
||||||
| `msg_purpose` | `string` | Yes | Enum | Purpose of the message | FR-013 |
|
| `msg_purpose` | `string` | Yes | Enum | Purpose of the message | FR-013 |
|
||||||
| `sender_name` | `string` | Yes | Non-empty string | Name of the sender application | FR-013 |
|
| `sender_name` | `string` | Yes | Non-empty string | Name of the sender application | FR-013 |
|
||||||
| `sender_id` | `string` | Yes | UUID v4 format | Unique identifier for the sender | FR-013 |
|
| `sender_id` | `string` | Yes | UUID v4 format | Unique identifier for the sender | FR-013 |
|
||||||
@@ -103,7 +103,7 @@ This specification serves as the single source of truth for:
|
|||||||
| `receiver_id` | `string` | Yes | Any string | UUID of the receiver (empty = broadcast) | FR-013 |
|
| `receiver_id` | `string` | Yes | Any string | UUID of the receiver (empty = broadcast) | FR-013 |
|
||||||
| `reply_to` | `string` | Yes | Any string | Topic where receiver should reply | FR-013 |
|
| `reply_to` | `string` | Yes | Any string | Topic where receiver should reply | FR-013 |
|
||||||
| `reply_to_msg_id` | `string` | Yes | Any string | Message ID this message is replying to | FR-013 |
|
| `reply_to_msg_id` | `string` | Yes | Any string | Message ID this message is replying to | FR-013 |
|
||||||
| `broker_url` | `string` | Yes | Valid URL | NATS broker URL | FR-013 |
|
| `broker_url` | `string` | Yes | Valid URL | Broker URL for the transport layer | FR-013 |
|
||||||
| `metadata` | `object` | No | Any JSON object | Message-level metadata | NFR-401 |
|
| `metadata` | `object` | No | Any JSON object | Message-level metadata | NFR-401 |
|
||||||
| `payloads` | `array` | Yes | Non-empty array | List of payload objects | FR-012, FR-013 |
|
| `payloads` | `array` | Yes | Non-empty array | List of payload objects | FR-012, FR-013 |
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ await smartsend("/agent/v1/process", data)
|
|||||||
|
|
||||||
| Value | Description | Data Format | Use Case |
|
| Value | Description | Data Format | Use Case |
|
||||||
|-------|-------------|-------------|----------|
|
|-------|-------------|-------------|----------|
|
||||||
| `direct` | Payload sent directly via NATS | Base64-encoded string | Payloads < size_threshold |
|
| `direct` | Payload sent directly via the transport layer | Base64-encoded string | Payloads < size_threshold |
|
||||||
| `link` | Payload uploaded to file server | HTTP URL | Payloads ≥ size_threshold |
|
| `link` | Payload uploaded to file server | HTTP URL | Payloads ≥ size_threshold |
|
||||||
|
|
||||||
### `encoding` Enum
|
### `encoding` Enum
|
||||||
@@ -312,7 +312,7 @@ When `transport = "link"`, the `data` field contains a URL pointing to the uploa
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## NATS Subject Convention
|
## Topic Convention
|
||||||
|
|
||||||
### Subject Naming Pattern
|
### Subject Naming Pattern
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ When `transport = "link"`, the `data` field contains a URL pointing to the uploa
|
|||||||
| `INVALID_TRANSPORT` | 400 | Unsupported transport type | Use `direct` or `link` | FR-003, FR-004, FR-006 |
|
| `INVALID_TRANSPORT` | 400 | Unsupported transport type | Use `direct` or `link` | FR-003, FR-004, FR-006 |
|
||||||
| `UPLOAD_FAILED` | 500 | File server upload failed | Retry or use direct transport | FR-008, FR-009 |
|
| `UPLOAD_FAILED` | 500 | File server upload failed | Retry or use direct transport | FR-008, FR-009 |
|
||||||
| `DOWNLOAD_FAILED` | 503 | File server download failed | Retry with exponential backoff | FR-010, FR-011, NFR-201, NFR-202 |
|
| `DOWNLOAD_FAILED` | 503 | File server download failed | Retry with exponential backoff | FR-010, FR-011, NFR-201, NFR-202 |
|
||||||
| `NATS_CONNECTION_FAILED` | 503 | NATS connection failed | Check NATS server availability | FR-013, FR-014, NFR-201, NFR-203 |
|
| `TRANSPORT_CONNECTION_FAILED` | 503 | Transport connection failed | Check broker/server availability | FR-013, FR-014, NFR-201, NFR-203 |
|
||||||
| `DESERIALIZATION_ERROR` | 500 | Payload deserialization failed | Check payload_type matches data | FR-001, FR-002, FR-003, FR-012 |
|
| `DESERIALIZATION_ERROR` | 500 | Payload deserialization failed | Check payload_type matches data | FR-001, FR-002, FR-003, FR-012 |
|
||||||
| `SIZE_EXCEEDED` | 413 | Payload exceeds maximum size | Split payload or use link transport | FR-003, FR-004, FR-005, NFR-104, NFR-105 |
|
| `SIZE_EXCEEDED` | 413 | Payload exceeds maximum size | Split payload or use link transport | FR-003, FR-004, FR-005, NFR-104, NFR-105 |
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ When `transport = "link"`, the `data` field contains a URL pointing to the uploa
|
|||||||
| Scenario | Handler | Retry Policy | Requirement ID |
|
| Scenario | Handler | Retry Policy | Requirement ID |
|
||||||
|----------|---------|--------------|----------------|
|
|----------|---------|--------------|----------------|
|
||||||
| File server unavailable | Retry up to 5 times | Exponential backoff (100ms → 5000ms) | FR-010, NFR-202 |
|
| File server unavailable | Retry up to 5 times | Exponential backoff (100ms → 5000ms) | FR-010, NFR-202 |
|
||||||
| NATS publish failure | Connection auto-reconnect | TCP-level reconnection | FR-013, FR-014, NFR-201, NFR-203 |
|
| Transport publish failure | Handled by caller | Caller's retry logic | FR-013, FR-014, NFR-201, NFR-203 |
|
||||||
| Deserialization error | Log correlation ID and throw | No retry (data corruption) | FR-001, FR-002, FR-003, FR-012, NFR-401 |
|
| Deserialization error | Log correlation ID and throw | No retry (data corruption) | FR-001, FR-002, FR-003, FR-012, NFR-401 |
|
||||||
| Memory overflow (MicroPython) | Reject payloads >50KB | No retry (client-side check) | FR-005, NFR-106 |
|
| Memory overflow (MicroPython) | Reject payloads >50KB | No retry (client-side check) | FR-005, NFR-106 |
|
||||||
|
|
||||||
@@ -435,7 +435,7 @@ function smartsend(
|
|||||||
)::Tuple{msg_envelope_v1, String} where {T1<:Any}
|
)::Tuple{msg_envelope_v1, String} where {T1<:Any}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility. Returns `(env::msg_envelope_v1, env_json_str::String)`.
|
**Note**: Publishing via the transport layer is the caller's responsibility. Returns `(env::msg_envelope_v1, env_json_str::String)`.
|
||||||
|
|
||||||
#### Python
|
#### Python
|
||||||
|
|
||||||
@@ -443,7 +443,7 @@ function smartsend(
|
|||||||
async def smartsend(
|
async def smartsend(
|
||||||
subject: str,
|
subject: str,
|
||||||
data: List[Tuple[str, Any, str]],
|
data: List[Tuple[str, Any, str]],
|
||||||
broker_url: str = "nats://localhost:4222",
|
broker_url: str = DEFAULT_BROKER_URL,
|
||||||
fileserver_url: str = "http://localhost:8080",
|
fileserver_url: str = "http://localhost:8080",
|
||||||
fileserver_upload_handler: Callable = plik_oneshot_upload,
|
fileserver_upload_handler: Callable = plik_oneshot_upload,
|
||||||
size_threshold: int = 500_000,
|
size_threshold: int = 500_000,
|
||||||
@@ -459,7 +459,7 @@ async def smartsend(
|
|||||||
) -> Tuple[Dict, str]:
|
) -> Tuple[Dict, str]:
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility.
|
**Note**: Publishing via the transport layer is the caller's responsibility.
|
||||||
|
|
||||||
#### JavaScript (Node.js)
|
#### JavaScript (Node.js)
|
||||||
|
|
||||||
@@ -485,7 +485,7 @@ async function smartsend(
|
|||||||
): Promise<[Object, string]>;
|
): Promise<[Object, string]>;
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility.
|
**Note**: Publishing via the transport layer is the caller's responsibility.
|
||||||
|
|
||||||
#### JavaScript (Browser)
|
#### JavaScript (Browser)
|
||||||
|
|
||||||
@@ -511,7 +511,7 @@ async function smartsend(
|
|||||||
): Promise<[Object, string]>;
|
): Promise<[Object, string]>;
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility.
|
**Note**: Publishing via the transport layer is the caller's responsibility.
|
||||||
|
|
||||||
#### MicroPython
|
#### MicroPython
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ def smartsend(
|
|||||||
) -> Tuple[Dict, str]:
|
) -> Tuple[Dict, str]:
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility.
|
**Note**: Publishing via the transport layer is the caller's responsibility.
|
||||||
|
|
||||||
#### Dart (Desktop/Flutter)
|
#### Dart (Desktop/Flutter)
|
||||||
|
|
||||||
@@ -532,10 +532,10 @@ def smartsend(
|
|||||||
Future<[Map<String, dynamic>, String]> smartsend(
|
Future<[Map<String, dynamic>, String]> smartsend(
|
||||||
String subject,
|
String subject,
|
||||||
List<List<dynamic>> data, {
|
List<List<dynamic>> data, {
|
||||||
String brokerUrl = 'nats://localhost:4222',
|
String brokerUrl = DEFAULT_BROKER_URL,
|
||||||
String fileserverUrl = 'http://localhost:8080',
|
String fileserverUrl = DEFAULT_FILESERVER_URL,
|
||||||
Function? fileserverUploadHandler,
|
Function? fileserverUploadHandler,
|
||||||
int sizeThreshold = 500000,
|
int sizeThreshold = DEFAULT_SIZE_THRESHOLD,
|
||||||
String? correlationId,
|
String? correlationId,
|
||||||
String msgPurpose = 'chat',
|
String msgPurpose = 'chat',
|
||||||
String senderName = 'msghandler',
|
String senderName = 'msghandler',
|
||||||
@@ -547,9 +547,8 @@ Future<[Map<String, dynamic>, String]> smartsend(
|
|||||||
String? senderId,
|
String? senderId,
|
||||||
}) async {
|
}) async {
|
||||||
// Returns [envelope, jsonString]
|
// Returns [envelope, jsonString]
|
||||||
// NATS publishing is caller's responsibility
|
// Publishing via transport layer is caller's responsibility
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
#### Dart Web
|
#### Dart Web
|
||||||
|
|
||||||
@@ -557,7 +556,7 @@ Future<[Map<String, dynamic>, String]> smartsend(
|
|||||||
Future<[Map<String, dynamic>, String]> smartsend(
|
Future<[Map<String, dynamic>, String]> smartsend(
|
||||||
String subject,
|
String subject,
|
||||||
List<List<dynamic>> data, {
|
List<List<dynamic>> data, {
|
||||||
String brokerUrl = 'nats://localhost:4222',
|
String brokerUrl = DEFAULT_BROKER_URL,
|
||||||
String fileserverUrl = 'http://localhost:8080',
|
String fileserverUrl = 'http://localhost:8080',
|
||||||
Function? fileserverUploadHandler,
|
Function? fileserverUploadHandler,
|
||||||
int sizeThreshold = 500000,
|
int sizeThreshold = 500000,
|
||||||
@@ -572,7 +571,7 @@ Future<[Map<String, dynamic>, String]> smartsend(
|
|||||||
String? senderId,
|
String? senderId,
|
||||||
}) async {
|
}) async {
|
||||||
// Returns [envelope, jsonString]
|
// Returns [envelope, jsonString]
|
||||||
// NATS publishing is caller's responsibility
|
// Publishing via transport layer is caller's responsibility
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -635,7 +634,7 @@ pub struct MsgEnvelopeV1 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: NATS publishing is the caller's responsibility. Returns `Result<(MsgEnvelopeV1, String), msghandlerError>`. Uses `serde` for JSON serialization.
|
**Note**: Publishing via the transport layer is the caller's responsibility. Returns `Result<(MsgEnvelopeV1, String), msghandlerError>`. Uses `serde` for JSON serialization.
|
||||||
|
|
||||||
### `smartreceive` Function Signature
|
### `smartreceive` Function Signature
|
||||||
|
|
||||||
@@ -643,7 +642,7 @@ pub struct MsgEnvelopeV1 {
|
|||||||
|
|
||||||
```julia
|
```julia
|
||||||
function smartreceive(
|
function smartreceive(
|
||||||
msg_json_str::String; # Pass String(nats_msg.payload) from NATS subscription
|
msg_json_str::String; # Pass payload from transport subscription
|
||||||
fileserver_download_handler::Function = _fetch_with_backoff,
|
fileserver_download_handler::Function = _fetch_with_backoff,
|
||||||
max_retries::Int = 5,
|
max_retries::Int = 5,
|
||||||
base_delay::Int = 100,
|
base_delay::Int = 100,
|
||||||
@@ -651,13 +650,13 @@ function smartreceive(
|
|||||||
)::JSON.Object{String, Any}
|
)::JSON.Object{String, Any}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Input is JSON string from NATS message payload, not NATS.Msg directly.
|
**Note**: Input is the JSON string payload from the transport subscription, not the transport message object directly.
|
||||||
|
|
||||||
#### Python
|
#### Python
|
||||||
|
|
||||||
```python
|
```python
|
||||||
async def smartreceive(
|
async def smartreceive(
|
||||||
msg_json_str: str, # JSON string from NATS message payload
|
msg_json_str: str, # JSON string from transport message payload
|
||||||
fileserver_download_handler: Callable = fetch_with_backoff,
|
fileserver_download_handler: Callable = fetch_with_backoff,
|
||||||
max_retries: int = 5,
|
max_retries: int = 5,
|
||||||
base_delay: int = 100,
|
base_delay: int = 100,
|
||||||
@@ -665,13 +664,13 @@ async def smartreceive(
|
|||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Input is JSON string from NATS message payload.
|
**Note**: Input is the JSON string payload from the transport message.
|
||||||
|
|
||||||
#### JavaScript (Node.js)
|
#### JavaScript (Node.js)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
async function smartreceive(
|
async function smartreceive(
|
||||||
msg_json_str: string, // JSON string from NATS message payload
|
msg_json_str: string, // JSON string from transport message payload
|
||||||
options?: {
|
options?: {
|
||||||
fileserver_download_handler?: Function;
|
fileserver_download_handler?: Function;
|
||||||
max_retries?: number;
|
max_retries?: number;
|
||||||
@@ -685,7 +684,7 @@ async function smartreceive(
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
async function smartreceive(
|
async function smartreceive(
|
||||||
msg_json_str: string, // JSON string from NATS message payload
|
msg_json_str: string, // JSON string from transport message payload
|
||||||
options?: {
|
options?: {
|
||||||
fileserver_download_handler?: Function;
|
fileserver_download_handler?: Function;
|
||||||
max_retries?: number;
|
max_retries?: number;
|
||||||
@@ -695,7 +694,7 @@ async function smartreceive(
|
|||||||
): Promise<Object>;
|
): Promise<Object>;
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Input is JSON string from NATS message payload.
|
**Note**: Input is the JSON string payload from the transport message.
|
||||||
|
|
||||||
#### MicroPython
|
#### MicroPython
|
||||||
|
|
||||||
@@ -703,13 +702,13 @@ async function smartreceive(
|
|||||||
def smartreceive(msg_json_str: str, **kwargs) -> Dict[str, Any]:
|
def smartreceive(msg_json_str: str, **kwargs) -> Dict[str, Any]:
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Input is JSON string from NATS message payload.
|
**Note**: Input is the JSON string payload from the transport message.
|
||||||
|
|
||||||
#### Dart (Desktop/Flutter)
|
#### Dart (Desktop/Flutter)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Future<Map<String, dynamic>> smartreceive(
|
Future<Map<String, dynamic>> smartreceive(
|
||||||
Map<String, dynamic> msg_json_str, // JSON object from NATS message payload
|
Map<String, dynamic> msg_json_str, // JSON object from transport message payload
|
||||||
{
|
{
|
||||||
Function? fileserverDownloadHandler,
|
Function? fileserverDownloadHandler,
|
||||||
int maxRetries = 5,
|
int maxRetries = 5,
|
||||||
@@ -724,7 +723,7 @@ Future<Map<String, dynamic>> smartreceive(
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
Future<Map<String, dynamic>> smartreceive(
|
Future<Map<String, dynamic>> smartreceive(
|
||||||
Map<String, dynamic> msg_json_str, // JSON object from NATS message payload
|
Map<String, dynamic> msg_json_str, // JSON object from transport message payload
|
||||||
{
|
{
|
||||||
Function? fileserverDownloadHandler,
|
Function? fileserverDownloadHandler,
|
||||||
int maxRetries = 5,
|
int maxRetries = 5,
|
||||||
@@ -739,7 +738,7 @@ Future<Map<String, dynamic>> smartreceive(
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub async fn smartreceive(
|
pub async fn smartreceive(
|
||||||
msg_json_str: &str, // JSON string from NATS message payload
|
msg_json_str: &str, // JSON string from transport message payload
|
||||||
options: &SmartreceiveOptions,
|
options: &SmartreceiveOptions,
|
||||||
) -> Result<MsgEnvelopeV1, msghandlerError>
|
) -> Result<MsgEnvelopeV1, msghandlerError>
|
||||||
|
|
||||||
@@ -752,7 +751,7 @@ pub struct SmartreceiveOptions {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Input is JSON string from NATS message payload. Returns `Result<MsgEnvelopeV1, msghandlerError>`.
|
**Note**: Input is the JSON string payload from the transport message. Returns `Result<MsgEnvelopeV1, msghandlerError>`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -897,7 +896,7 @@ function fileserver_download_handler(
|
|||||||
|------|----------|----------|-------|
|
|------|----------|----------|-------|
|
||||||
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | Ground truth implementation |
|
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | Ground truth implementation |
|
||||||
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | Server-side JavaScript |
|
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | Server-side JavaScript |
|
||||||
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only, WebSocket NATS | Client-side rendering |
|
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only | Client-side rendering |
|
||||||
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | Desktop Python |
|
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | Desktop Python |
|
||||||
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | Desktop/Flutter/Web |
|
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | Desktop/Flutter/Web |
|
||||||
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe | Uses tokio + serde + arrow2 |
|
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe | Uses tokio + serde + arrow2 |
|
||||||
@@ -910,7 +909,7 @@ The browser implementation ([`src/msghandler_csr.js`](../src/msghandler_csr.js))
|
|||||||
| Constraint | Reason | Workaround |
|
| Constraint | Reason | Workaround |
|
||||||
|------------|--------|------------|
|
|------------|--------|------------|
|
||||||
| No Apache Arrow IPC | Browser-incompatible dependency | Use `jsontable` for tabular data |
|
| No Apache Arrow IPC | Browser-incompatible dependency | Use `jsontable` for tabular data |
|
||||||
| WebSocket NATS only | Browser cannot use TCP directly | Use `ws://` or `wss://` broker URLs |
|
| WebSocket only | Browser cannot use TCP directly | Use `ws://` or `wss://` broker URLs |
|
||||||
| Fetch API for HTTP | Browser fetch() API only | Compatible with Plik and other HTTP servers |
|
| Fetch API for HTTP | Browser fetch() API only | Compatible with Plik and other HTTP servers |
|
||||||
|
|
||||||
### Payload Type Availability by Platform
|
### Payload Type Availability by Platform
|
||||||
@@ -941,7 +940,7 @@ flowchart TD
|
|||||||
D --> F[Build envelope with metadata]
|
D --> F[Build envelope with metadata]
|
||||||
E --> F
|
E --> F
|
||||||
F --> G[Convert envelope to JSON string]
|
F --> G[Convert envelope to JSON string]
|
||||||
G --> H[Publish to NATS subject]
|
G --> H[Publish to topic via transport]
|
||||||
H --> I[Return envelope and JSON string to caller]
|
H --> I[Return envelope and JSON string to caller]
|
||||||
|
|
||||||
style A fill:#f9f9f9,stroke:#333
|
style A fill:#f9f9f9,stroke:#333
|
||||||
@@ -954,7 +953,7 @@ flowchart TD
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
A[NATS message arrives] --> B[Parse JSON envelope]
|
A[Transport message arrives] --> B[Parse JSON envelope]
|
||||||
B --> C[For each payload: Check transport type]
|
B --> C[For each payload: Check transport type]
|
||||||
C -->|transport == direct| D[Direct Transport: Extract Base64]
|
C -->|transport == direct| D[Direct Transport: Extract Base64]
|
||||||
C -->|transport == link| E[Link Transport: Fetch from URL]
|
C -->|transport == link| E[Link Transport: Fetch from URL]
|
||||||
@@ -1046,23 +1045,17 @@ flowchart TD
|
|||||||
|
|
||||||
| Platform | Package | Version | Purpose |
|
| Platform | Package | Version | Purpose |
|
||||||
|----------|---------|---------|---------|
|
|----------|---------|---------|---------|
|
||||||
| Julia | NATS.jl | Latest | NATS client |
|
|
||||||
| Julia | JSON.jl | Latest | JSON serialization |
|
| Julia | JSON.jl | Latest | JSON serialization |
|
||||||
| Julia | Arrow.jl | Latest | Arrow IPC support |
|
| Julia | Arrow.jl | Latest | Arrow IPC support |
|
||||||
| Julia | HTTP.jl | Latest | HTTP file server |
|
| Julia | HTTP.jl | Latest | HTTP file server |
|
||||||
| Julia | UUIDs.jl | Latest | UUID generation |
|
| Julia | UUIDs.jl | Latest | UUID generation |
|
||||||
| Node.js | nats | Latest | NATS client (TCP) |
|
|
||||||
| Node.js | node-fetch | Latest | HTTP file server |
|
| Node.js | node-fetch | Latest | HTTP file server |
|
||||||
| Browser | nats.ws | Latest | NATS client (WebSocket) |
|
| Browser | - | - | Transport-agnostic (caller provides) |
|
||||||
| Browser | nats | Latest | NATS client (for bundling) |
|
|
||||||
| Python | nats-py | Latest | NATS client |
|
|
||||||
| Python | aiohttp | Latest | HTTP file server |
|
| Python | aiohttp | Latest | HTTP file server |
|
||||||
| Python | pyarrow | Latest | Arrow IPC support |
|
| Python | pyarrow | Latest | Arrow IPC support |
|
||||||
| Dart | nats | Latest | NATS client |
|
|
||||||
| Dart | http | Latest | HTTP file server |
|
| Dart | http | Latest | HTTP file server |
|
||||||
| Dart | uuid | Latest | UUID generation |
|
| Dart | uuid | Latest | UUID generation |
|
||||||
| Dart | dart-arrow | Latest | Arrow IPC support (Desktop/Flutter) |
|
| Dart | dart-arrow | Latest | Arrow IPC support (Desktop/Flutter) |
|
||||||
| Rust | nats | Latest | NATS client |
|
|
||||||
| Rust | serde | Latest | JSON serialization |
|
| Rust | serde | Latest | JSON serialization |
|
||||||
| Rust | serde_json | Latest | JSON handling |
|
| Rust | serde_json | Latest | JSON handling |
|
||||||
| Rust | tokio | Latest | Async runtime |
|
| Rust | tokio | Latest | Async runtime |
|
||||||
@@ -1084,6 +1077,10 @@ flowchart TD
|
|||||||
|
|
||||||
| Date | Version | Changes |
|
| Date | Version | Changes |
|
||||||
|------|---------|---------|
|
|------|---------|---------|
|
||||||
|
| 2026-05-15 | 1.3.0 | Made transport layer agnostic |
|
||||||
|
| - | - | Removed all NATS-specific dependencies (NATS.jl, nats, nats-py, nats.ws) |
|
||||||
|
| - | - | Updated docs to reference generic message broker/transport |
|
||||||
|
| - | - | broker_url is now metadata only, not used for active connections |
|
||||||
| 2026-03-15 | 1.1.0 | Browser connection management |
|
| 2026-03-15 | 1.1.0 | Browser connection management |
|
||||||
| - | - | Added NATSClient class with keepAlive support |
|
| - | - | Added NATSClient class with keepAlive support |
|
||||||
| - | - | Added NATSConnectionPool for connection reuse |
|
| - | - | Added NATSConnectionPool for connection reuse |
|
||||||
@@ -1119,7 +1116,7 @@ flowchart TD
|
|||||||
|------|----------|----------|--------------------------|
|
|------|----------|----------|--------------------------|
|
||||||
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only, WebSocket NATS | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe | FR-001 through FR-014, NFR-101 through NFR-405 |
|
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe | FR-001 through FR-014, NFR-101 through NFR-405 |
|
||||||
@@ -1129,23 +1126,17 @@ flowchart TD
|
|||||||
|
|
||||||
| Platform | Package | Version | Purpose | Requirements Traceability |
|
| Platform | Package | Version | Purpose | Requirements Traceability |
|
||||||
|----------|---------|---------|---------|--------------------------|
|
|----------|---------|---------|---------|--------------------------|
|
||||||
| Julia | NATS.jl | Latest | NATS client | FR-013, FR-014, NFR-201 |
|
|
||||||
| Julia | JSON.jl | Latest | JSON serialization | FR-012, NFR-101, NFR-102 |
|
| Julia | JSON.jl | Latest | JSON serialization | FR-012, NFR-101, NFR-102 |
|
||||||
| Julia | Arrow.jl | Latest | Arrow IPC support | FR-002, FR-012 |
|
| Julia | Arrow.jl | Latest | Arrow IPC support | FR-002, FR-012 |
|
||||||
| Julia | HTTP.jl | Latest | HTTP file server | FR-008, FR-009 |
|
| Julia | HTTP.jl | Latest | HTTP file server | FR-008, FR-009 |
|
||||||
| Julia | UUIDs.jl | Latest | UUID generation | FR-011, NFR-401 |
|
| Julia | UUIDs.jl | Latest | UUID generation | FR-011, NFR-401 |
|
||||||
| Node.js | nats | Latest | NATS client (TCP) | FR-013, FR-014 |
|
|
||||||
| Node.js | node-fetch | Latest | HTTP file server | FR-008, FR-009 |
|
| Node.js | node-fetch | Latest | HTTP file server | FR-008, FR-009 |
|
||||||
| Browser | nats.ws | Latest | NATS client (WebSocket) | FR-013, FR-014 |
|
| Browser | - | - | Transport-agnostic (caller provides) | FR-013, FR-014 |
|
||||||
| Browser | nats | Latest | NATS client (for bundling) | FR-013, FR-014 |
|
|
||||||
| Python | nats-py | Latest | NATS client | FR-013, FR-014 |
|
|
||||||
| Python | aiohttp | Latest | HTTP file server | FR-008, FR-009 |
|
| Python | aiohttp | Latest | HTTP file server | FR-008, FR-009 |
|
||||||
| Python | pyarrow | Latest | Arrow IPC support | FR-002, FR-012 |
|
| Python | pyarrow | Latest | Arrow IPC support | FR-002, FR-012 |
|
||||||
| Dart | nats | Latest | NATS client | FR-013, FR-014 |
|
|
||||||
| Dart | http | Latest | HTTP file server | FR-008, FR-009 |
|
| Dart | http | Latest | HTTP file server | FR-008, FR-009 |
|
||||||
| Dart | uuid | Latest | UUID generation | FR-011, NFR-401 |
|
| Dart | uuid | Latest | UUID generation | FR-011, NFR-401 |
|
||||||
| Dart | dart-arrow | Latest | Arrow IPC support | FR-002, FR-012 |
|
| Dart | dart-arrow | Latest | Arrow IPC support | FR-002, FR-012 |
|
||||||
| Rust | nats | Latest | NATS client | FR-013, FR-014 |
|
|
||||||
| Rust | serde | Latest | JSON serialization | FR-012, NFR-101, NFR-102 |
|
| Rust | serde | Latest | JSON serialization | FR-012, NFR-101, NFR-102 |
|
||||||
| Rust | serde_json | Latest | JSON handling | FR-012, NFR-101, NFR-102 |
|
| Rust | serde_json | Latest | JSON handling | FR-012, NFR-101, NFR-102 |
|
||||||
| Rust | tokio | Latest | Async runtime | FR-013, FR-014 |
|
| Rust | tokio | Latest | Async runtime | FR-013, FR-014 |
|
||||||
@@ -1160,6 +1151,10 @@ flowchart TD
|
|||||||
|
|
||||||
| Date | Version | Changes | Requirement ID(s) |
|
| Date | Version | Changes | Requirement ID(s) |
|
||||||
|------|---------|---------|-------------------|
|
|------|---------|---------|-------------------|
|
||||||
|
| 2026-05-15 | 1.3.0 | Made transport layer agnostic | All |
|
||||||
|
| - | - | Removed NATS-specific dependencies and references from all docs | All |
|
||||||
|
| - | - | Updated all NATS references to generic "transport layer"/"message broker" | All |
|
||||||
|
| - | - | Removed NATS client packages from dependencies tables | All |
|
||||||
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) | All |
|
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) | All |
|
||||||
| - | - | Updated smartsend signatures: removed is_publish, nats_connection; added sender_name | FR-001 through FR-014 |
|
| - | - | Updated smartsend signatures: removed is_publish, nats_connection; added sender_name | FR-001 through FR-014 |
|
||||||
| - | - | Updated smartreceive signatures: takes msg_json_str::String instead of msg | FR-001 through FR-014 |
|
| - | - | Updated smartreceive signatures: takes msg_json_str::String instead of msg | FR-001 through FR-014 |
|
||||||
@@ -1200,7 +1195,7 @@ flowchart TD
|
|||||||
"send_to": {
|
"send_to": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"description": "NATS subject to publish to"
|
"description": "Topic/subject to publish to"
|
||||||
},
|
},
|
||||||
"msg_purpose": {
|
"msg_purpose": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1236,8 +1231,7 @@ flowchart TD
|
|||||||
},
|
},
|
||||||
"broker_url": {
|
"broker_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^nats://[^\\s]+$",
|
"description": "Broker URL for the transport layer"
|
||||||
"description": "NATS broker URL"
|
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -1302,14 +1296,14 @@ flowchart TD
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### B. AsyncAPI Specification (NATS)
|
### B. AsyncAPI Specification
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
asyncapi: '2.6.0'
|
asyncapi: '2.6.0'
|
||||||
info:
|
info:
|
||||||
title: msghandler API
|
title: msghandler API
|
||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
description: Cross-platform bi-directional data bridge using NATS
|
description: Cross-platform bi-directional data bridge using a message broker
|
||||||
contact:
|
contact:
|
||||||
name: msghandler Team
|
name: msghandler Team
|
||||||
url: https://github.com/your-org/msghandler
|
url: https://github.com/your-org/msghandler
|
||||||
@@ -1331,12 +1325,12 @@ channels:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
publish:
|
publish:
|
||||||
summary: Publish message to NATS
|
summary: Publish message to transport
|
||||||
operationId: publishMessage
|
operationId: publishMessage
|
||||||
message:
|
message:
|
||||||
$ref: '#/components/message'
|
$ref: '#/components/message'
|
||||||
subscribe:
|
subscribe:
|
||||||
summary: Subscribe to NATS messages
|
summary: Subscribe to messages from transport
|
||||||
operationId: subscribeMessage
|
operationId: subscribeMessage
|
||||||
message:
|
message:
|
||||||
$ref: '#/components/message'
|
$ref: '#/components/message'
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## 1. Executive Summary
|
## 1. Executive Summary
|
||||||
|
|
||||||
This document provides the **end-to-end trace** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using NATS as the message bus.
|
This document provides the **end-to-end trace** for msghandler - the cross-platform bi-directional data bridge that enables seamless communication between **Julia**, **JavaScript**, **Python**, **Dart**, **Rust**, and **MicroPython** applications using a message broker as the transport layer.
|
||||||
|
|
||||||
This walkthrough serves as the primary onboarding guide for new developers and explains:
|
This walkthrough serves as the primary onboarding guide for new developers and explains:
|
||||||
- **User scenarios** - Real-world use cases from developer perspective
|
- **User scenarios** - Real-world use cases from developer perspective
|
||||||
@@ -51,7 +51,7 @@ flowchart TB
|
|||||||
S3["Size Check"]
|
S3["Size Check"]
|
||||||
S4["Transport Selection"]
|
S4["Transport Selection"]
|
||||||
S5["Build Envelope"]
|
S5["Build Envelope"]
|
||||||
S6["Publish to NATS"]
|
S6["Publish to transport"]
|
||||||
|
|
||||||
S1 --> S2
|
S1 --> S2
|
||||||
S2 --> S3
|
S2 --> S3
|
||||||
@@ -62,7 +62,7 @@ flowchart TB
|
|||||||
|
|
||||||
subgraph Receiver["Receiver (smartreceive)"]
|
subgraph Receiver["Receiver (smartreceive)"]
|
||||||
direction LR
|
direction LR
|
||||||
R1["Subscribe to NATS"]
|
R1["Subscribe via transport"]
|
||||||
R2["Parse Envelope"]
|
R2["Parse Envelope"]
|
||||||
R3["Check Transport"]
|
R3["Check Transport"]
|
||||||
R4["Deserialize Data"]
|
R4["Deserialize Data"]
|
||||||
@@ -99,7 +99,7 @@ flowchart TB
|
|||||||
|
|
||||||
| Principle | Description | Rationale |
|
| Principle | Description | Rationale |
|
||||||
|-----------|-------------|-----------|
|
|-----------|-------------|-----------|
|
||||||
| **Claim-Check Pattern** | Large payloads uploaded to HTTP server, URL sent via NATS | NATS has message size limits; avoids NATS overflow |
|
| **Claim-Check Pattern** | Large payloads uploaded to HTTP server, URL sent via transport | Transport has message size limits; avoids overflow |
|
||||||
| **Automatic Transport Selection** | Direct (< threshold) vs Link (≥ threshold) based on size | Optimizes memory vs network I/O trade-off |
|
| **Automatic Transport Selection** | Direct (< threshold) vs Link (≥ threshold) based on size | Optimizes memory vs network I/O trade-off |
|
||||||
| **Cross-Platform API** | Consistent `smartsend()`/`smartreceive()` across all platforms | Simplifies developer experience |
|
| **Cross-Platform API** | Consistent `smartsend()`/`smartreceive()` across all platforms | Simplifies developer experience |
|
||||||
| **Exponential Backoff** | Retry downloads with increasing delays | Handles transient failures gracefully |
|
| **Exponential Backoff** | Retry downloads with increasing delays | Handles transient failures gracefully |
|
||||||
@@ -148,7 +148,7 @@ For each payload, msghandler determines transport:
|
|||||||
|
|
||||||
**Rationale**:
|
**Rationale**:
|
||||||
- Direct transport is faster for small payloads (no file server round-trip)
|
- Direct transport is faster for small payloads (no file server round-trip)
|
||||||
- Link transport is used when payload ≥ 0.5MB (avoids NATS size limits)
|
- Link transport is used when payload ≥ 0.5MB (avoids transport size limits)
|
||||||
|
|
||||||
#### Step 3: Serialization and Encoding
|
#### Step 3: Serialization and Encoding
|
||||||
|
|
||||||
@@ -213,25 +213,26 @@ msghandler builds the message envelope:
|
|||||||
- **reply_to**: Tells backend where to send response
|
- **reply_to**: Tells backend where to send response
|
||||||
- **payloads array**: Contains all data with metadata for proper handling
|
- **payloads array**: Contains all data with metadata for proper handling
|
||||||
|
|
||||||
#### Step 5: Publish to NATS (Caller's Responsibility)
|
#### Step 5: Publish to Transport (Caller's Responsibility)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// NATS publishing is the caller's responsibility
|
// Publishing via the transport layer is the caller's responsibility
|
||||||
const conn = await NATS.connect({ servers: "ws://localhost:4222" });
|
// Example with any transport (NATS, MQTT, WebSocket, etc.)
|
||||||
await conn.publish("/agent/wine/api/v1/prompt", msgJson);
|
// const conn = await transportClient.connect({ servers: "ws://localhost:4222" });
|
||||||
|
// await conn.publish("/agent/wine/api/v1/prompt", msgJson);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Rationale**:
|
**Rationale**:
|
||||||
- NATS provides low-latency message delivery
|
- The transport layer provides message delivery (NATS, MQTT, WebSocket, etc.)
|
||||||
- JSON format ensures cross-platform compatibility
|
- JSON format ensures cross-platform compatibility
|
||||||
- `smartsend()` returns `(env, msgJson)` - caller handles publishing
|
- `smartsend()` returns `(env, msgJson)` - caller handles publishing via their chosen transport
|
||||||
|
|
||||||
#### Step 6: Julia Backend Receives Message
|
#### Step 6: Julia Backend Receives Message
|
||||||
|
|
||||||
```julia
|
```julia
|
||||||
# Julia backend
|
# Julia backend
|
||||||
nats_msg = NATS.subscription.next() # Get message from NATS
|
transport_msg = transport_subscription.next() # Get message from transport
|
||||||
env = smartreceive(String(nats_msg.payload))
|
env = smartreceive(String(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"] is now:
|
# env["payloads"] is now:
|
||||||
# [
|
# [
|
||||||
@@ -302,7 +303,7 @@ const [env, msgJson] = await msghandler.smartsend(
|
|||||||
**Rationale**:
|
**Rationale**:
|
||||||
- Link transport used for large payloads
|
- Link transport used for large payloads
|
||||||
- File server handles large file upload
|
- File server handles large file upload
|
||||||
- NATS only sends URL (small message)
|
- Transport only sends URL (small message)
|
||||||
|
|
||||||
#### Step 3: File Server Upload
|
#### Step 3: File Server Upload
|
||||||
|
|
||||||
@@ -356,8 +357,8 @@ const response = await plikOneshotUpload(
|
|||||||
|
|
||||||
```julia
|
```julia
|
||||||
# Julia backend
|
# Julia backend
|
||||||
nats_msg = NATS.subscription.next()
|
transport_msg = transport_subscription.next()
|
||||||
env = smartreceive(String(nats_msg.payload))
|
env = smartreceive(String(transport_msg.payload))
|
||||||
|
|
||||||
# msghandler automatically:
|
# msghandler automatically:
|
||||||
# 1. Extracts URL from payload
|
# 1. Extracts URL from payload
|
||||||
@@ -396,7 +397,7 @@ df = pd.DataFrame({
|
|||||||
env, msg_json = await smartsend(
|
env, msg_json = await smartsend(
|
||||||
"/agent/wine/api/v1/analyze",
|
"/agent/wine/api/v1/analyze",
|
||||||
[("data", df, "arrowtable")],
|
[("data", df, "arrowtable")],
|
||||||
broker_url="nats://localhost:4222",
|
broker_url=DEFAULT_BROKER_URL,
|
||||||
receiver_name="agent-backend"
|
receiver_name="agent-backend"
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -429,8 +430,8 @@ arrow_bytes = buf.getvalue()
|
|||||||
|
|
||||||
```julia
|
```julia
|
||||||
# Julia backend
|
# Julia backend
|
||||||
nats_msg = NATS.subscription.next()
|
transport_msg = transport_subscription.next()
|
||||||
env = smartreceive(String(nats_msg.payload))
|
env = smartreceive(String(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"][1] is now:
|
# env["payloads"][1] is now:
|
||||||
# ("data", DataFrame with id, name, score columns, "arrowtable")
|
# ("data", DataFrame with id, name, score columns, "arrowtable")
|
||||||
@@ -479,7 +480,7 @@ use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let conn = nats::connect("nats://localhost:4222").unwrap();
|
let conn = transport_client::connect("ws://localhost:4222").unwrap();
|
||||||
|
|
||||||
// Subscribe and receive messages
|
// Subscribe and receive messages
|
||||||
let mut sub = conn.subscribe("/agent/wine/api/v1/analyze").unwrap();
|
let mut sub = conn.subscribe("/agent/wine/api/v1/analyze").unwrap();
|
||||||
@@ -520,7 +521,7 @@ async fn main() {
|
|||||||
|
|
||||||
**Rationale**:
|
**Rationale**:
|
||||||
- **serde serialization**: Automatic JSON deserialization to `MsgEnvelopeV1`
|
- **serde serialization**: Automatic JSON deserialization to `MsgEnvelopeV1`
|
||||||
- **tokio runtime**: Efficient async I/O for NATS and HTTP operations
|
- **tokio runtime**: Efficient async I/O for transport and HTTP operations
|
||||||
- **smartreceive deserialization**: Payload data is deserialized and stored as strings in `payload.data`
|
- **smartreceive deserialization**: Payload data is deserialized and stored as strings in `payload.data`
|
||||||
- **Type dispatch**: `payload_type` field determines how to interpret the `data` string
|
- **Type dispatch**: `payload_type` field determines how to interpret the `data` string
|
||||||
|
|
||||||
@@ -548,14 +549,14 @@ let (envelope, json_str) = smartsend(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
&SmartsendOptions {
|
&SmartsendOptions {
|
||||||
broker_url: "nats://localhost:4222".to_string(),
|
broker_url: DEFAULT_BROKER_URL.to_string(),
|
||||||
reply_to: "/python/worker/v1/results".to_string(),
|
reply_to: "/python/worker/v1/results".to_string(),
|
||||||
msg_purpose: "chat".to_string(),
|
msg_purpose: "chat".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
// Caller publishes to NATS
|
// Caller publishes via transport
|
||||||
conn.publish("/agent/wine/api/v1/results", &json_str)?;
|
conn.publish("/agent/wine/api/v1/results", &json_str)?;
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -569,7 +570,7 @@ conn.publish("/agent/wine/api/v1/results", &json_str)?;
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
# Python backend receives Rust response
|
# Python backend receives Rust response
|
||||||
env = await smartreceive(str(nats_msg.payload))
|
env = await smartreceive(str(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"][0] is now:
|
# env["payloads"][0] is now:
|
||||||
# ("results", arrow_table_data, "arrowtable")
|
# ("results", arrow_table_data, "arrowtable")
|
||||||
@@ -598,9 +599,9 @@ let (envelope, json_str) = smartsend(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
&SmartsendOptions {
|
&SmartsendOptions {
|
||||||
broker_url: "nats://localhost:4222".to_string(),
|
broker_url: DEFAULT_BROKER_URL.to_string(),
|
||||||
fileserver_url: "http://localhost:8080".to_string(),
|
fileserver_url: DEFAULT_FILESERVER_URL.to_string(),
|
||||||
size_threshold: 500_000, // 0.5MB triggers link transport
|
size_threshold: DEFAULT_SIZE_THRESHOLD, // threshold triggers link transport
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
).await?;
|
).await?;
|
||||||
@@ -637,7 +638,7 @@ sensor_data = {
|
|||||||
env, msg_json = smartsend(
|
env, msg_json = smartsend(
|
||||||
"/sensor/device/v1/readings",
|
"/sensor/device/v1/readings",
|
||||||
[("data", sensor_data, "dictionary")],
|
[("data", sensor_data, "dictionary")],
|
||||||
broker_url="nats://localhost:4222",
|
broker_url=DEFAULT_BROKER_URL,
|
||||||
size_threshold=100000 # 100KB for MicroPython
|
size_threshold=100000 # 100KB for MicroPython
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -658,15 +659,15 @@ payload_b64 = base64.b64encode(json_bytes).decode('ascii')
|
|||||||
|
|
||||||
**Rationale**:
|
**Rationale**:
|
||||||
- JSON format for human-readable data
|
- JSON format for human-readable data
|
||||||
- Base64 for NATS compatibility
|
- Base64 for transport compatibility
|
||||||
- UTF-8 for text encoding
|
- UTF-8 for text encoding
|
||||||
|
|
||||||
#### Step 3: Python Backend Receives
|
#### Step 3: Python Backend Receives
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Python backend
|
# Python backend
|
||||||
nats_msg = await nats_consumer.next()
|
transport_msg = await transport_consumer.next()
|
||||||
env = await smartreceive(str(nats_msg.payload))
|
env = await smartreceive(str(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"][0] is now:
|
# env["payloads"][0] is now:
|
||||||
# ("data", {"temperature": 25.5, "humidity": 60.0, ...}, "dictionary")
|
# ("data", {"temperature": 25.5, "humidity": 60.0, ...}, "dictionary")
|
||||||
@@ -708,14 +709,14 @@ const [env, msgJson] = await msghandler.smartsend(
|
|||||||
**Rationale**:
|
**Rationale**:
|
||||||
- Empty `receiver_name` = broadcast to all subscribers
|
- Empty `receiver_name` = broadcast to all subscribers
|
||||||
- Chat messages often include text + images
|
- Chat messages often include text + images
|
||||||
- NATS wildcard subscriptions route to correct recipients
|
- Transport wildcard subscriptions route to correct recipients
|
||||||
|
|
||||||
#### Step 2: Python Backend Receives
|
#### Step 2: Python Backend Receives
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Python (Backend)
|
# Python (Backend)
|
||||||
nats_msg = await nats_consumer.next()
|
transport_msg = await transport_consumer.next()
|
||||||
env = await smartreceive(str(nats_msg.payload))
|
env = await smartreceive(str(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"] is now:
|
# env["payloads"] is now:
|
||||||
# [
|
# [
|
||||||
@@ -733,8 +734,8 @@ env = await smartreceive(str(nats_msg.payload))
|
|||||||
|
|
||||||
```julia
|
```julia
|
||||||
# Julia (Backend)
|
# Julia (Backend)
|
||||||
nats_msg = NATS.subscription.next()
|
transport_msg = transport_subscription.next()
|
||||||
env = smartreceive(String(nats_msg.payload))
|
env = smartreceive(String(transport_msg.payload))
|
||||||
|
|
||||||
# env["payloads"] is now:
|
# env["payloads"] is now:
|
||||||
# [
|
# [
|
||||||
@@ -795,7 +796,7 @@ await msghandler.smartsend(
|
|||||||
| File server unavailable | `UPLOAD_FAILED` | Fall back to direct transport or smaller payloads |
|
| File server unavailable | `UPLOAD_FAILED` | Fall back to direct transport or smaller payloads |
|
||||||
| File server download fails | `DOWNLOAD_FAILED` | Retry with exponential backoff |
|
| File server download fails | `DOWNLOAD_FAILED` | Retry with exponential backoff |
|
||||||
| Payload type mismatch | `DESERIALIZATION_ERROR` | Validate payload_type matches data |
|
| Payload type mismatch | `DESERIALIZATION_ERROR` | Validate payload_type matches data |
|
||||||
| NATS connection lost | `NATS_CONNECTION_FAILED` | NATS client auto-reconnects |
|
| Transport connection lost | `TRANSPORT_CONNECTION_FAILED` | Transport client auto-reconnects |
|
||||||
|
|
||||||
### Error Response Format
|
### Error Response Format
|
||||||
|
|
||||||
@@ -828,14 +829,14 @@ correlation_id = string(uuid4())
|
|||||||
# Use throughout the flow
|
# Use throughout the flow
|
||||||
log_trace(correlation_id, "Starting smartsend")
|
log_trace(correlation_id, "Starting smartsend")
|
||||||
log_trace(correlation_id, "Serialized payload size: 100 bytes")
|
log_trace(correlation_id, "Serialized payload size: 100 bytes")
|
||||||
log_trace(correlation_id, "Published to NATS")
|
log_trace(correlation_id, "Published to transport")
|
||||||
```
|
```
|
||||||
|
|
||||||
**Log Format**:
|
**Log Format**:
|
||||||
```
|
```
|
||||||
[2026-03-13T16:30:00.000Z] [Correlation: abc123...] Starting smartsend
|
[2026-03-13T16:30:00.000Z] [Correlation: abc123...] Starting smartsend
|
||||||
[2026-03-13T16:30:00.001Z] [Correlation: abc123...] Serialized payload size: 100 bytes
|
[2026-03-13T16:30:00.001Z] [Correlation: abc123...] Serialized payload size: 100 bytes
|
||||||
[2026-03-13T16:30:00.002Z] [Correlation: abc123...] Published to NATS
|
[2026-03-13T16:30:00.002Z] [Correlation: abc123...] Published to transport
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -846,7 +847,7 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
|
|
||||||
| Strategy | Description | When to Use |
|
| Strategy | Description | When to Use |
|
||||||
|----------|-------------|-------------|
|
|----------|-------------|-------------|
|
||||||
| Pre-create NATS connection | Reuse connection for multiple sends | High-throughput scenarios |
|
| Pre-create transport connection | Reuse connection for multiple sends | High-throughput scenarios |
|
||||||
| Adjust size threshold | Increase threshold if file server slow | File server bottleneck |
|
| Adjust size threshold | Increase threshold if file server slow | File server bottleneck |
|
||||||
| Use direct transport | Avoid file server for small payloads | Low latency requirements |
|
| Use direct transport | Avoid file server for small payloads | Low latency requirements |
|
||||||
|
|
||||||
@@ -868,7 +869,7 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
|
|
||||||
| Component | Minimum | Notes |
|
| Component | Minimum | Notes |
|
||||||
|-----------|---------|-------|
|
|-----------|---------|-------|
|
||||||
| NATS Server | 1 instance | Single node for development |
|
| Message Broker | 1 instance | Single node for development |
|
||||||
| File Server | 1 instance | HTTP server for large payloads |
|
| File Server | 1 instance | HTTP server for large payloads |
|
||||||
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
| Client Memory | 50MB | Desktop platforms (Julia/JS/Python/Dart) |
|
||||||
| Client Memory | 256KB | MicroPython devices |
|
| Client Memory | 256KB | MicroPython devices |
|
||||||
@@ -877,7 +878,7 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `NATS_URL` | `nats://localhost:4222` | NATS server URL |
|
| `BROKER_URL` | `ws://localhost:4222` | Message broker URL |
|
||||||
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
| `FILESERVER_URL` | `http://localhost:8080` | HTTP file server URL |
|
||||||
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
| `SIZE_THRESHOLD` | `500000` | Size threshold in bytes (0.5MB) |
|
||||||
|
|
||||||
@@ -911,7 +912,7 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
|------|----------|----------|---------------------------|
|
|------|----------|----------|---------------------------|
|
||||||
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | specification.md:2-19 (all sections) |
|
| [`src/msghandler.jl`](../src/msghandler.jl) | Julia | Full feature set, Arrow IPC, multiple dispatch | specification.md:2-19 (all sections) |
|
||||||
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
| [`src/msghandler_ssr.js`](../src/msghandler_ssr.js) | Node.js | Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
||||||
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only, WebSocket NATS | specification.md:2-19 (all sections) |
|
| [`src/msghandler_csr.js`](../src/msghandler_csr.js) | Browser | JSON table only | specification.md:2-19 (all sections) |
|
||||||
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
| [`src/msghandler.py`](../src/msghandler.py) | Python | Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
||||||
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
| [`src/msghandler.dart`](../src/msghandler.dart) | Dart | Full feature set, Arrow IPC, async/await | specification.md:2-19 (all sections) |
|
||||||
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe, file upload helpers | specification.md:2-19 (all sections) |
|
| [`src/msghandler.rs`](../src/msghandler.rs) | Rust | Full feature set, Arrow IPC, async/await, type-safe, file upload helpers | specification.md:2-19 (all sections) |
|
||||||
@@ -923,6 +924,10 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
|
|
||||||
| Date | Version | Changes | Specification Reference |
|
| Date | Version | Changes | Specification Reference |
|
||||||
|------|---------|---------|------------------------|
|
|------|---------|---------|------------------------|
|
||||||
|
| 2026-05-15 | 1.5.0 | Made transport layer agnostic | All sections |
|
||||||
|
| - | - | Removed all NATS-specific references from walkthrough | All sections |
|
||||||
|
| - | - | Updated code examples to use transport-agnostic patterns | All sections |
|
||||||
|
| - | - | Updated diagrams to remove NATS-specific labels | All sections |
|
||||||
| 2026-05-14 | 1.4.0 | Updated Rust API to reflect `smartreceive` deserialization changes | All sections |
|
| 2026-05-14 | 1.4.0 | Updated Rust API to reflect `smartreceive` deserialization changes | All sections |
|
||||||
| - | - | `smartreceive` now stores deserialized data in `MsgPayloadV1.data` | specification.md:8 |
|
| - | - | `smartreceive` now stores deserialized data in `MsgPayloadV1.data` | specification.md:8 |
|
||||||
| - | - | Added `plik_upload_file` convenience function documentation | specification.md:13 |
|
| - | - | Added `plik_upload_file` convenience function documentation | specification.md:13 |
|
||||||
@@ -932,8 +937,8 @@ log_trace(correlation_id, "Published to NATS")
|
|||||||
| - | - | Added Rust user scenario (User Scenario 4) | specification.md:11 (Rust API) |
|
| - | - | Added Rust user scenario (User Scenario 4) | specification.md:11 (Rust API) |
|
||||||
| - | - | Updated scenario numbering (MicroPython → Scenario 5, Cross-Platform → Scenario 6) | All sections |
|
| - | - | Updated scenario numbering (MicroPython → Scenario 5, Cross-Platform → Scenario 6) | All sections |
|
||||||
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) | All sections |
|
| 2026-05-13 | 1.2.0 | Aligned with ground truth implementation (src/msghandler.jl) | All sections |
|
||||||
| - | - | Updated smartreceive calls to use String(nats_msg.payload) pattern | All sections |
|
| - | - | Updated smartreceive calls to use transport payload pattern | All sections |
|
||||||
| - | - | Removed NATSClient.publish() calls (caller responsible for NATS publishing) | All sections |
|
| - | - | Removed NATSClient.publish() calls (caller responsible for transport publishing) | All sections |
|
||||||
| - | - | Removed is_publish and nats_connection parameter references | All sections |
|
| - | - | Removed is_publish and nats_connection parameter references | All sections |
|
||||||
| 2026-03-23 | 1.0.0 | Updated to ASG Framework walkthrough guidelines | All sections |
|
| 2026-03-23 | 1.0.0 | Updated to ASG Framework walkthrough guidelines | All sections |
|
||||||
| 2026-03-13 | 1.0.0 | Initial walkthrough documentation | specification.md:2-19 (all sections) |
|
| 2026-03-13 | 1.0.0 | Initial walkthrough documentation | specification.md:2-19 (all sections) |
|
||||||
|
|||||||
Reference in New Issue
Block a user