update
This commit is contained in:
@@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -388,6 +388,12 @@ graph TD
|
|||||||
- **Julia:** Uses `NATS_connection` keyword parameter with function overloading
|
- **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
|
- **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
|
### Julia Implementation
|
||||||
|
|
||||||
#### Dependencies
|
#### Dependencies
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ node test/scenario3_julia_to_julia.js
|
|||||||
**Why the Difference?**
|
**Why the Difference?**
|
||||||
- Julia supports function overloading and keyword arguments, allowing `NATS_connection` to be passed as an optional parameter
|
- 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
|
- 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
|
- 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
|
## Usage
|
||||||
|
|||||||
+22
-71
@@ -17,7 +17,7 @@
|
|||||||
* // The handler is passed to smartsend as fileserverUploadHandler parameter
|
* // The handler is passed to smartsend as fileserverUploadHandler parameter
|
||||||
* // It receives: (fileserver_url, dataname, data)
|
* // It receives: (fileserver_url, dataname, data)
|
||||||
* // Returns: { status, uploadid, fileid, url }
|
* // 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
|
* // 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 fileserverDownloadHandler parameter
|
||||||
@@ -213,73 +213,16 @@ function _deserialize_data(data, type, correlation_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Upload data to file server
|
// 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) {
|
async function _upload_to_fileserver(fileserver_url, dataname, data, correlation_id) {
|
||||||
/**
|
/**
|
||||||
* Upload data to HTTP file server (plik-like API)
|
* 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
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
log_trace(correlation_id, `Uploading ${dataname} to fileserver: ${fileserver_url}`);
|
log_trace(correlation_id, `Uploading ${dataname} to fileserver: ${fileserver_url}`);
|
||||||
|
const result = await plik_oneshot_upload(fileserver_url, dataname, data);
|
||||||
// Step 1: Get upload ID and token
|
log_trace(correlation_id, `Uploaded to URL: ${result.url}`);
|
||||||
const url_getUploadID = `${fileserver_url}/upload`;
|
return result;
|
||||||
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
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Fetch data from URL with exponential backoff
|
// Helper: Fetch data from URL with exponential backoff
|
||||||
@@ -481,11 +424,14 @@ async function smartsend(subject, data, options = {}) {
|
|||||||
* @param {string} options.receiver_name - Name of the receiver (default: "")
|
* @param {string} options.receiver_name - Name of the receiver (default: "")
|
||||||
* @param {string} options.receiver_id - UUID of the receiver (default: "")
|
* @param {string} options.receiver_id - UUID of the receiver (default: "")
|
||||||
* @param {string} options.reply_to - Topic to reply to (default: "")
|
* @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 {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)
|
* @param {boolean} options.is_publish - Whether to automatically publish the message to NATS (default: true)
|
||||||
*
|
* - When true: Message is published to NATS automatically
|
||||||
* @returns {Promise<Object>} - A tuple-like object with { env: MessageEnvelope, env_json_str: string }
|
* - 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 {
|
const {
|
||||||
broker_url = DEFAULT_NATS_URL,
|
broker_url = DEFAULT_NATS_URL,
|
||||||
fileserver_url = DEFAULT_FILESERVER_URL,
|
fileserver_url = DEFAULT_FILESERVER_URL,
|
||||||
@@ -541,8 +487,8 @@ async function smartsend(subject, data, options = {}) {
|
|||||||
// Link path - Upload to HTTP server, send URL via NATS
|
// Link path - Upload to HTTP server, send URL via NATS
|
||||||
log_trace(correlation_id, `Using link transport, uploading to fileserver`);
|
log_trace(correlation_id, `Using link transport, uploading to fileserver`);
|
||||||
|
|
||||||
// Upload to HTTP server
|
// Upload to HTTP server using plik_oneshot_upload handler
|
||||||
const response = await fileserver_upload_handler(fileserver_url, dataname, payloadBytes, correlation_id);
|
const response = await fileserver_upload_handler(fileserver_url, dataname, payloadBytes);
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error(`Failed to upload data to fileserver: ${response.status}`);
|
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
|
// 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) {
|
async function plik_oneshot_upload(file_server_url, dataname, data) {
|
||||||
/**
|
/**
|
||||||
* Upload a single file to a plik server using one-shot mode
|
* 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},
|
* 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.
|
* 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} file_server_url - Base URL of the plik server (e.g., "http://localhost:8080")
|
||||||
* @param {string} dataname - Name of the file being uploaded
|
* @param {string} dataname - Name of the file being uploaded
|
||||||
* @param {Uint8Array} data - Raw byte data of the file content
|
* @param {Uint8Array} data - Raw byte data of the file content
|
||||||
|
|||||||
Reference in New Issue
Block a user