couchbase
Version:
The official Couchbase Node.js Client Library.
641 lines (640 loc) • 24.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cluster = void 0;
const analyticsexecutor_1 = require("./analyticsexecutor");
const analyticsindexmanager_1 = require("./analyticsindexmanager");
const binding_1 = __importDefault(require("./binding"));
const bindingutilities_1 = require("./bindingutilities");
const bucket_1 = require("./bucket");
const bucketmanager_1 = require("./bucketmanager");
const configProfile_1 = require("./configProfile");
const connspec_1 = require("./connspec");
const diagnosticsexecutor_1 = require("./diagnosticsexecutor");
const eventingfunctionmanager_1 = require("./eventingfunctionmanager");
const logger_1 = require("./logger");
const loggingmeter_1 = require("./loggingmeter");
const observability_1 = require("./observability");
const observabilitytypes_1 = require("./observabilitytypes");
const queryexecutor_1 = require("./queryexecutor");
const queryindexmanager_1 = require("./queryindexmanager");
const searchexecutor_1 = require("./searchexecutor");
const searchindexmanager_1 = require("./searchindexmanager");
const thresholdlogging_1 = require("./thresholdlogging");
const transactions_1 = require("./transactions");
const transcoders_1 = require("./transcoders");
const usermanager_1 = require("./usermanager");
const utilities_1 = require("./utilities");
const utilities_internal_1 = require("./utilities_internal");
const util_1 = require("util");
/**
* Exposes the operations which are available to be performed against a cluster.
* Namely the ability to access to Buckets as well as performing management
* operations against the cluster.
*
* @category Core
*/
class Cluster {
/**
* @internal
*/
get conn() {
return this._conn;
}
/**
@internal
*/
get transcoder() {
return this._transcoder;
}
/**
@internal
*/
get kvTimeout() {
return this._kvTimeout;
}
/**
@internal
*/
get kvDurableTimeout() {
return this._kvDurableTimeout;
}
/**
@internal
*/
get viewTimeout() {
return this._viewTimeout;
}
/**
@internal
*/
get queryTimeout() {
return this._queryTimeout;
}
/**
@internal
*/
get analyticsTimeout() {
return this._analyticsTimeout;
}
/**
@internal
*/
get searchTimeout() {
return this._searchTimeout;
}
/**
@internal
*/
get managementTimeout() {
return this._managementTimeout;
}
/**
@internal
*/
get bootstrapTimeout() {
return this._bootstrapTimeout;
}
/**
@internal
*/
get connectTimeout() {
return this._connectTimeout;
}
/**
@internal
*/
get resolveTimeout() {
return this._resolveTimeout;
}
/**
@internal
*/
get logger() {
return this._logger;
}
/**
* @internal
*/
get observabilityInstruments() {
return this._observabilityInstruments;
}
/**
* @internal
*/
[util_1.inspect.custom]() {
const { _auth, ...rest } = this;
return { ...rest, _auth: '***hidden***' };
}
/**
* @internal
*/
toJSON() {
const { _auth, ...rest } = this;
return { ...rest, _auth: '***hidden***' };
}
/**
@internal
@deprecated Use the static sdk-level {@link connect} method instead.
*/
constructor(connStr, options) {
var _a, _b, _c;
if (!options) {
options = {};
}
if (!options.security) {
options.security = {};
}
if (!options.timeouts) {
options.timeouts = {};
}
this._connStr = connStr;
this._trustStorePath = options.security.trustStorePath || '';
if (options.configProfile) {
configProfile_1.knownProfiles.applyProfile(options.configProfile, options);
}
this._kvTimeout = options.timeouts.kvTimeout || 2500;
this._kvDurableTimeout = options.timeouts.kvDurableTimeout || 10000;
this._viewTimeout = options.timeouts.viewTimeout || 75000;
this._queryTimeout = options.timeouts.queryTimeout || 75000;
this._analyticsTimeout = options.timeouts.analyticsTimeout || 75000;
this._searchTimeout = options.timeouts.searchTimeout || 75000;
this._managementTimeout = options.timeouts.managementTimeout || 75000;
this._bootstrapTimeout = (_a = options.timeouts) === null || _a === void 0 ? void 0 : _a.bootstrapTimeout;
this._connectTimeout = (_b = options.timeouts) === null || _b === void 0 ? void 0 : _b.connectTimeout;
this._resolveTimeout = (_c = options.timeouts) === null || _c === void 0 ? void 0 : _c.resolveTimeout;
if (options.transcoder) {
this._transcoder = options.transcoder;
}
else {
this._transcoder = new transcoders_1.DefaultTranscoder();
}
if (options.preferredServerGroup) {
this._preferredServerGroup = options.preferredServerGroup;
}
if (options.transactions) {
this._txnConfig = options.transactions;
}
else {
this._txnConfig = {};
}
if (options.username || options.password) {
if (options.authenticator) {
throw new Error('Cannot specify authenticator along with username/password.');
}
this._auth = {
username: options.username || '',
password: options.password || '',
};
}
else if (options.authenticator) {
this._auth = options.authenticator;
}
else {
this._auth = {
username: '',
password: '',
};
}
if (options.dnsConfig &&
(options.dnsConfig.nameserver ||
options.dnsConfig.port ||
options.dnsConfig.dnsSrvTimeout)) {
this._dnsConfig = {
nameserver: options.dnsConfig.nameserver,
port: options.dnsConfig.port,
dnsSrvTimeout: options.dnsConfig.dnsSrvTimeout || 500,
};
}
else {
this._dnsConfig = null;
}
if (options.appTelemetryConfig) {
this._appTelemetryConfig = {
enabled: options.appTelemetryConfig.enabled,
endpoint: options.appTelemetryConfig.endpoint,
backoff: options.appTelemetryConfig.backoff,
pingInterval: options.appTelemetryConfig.pingInterval,
pingTimeout: options.appTelemetryConfig.pingTimeout,
};
}
else {
this._appTelemetryConfig = null;
}
if (options.tracer) {
this._tracer = options.tracer;
}
if (options.tracingConfig) {
this._tracingConfig = {
enableTracing: options.tracingConfig.enableTracing,
emitInterval: options.tracingConfig.emitInterval,
sampleSize: options.tracingConfig.sampleSize,
kvThreshold: options.tracingConfig.kvThreshold,
queryThreshold: options.tracingConfig.queryThreshold,
searchThreshold: options.tracingConfig.searchThreshold,
analyticsThreshold: options.tracingConfig.analyticsThreshold,
managementThreshold: options.tracingConfig.managementThreshold,
eventingThreshold: options.tracingConfig.eventingThreshold,
viewsThreshold: options.tracingConfig.viewsThreshold,
};
}
else {
this._tracingConfig = null;
}
if (options.orphanReporterConfig) {
this._orphanReporterConfig = {
enableOrphanReporting: options.orphanReporterConfig.enableOrphanReporting,
emitInterval: options.orphanReporterConfig.emitInterval,
sampleSize: options.orphanReporterConfig.sampleSize,
};
}
else {
this._orphanReporterConfig = null;
}
if (options.meter) {
this._meter = options.meter;
}
if (options.metricsConfig) {
this._metricsConfig = {
enableMetrics: options.metricsConfig.enableMetrics,
emitInterval: options.metricsConfig.emitInterval,
};
}
else {
this._metricsConfig = null;
}
if (!options.logger) {
const envLogLevel = process.env.CNLOGLEVEL;
if (envLogLevel) {
const level = (0, logger_1.parseLogLevel)(envLogLevel);
if (level !== undefined) {
this._logger = (0, logger_1.createConsoleLogger)(level);
}
else {
this._logger = new logger_1.CouchbaseLogger(new logger_1.NoOpLogger());
}
}
else {
this._logger = new logger_1.CouchbaseLogger(new logger_1.NoOpLogger());
}
}
else {
this._logger =
options.logger instanceof logger_1.CouchbaseLogger
? options.logger
: new logger_1.CouchbaseLogger(options.logger);
}
this._openBuckets = [];
this._conn = new binding_1.default.Connection();
}
/**
@internal
*/
static async connect(connStr, options, callback) {
return utilities_1.PromiseHelper.wrapAsync(async () => {
const cluster = new Cluster(connStr, options);
await cluster._connect();
return cluster;
}, callback);
}
/**
* Creates a Bucket object reference to a specific bucket.
*
* @param bucketName The name of the bucket to reference.
*/
bucket(bucketName) {
if (!this._openBuckets.includes(bucketName)) {
this._conn.openBucket(bucketName, (err) => {
if (err) {
// BUG(JSCBC-1011): Move this to log framework once it is implemented.
console.error(`failed to open bucket: ${bucketName}`, err);
}
});
this._openBuckets.push(bucketName);
}
return new bucket_1.Bucket(this, bucketName);
}
/**
* Returns a UserManager which can be used to manage the users
* of this cluster.
*/
users() {
return new usermanager_1.UserManager(this);
}
/**
* Returns a BucketManager which can be used to manage the buckets
* of this cluster.
*/
buckets() {
return new bucketmanager_1.BucketManager(this);
}
/**
* Returns a QueryIndexManager which can be used to manage the query indexes
* of this cluster.
*/
queryIndexes() {
return new queryindexmanager_1.QueryIndexManager(this);
}
/**
* Returns a AnalyticsIndexManager which can be used to manage the analytics
* indexes of this cluster.
*/
analyticsIndexes() {
return new analyticsindexmanager_1.AnalyticsIndexManager(this);
}
/**
* Returns a SearchIndexManager which can be used to manage the search
* indexes of this cluster.
*/
searchIndexes() {
return new searchindexmanager_1.SearchIndexManager(this);
}
/**
* Returns a EventingFunctionManager which can be used to manage the eventing
* functions of this cluster.
* Uncommitted: This API is subject to change in the future.
*/
eventingFunctions() {
return new eventingfunctionmanager_1.EventingFunctionManager(this);
}
/**
* Returns a Transactions object which can be used to perform transactions
* on this cluster.
*/
transactions() {
if (!this._transactions) {
this._transactions = new transactions_1.Transactions(this, this._txnConfig);
}
return this._transactions;
}
/**
* Executes a N1QL query against the cluster.
*
* @param statement The N1QL statement to execute.
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
query(statement, options, callback) {
if (options instanceof Function) {
callback = arguments[1];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new queryexecutor_1.QueryExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.query(statement, options_), callback);
}
/**
* Executes an analytics query against the cluster.
*
* @param statement The analytics statement to execute.
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
analyticsQuery(statement, options, callback) {
if (options instanceof Function) {
callback = arguments[1];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new analyticsexecutor_1.AnalyticsExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.query(statement, options_), callback);
}
/**
* Executes a search query against the cluster.
*
* @param indexName The name of the index to query.
* @param query The SearchQuery describing the query to execute.
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
searchQuery(indexName, query, options, callback) {
if (options instanceof Function) {
callback = arguments[2];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new searchexecutor_1.SearchExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.query(indexName, query, options_), callback);
}
/**
* Executes a search query against the cluster.
*
* @param indexName The name of the index to query.
* @param request The SearchRequest describing the search to execute.
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
search(indexName, request, options, callback) {
if (options instanceof Function) {
callback = arguments[2];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new searchexecutor_1.SearchExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.query(indexName, request, options_), callback);
}
/**
* Returns a diagnostics report about the currently active connections with the
* cluster. Includes information about remote and local addresses, last activity,
* and other diagnostics information.
*
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
diagnostics(options, callback) {
if (options instanceof Function) {
callback = arguments[0];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new diagnosticsexecutor_1.DiagnoticsExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.diagnostics(options_), callback);
}
/**
* Performs a ping operation against the cluster. Pinging the services which
* are specified (or all services if none are specified). Returns a report
* which describes the outcome of the ping operations which were performed.
*
* @param options Optional parameters for this operation.
* @param callback A node-style callback to be invoked after execution.
*/
ping(options, callback) {
if (options instanceof Function) {
callback = arguments[0];
options = undefined;
}
if (!options) {
options = {};
}
const exec = new diagnosticsexecutor_1.PingExecutor(this);
const options_ = options;
return utilities_1.PromiseHelper.wrapAsync(() => exec.ping(options_), callback);
}
/**
* Shuts down this cluster object. Cleaning up all resources associated with it.
*
* @param callback A node-style callback to be invoked after execution.
*/
async close(callback) {
if (this._transactions) {
await this._transactions._close();
this._transactions = undefined;
}
if (this._tracer instanceof thresholdlogging_1.ThresholdLoggingTracer) {
this._tracer.cleanup();
}
if (this._meter instanceof loggingmeter_1.LoggingMeter) {
this._meter.cleanup();
}
return utilities_1.PromiseHelper.wrap((wrapCallback) => {
this._conn.shutdown((cppErr) => {
wrapCallback((0, bindingutilities_1.errorFromCpp)(cppErr));
});
}, callback);
}
/**
* Update the credentials used by this cluster.
*
* @param auth The new credentials to use.
*/
updateCredentials(auth) {
const cppErr = this._conn.updateCredentials(this._getCppCredentials(auth));
if (cppErr) {
const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
throw err;
}
}
/**
* @internal
*/
_getClusterLabels() {
const resp = this._conn.getClusterLabels();
return { clusterName: resp.clusterName, clusterUUID: resp.clusterUUID };
}
_getCppCredentials(auth, saslMechanisms) {
const authOpts = {};
if (auth) {
const passAuth = auth;
if (passAuth.username || passAuth.password) {
authOpts.username = passAuth.username;
authOpts.password = passAuth.password;
if (saslMechanisms) {
authOpts.allowed_sasl_mechanisms = saslMechanisms;
}
}
const certAuth = auth;
if (certAuth.certificatePath || certAuth.keyPath) {
authOpts.certificate_path = certAuth.certificatePath;
authOpts.key_path = certAuth.keyPath;
}
const jwtAuth = auth;
if (jwtAuth.token) {
authOpts.jwt_token = jwtAuth.token;
}
}
return authOpts;
}
_setupObservability() {
// [tracing|metrics] is explicitly disabled IFF:
// we have a [tracing|metrics]Config AND [tracing|metrics]Config.enable[Tracing|Metrics] === false
// _[tracing|metrics]Config = null => FALSE
// _[tracing|metrics]Config = undefined => FALSE
// _[tracing|metrics]Config.enable[Tracing|Metrics] = true => FALSE
// _[tracing|metrics]Config.enable[Tracing|Metrics] = false => TRUE
var _a, _b, _c, _d, _e;
const tracingExplicitlyDisabled = ((_a = this._tracingConfig) !== null && _a !== void 0 ? _a : false) && !((_b = this._tracingConfig) === null || _b === void 0 ? void 0 : _b.enableTracing);
// we want to enable tracing IFF we don't have a tracer && tracing was NOT explicitly disabled
const enableTracing = typeof this._tracer !== 'undefined' || !tracingExplicitlyDisabled;
// if tracing is enabled, but we don't have a tracer, default to the ThresholdLoggingTracer
if (enableTracing && !this._tracer) {
this._tracer = new thresholdlogging_1.ThresholdLoggingTracer(this._logger, this._tracingConfig);
}
// if we don't have a tracer at this point, tracing is NOT enabled, use the NoOpTracer
if (!this._tracer) {
this._tracer = new observability_1.NoOpTracer();
}
const metricsExplicitlyDisabled = ((_c = this._metricsConfig) !== null && _c !== void 0 ? _c : false) && !((_d = this._metricsConfig) === null || _d === void 0 ? void 0 : _d.enableMetrics);
// we want to enable metrics IFF we don't have a meter && metrics was NOT explicitly disabled
const enableMetrics = typeof this._meter !== 'undefined' || !metricsExplicitlyDisabled;
// if metrics is enabled, but we don't have a meter, default to the LoggingMeter
if (enableMetrics && !this._meter) {
this._meter = new loggingmeter_1.LoggingMeter(this._logger, (_e = this._metricsConfig) === null || _e === void 0 ? void 0 : _e.emitInterval);
}
// if we don't have a meter at this point, metrics is NOT enabled, use the NoOpMeter
if (!this._meter) {
this._meter = new observability_1.NoOpMeter();
}
this._observabilityInstruments = new observabilitytypes_1.ObservabilityInstruments(this._tracer, this._meter, () => this._getClusterLabels());
return [enableTracing, enableMetrics];
}
async _connect() {
return new Promise((resolve, reject) => {
const dsnObj = connspec_1.ConnSpec.parse(this._connStr);
dsnObj.options.user_agent_extra = (0, utilities_internal_1.generateClientString)();
//trust_store_path is legacy, C++ SDK expects trust_certificate
if ('trust_store_path' in dsnObj.options &&
!('trust_certificate' in dsnObj.options)) {
dsnObj.options.trust_certificate = dsnObj.options.trust_store_path;
delete dsnObj.options['trust_store_path'];
}
//if trust store was passed in via `SecurityConfig` override connstr
if (this._trustStorePath) {
dsnObj.options.trust_certificate = this._trustStorePath;
}
if (this.bootstrapTimeout) {
dsnObj.options['bootstrap_timeout'] = this.bootstrapTimeout.toString();
}
if (this.connectTimeout) {
dsnObj.options['kv_connect_timeout'] = this.connectTimeout.toString();
}
if (this.resolveTimeout) {
dsnObj.options['resolve_timeout'] = this.resolveTimeout.toString();
}
if (this._preferredServerGroup) {
dsnObj.options['server_group'] = this._preferredServerGroup;
}
const connStr = dsnObj.toString();
// lets allow `allowed_sasl_mechanisms` to override legacy connstr option
let saslMechansims;
for (const saslKey of ['sasl_mech_force', 'allowed_sasl_mechanisms']) {
if (!(saslKey in dsnObj.options)) {
continue;
}
if (typeof dsnObj.options[saslKey] === 'string') {
saslMechansims = [dsnObj.options[saslKey]];
}
else {
saslMechansims = dsnObj.options[saslKey];
}
delete dsnObj.options[saslKey];
}
const authOpts = this._getCppCredentials(this._auth, saslMechansims);
const [enableTracing, _enableMetrics] = this._setupObservability();
this._conn.connect(connStr, authOpts, this._dnsConfig, this._appTelemetryConfig, enableTracing, this._orphanReporterConfig, (cppErr) => {
if (cppErr) {
const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
return reject(err);
}
resolve(null);
});
});
}
}
exports.Cluster = Cluster;