196 lines
7.6 KiB
JavaScript
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;
|