server_description.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.compareTopologyVersion = exports.parseServerType = exports.ServerDescription = void 0;
  4. const bson_1 = require("../bson");
  5. const utils_1 = require("../utils");
  6. const common_1 = require("./common");
  7. const WRITABLE_SERVER_TYPES = new Set([
  8. common_1.ServerType.RSPrimary,
  9. common_1.ServerType.Standalone,
  10. common_1.ServerType.Mongos,
  11. common_1.ServerType.LoadBalancer
  12. ]);
  13. const DATA_BEARING_SERVER_TYPES = new Set([
  14. common_1.ServerType.RSPrimary,
  15. common_1.ServerType.RSSecondary,
  16. common_1.ServerType.Mongos,
  17. common_1.ServerType.Standalone,
  18. common_1.ServerType.LoadBalancer
  19. ]);
  20. /**
  21. * The client's view of a single server, based on the most recent hello outcome.
  22. *
  23. * Internal type, not meant to be directly instantiated
  24. * @public
  25. */
  26. class ServerDescription {
  27. /**
  28. * Create a ServerDescription
  29. * @internal
  30. *
  31. * @param address - The address of the server
  32. * @param hello - An optional hello response for this server
  33. */
  34. constructor(address, hello, options) {
  35. var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
  36. if (typeof address === 'string') {
  37. this._hostAddress = new utils_1.HostAddress(address);
  38. this.address = this._hostAddress.toString();
  39. }
  40. else {
  41. this._hostAddress = address;
  42. this.address = this._hostAddress.toString();
  43. }
  44. this.type = parseServerType(hello, options);
  45. this.hosts = (_b = (_a = hello === null || hello === void 0 ? void 0 : hello.hosts) === null || _a === void 0 ? void 0 : _a.map((host) => host.toLowerCase())) !== null && _b !== void 0 ? _b : [];
  46. this.passives = (_d = (_c = hello === null || hello === void 0 ? void 0 : hello.passives) === null || _c === void 0 ? void 0 : _c.map((host) => host.toLowerCase())) !== null && _d !== void 0 ? _d : [];
  47. this.arbiters = (_f = (_e = hello === null || hello === void 0 ? void 0 : hello.arbiters) === null || _e === void 0 ? void 0 : _e.map((host) => host.toLowerCase())) !== null && _f !== void 0 ? _f : [];
  48. this.tags = (_g = hello === null || hello === void 0 ? void 0 : hello.tags) !== null && _g !== void 0 ? _g : {};
  49. this.minWireVersion = (_h = hello === null || hello === void 0 ? void 0 : hello.minWireVersion) !== null && _h !== void 0 ? _h : 0;
  50. this.maxWireVersion = (_j = hello === null || hello === void 0 ? void 0 : hello.maxWireVersion) !== null && _j !== void 0 ? _j : 0;
  51. this.roundTripTime = (_k = options === null || options === void 0 ? void 0 : options.roundTripTime) !== null && _k !== void 0 ? _k : -1;
  52. this.lastUpdateTime = (0, utils_1.now)();
  53. this.lastWriteDate = (_m = (_l = hello === null || hello === void 0 ? void 0 : hello.lastWrite) === null || _l === void 0 ? void 0 : _l.lastWriteDate) !== null && _m !== void 0 ? _m : 0;
  54. if (options === null || options === void 0 ? void 0 : options.topologyVersion) {
  55. this.topologyVersion = options.topologyVersion;
  56. }
  57. else if (hello === null || hello === void 0 ? void 0 : hello.topologyVersion) {
  58. this.topologyVersion = hello.topologyVersion;
  59. }
  60. if (options === null || options === void 0 ? void 0 : options.error) {
  61. this.error = options.error;
  62. }
  63. if (hello === null || hello === void 0 ? void 0 : hello.primary) {
  64. this.primary = hello.primary;
  65. }
  66. if (hello === null || hello === void 0 ? void 0 : hello.me) {
  67. this.me = hello.me.toLowerCase();
  68. }
  69. if (hello === null || hello === void 0 ? void 0 : hello.setName) {
  70. this.setName = hello.setName;
  71. }
  72. if (hello === null || hello === void 0 ? void 0 : hello.setVersion) {
  73. this.setVersion = hello.setVersion;
  74. }
  75. if (hello === null || hello === void 0 ? void 0 : hello.electionId) {
  76. this.electionId = hello.electionId;
  77. }
  78. if (hello === null || hello === void 0 ? void 0 : hello.logicalSessionTimeoutMinutes) {
  79. this.logicalSessionTimeoutMinutes = hello.logicalSessionTimeoutMinutes;
  80. }
  81. if (hello === null || hello === void 0 ? void 0 : hello.$clusterTime) {
  82. this.$clusterTime = hello.$clusterTime;
  83. }
  84. }
  85. get hostAddress() {
  86. if (this._hostAddress)
  87. return this._hostAddress;
  88. else
  89. return new utils_1.HostAddress(this.address);
  90. }
  91. get allHosts() {
  92. return this.hosts.concat(this.arbiters).concat(this.passives);
  93. }
  94. /** Is this server available for reads*/
  95. get isReadable() {
  96. return this.type === common_1.ServerType.RSSecondary || this.isWritable;
  97. }
  98. /** Is this server data bearing */
  99. get isDataBearing() {
  100. return DATA_BEARING_SERVER_TYPES.has(this.type);
  101. }
  102. /** Is this server available for writes */
  103. get isWritable() {
  104. return WRITABLE_SERVER_TYPES.has(this.type);
  105. }
  106. get host() {
  107. const chopLength = `:${this.port}`.length;
  108. return this.address.slice(0, -chopLength);
  109. }
  110. get port() {
  111. const port = this.address.split(':').pop();
  112. return port ? Number.parseInt(port, 10) : 27017;
  113. }
  114. /**
  115. * Determines if another `ServerDescription` is equal to this one per the rules defined
  116. * in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
  117. */
  118. equals(other) {
  119. const topologyVersionsEqual = this.topologyVersion === other.topologyVersion ||
  120. compareTopologyVersion(this.topologyVersion, other.topologyVersion) === 0;
  121. const electionIdsEqual = this.electionId && other.electionId
  122. ? other.electionId && this.electionId.equals(other.electionId)
  123. : this.electionId === other.electionId;
  124. return (other != null &&
  125. (0, utils_1.errorStrictEqual)(this.error, other.error) &&
  126. this.type === other.type &&
  127. this.minWireVersion === other.minWireVersion &&
  128. (0, utils_1.arrayStrictEqual)(this.hosts, other.hosts) &&
  129. tagsStrictEqual(this.tags, other.tags) &&
  130. this.setName === other.setName &&
  131. this.setVersion === other.setVersion &&
  132. electionIdsEqual &&
  133. this.primary === other.primary &&
  134. this.logicalSessionTimeoutMinutes === other.logicalSessionTimeoutMinutes &&
  135. topologyVersionsEqual);
  136. }
  137. }
  138. exports.ServerDescription = ServerDescription;
  139. // Parses a `hello` message and determines the server type
  140. function parseServerType(hello, options) {
  141. if (options === null || options === void 0 ? void 0 : options.loadBalanced) {
  142. return common_1.ServerType.LoadBalancer;
  143. }
  144. if (!hello || !hello.ok) {
  145. return common_1.ServerType.Unknown;
  146. }
  147. if (hello.isreplicaset) {
  148. return common_1.ServerType.RSGhost;
  149. }
  150. if (hello.msg && hello.msg === 'isdbgrid') {
  151. return common_1.ServerType.Mongos;
  152. }
  153. if (hello.setName) {
  154. if (hello.hidden) {
  155. return common_1.ServerType.RSOther;
  156. }
  157. else if (hello.isWritablePrimary) {
  158. return common_1.ServerType.RSPrimary;
  159. }
  160. else if (hello.secondary) {
  161. return common_1.ServerType.RSSecondary;
  162. }
  163. else if (hello.arbiterOnly) {
  164. return common_1.ServerType.RSArbiter;
  165. }
  166. else {
  167. return common_1.ServerType.RSOther;
  168. }
  169. }
  170. return common_1.ServerType.Standalone;
  171. }
  172. exports.parseServerType = parseServerType;
  173. function tagsStrictEqual(tags, tags2) {
  174. const tagsKeys = Object.keys(tags);
  175. const tags2Keys = Object.keys(tags2);
  176. return (tagsKeys.length === tags2Keys.length &&
  177. tagsKeys.every((key) => tags2[key] === tags[key]));
  178. }
  179. /**
  180. * Compares two topology versions.
  181. *
  182. * @returns A negative number if `lhs` is older than `rhs`; positive if `lhs` is newer than `rhs`; 0 if they are equivalent.
  183. */
  184. function compareTopologyVersion(lhs, rhs) {
  185. if (lhs == null || rhs == null) {
  186. return -1;
  187. }
  188. if (lhs.processId.equals(rhs.processId)) {
  189. // tests mock counter as just number, but in a real situation counter should always be a Long
  190. const lhsCounter = bson_1.Long.isLong(lhs.counter) ? lhs.counter : bson_1.Long.fromNumber(lhs.counter);
  191. const rhsCounter = bson_1.Long.isLong(rhs.counter) ? lhs.counter : bson_1.Long.fromNumber(rhs.counter);
  192. return lhsCounter.compare(rhsCounter);
  193. }
  194. return -1;
  195. }
  196. exports.compareTopologyVersion = compareTopologyVersion;
  197. //# sourceMappingURL=server_description.js.map