From 6a862ef24305d4fd6851b166aa93c1ee8bf55cf8 Mon Sep 17 00:00:00 2001 From: narawat Date: Wed, 25 Feb 2026 12:09:00 +0700 Subject: [PATCH] update --- docs/architecture.md | 52 ++++++++++++++++++++++--- docs/implementation.md | 87 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 8 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index d89d0e0..3275141 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -369,6 +369,25 @@ graph TD ## Implementation Details +### API Consistency Across Languages + +**High-Level API (Consistent Across All Languages):** +- `smartsend(subject, data, ...)` - Main publishing function +- `smartreceive(msg, ...)` - Main receiving function +- Message envelope structure (`msg_envelope_v1` / `MessageEnvelope`) +- Payload structure (`msg_payload_v1` / `MessagePayload`) +- Transport strategy (direct vs link based on size threshold) +- Supported payload types: text, dictionary, table, image, audio, video, binary + +**Low-Level Native Functions (Language-Specific Conventions):** +- Julia: `NATS.connect()`, `publish_message()`, function overloading +- JavaScript: `nats.js` client, native async/await patterns +- Python: `nats-python` client, native async/await patterns + +**Connection Reuse Pattern:** +- **Julia:** Uses `NATS_connection` keyword parameter with function overloading +- **JavaScript/Python:** Achieved by creating NATS client outside the function and reusing it in custom handlers + ### Julia Implementation #### Dependencies @@ -400,7 +419,7 @@ function smartsend( ) ``` -**New Keyword Parameter:** +**Keyword Parameter - NATS_connection:** - `NATS_connection::Union{NATS.Connection, Nothing} = nothing` - Pre-existing NATS connection. When provided, `smartsend` uses this connection instead of creating a new one, avoiding the overhead of connection establishment. This is useful for high-frequency publishing scenarios where connection reuse provides performance benefits. **Connection Handling Logic:** @@ -498,7 +517,7 @@ function publish_message(conn::NATS.Connection, subject::String, message::String end ``` -**Use Case:** Use the connection-based overload when you already have an established NATS connection and want to publish multiple messages without the overhead of creating a new connection for each publish. +**Use Case:** Use the connection-based overload when you already have an established NATS connection and want to publish multiple messages without the overhead of creating a new connection for each publish. This is a Julia-specific optimization that leverages function overloading. **Integration with smartsend:** ```julia @@ -521,6 +540,10 @@ env, env_json_str = smartsend( # Uses: publish_message(broker_url, subject, env_json_str, cid) ``` +**API Consistency Note:** +- **High-level API (smartsend, smartreceive):** Uses consistent naming across all three languages (Julia, JavaScript, Python/Micropython) +- **Low-level native functions (NATS.connect(), publish_message()):** Follow the conventions of the specific language ecosystem and do not require cross-language consistency + ### JavaScript Implementation #### Dependencies @@ -551,8 +574,11 @@ async function smartsend( - `receiver_id` (String) - Message receiver ID (default: `""`) - `reply_to` (String) - Topic to reply to (default: `""`) - `reply_to_msg_id` (String) - Message ID this message is replying to (default: `""`) +- `is_publish` (Boolean) - Whether to automatically publish the message to NATS (default: `true`) - `fileserver_upload_handler` (Function) - Custom upload handler function +**Note:** JavaScript uses `is_publish` option (instead of `NATS_connection` keyword) to control automatic publishing behavior. Connection reuse can be achieved by creating a NATS client outside the function and reusing it in a custom `fileserver_upload_handler` or custom publish implementation. + **Return Value:** - Returns a Promise that resolves to an object containing: - `env` - The envelope object containing all metadata and payloads @@ -618,26 +644,40 @@ async function smartreceive(msg, options = {}) #### smartsend Function ```python -async def smartsend( +def smartsend( subject: str, data: List[Tuple[str, Any, str]], # List of (dataname, data, type) tuples - options: Dict = {} -) + broker_url: str = DEFAULT_BROKER_URL, + fileserver_url: str = DEFAULT_FILESERVER_URL, + fileserver_upload_handler: Callable = plik_oneshot_upload, + size_threshold: int = DEFAULT_SIZE_THRESHOLD, + correlation_id: Union[str, None] = None, + msg_purpose: str = "chat", + sender_name: str = "NATSBridge", + receiver_name: str = "", + receiver_id: str = "", + reply_to: str = "", + reply_to_msg_id: str = "", + is_publish: bool = True +) -> Tuple[MessageEnvelope, str] ``` **Options:** - `broker_url` (str) - NATS server URL (default: `"nats://localhost:4222"`) - `fileserver_url` (str) - Base URL of the file server (default: `"http://localhost:8080"`) - `size_threshold` (int) - Threshold in bytes for transport selection (default: `1048576` = 1MB) -- `correlation_id` (str) - Optional correlation ID for tracing +- `correlation_id` (str) - Optional correlation ID for tracing (auto-generated if None) - `msg_purpose` (str) - Purpose of the message (default: `"chat"`) - `sender_name` (str) - Sender name (default: `"NATSBridge"`) - `receiver_name` (str) - Message receiver name (default: `""`) - `receiver_id` (str) - Message receiver ID (default: `""`) - `reply_to` (str) - Topic to reply to (default: `""`) - `reply_to_msg_id` (str) - Message ID this message is replying to (default: `""`) +- `is_publish` (bool) - Whether to automatically publish the message to NATS (default: `True`) - `fileserver_upload_handler` (Callable) - Custom upload handler function +**Note:** Python uses `is_publish` parameter (instead of `NATS_connection` keyword) to control automatic publishing behavior. Connection reuse can be achieved by creating a NATS client outside the function and reusing it in a custom `fileserver_upload_handler` or custom publish implementation. + **Return Value:** - Returns a tuple `(env, env_json_str)` where: - `env` - The envelope dictionary containing all metadata and payloads diff --git a/docs/implementation.md b/docs/implementation.md index 07727e0..8da6ce3 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -316,6 +316,30 @@ julia test/scenario3_julia_to_julia.jl node test/scenario3_julia_to_julia.js ``` +## API Consistency Across Languages + +**High-Level API (Consistent Across All Languages):** +- `smartsend(subject, data, ...)` - Main publishing function +- `smartreceive(msg, ...)` - Main receiving function +- Message envelope structure (`msg_envelope_v1` / `MessageEnvelope`) +- Payload structure (`msg_payload_v1` / `MessagePayload`) +- Transport strategy (direct vs link based on size threshold) +- Supported payload types: text, dictionary, table, image, audio, video, binary + +**Low-Level Native Functions (Language-Specific Conventions):** +- Julia: `NATS.connect()`, `publish_message()`, function overloading +- JavaScript: `nats.js` client, native async/await patterns +- Python: `nats-python` client, native async/await patterns + +**Connection Reuse Pattern - Key Differences:** +- **Julia:** Uses `NATS_connection` keyword parameter with function overloading for automatic connection management +- **JavaScript/Python:** Achieved by creating NATS client outside the function and reusing it in custom handlers or custom publish implementations + +**Why the Difference?** +- Julia supports function overloading and keyword arguments, allowing `NATS_connection` to be passed as an optional parameter +- JavaScript/Python use a simpler `is_publish` option to control automatic publishing +- For connection reuse in JavaScript/Python, create a NATS client once and reuse it in your custom `fileserver_upload_handler` or custom publish logic + ## Usage ### Scenario 1: Command & Control (Small Dictionary) @@ -373,9 +397,39 @@ const config = { threshold: 0.5 }; +// Use is_publish option to control automatic publishing await smartsend("control", [ { dataname: "config", data: config, type: "dictionary" } -]); +], { + is_publish: true // Automatically publish to NATS +}); +``` + +**Connection Reuse in JavaScript:** +To achieve connection reuse in JavaScript, create a NATS client outside the function and use it in a custom `fileserver_upload_handler` or custom publish implementation: + +```javascript +const { connect } = require('nats'); +const { smartsend } = require('./src/NATSBridge'); + +// Create connection once +const nc = await connect({ servers: ['nats://localhost:4222'] }); + +// Send multiple messages using the same connection +for (let i = 0; i < 100; i++) { + const config = { iteration: i, data: Math.random() }; + + // Option 1: Use is_publish=false and publish manually with your connection + const { env, env_json_str } = await smartsend("control", [ + { dataname: "config", data: config, type: "dictionary" } + ], { is_publish: false }); + + // Publish with your existing connection + await nc.publish("control", env_json_str); +} + +// Close connection when done +await nc.close(); ``` **Python/Micropython (Sender/Receiver):** @@ -390,7 +444,32 @@ config = { "threshold": 0.5 } -smartsend("control", [("config", config, "dictionary")]) +# Use is_publish parameter to control automatic publishing +smartsend("control", [("config", config, "dictionary")], is_publish=True) +``` + +**Connection Reuse in Python:** +To achieve connection reuse in Python, create a NATS client outside the function and use it in a custom `fileserver_upload_handler` or custom publish implementation: + +```python +from nats_bridge import smartsend +import nats + +# Create connection once +nc = await nats.connect("nats://localhost:4222") + +# Send multiple messages using the same connection +for i in range(100): + config = {"iteration": i, "data": random.random()} + + # Option 1: Use is_publish=False and publish manually with your connection + env, env_json_str = smartsend("control", [("config", config, "dictionary")], is_publish=False) + + # Publish with your existing connection + await nc.publish("control", env_json_str) + +# Close connection when done +await nc.close() ``` ### Basic Multi-Payload Example @@ -607,6 +686,10 @@ env, env_json_str = smartsend( # Uses: publish_message(broker_url, subject, env_json_str, cid) ``` +**API Consistency Note:** +- **Julia:** Uses `NATS_connection` keyword parameter with function overloading for automatic connection management +- **JavaScript/Python:** Use `is_publish` option and achieve connection reuse by creating NATS client outside the function and reusing it in custom handlers or custom publish implementations + #### JavaScript (Receiver) ```javascript const { smartreceive } = require('./src/NATSBridge');