This commit is contained in:
2026-02-24 20:09:10 +07:00
parent 45f1257896
commit b51641dc7e
9 changed files with 317 additions and 309 deletions

View File

@@ -17,16 +17,16 @@ The system uses **handler functions** to abstract file server operations, allowi
```julia ```julia
# Upload handler - uploads data to file server and returns URL # Upload handler - uploads data to file server and returns URL
# The handler is passed to smartsend as fileserverUploadHandler parameter # The handler is passed to smartsend as fileserver_upload_handler parameter
# It receives: (fileserver_url::String, dataname::String, data::Vector{UInt8}) # It receives: (file_server_url::String, dataname::String, data::Vector{UInt8})
# Returns: Dict{String, Any} with keys: "status", "uploadid", "fileid", "url" # Returns: Dict{String, Any} with keys: "status", "uploadid", "fileid", "url"
fileserverUploadHandler(fileserver_url::String, dataname::String, data::Vector{UInt8})::Dict{String, Any} fileserver_upload_handler(file_server_url::String, dataname::String, data::Vector{UInt8})::Dict{String, Any}
# Download handler - fetches data from file server URL with exponential backoff # Download handler - fetches data from file server URL with exponential backoff
# The handler is passed to smartreceive as fileserverDownloadHandler parameter # The handler is passed to smartreceive as fileserver_download_handler parameter
# It receives: (url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String) # It receives: (url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)
# Returns: Vector{UInt8} (the downloaded data) # Returns: Vector{UInt8} (the downloaded data)
fileserverDownloadHandler(url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)::Vector{UInt8} fileserver_download_handler(url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)::Vector{UInt8}
``` ```
This design allows the system to support multiple file server backends without changing the core messaging logic. This design allows the system to support multiple file server backends without changing the core messaging logic.
@@ -40,21 +40,21 @@ The system uses a **standardized list-of-tuples format** for all payload operati
# Input format for smartsend (always a list of tuples with type info) # Input format for smartsend (always a list of tuples with type info)
[(dataname1, data1, type1), (dataname2, data2, type2), ...] [(dataname1, data1, type1), (dataname2, data2, type2), ...]
# Output format for smartreceive (returns envelope dictionary with payloads field) # Output format for smartreceive (returns a dictionary with payloads field containing list of tuples)
# Returns: Dict with envelope metadata and payloads field containing list of tuples # Returns: Dict with envelope metadata and payloads field containing Vector{Tuple{String, Any, String}}
# { # {
# "correlationId": "...", # "correlation_id": "...",
# "msgId": "...", # "msg_id": "...",
# "timestamp": "...", # "timestamp": "...",
# "sendTo": "...", # "send_to": "...",
# "msgPurpose": "...", # "msg_purpose": "...",
# "senderName": "...", # "sender_name": "...",
# "senderId": "...", # "sender_id": "...",
# "receiverName": "...", # "receiver_name": "...",
# "receiverId": "...", # "receiver_id": "...",
# "replyTo": "...", # "reply_to": "...",
# "replyToMsgId": "...", # "reply_to_msg_id": "...",
# "brokerURL": "...", # "broker_url": "...",
# "metadata": {...}, # "metadata": {...},
# "payloads": [(dataname1, data1, type1), (dataname2, data2, type2), ...] # "payloads": [(dataname1, data1, type1), (dataname2, data2, type2), ...]
# } # }
@@ -78,17 +78,16 @@ This design allows per-payload type specification, enabling **mixed-content mess
smartsend( smartsend(
"/test", "/test",
[("dataname1", data1, "dictionary")], # List with one tuple (data, type) [("dataname1", data1, "dictionary")], # List with one tuple (data, type)
nats_url="nats://localhost:4222", broker_url="nats://localhost:4222",
fileserverUploadHandler=plik_oneshot_upload, fileserver_upload_handler=plik_oneshot_upload
metadata=user_provided_envelope_level_metadata
) )
# Multiple payloads in one message with different types # Multiple payloads in one message with different types
smartsend( smartsend(
"/test", "/test",
[("dataname1", data1, "dictionary"), ("dataname2", data2, "table")], [("dataname1", data1, "dictionary"), ("dataname2", data2, "table")],
nats_url="nats://localhost:4222", broker_url="nats://localhost:4222",
fileserverUploadHandler=plik_oneshot_upload fileserver_upload_handler=plik_oneshot_upload
) )
# Mixed content (e.g., chat with text, image, audio) # Mixed content (e.g., chat with text, image, audio)
@@ -99,13 +98,14 @@ smartsend(
("user_image", image_data, "image"), ("user_image", image_data, "image"),
("audio_clip", audio_data, "audio") ("audio_clip", audio_data, "audio")
], ],
nats_url="nats://localhost:4222" broker_url="nats://localhost:4222"
) )
# Receive returns a dictionary envelope with all metadata and deserialized payloads # Receive returns a dictionary envelope with all metadata and deserialized payloads
env = smartreceive(msg, fileserverDownloadHandler, max_retries, base_delay, max_delay) env = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff, max_retries=5, base_delay=100, max_delay=5000)
# env["payloads"] = [("dataname1", data1, type1), ("dataname2", data2, type2), ...] # env["payloads"] = [("dataname1", data1, type1), ("dataname2", data2, type2), ...]
# env["correlationId"], env["msgId"], etc. # env["correlation_id"], env["msg_id"], etc.
# env is a dictionary containing envelope metadata and payloads field
``` ```
## Architecture Diagram ## Architecture Diagram
@@ -138,48 +138,48 @@ flowchart TD
## System Components ## System Components
### 1. msgEnvelope_v1 - Message Envelope ### 1. msg_envelope_v1 - Message Envelope
The `msgEnvelope_v1` structure provides a comprehensive message format for bidirectional communication between Julia, JavaScript, and Python/Micropython applications. The `msg_envelope_v1` structure provides a comprehensive message format for bidirectional communication between Julia, JavaScript, and Python/Micropython applications.
**Julia Structure:** **Julia Structure:**
```julia ```julia
struct msgEnvelope_v1 struct msg_envelope_v1
correlationId::String # Unique identifier to track messages across systems correlation_id::String # Unique identifier to track messages across systems
msgId::String # This message id msg_id::String # This message id
timestamp::String # Message published timestamp timestamp::String # Message published timestamp
sendTo::String # Topic/subject the sender sends to send_to::String # Topic/subject the sender sends to
msgPurpose::String # Purpose of this message (ACK | NACK | updateStatus | shutdown | ...) msg_purpose::String # Purpose of this message (ACK | NACK | updateStatus | shutdown | ...)
senderName::String # Sender name (e.g., "agent-wine-web-frontend") sender_name::String # Sender name (e.g., "agent-wine-web-frontend")
senderId::String # Sender id (uuid4) sender_id::String # Sender id (uuid4)
receiverName::String # Message receiver name (e.g., "agent-backend") receiver_name::String # Message receiver name (e.g., "agent-backend")
receiverId::String # Message receiver id (uuid4 or nothing for broadcast) receiver_id::String # Message receiver id (uuid4 or nothing for broadcast)
replyTo::String # Topic to reply to reply_to::String # Topic to reply to
replyToMsgId::String # Message id this message is replying to reply_to_msg_id::String # Message id this message is replying to
brokerURL::String # NATS server address broker_url::String # NATS server address
metadata::Dict{String, Any} metadata::Dict{String, Any}
payloads::AbstractArray{msgPayload_v1} # Multiple payloads stored here payloads::Vector{msg_payload_v1} # Multiple payloads stored here
end end
``` ```
**JSON Schema:** **JSON Schema:**
```json ```json
{ {
"correlationId": "uuid-v4-string", "correlation_id": "uuid-v4-string",
"msgId": "uuid-v4-string", "msg_id": "uuid-v4-string",
"timestamp": "2024-01-15T10:30:00Z", "timestamp": "2024-01-15T10:30:00Z",
"sendTo": "topic/subject", "send_to": "topic/subject",
"msgPurpose": "ACK | NACK | updateStatus | shutdown | chat", "msg_purpose": "ACK | NACK | updateStatus | shutdown | chat",
"senderName": "agent-wine-web-frontend", "sender_name": "agent-wine-web-frontend",
"senderId": "uuid4", "sender_id": "uuid4",
"receiverName": "agent-backend", "receiver_name": "agent-backend",
"receiverId": "uuid4", "receiver_id": "uuid4",
"replyTo": "topic", "reply_to": "topic",
"replyToMsgId": "uuid4", "reply_to_msg_id": "uuid4",
"brokerURL": "nats://localhost:4222", "broker_url": "nats://localhost:4222",
"metadata": { "metadata": {
@@ -189,7 +189,7 @@ end
{ {
"id": "uuid4", "id": "uuid4",
"dataname": "login_image", "dataname": "login_image",
"type": "image", "payload_type": "image",
"transport": "direct", "transport": "direct",
"encoding": "base64", "encoding": "base64",
"size": 15433, "size": 15433,
@@ -201,7 +201,7 @@ end
{ {
"id": "uuid4", "id": "uuid4",
"dataname": "large_data", "dataname": "large_data",
"type": "table", "payload_type": "table",
"transport": "link", "transport": "link",
"encoding": "none", "encoding": "none",
"size": 524288, "size": 524288,
@@ -214,16 +214,16 @@ end
} }
``` ```
### 2. msgPayload_v1 - Payload Structure ### 2. msg_payload_v1 - Payload Structure
The `msgPayload_v1` structure provides flexible payload handling for various data types across all supported platforms. The `msg_payload_v1` structure provides flexible payload handling for various data types across all supported platforms.
**Julia Structure:** **Julia Structure:**
```julia ```julia
struct msgPayload_v1 struct msg_payload_v1
id::String # Id of this payload (e.g., "uuid4") id::String # Id of this payload (e.g., "uuid4")
dataname::String # Name of this payload (e.g., "login_image") dataname::String # Name of this payload (e.g., "login_image")
type::String # "text | dictionary | table | image | audio | video | binary" payload_type::String # "text | dictionary | table | image | audio | video | binary"
transport::String # "direct | link" transport::String # "direct | link"
encoding::String # "none | json | base64 | arrow-ipc" encoding::String # "none | json | base64 | arrow-ipc"
size::Integer # Data size in bytes size::Integer # Data size in bytes
@@ -383,17 +383,25 @@ graph TD
```julia ```julia
function smartsend( function smartsend(
subject::String, subject::String,
data::AbstractArray{Tuple{String, Any, String}}; # No standalone type parameter data::AbstractArray{Tuple{String, Any, String}, 1}; # List of (dataname, data, type) tuples
nats_url::String = "nats://localhost:4222", broker_url::String = DEFAULT_BROKER_URL, # NATS server URL
fileserverUploadHandler::Function = plik_oneshot_upload, fileserver_url = DEFAULT_FILESERVER_URL,
size_threshold::Int = 1_000_000 # 1MB fileserver_upload_handler::Function = plik_oneshot_upload,
size_threshold::Int = DEFAULT_SIZE_THRESHOLD,
correlation_id::Union{String, Nothing} = nothing,
msg_purpose::String = "chat",
sender_name::String = "NATSBridge",
receiver_name::String = "",
receiver_id::String = "",
reply_to::String = "",
reply_to_msg_id::String = "",
is_publish::Bool = true # Whether to automatically publish to NATS is_publish::Bool = true # Whether to automatically publish to NATS
) )
``` ```
**Return Value:** **Return Value:**
- Returns a tuple `(env, env_json_str)` where: - Returns a tuple `(env, env_json_str)` where:
- `env::msgEnvelope_v1` - The envelope object containing all metadata and payloads - `env::msg_envelope_v1` - The envelope object containing all metadata and payloads
- `env_json_str::String` - JSON string representation of the envelope for publishing - `env_json_str::String` - JSON string representation of the envelope for publishing
**Options:** **Options:**
@@ -417,8 +425,8 @@ The envelope object can be accessed directly for programmatic use, while the JSO
```julia ```julia
function smartreceive( function smartreceive(
msg::NATS.Message, msg::NATS.Msg;
fileserverDownloadHandler::Function; fileserver_download_handler::Function = _fetch_with_backoff,
max_retries::Int = 5, max_retries::Int = 5,
base_delay::Int = 100, base_delay::Int = 100,
max_delay::Int = 5000 max_delay::Int = 5000
@@ -427,7 +435,7 @@ function smartreceive(
# Iterate through all payloads # Iterate through all payloads
# For each payload: check transport type # For each payload: check transport type
# If direct: decode Base64 payload # If direct: decode Base64 payload
# If link: fetch from URL with exponential backoff using fileserverDownloadHandler # If link: fetch from URL with exponential backoff using fileserver_download_handler
# Deserialize payload based on type # Deserialize payload based on type
# Return envelope dictionary with all metadata and deserialized payloads # Return envelope dictionary with all metadata and deserialized payloads
end end
@@ -435,7 +443,7 @@ end
**Output Format:** **Output Format:**
- Returns a dictionary (key-value map) containing all envelope fields: - Returns a dictionary (key-value map) containing all envelope fields:
- `correlationId`, `msgId`, `timestamp`, `sendTo`, `msgPurpose`, `senderName`, `senderId`, `receiverName`, `receiverId`, `replyTo`, `replyToMsgId`, `brokerURL` - `correlation_id`, `msg_id`, `timestamp`, `send_to`, `msg_purpose`, `sender_name`, `sender_id`, `receiver_name`, `receiver_id`, `reply_to`, `reply_to_msg_id`, `broker_url`
- `metadata` - Message-level metadata dictionary - `metadata` - Message-level metadata dictionary
- `payloads` - List of dictionaries, each containing deserialized payload data - `payloads` - List of dictionaries, each containing deserialized payload data
@@ -445,11 +453,11 @@ end
3. For each payload: 3. For each payload:
- Determine transport type (`direct` or `link`) - Determine transport type (`direct` or `link`)
- If `direct`: decode Base64 data from the message - If `direct`: decode Base64 data from the message
- If `link`: fetch data from URL using exponential backoff (via `fileserverDownloadHandler`) - If `link`: fetch data from URL using exponential backoff (via `fileserver_download_handler`)
- Deserialize based on payload type (`dictionary`, `table`, `binary`, etc.) - Deserialize based on payload type (`dictionary`, `table`, `binary`, etc.)
4. Return envelope dictionary with `payloads` field containing list of `(dataname, data, type)` tuples 4. Return envelope dictionary with `payloads` field containing list of `(dataname, data, type)` tuples
**Note:** The `fileserverDownloadHandler` receives `(url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)` and returns `Vector{UInt8}`. **Note:** The `fileserver_download_handler` receives `(url::String, max_retries::Int, base_delay::Int, max_delay::Int, correlation_id::String)` and returns `Vector{UInt8}`.
### JavaScript Implementation ### JavaScript Implementation

View File

@@ -31,18 +31,18 @@ The implementation uses a **standardized list-of-tuples format** for all payload
# Output format for smartreceive (returns envelope dictionary with payloads field) # Output format for smartreceive (returns envelope dictionary with payloads field)
# Returns: Dict with envelope metadata and payloads field containing list of tuples # Returns: Dict with envelope metadata and payloads field containing list of tuples
# { # {
# "correlationId": "...", # "correlation_id": "...",
# "msgId": "...", # "msg_id": "...",
# "timestamp": "...", # "timestamp": "...",
# "sendTo": "...", # "send_to": "...",
# "msgPurpose": "...", # "msg_purpose": "...",
# "senderName": "...", # "sender_name": "...",
# "senderId": "...", # "sender_id": "...",
# "receiverName": "...", # "receiver_name": "...",
# "receiverId": "...", # "receiver_id": "...",
# "replyTo": "...", # "reply_to": "...",
# "replyToMsgId": "...", # "reply_to_msg_id": "...",
# "brokerURL": "...", # "broker_url": "...",
# "metadata": {...}, # "metadata": {...},
# "payloads": [(dataname1, data1, type1), (dataname2, data2, type2), ...] # "payloads": [(dataname1, data1, type1), (dataname2, data2, type2), ...]
# } # }
@@ -53,15 +53,15 @@ Where `type` can be: `"text"`, `"dictionary"`, `"table"`, `"image"`, `"audio"`,
**Examples:** **Examples:**
```julia ```julia
# Single payload - still wrapped in a list (type is required as third element) # Single payload - still wrapped in a list (type is required as third element)
smartsend("/test", [(dataname1, data1, "text")], ...) smartsend("/test", [(dataname1, data1, "text")], broker_url="nats://localhost:4222")
# Multiple payloads in one message (each payload has its own type) # Multiple payloads in one message (each payload has its own type)
smartsend("/test", [(dataname1, data1, "dictionary"), (dataname2, data2, "table")], ...) smartsend("/test", [(dataname1, data1, "dictionary"), (dataname2, data2, "table")], broker_url="nats://localhost:4222")
# Receive returns a dictionary envelope with all metadata and deserialized payloads # Receive returns a dictionary envelope with all metadata and deserialized payloads
env = smartreceive(msg, ...) env = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff, max_retries=5, base_delay=100, max_delay=5000)
# env["payloads"] = [(dataname1, data1, "text"), (dataname2, data2, "table"), ...] # env["payloads"] = [(dataname1, data1, "text"), (dataname2, data2, "table"), ...]
# env["correlationId"], env["msgId"], etc. # env["correlation_id"], env["msg_id"], etc.
``` ```
## Cross-Platform Interoperability ## Cross-Platform Interoperability
@@ -98,7 +98,7 @@ NATSBridge is designed for seamless communication between Julia, JavaScript, and
# Julia sender # Julia sender
using NATSBridge using NATSBridge
data = [("message", "Hello from Julia!", "text")] data = [("message", "Hello from Julia!", "text")]
smartsend("/cross_platform", data, nats_url="nats://localhost:4222") smartsend("/cross_platform", data, broker_url="nats://localhost:4222")
``` ```
```javascript ```javascript
@@ -152,7 +152,7 @@ The `smartsend` function now returns a tuple containing both the envelope object
```julia ```julia
env, env_json_str = smartsend(...) env, env_json_str = smartsend(...)
# env::msgEnvelope_v1 - The envelope object with all metadata and payloads # env::msg_envelope_v1 - The envelope object with all metadata and payloads
# env_json_str::String - JSON string for publishing to NATS # env_json_str::String - JSON string for publishing to NATS
``` ```
@@ -167,9 +167,10 @@ This enables two use cases:
The Julia implementation provides: The Julia implementation provides:
- **[`MessageEnvelope`](src/NATSBridge.jl)**: Struct for the unified JSON envelope - **[`msg_envelope_v1`](src/NATSBridge.jl)**: Struct for the unified JSON envelope
- **[`SmartSend()`](src/NATSBridge.jl)**: Handles transport selection based on payload size - **[`msg_payload_v1`](src/NATSBridge.jl)**: Struct for individual payload representation
- **[`SmartReceive()`](src/NATSBridge.jl)**: Handles both direct and link transport - **[`smartsend()`](src/NATSBridge.jl)**: Handles transport selection based on payload size
- **[`smartreceive()`](src/NATSBridge.jl)**: Handles both direct and link transport
### JavaScript Module: [`src/NATSBridge.js`](../src/NATSBridge.js) ### JavaScript Module: [`src/NATSBridge.js`](../src/NATSBridge.js)
@@ -277,16 +278,16 @@ smartsend(
) )
# Even single payload must be wrapped in a list with type # Even single payload must be wrapped in a list with type
smartsend("/test", [("single_data", mydata, "dictionary")]) smartsend("/test", [("single_data", mydata, "dictionary")], nats_url="nats://localhost:4222")
``` ```
#### Python/Micropython (Receiver) #### Python/Micropython (Receiver)
```python ```python
from nats_bridge import smartreceive from nats_bridge import smartreceive
# Receive returns a list of (dataname, data, type) tuples # Receive returns a dictionary with envelope metadata and payloads field
payloads = smartreceive(msg) env = smartreceive(msg)
# payloads = [(dataname1, data1, "dictionary"), (dataname2, data2, "table"), ...] # env["payloads"] = [(dataname1, data1, "dictionary"), (dataname2, data2, "table"), ...]
``` ```
#### JavaScript (Sender) #### JavaScript (Sender)
@@ -340,8 +341,8 @@ for await (const msg of sub) {
} }
// Also access envelope metadata // Also access envelope metadata
console.log(`Correlation ID: ${env.correlationId}`); console.log(`Correlation ID: ${env.correlation_id}`);
console.log(`Message ID: ${env.msgId}`); console.log(`Message ID: ${env.msg_id}`);
} }
``` ```
@@ -359,9 +360,9 @@ df = DataFrame(
category = rand(["A", "B", "C"], 10_000_000) category = rand(["A", "B", "C"], 10_000_000)
) )
# Send via SmartSend - wrapped in a list (type is part of each tuple) # Send via smartsend - wrapped in a list (type is part of each tuple)
env, env_json_str = SmartSend("analysis_results", [("table_data", df, "table")]) env, env_json_str = smartsend("analysis_results", [("table_data", df, "table")], broker_url="nats://localhost:4222")
# env: msgEnvelope_v1 object with all metadata and payloads # env: msg_envelope_v1 object with all metadata and payloads
# env_json_str: JSON string representation of the envelope for publishing # env_json_str: JSON string representation of the envelope for publishing
``` ```
@@ -461,7 +462,7 @@ using NATSBridge
function publish_health_status(nats_url) function publish_health_status(nats_url)
# Send status wrapped in a list (type is part of each tuple) # Send status wrapped in a list (type is part of each tuple)
status = Dict("cpu" => rand(), "memory" => rand()) status = Dict("cpu" => rand(), "memory" => rand())
smartsend("health", [("status", status, "dictionary")], nats_url=nats_url) smartsend("health", [("status", status, "dictionary")], broker_url=nats_url)
sleep(5) # Every 5 seconds sleep(5) # Every 5 seconds
end end
``` ```
@@ -523,7 +524,7 @@ def handle_device_config(msg):
"device/response", "device/response",
[("config", config, "dictionary")], [("config", config, "dictionary")],
nats_url="nats://localhost:4222", nats_url="nats://localhost:4222",
reply_to=env.get("replyTo") reply_to=env.get("reply_to")
) )
``` ```
@@ -636,7 +637,7 @@ chat_message = [
smartsend( smartsend(
"chat.room123", "chat.room123",
chat_message, chat_message,
nats_url="nats://localhost:4222", broker_url="nats://localhost:4222",
msg_purpose="chat", msg_purpose="chat",
reply_to="chat.room123.responses" reply_to="chat.room123.responses"
) )
@@ -684,7 +685,7 @@ await smartsend("chat.room123", message);
**Use Case:** Full-featured chat system supporting rich media. User can send text, small images directly, or upload large files that get uploaded to HTTP server and referenced via URLs. Claim-check pattern ensures reliable delivery tracking for all message components. **Use Case:** Full-featured chat system supporting rich media. User can send text, small images directly, or upload large files that get uploaded to HTTP server and referenced via URLs. Claim-check pattern ensures reliable delivery tracking for all message components.
**Implementation Note:** The `smartreceive` function iterates through all payloads in the envelope and processes each according to its transport type. See the standard API format in Section 1: `msgEnvelope_v1` supports `AbstractArray{msgPayload_v1}` for multiple payloads. **Implementation Note:** The `smartreceive` function iterates through all payloads in the envelope and processes each according to its transport type. See the standard API format in Section 1: `msg_envelope_v1` supports `Vector{msg_payload_v1}` for multiple payloads.
## Configuration ## Configuration
@@ -700,19 +701,19 @@ await smartsend("chat.room123", message);
```json ```json
{ {
"correlationId": "uuid-v4-string", "correlation_id": "uuid-v4-string",
"msgId": "uuid-v4-string", "msg_id": "uuid-v4-string",
"timestamp": "2024-01-15T10:30:00Z", "timestamp": "2024-01-15T10:30:00Z",
"sendTo": "topic/subject", "send_to": "topic/subject",
"msgPurpose": "ACK | NACK | updateStatus | shutdown | chat", "msg_purpose": "ACK | NACK | updateStatus | shutdown | chat",
"senderName": "agent-wine-web-frontend", "sender_name": "agent-wine-web-frontend",
"senderId": "uuid4", "sender_id": "uuid4",
"receiverName": "agent-backend", "receiver_name": "agent-backend",
"receiverId": "uuid4", "receiver_id": "uuid4",
"replyTo": "topic", "reply_to": "topic",
"replyToMsgId": "uuid4", "reply_to_msg_id": "uuid4",
"BrokerURL": "nats://localhost:4222", "broker_url": "nats://localhost:4222",
"metadata": { "metadata": {
"content_type": "application/octet-stream", "content_type": "application/octet-stream",
@@ -723,7 +724,7 @@ await smartsend("chat.room123", message);
{ {
"id": "uuid4", "id": "uuid4",
"dataname": "login_image", "dataname": "login_image",
"type": "image", "payload_type": "image",
"transport": "direct", "transport": "direct",
"encoding": "base64", "encoding": "base64",
"size": 15433, "size": 15433,

View File

@@ -182,7 +182,7 @@ for (const payload of env.payloads) {
using NATSBridge using NATSBridge
# Receive and process message # Receive and process message
env = smartreceive(msg, fileserverDownloadHandler) env = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff)
for (dataname, data, type) in env["payloads"] for (dataname, data, type) in env["payloads"]
println("Received $dataname: $data") println("Received $dataname: $data")
end end

View File

@@ -718,7 +718,7 @@ payloads = smartreceive(msg; fileserver_download_handler=_fetch_with_backoff, ma
""" """
function smartreceive( function smartreceive(
msg::NATS.Msg; msg::NATS.Msg;
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,
max_delay::Int = 5000 max_delay::Int = 5000
@@ -1047,7 +1047,6 @@ function plik_oneshot_upload(file_server_url::String, filepath::String)
error("Failed to upload file: server returned status $(http_response.status)") error("Failed to upload file: server returned status $(http_response.status)")
end end
response_json = JSON.parse(http_response.body) response_json = JSON.parse(http_response.body)
fileid = response_json["id"] fileid = response_json["id"]
# url of the uploaded data e.g. "http://192.168.1.20:8080/file/3F62E/4AgGT/test.zip" # url of the uploaded data e.g. "http://192.168.1.20:8080/file/3F62E/4AgGT/test.zip"

View File

@@ -95,9 +95,9 @@ function test_dict_send()
env, env_json_str = NATSBridge.smartsend( env, env_json_str = NATSBridge.smartsend(
SUBJECT, SUBJECT,
[data1, data2]; # List of (dataname, data, type) tuples [data1, data2]; # List of (dataname, data, type) tuples
nats_url = NATS_URL, broker_url = NATS_URL,
fileserver_url = FILESERVER_URL, fileserver_url = FILESERVER_URL,
fileserverUploadHandler = plik_upload_handler, fileserver_upload_handler = plik_upload_handler,
size_threshold = 1_000_000, # 1MB threshold size_threshold = 1_000_000, # 1MB threshold
correlation_id = correlation_id, correlation_id = correlation_id,
msg_purpose = "chat", msg_purpose = "chat",
@@ -115,7 +115,7 @@ function test_dict_send()
for (i, payload) in enumerate(env.payloads) for (i, payload) in enumerate(env.payloads)
log_trace("Payload $i ('$payload.dataname'):") log_trace("Payload $i ('$payload.dataname'):")
log_trace(" Transport: $(payload.transport)") log_trace(" Transport: $(payload.transport)")
log_trace(" Type: $(payload.type)") log_trace(" Type: $(payload.payload_type)")
log_trace(" Size: $(payload.size) bytes") log_trace(" Size: $(payload.size) bytes")
log_trace(" Encoding: $(payload.encoding)") log_trace(" Encoding: $(payload.encoding)")

View File

@@ -82,9 +82,9 @@ function test_large_binary_send()
env, env_json_str = NATSBridge.smartsend( env, env_json_str = NATSBridge.smartsend(
SUBJECT, SUBJECT,
[data1, data2]; # List of (dataname, data, type) tuples [data1, data2]; # List of (dataname, data, type) tuples
nats_url = NATS_URL; broker_url = NATS_URL;
fileserver_url = FILESERVER_URL, fileserver_url = FILESERVER_URL,
fileserverUploadHandler = plik_upload_handler, fileserver_upload_handler = plik_upload_handler,
size_threshold = 1_000_000, size_threshold = 1_000_000,
correlation_id = correlation_id, correlation_id = correlation_id,
msg_purpose = "chat", msg_purpose = "chat",
@@ -97,7 +97,7 @@ function test_large_binary_send()
) )
log_trace("Sent message with transport: $(env.payloads[1].transport)") log_trace("Sent message with transport: $(env.payloads[1].transport)")
log_trace("Envelope type: $(env.payloads[1].type)") log_trace("Envelope type: $(env.payloads[1].payload_type)")
# Check if link transport was used # Check if link transport was used
if env.payloads[1].transport == "link" if env.payloads[1].transport == "link"

View File

@@ -189,9 +189,9 @@ function test_mix_send()
env, env_json_str = NATSBridge.smartsend( env, env_json_str = NATSBridge.smartsend(
SUBJECT, SUBJECT,
payloads; # List of (dataname, data, type) tuples payloads; # List of (dataname, data, type) tuples
nats_url = NATS_URL, broker_url = NATS_URL,
fileserver_url = FILESERVER_URL, fileserver_url = FILESERVER_URL,
fileserverUploadHandler = plik_upload_handler, fileserver_upload_handler = plik_upload_handler,
size_threshold = 1_000_000, # 1MB threshold size_threshold = 1_000_000, # 1MB threshold
correlation_id = correlation_id, correlation_id = correlation_id,
msg_purpose = "chat", msg_purpose = "chat",
@@ -209,7 +209,7 @@ function test_mix_send()
for (i, payload) in enumerate(env.payloads) for (i, payload) in enumerate(env.payloads)
log_trace("Payload $i ('$payload.dataname'):") log_trace("Payload $i ('$payload.dataname'):")
log_trace(" Transport: $(payload.transport)") log_trace(" Transport: $(payload.transport)")
log_trace(" Type: $(payload.type)") log_trace(" Type: $(payload.payload_type)")
log_trace(" Size: $(payload.size) bytes") log_trace(" Size: $(payload.size) bytes")
log_trace(" Encoding: $(payload.encoding)") log_trace(" Encoding: $(payload.encoding)")

View File

@@ -93,9 +93,9 @@ function test_table_send()
env, env_json_str = NATSBridge.smartsend( env, env_json_str = NATSBridge.smartsend(
SUBJECT, SUBJECT,
[data1, data2]; # List of (dataname, data, type) tuples [data1, data2]; # List of (dataname, data, type) tuples
nats_url = NATS_URL, broker_url = NATS_URL,
fileserver_url = FILESERVER_URL, fileserver_url = FILESERVER_URL,
fileserverUploadHandler = plik_upload_handler, fileserver_upload_handler = plik_upload_handler,
size_threshold = 1_000_000, # 1MB threshold size_threshold = 1_000_000, # 1MB threshold
correlation_id = correlation_id, correlation_id = correlation_id,
msg_purpose = "chat", msg_purpose = "chat",
@@ -113,7 +113,7 @@ function test_table_send()
for (i, payload) in enumerate(env.payloads) for (i, payload) in enumerate(env.payloads)
log_trace("Payload $i ('$payload.dataname'):") log_trace("Payload $i ('$payload.dataname'):")
log_trace(" Transport: $(payload.transport)") log_trace(" Transport: $(payload.transport)")
log_trace(" Type: $(payload.type)") log_trace(" Type: $(payload.payload_type)")
log_trace(" Size: $(payload.size) bytes") log_trace(" Size: $(payload.size) bytes")
log_trace(" Encoding: $(payload.encoding)") log_trace(" Encoding: $(payload.encoding)")

View File

@@ -78,9 +78,9 @@ function test_text_send()
env, env_json_str = NATSBridge.smartsend( env, env_json_str = NATSBridge.smartsend(
SUBJECT, SUBJECT,
[data1, data2]; # List of (dataname, data, type) tuples [data1, data2]; # List of (dataname, data, type) tuples
nats_url = NATS_URL, broker_url = NATS_URL,
fileserver_url = FILESERVER_URL, fileserver_url = FILESERVER_URL,
fileserverUploadHandler = plik_upload_handler, fileserver_upload_handler = plik_upload_handler,
size_threshold = 1_000_000, # 1MB threshold size_threshold = 1_000_000, # 1MB threshold
correlation_id = correlation_id, correlation_id = correlation_id,
msg_purpose = "chat", msg_purpose = "chat",
@@ -98,7 +98,7 @@ function test_text_send()
for (i, payload) in enumerate(env.payloads) for (i, payload) in enumerate(env.payloads)
log_trace("Payload $i ('$payload.dataname'):") log_trace("Payload $i ('$payload.dataname'):")
log_trace(" Transport: $(payload.transport)") log_trace(" Transport: $(payload.transport)")
log_trace(" Type: $(payload.type)") log_trace(" Type: $(payload.payload_type)")
log_trace(" Size: $(payload.size) bytes") log_trace(" Size: $(payload.size) bytes")
log_trace(" Encoding: $(payload.encoding)") log_trace(" Encoding: $(payload.encoding)")