socket.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. "use strict";
  2. var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  3. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  4. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  5. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  6. };
  7. var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  8. if (kind === "m") throw new TypeError("Private method is not writable");
  9. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  10. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  11. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  12. };
  13. var _RedisSocket_instances, _a, _RedisSocket_initiateOptions, _RedisSocket_isTlsSocket, _RedisSocket_initiator, _RedisSocket_options, _RedisSocket_socket, _RedisSocket_isOpen, _RedisSocket_isReady, _RedisSocket_writableNeedDrain, _RedisSocket_isSocketUnrefed, _RedisSocket_reconnectStrategy, _RedisSocket_shouldReconnect, _RedisSocket_connect, _RedisSocket_createSocket, _RedisSocket_createNetSocket, _RedisSocket_createTlsSocket, _RedisSocket_onSocketError, _RedisSocket_disconnect, _RedisSocket_isCorked;
  14. Object.defineProperty(exports, "__esModule", { value: true });
  15. const events_1 = require("events");
  16. const net = require("net");
  17. const tls = require("tls");
  18. const errors_1 = require("../errors");
  19. const utils_1 = require("../utils");
  20. class RedisSocket extends events_1.EventEmitter {
  21. get isOpen() {
  22. return __classPrivateFieldGet(this, _RedisSocket_isOpen, "f");
  23. }
  24. get isReady() {
  25. return __classPrivateFieldGet(this, _RedisSocket_isReady, "f");
  26. }
  27. get writableNeedDrain() {
  28. return __classPrivateFieldGet(this, _RedisSocket_writableNeedDrain, "f");
  29. }
  30. constructor(initiator, options) {
  31. super();
  32. _RedisSocket_instances.add(this);
  33. _RedisSocket_initiator.set(this, void 0);
  34. _RedisSocket_options.set(this, void 0);
  35. _RedisSocket_socket.set(this, void 0);
  36. _RedisSocket_isOpen.set(this, false);
  37. _RedisSocket_isReady.set(this, false);
  38. // `writable.writableNeedDrain` was added in v15.2.0 and therefore can't be used
  39. // https://nodejs.org/api/stream.html#stream_writable_writableneeddrain
  40. _RedisSocket_writableNeedDrain.set(this, false);
  41. _RedisSocket_isSocketUnrefed.set(this, false);
  42. _RedisSocket_isCorked.set(this, false);
  43. __classPrivateFieldSet(this, _RedisSocket_initiator, initiator, "f");
  44. __classPrivateFieldSet(this, _RedisSocket_options, __classPrivateFieldGet(_a, _a, "m", _RedisSocket_initiateOptions).call(_a, options), "f");
  45. }
  46. async connect() {
  47. if (__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) {
  48. throw new Error('Socket already opened');
  49. }
  50. __classPrivateFieldSet(this, _RedisSocket_isOpen, true, "f");
  51. return __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_connect).call(this);
  52. }
  53. writeCommand(args) {
  54. if (!__classPrivateFieldGet(this, _RedisSocket_socket, "f")) {
  55. throw new errors_1.ClientClosedError();
  56. }
  57. for (const toWrite of args) {
  58. __classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, !__classPrivateFieldGet(this, _RedisSocket_socket, "f").write(toWrite), "f");
  59. }
  60. }
  61. disconnect() {
  62. if (!__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) {
  63. throw new errors_1.ClientClosedError();
  64. }
  65. __classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f");
  66. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_disconnect).call(this);
  67. }
  68. async quit(fn) {
  69. if (!__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) {
  70. throw new errors_1.ClientClosedError();
  71. }
  72. __classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f");
  73. const reply = await fn();
  74. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_disconnect).call(this);
  75. return reply;
  76. }
  77. cork() {
  78. if (!__classPrivateFieldGet(this, _RedisSocket_socket, "f") || __classPrivateFieldGet(this, _RedisSocket_isCorked, "f")) {
  79. return;
  80. }
  81. __classPrivateFieldGet(this, _RedisSocket_socket, "f").cork();
  82. __classPrivateFieldSet(this, _RedisSocket_isCorked, true, "f");
  83. setImmediate(() => {
  84. __classPrivateFieldGet(this, _RedisSocket_socket, "f")?.uncork();
  85. __classPrivateFieldSet(this, _RedisSocket_isCorked, false, "f");
  86. });
  87. }
  88. ref() {
  89. __classPrivateFieldSet(this, _RedisSocket_isSocketUnrefed, false, "f");
  90. __classPrivateFieldGet(this, _RedisSocket_socket, "f")?.ref();
  91. }
  92. unref() {
  93. __classPrivateFieldSet(this, _RedisSocket_isSocketUnrefed, true, "f");
  94. __classPrivateFieldGet(this, _RedisSocket_socket, "f")?.unref();
  95. }
  96. }
  97. _a = RedisSocket, _RedisSocket_initiator = new WeakMap(), _RedisSocket_options = new WeakMap(), _RedisSocket_socket = new WeakMap(), _RedisSocket_isOpen = new WeakMap(), _RedisSocket_isReady = new WeakMap(), _RedisSocket_writableNeedDrain = new WeakMap(), _RedisSocket_isSocketUnrefed = new WeakMap(), _RedisSocket_isCorked = new WeakMap(), _RedisSocket_instances = new WeakSet(), _RedisSocket_initiateOptions = function _RedisSocket_initiateOptions(options) {
  98. var _b, _c;
  99. options ?? (options = {});
  100. if (!options.path) {
  101. (_b = options).port ?? (_b.port = 6379);
  102. (_c = options).host ?? (_c.host = 'localhost');
  103. }
  104. options.connectTimeout ?? (options.connectTimeout = 5000);
  105. options.keepAlive ?? (options.keepAlive = 5000);
  106. options.noDelay ?? (options.noDelay = true);
  107. return options;
  108. }, _RedisSocket_isTlsSocket = function _RedisSocket_isTlsSocket(options) {
  109. return options.tls === true;
  110. }, _RedisSocket_reconnectStrategy = function _RedisSocket_reconnectStrategy(retries, cause) {
  111. if (__classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy === false) {
  112. return false;
  113. }
  114. else if (typeof __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy === 'number') {
  115. return __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy;
  116. }
  117. else if (__classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy) {
  118. try {
  119. const retryIn = __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy(retries, cause);
  120. if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') {
  121. throw new TypeError(`Reconnect strategy should return \`false | Error | number\`, got ${retryIn} instead`);
  122. }
  123. return retryIn;
  124. }
  125. catch (err) {
  126. this.emit('error', err);
  127. }
  128. }
  129. return Math.min(retries * 50, 500);
  130. }, _RedisSocket_shouldReconnect = function _RedisSocket_shouldReconnect(retries, cause) {
  131. const retryIn = __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_reconnectStrategy).call(this, retries, cause);
  132. if (retryIn === false) {
  133. __classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f");
  134. this.emit('error', cause);
  135. return cause;
  136. }
  137. else if (retryIn instanceof Error) {
  138. __classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f");
  139. this.emit('error', cause);
  140. return new errors_1.ReconnectStrategyError(retryIn, cause);
  141. }
  142. return retryIn;
  143. }, _RedisSocket_connect = async function _RedisSocket_connect() {
  144. let retries = 0;
  145. do {
  146. try {
  147. __classPrivateFieldSet(this, _RedisSocket_socket, await __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createSocket).call(this), "f");
  148. __classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, false, "f");
  149. this.emit('connect');
  150. try {
  151. await __classPrivateFieldGet(this, _RedisSocket_initiator, "f").call(this);
  152. }
  153. catch (err) {
  154. __classPrivateFieldGet(this, _RedisSocket_socket, "f").destroy();
  155. __classPrivateFieldSet(this, _RedisSocket_socket, undefined, "f");
  156. throw err;
  157. }
  158. __classPrivateFieldSet(this, _RedisSocket_isReady, true, "f");
  159. this.emit('ready');
  160. }
  161. catch (err) {
  162. const retryIn = __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_shouldReconnect).call(this, retries++, err);
  163. if (typeof retryIn !== 'number') {
  164. throw retryIn;
  165. }
  166. this.emit('error', err);
  167. await (0, utils_1.promiseTimeout)(retryIn);
  168. this.emit('reconnecting');
  169. }
  170. } while (__classPrivateFieldGet(this, _RedisSocket_isOpen, "f") && !__classPrivateFieldGet(this, _RedisSocket_isReady, "f"));
  171. }, _RedisSocket_createSocket = function _RedisSocket_createSocket() {
  172. return new Promise((resolve, reject) => {
  173. const { connectEvent, socket } = __classPrivateFieldGet(_a, _a, "m", _RedisSocket_isTlsSocket).call(_a, __classPrivateFieldGet(this, _RedisSocket_options, "f")) ?
  174. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createTlsSocket).call(this) :
  175. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createNetSocket).call(this);
  176. if (__classPrivateFieldGet(this, _RedisSocket_options, "f").connectTimeout) {
  177. socket.setTimeout(__classPrivateFieldGet(this, _RedisSocket_options, "f").connectTimeout, () => socket.destroy(new errors_1.ConnectionTimeoutError()));
  178. }
  179. if (__classPrivateFieldGet(this, _RedisSocket_isSocketUnrefed, "f")) {
  180. socket.unref();
  181. }
  182. socket
  183. .setNoDelay(__classPrivateFieldGet(this, _RedisSocket_options, "f").noDelay)
  184. .once('error', reject)
  185. .once(connectEvent, () => {
  186. socket
  187. .setTimeout(0)
  188. // https://github.com/nodejs/node/issues/31663
  189. .setKeepAlive(__classPrivateFieldGet(this, _RedisSocket_options, "f").keepAlive !== false, __classPrivateFieldGet(this, _RedisSocket_options, "f").keepAlive || 0)
  190. .off('error', reject)
  191. .once('error', (err) => __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_onSocketError).call(this, err))
  192. .once('close', hadError => {
  193. if (!hadError && __classPrivateFieldGet(this, _RedisSocket_isOpen, "f") && __classPrivateFieldGet(this, _RedisSocket_socket, "f") === socket) {
  194. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_onSocketError).call(this, new errors_1.SocketClosedUnexpectedlyError());
  195. }
  196. })
  197. .on('drain', () => {
  198. __classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, false, "f");
  199. this.emit('drain');
  200. })
  201. .on('data', data => this.emit('data', data));
  202. resolve(socket);
  203. });
  204. });
  205. }, _RedisSocket_createNetSocket = function _RedisSocket_createNetSocket() {
  206. return {
  207. connectEvent: 'connect',
  208. socket: net.connect(__classPrivateFieldGet(this, _RedisSocket_options, "f")) // TODO
  209. };
  210. }, _RedisSocket_createTlsSocket = function _RedisSocket_createTlsSocket() {
  211. return {
  212. connectEvent: 'secureConnect',
  213. socket: tls.connect(__classPrivateFieldGet(this, _RedisSocket_options, "f")) // TODO
  214. };
  215. }, _RedisSocket_onSocketError = function _RedisSocket_onSocketError(err) {
  216. const wasReady = __classPrivateFieldGet(this, _RedisSocket_isReady, "f");
  217. __classPrivateFieldSet(this, _RedisSocket_isReady, false, "f");
  218. this.emit('error', err);
  219. if (!wasReady || !__classPrivateFieldGet(this, _RedisSocket_isOpen, "f") || typeof __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_shouldReconnect).call(this, 0, err) !== 'number')
  220. return;
  221. this.emit('reconnecting');
  222. __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_connect).call(this).catch(() => {
  223. // the error was already emitted, silently ignore it
  224. });
  225. }, _RedisSocket_disconnect = function _RedisSocket_disconnect() {
  226. __classPrivateFieldSet(this, _RedisSocket_isReady, false, "f");
  227. if (__classPrivateFieldGet(this, _RedisSocket_socket, "f")) {
  228. __classPrivateFieldGet(this, _RedisSocket_socket, "f").destroy();
  229. __classPrivateFieldSet(this, _RedisSocket_socket, undefined, "f");
  230. }
  231. this.emit('end');
  232. };
  233. exports.default = RedisSocket;