You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							189 lines
						
					
					
						
							7.6 KiB
						
					
					
				
			
		
		
	
	
							189 lines
						
					
					
						
							7.6 KiB
						
					
					
				| "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 type
 | |
| function 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
 |