testFlow/ui/assets/nats/NatsUtils.js
Wyle.Gong-巩文昕 7a1aae1e2f ui
2025-04-23 11:21:08 +08:00

196 lines
7.6 KiB
JavaScript

// NatsUtils.js (Stateless Utility - Minimal Imports Version)
// Import only the essentials needed for basic pub/sub/req/status
// We assume these are all exported by your "../esm/nats.js" bundle
import {
connect, // For establishing the connection
JSONCodec, // For encoding/decoding JSON payloads
StringCodec, // For decoding potential error payloads or raw strings
// Subscription object type might be implicitly handled or imported if needed for type hinting
// Methods like publish, subscribe, request, status, close are part of the 'nc' object returned by connect.
} from "../nats.ws-1.30.3/esm/nats.js"; // <--- Adjust this path as needed
class NatsUtils {
/**
* Get NATS Codecs.
* @returns {{jsonCodec: object, stringCodec: object}}
*/
static getCodecs() {
// We need to instantiate them. The imports just bring in the classes/factories.
try {
return { jsonCodec: JSONCodec(), stringCodec: StringCodec() };
} catch (e) {
console.error("Failed to create NATS codecs. Ensure nats.ws is loaded correctly.", e);
// Return dummy objects or null to avoid breaking caller immediately,
// but subsequent operations will likely fail.
return { jsonCodec: null, stringCodec: null };
}
}
/**
* Connect to NATS server.
* @param {string} url - WebSocket URL
* @param {object} [options] - NATS connection options
* @returns {Promise<NatsConnection>} - The connection instance (nc)
*/
static async Natsconnect(url, options = {}) {
console.log(`Attempting NATS connection to ${url}...`);
try {
// 'connect' is imported directly
const nc = await connect({ servers: url, ...options });
console.log("NATS connected.");
nc.publish("enter", JSONCodec().encode({ id:"gwx" })); // Example publish
nc.publish("enter", JSONCodec().encode({ id:"gwx2" })); // Example publish
console.log("Published 'enter' message.",nc);
return nc;
} catch (err) {
console.error("NATS connection failed:", err);
throw err; // Re-throw for the caller to handle
}
}
/**
* Disconnect from NATS.
* @param {NatsConnection} nc - The connection instance
* @returns {Promise<void>}
*/
static async disconnect(nc) {
if (nc && !nc.isClosed()) {
console.log("Closing NATS connection...");
try {
await nc.close(); // Use the close method on the connection object
console.log("NATS connection closed.");
} catch (err) {
console.error("Error closing NATS connection:", err);
}
}
}
/**
* Check if connected.
* @param {NatsConnection} nc - The connection instance
* @returns {boolean}
*/
static isConnected(nc) {
// Use the isClosed method on the connection object
return nc && !nc.isClosed();
}
/**
* Publish a JSON message.
* @param {NatsConnection} nc
* @param {object} jsonCodec - Instance from getCodecs()
* @param {string} subject
* @param {object} data - JSON object
* @returns {boolean} - Success indicator
*/
static publish(nc, jsonCodec, subject, data) {
if (!this.isConnected(nc)) return false;
if (!jsonCodec) { console.error("JSON Codec required for publish"); return false; }
try {
// Use the publish method on the connection object
nc.publish(subject, jsonCodec.encode(data));
console.log(`Published to ${subject}:`, data);
return true;
} catch (err) {
console.error(`Publish to ${subject} failed:`, err);
return false;
}
}
/**
* Subscribe to a subject for JSON messages.
* @param {NatsConnection} nc
* @param {object} jsonCodec - Instance from getCodecs()
* @param {string} subject
* @param {function(object, string): void} callback - Receives (decodedData, messageSubject)
* @returns {NatsSubscription | null} - The subscription object (for unsubscribing)
*/
static subscribe(nc, jsonCodec, subject, callback) {
if (!this.isConnected(nc)) return null;
if (!jsonCodec) { console.error("JSON Codec required for subscribe"); return null; }
try {
// Use the subscribe method on the connection object
const sub = nc.subscribe(subject, {
callback: (err, msg) => {
if (err) { /* ... error handling ... */ return; }
try {
callback(jsonCodec.decode(msg.data), msg.subject);
} catch (decodeErr) { /* ... decode error handling ... */ }
},
});
console.log(`Subscription created for ${subject}`);
return sub;
} catch (err) {
console.error(`Subscribe to ${subject} failed:`, err);
return null;
}
}
/**
* Unsubscribe.
* @param {NatsSubscription} subscription - The object returned by subscribe
*/
static unsubscribe(subscription) {
if (subscription && typeof subscription.unsubscribe === 'function') {
try {
const subSubject = subscription.getSubject ? subscription.getSubject() : 'unknown'; // Get subject if method exists
subscription.unsubscribe();
console.log(`Unsubscribed from ${subSubject}`);
} catch (err) {
console.error(`Unsubscribe failed:`, err);
}
}
}
/**
* Send a JSON request and wait for a JSON reply.
* @param {NatsConnection} nc
* @param {object} jsonCodec - Instance from getCodecs()
* @param {string} subject
* @param {object} data - JSON request object
* @param {number} [timeoutMs=10000] - Timeout
* @returns {Promise<object>} - Promise resolving with the JSON response object
*/
static async request(nc, jsonCodec, subject, data, timeoutMs = 10000) {
if (!this.isConnected(nc)) throw new Error("NATS not connected");
if (!jsonCodec) throw new Error("JSON Codec required for request");
try {
// Use the request method on the connection object
const responseMsg = await nc.request(subject, jsonCodec.encode(data), { timeout: timeoutMs });
return jsonCodec.decode(responseMsg.data);
} catch (err) {
console.error(`Request to ${subject} failed:`, err.message);
throw err;
}
}
/**
* Monitor connection status events.
* @param {NatsConnection} nc
* @param {function(string, any?): void} statusCallback - Receives (statusType, eventData)
*/
static monitorStatus(nc, statusCallback) {
if (!nc) return;
(async () => {
try {
console.log("Starting NATS status monitoring...");
statusCallback('monitoring_started');
// Use the status async iterator on the connection object
for await (const s of nc.status()) {
statusCallback(s.type, s.data);
}
console.log("NATS status monitoring finished (connection closed).");
statusCallback('closed');
} catch (err) {
console.error("NATS status monitoring error:", err);
statusCallback('monitoring_error', err);
}
})();
}
}
// Make it globally available or export
window.NatsUtils = NatsUtils;
// export default NatsUtils;