| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 | "use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.compareTopologyVersion = exports.parseServerType = exports.ServerDescription = void 0;const bson_1 = require("../bson");const error_1 = require("../error");const utils_1 = require("../utils");const common_1 = require("./common");const WRITABLE_SERVER_TYPES = new Set([    common_1.ServerType.RSPrimary,    common_1.ServerType.Standalone,    common_1.ServerType.Mongos,    common_1.ServerType.LoadBalancer]);const DATA_BEARING_SERVER_TYPES = new Set([    common_1.ServerType.RSPrimary,    common_1.ServerType.RSSecondary,    common_1.ServerType.Mongos,    common_1.ServerType.Standalone,    common_1.ServerType.LoadBalancer]);/** * The client's view of a single server, based on the most recent hello outcome. * * Internal type, not meant to be directly instantiated * @public */class ServerDescription {    /**     * Create a ServerDescription     * @internal     *     * @param address - The address of the server     * @param hello - An optional hello response for this server     */    constructor(address, hello, options = {}) {        if (address == null || address === '') {            throw new error_1.MongoRuntimeError('ServerDescription must be provided with a non-empty address');        }        this.address =            typeof address === 'string'                ? utils_1.HostAddress.fromString(address).toString() // Use HostAddress to normalize                : address.toString();        this.type = parseServerType(hello, options);        this.hosts = hello?.hosts?.map((host) => host.toLowerCase()) ?? [];        this.passives = hello?.passives?.map((host) => host.toLowerCase()) ?? [];        this.arbiters = hello?.arbiters?.map((host) => host.toLowerCase()) ?? [];        this.tags = hello?.tags ?? {};        this.minWireVersion = hello?.minWireVersion ?? 0;        this.maxWireVersion = hello?.maxWireVersion ?? 0;        this.roundTripTime = options?.roundTripTime ?? -1;        this.lastUpdateTime = (0, utils_1.now)();        this.lastWriteDate = hello?.lastWrite?.lastWriteDate ?? 0;        this.error = options.error ?? null;        // TODO(NODE-2674): Preserve int64 sent from MongoDB        this.topologyVersion = this.error?.topologyVersion ?? hello?.topologyVersion ?? null;        this.setName = hello?.setName ?? null;        this.setVersion = hello?.setVersion ?? null;        this.electionId = hello?.electionId ?? null;        this.logicalSessionTimeoutMinutes = hello?.logicalSessionTimeoutMinutes ?? null;        this.primary = hello?.primary ?? null;        this.me = hello?.me?.toLowerCase() ?? null;        this.$clusterTime = hello?.$clusterTime ?? null;    }    get hostAddress() {        return utils_1.HostAddress.fromString(this.address);    }    get allHosts() {        return this.hosts.concat(this.arbiters).concat(this.passives);    }    /** Is this server available for reads*/    get isReadable() {        return this.type === common_1.ServerType.RSSecondary || this.isWritable;    }    /** Is this server data bearing */    get isDataBearing() {        return DATA_BEARING_SERVER_TYPES.has(this.type);    }    /** Is this server available for writes */    get isWritable() {        return WRITABLE_SERVER_TYPES.has(this.type);    }    get host() {        const chopLength = `:${this.port}`.length;        return this.address.slice(0, -chopLength);    }    get port() {        const port = this.address.split(':').pop();        return port ? Number.parseInt(port, 10) : 27017;    }    /**     * Determines if another `ServerDescription` is equal to this one per the rules defined     * in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}     */    equals(other) {        // Despite using the comparator that would determine a nullish topologyVersion as greater than        // for equality we should only always perform direct equality comparison        const topologyVersionsEqual = this.topologyVersion === other?.topologyVersion ||            compareTopologyVersion(this.topologyVersion, other?.topologyVersion) === 0;        const electionIdsEqual = this.electionId != null && other?.electionId != null            ? (0, utils_1.compareObjectId)(this.electionId, other.electionId) === 0            : this.electionId === other?.electionId;        return (other != null &&            (0, utils_1.errorStrictEqual)(this.error, other.error) &&            this.type === other.type &&            this.minWireVersion === other.minWireVersion &&            (0, utils_1.arrayStrictEqual)(this.hosts, other.hosts) &&            tagsStrictEqual(this.tags, other.tags) &&            this.setName === other.setName &&            this.setVersion === other.setVersion &&            electionIdsEqual &&            this.primary === other.primary &&            this.logicalSessionTimeoutMinutes === other.logicalSessionTimeoutMinutes &&            topologyVersionsEqual);    }}exports.ServerDescription = ServerDescription;// Parses a `hello` message and determines the server typefunction parseServerType(hello, options) {    if (options?.loadBalanced) {        return common_1.ServerType.LoadBalancer;    }    if (!hello || !hello.ok) {        return common_1.ServerType.Unknown;    }    if (hello.isreplicaset) {        return common_1.ServerType.RSGhost;    }    if (hello.msg && hello.msg === 'isdbgrid') {        return common_1.ServerType.Mongos;    }    if (hello.setName) {        if (hello.hidden) {            return common_1.ServerType.RSOther;        }        else if (hello.isWritablePrimary) {            return common_1.ServerType.RSPrimary;        }        else if (hello.secondary) {            return common_1.ServerType.RSSecondary;        }        else if (hello.arbiterOnly) {            return common_1.ServerType.RSArbiter;        }        else {            return common_1.ServerType.RSOther;        }    }    return common_1.ServerType.Standalone;}exports.parseServerType = parseServerType;function tagsStrictEqual(tags, tags2) {    const tagsKeys = Object.keys(tags);    const tags2Keys = Object.keys(tags2);    return (tagsKeys.length === tags2Keys.length &&        tagsKeys.every((key) => tags2[key] === tags[key]));}/** * Compares two topology versions. * * 1. If the response topologyVersion is unset or the ServerDescription's *    topologyVersion is null, the client MUST assume the response is more recent. * 1. If the response's topologyVersion.processId is not equal to the *    ServerDescription's, the client MUST assume the response is more recent. * 1. If the response's topologyVersion.processId is equal to the *    ServerDescription's, the client MUST use the counter field to determine *    which topologyVersion is more recent. * * ```ts * currentTv <   newTv === -1 * currentTv === newTv === 0 * currentTv >   newTv === 1 * ``` */function compareTopologyVersion(currentTv, newTv) {    if (currentTv == null || newTv == null) {        return -1;    }    if (!currentTv.processId.equals(newTv.processId)) {        return -1;    }    // TODO(NODE-2674): Preserve int64 sent from MongoDB    const currentCounter = bson_1.Long.isLong(currentTv.counter)        ? currentTv.counter        : bson_1.Long.fromNumber(currentTv.counter);    const newCounter = bson_1.Long.isLong(newTv.counter) ? newTv.counter : bson_1.Long.fromNumber(newTv.counter);    return currentCounter.compare(newCounter);}exports.compareTopologyVersion = compareTopologyVersion;//# sourceMappingURL=server_description.js.map
 |