UNPKG

@sourceregistry/node-ovsdb

Version:

Open vSwitch Database Management Protocol typescript client

222 lines (221 loc) 7.05 kB
import { createConnection as a } from "net"; import { existsSync as h } from "fs"; class m { /** * Creates a new OVSDBClient instance. * @param options - Configuration options for the client. */ constructor(r = {}) { this.socket = null, this.requestId = 1, this.pendingRequests = /* @__PURE__ */ new Map(), this.isConnected = !1, this.socketPath = r.socketPath || "/var/run/openvswitch/db.sock", this.timeout = r.timeout || 5e3; } /** * Connects to the OVSDB Unix socket. * @returns A promise that resolves when connected. * @throws An error if the socket file does not exist or the connection fails. */ connect() { return new Promise((r, e) => { if (this.isConnected) { r(this); return; } if (!h(this.socketPath)) { e(new Error(`OVSDB socket not found: ${this.socketPath}`)); return; } this.socket = a(this.socketPath); const t = setTimeout(() => { this._cleanup(), e(new Error(`Connection timeout after ${this.timeout}ms`)); }, this.timeout); this.socket.on("connect", () => { clearTimeout(t), this.isConnected = !0, r(this); }), this.socket.on("error", (o) => { clearTimeout(t), this._cleanup(), e(o); }), this.socket.on("close", () => { this._cleanup(); }), this.socket.on("data", (o) => { this._handleData(o); }); }); } /** * Sends a JSON-RPC request to the OVSDB server. * @param method - The RPC method name. * @param params - The parameters for the RPC method. * @returns A promise that resolves with the result. * @throws An error if not connected, if the request times out, or if there is a network error. */ request(r, e) { return new Promise((t, o) => { if (!this.isConnected) { o(new Error("Not connected to OVSDB")); return; } const s = this.requestId++, c = JSON.stringify({ method: r, params: e, id: s }) + ` `, n = setTimeout(() => { this.pendingRequests.delete(s), o(new Error(`Request timeout for method: ${r}`)); }, this.timeout); this.pendingRequests.set(s, { resolve: t, reject: o, timeoutId: n }), this.socket.write(c, (i) => { i && (clearTimeout(n), this.pendingRequests.delete(s), o(i)); }); }); } // --- Core OVSDB RPC Methods (Fixed to handle the response structure) --- async listDbs() { const r = await this.request("list_dbs", []); if ("error" in r && r.error !== null) throw new Error(`RPC Error: ${r.error}`); const e = r.result; if ("error" in e) throw new Error(`OVSDB Error: ${e.error}`); return e; } async getSchema(r = "Open_vSwitch") { const e = await this.request("get_schema", [r]); if ("error" in e && e.error !== null) throw new Error(`RPC Error: ${e.error}`); const t = e.result; if ("error" in t) throw new Error(`OVSDB Error: ${t.error}`); return t; } async transact(r, e) { const t = await this.request("transact", [r, ...e]); if ("error" in t && t.error !== null) throw new Error(`RPC Error: ${t.error}`); return t.result; } async monitor(r, e, t) { const o = await this.request("monitor", [r, e, t]); if ("error" in o && o.error !== null) throw new Error(`RPC Error: ${o.error}`); const s = o.result; if ("error" in s) throw new Error(`OVSDB Error: ${s.error}`); return s; } async monitorCancel(r) { const e = await this.request("monitor_cancel", [r]); if ("error" in e && e.error !== null) throw new Error(`RPC Error: ${e.error}`); const t = e.result; if ("error" in t) throw new Error(`OVSDB Error: ${t.error}`); return t; } async echo(r = "ping") { const e = await this.request("echo", Array.isArray(r) ? r : [r]); if ("error" in e && e.error !== null) throw new Error(`RPC Error: ${e.error}`); const t = e.result; if ("error" in t) throw new Error(`OVSDB Error: ${t.error}`); return t; } /** * Closes the connection to the OVSDB server. * @returns A promise that resolves when the connection is closed. */ async close() { await this[Symbol.asyncDispose](); } /** * Implements the AsyncDisposable interface for use with 'using' statements. * This method is called automatically when exiting a 'using' block. * @returns A promise that resolves when cleanup is complete. */ async [Symbol.asyncDispose]() { if (this.isConnected) { const r = new Promise((e) => { if (this.socket) { if (this.socket.destroyed || this.socket.readyState === "closed") { e(); return; } this.socket.once("close", () => { e(); }); } else e(); }); this._cleanup(), await r; } } /** * Cleans up the connection and pending requests. * @private */ _cleanup() { this.isConnected = !1, this.socket && (this.socket.destroy(), this.socket = null), this.pendingRequests.forEach(({ reject: r, timeoutId: e }) => { clearTimeout(e), r(new Error("Connection closed")); }), this.pendingRequests.clear(); } /** * Handles incoming data from the socket. * @private * @param data - The raw data received. */ _handleData(r) { r.toString().trim().split(` `).forEach((t) => { if (t) try { const o = JSON.parse(t); this._handleResponse(o); } catch (o) { console.error("Failed to parse JSON:", o); } }); } /** * Handles a parsed JSON-RPC response. * @private * @param response - The JSON-RPC response object. */ _handleResponse(r) { if (typeof r != "object" || r === null || !("id" in r)) { console.error("Invalid response format:", r); return; } const e = r.id, t = this.pendingRequests.get(e); if (!t) { this._handleNotification(r); return; } this.pendingRequests.delete(e), clearTimeout(t.timeoutId), "error" in r && r.error !== null ? t.reject(new Error(`RPC Error: ${r.error}`)) : t.resolve(r); } /** * Handles JSON-RPC notifications (e.g., "update", "locked", "stolen"). * This can be overridden by subclasses or event listeners. * @private * @param notification - The notification object. */ _handleNotification(r) { if (typeof r != "object" || r === null || !("method" in r)) { console.error("Invalid notification format:", r); return; } const e = r.method; switch (e) { case "update": console.log("Received update notification:", r.params[0]); break; case "locked": console.log("Received locked notification:", r.params[0]); break; case "stolen": console.log("Received stolen notification:", r.params[0]); break; default: console.log("Received notification:", e); } } } export { m as OVSDBClient }; //# sourceMappingURL=index.es.js.map