This commit is contained in:
2026-02-25 15:20:29 +07:00
parent 1299febcdc
commit 3e1c8d563e
4 changed files with 51 additions and 75 deletions

View File

@@ -33,3 +33,21 @@ All API should be semantically consistent and naming should be consistent across
Task: Update NATSBridge.js to reflect recent changes in NATSBridge.jl and docs
Context: NATSBridge.jl and docs has been updated.
Requirements:
Source of Truth: Treat the updated NATSBridge.jl and docs as the definitive source.
API Consistency: Ensure the Main Package API (e.g., smartsend(), publish_message()) uses consistent naming across all three supported languages.
Ecosystem Variance: Low-level native functions (e.g., NATS.connect(), JSON.read()) should follow the conventions of the specific language ecosystem and do not require cross-language consistency.

View File

@@ -388,6 +388,12 @@ graph TD
- **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
**Note on `is_publish`:**
- `is_publish` is simply a switch to control automatic publishing
- When `true` (default): Message is published to NATS automatically
- When `false`: Returns `(env, env_json_str)` without publishing, allowing manual publishing
- Connection reuse is achieved separately by creating NATS client outside the function
### Julia Implementation
#### Dependencies

View File

@@ -338,6 +338,7 @@ node test/scenario3_julia_to_julia.js
**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
- `is_publish` is simply a switch: when `true`, publish automatically; when `false`, return `(env, env_json_str)` without 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

View File

@@ -17,7 +17,7 @@
* // The handler is passed to smartsend as fileserverUploadHandler parameter
* // It receives: (fileserver_url, dataname, data)
* // Returns: { status, uploadid, fileid, url }
* async function fileserverUploadHandler(fileserver_url, dataname, data) { ... }
* async function plik_oneshot_upload(fileserver_url, dataname, data) { ... }
*
* // Download handler - fetches data from file server URL with exponential backoff
* // The handler is passed to smartreceive as fileserverDownloadHandler parameter
@@ -213,73 +213,16 @@ function _deserialize_data(data, type, correlation_id) {
}
// Helper: Upload data to file server
// Internal wrapper that adds correlation_id logging for smartsend
async function _upload_to_fileserver(fileserver_url, dataname, data, correlation_id) {
/**
* Upload data to HTTP file server (plik-like API)
*
* This function implements the plik one-shot upload mode:
* 1. Creates a one-shot upload session by sending POST request with {"OneShot": true}
* 2. Uploads the file data as multipart form data
* 3. Returns identifiers and download URL for the uploaded file
* Internal upload helper - wraps plik_oneshot_upload to add correlation_id logging
* This allows smartsend to pass correlation_id for tracing without changing the handler signature
*/
log_trace(correlation_id, `Uploading ${dataname} to fileserver: ${fileserver_url}`);
// Step 1: Get upload ID and token
const url_getUploadID = `${fileserver_url}/upload`;
const headers = {
"Content-Type": "application/json"
};
const body = JSON.stringify({ OneShot: true });
let response = await fetch(url_getUploadID, {
method: "POST",
headers: headers,
body: body
});
if (!response.ok) {
throw new Error(`Failed to get upload ID: ${response.status} ${response.statusText}`);
}
const responseJson = await response.json();
const uploadid = responseJson.id;
const uploadtoken = responseJson.uploadToken;
// Step 2: Upload file data
const url_upload = `${fileserver_url}/file/${uploadid}`;
// Create multipart form data
const formData = new FormData();
// Create a Blob from the Uint8Array
const blob = new Blob([data], { type: "application/octet-stream" });
formData.append("file", blob, dataname);
response = await fetch(url_upload, {
method: "POST",
headers: {
"X-UploadToken": uploadtoken
},
body: formData
});
if (!response.ok) {
throw new Error(`Failed to upload file: ${response.status} ${response.statusText}`);
}
const fileResponseJson = await response.json();
const fileid = fileResponseJson.id;
// Build the download URL
const url = `${fileserver_url}/file/${uploadid}/${fileid}/${encodeURIComponent(dataname)}`;
log_trace(correlation_id, `Uploaded to URL: ${url}`);
return {
status: response.status,
uploadid: uploadid,
fileid: fileid,
url: url
};
const result = await plik_oneshot_upload(fileserver_url, dataname, data);
log_trace(correlation_id, `Uploaded to URL: ${result.url}`);
return result;
}
// Helper: Fetch data from URL with exponential backoff
@@ -483,8 +426,11 @@ async function smartsend(subject, data, options = {}) {
* @param {string} options.reply_to - Topic to reply to (default: "")
* @param {string} options.reply_to_msg_id - Message ID this message is replying to (default: "")
* @param {boolean} options.is_publish - Whether to automatically publish the message to NATS (default: true)
*
* - When true: Message is published to NATS automatically
* - When false: Returns (env, env_json_str) without publishing, allowing manual publishing
* @returns {Promise<Object>} - A tuple-like object with { env: MessageEnvelope, env_json_str: string }
* - env: MessageEnvelope object with all metadata and payloads
* - env_json_str: JSON string representation of the envelope for manual publishing
*/
const {
broker_url = DEFAULT_NATS_URL,
@@ -541,8 +487,8 @@ async function smartsend(subject, data, options = {}) {
// Link path - Upload to HTTP server, send URL via NATS
log_trace(correlation_id, `Using link transport, uploading to fileserver`);
// Upload to HTTP server
const response = await fileserver_upload_handler(fileserver_url, dataname, payloadBytes, correlation_id);
// Upload to HTTP server using plik_oneshot_upload handler
const response = await fileserver_upload_handler(fileserver_url, dataname, payloadBytes);
if (response.status !== 200) {
throw new Error(`Failed to upload data to fileserver: ${response.status}`);
@@ -705,6 +651,8 @@ async function smartreceive(msg, options = {}) {
}
// plik_oneshot_upload - matches Julia plik_oneshot_upload function
// Upload handler signature: plik_oneshot_upload(fileserver_url, dataname, data)
// Returns: { status, uploadid, fileid, url }
async function plik_oneshot_upload(file_server_url, dataname, data) {
/**
* Upload a single file to a plik server using one-shot mode
@@ -712,6 +660,9 @@ async function plik_oneshot_upload(file_server_url, dataname, data) {
* It first creates a one-shot upload session by sending a POST request with {"OneShot": true},
* retrieves an upload ID and token, then uploads the file data as multipart form data using the token.
*
* This is the default upload handler used by smartsend.
* Custom handlers can be passed via the fileserver_upload_handler option.
*
* @param {string} file_server_url - Base URL of the plik server (e.g., "http://localhost:8080")
* @param {string} dataname - Name of the file being uploaded
* @param {Uint8Array} data - Raw byte data of the file content