@sourceregistry/node-ovsdb
Version:
Open vSwitch Database Management Protocol typescript client
222 lines (221 loc) • 7.05 kB
JavaScript
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