server_description.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. 'use strict';
  2. // An enumeration of server types we know about
  3. const ServerType = {
  4. Standalone: 'Standalone',
  5. Mongos: 'Mongos',
  6. PossiblePrimary: 'PossiblePrimary',
  7. RSPrimary: 'RSPrimary',
  8. RSSecondary: 'RSSecondary',
  9. RSArbiter: 'RSArbiter',
  10. RSOther: 'RSOther',
  11. RSGhost: 'RSGhost',
  12. Unknown: 'Unknown'
  13. };
  14. const WRITABLE_SERVER_TYPES = new Set([
  15. ServerType.RSPrimary,
  16. ServerType.Standalone,
  17. ServerType.Mongos
  18. ]);
  19. const ISMASTER_FIELDS = [
  20. 'minWireVersion',
  21. 'maxWireVersion',
  22. 'maxBsonObjectSize',
  23. 'maxMessageSizeBytes',
  24. 'maxWriteBatchSize',
  25. 'compression',
  26. 'me',
  27. 'hosts',
  28. 'passives',
  29. 'arbiters',
  30. 'tags',
  31. 'setName',
  32. 'setVersion',
  33. 'electionId',
  34. 'primary',
  35. 'logicalSessionTimeoutMinutes',
  36. 'saslSupportedMechs',
  37. '__nodejs_mock_server__',
  38. '$clusterTime'
  39. ];
  40. /**
  41. * The client's view of a single server, based on the most recent ismaster outcome.
  42. *
  43. * Internal type, not meant to be directly instantiated
  44. */
  45. class ServerDescription {
  46. /**
  47. * Create a ServerDescription
  48. * @param {String} address The address of the server
  49. * @param {Object} [ismaster] An optional ismaster response for this server
  50. * @param {Object} [options] Optional settings
  51. * @param {Number} [options.roundTripTime] The round trip time to ping this server (in ms)
  52. */
  53. constructor(address, ismaster, options) {
  54. options = options || {};
  55. ismaster = Object.assign(
  56. {
  57. minWireVersion: 0,
  58. maxWireVersion: 0,
  59. hosts: [],
  60. passives: [],
  61. arbiters: [],
  62. tags: []
  63. },
  64. ismaster
  65. );
  66. this.address = address;
  67. this.error = options.error || null;
  68. this.roundTripTime = options.roundTripTime || 0;
  69. this.lastUpdateTime = Date.now();
  70. this.lastWriteDate = ismaster.lastWrite ? ismaster.lastWrite.lastWriteDate : null;
  71. this.opTime = ismaster.lastWrite ? ismaster.lastWrite.opTime : null;
  72. this.type = parseServerType(ismaster);
  73. // direct mappings
  74. ISMASTER_FIELDS.forEach(field => {
  75. if (typeof ismaster[field] !== 'undefined') this[field] = ismaster[field];
  76. });
  77. // normalize case for hosts
  78. if (this.me) this.me = this.me.toLowerCase();
  79. this.hosts = this.hosts.map(host => host.toLowerCase());
  80. this.passives = this.passives.map(host => host.toLowerCase());
  81. this.arbiters = this.arbiters.map(host => host.toLowerCase());
  82. }
  83. get allHosts() {
  84. return this.hosts.concat(this.arbiters).concat(this.passives);
  85. }
  86. /**
  87. * @return {Boolean} Is this server available for reads
  88. */
  89. get isReadable() {
  90. return this.type === ServerType.RSSecondary || this.isWritable;
  91. }
  92. /**
  93. * @return {Boolean} Is this server available for writes
  94. */
  95. get isWritable() {
  96. return WRITABLE_SERVER_TYPES.has(this.type);
  97. }
  98. }
  99. /**
  100. * Parses an `ismaster` message and determines the server type
  101. *
  102. * @param {Object} ismaster The `ismaster` message to parse
  103. * @return {ServerType}
  104. */
  105. function parseServerType(ismaster) {
  106. if (!ismaster || !ismaster.ok) {
  107. return ServerType.Unknown;
  108. }
  109. if (ismaster.isreplicaset) {
  110. return ServerType.RSGhost;
  111. }
  112. if (ismaster.msg && ismaster.msg === 'isdbgrid') {
  113. return ServerType.Mongos;
  114. }
  115. if (ismaster.setName) {
  116. if (ismaster.hidden) {
  117. return ServerType.RSOther;
  118. } else if (ismaster.ismaster) {
  119. return ServerType.RSPrimary;
  120. } else if (ismaster.secondary) {
  121. return ServerType.RSSecondary;
  122. } else if (ismaster.arbiterOnly) {
  123. return ServerType.RSArbiter;
  124. } else {
  125. return ServerType.RSOther;
  126. }
  127. }
  128. return ServerType.Standalone;
  129. }
  130. module.exports = {
  131. ServerDescription,
  132. ServerType
  133. };