internal.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // internal
  2. // DO NOT use this file, unless you know what you're doing.
  3. // Because its API may make broken change for internal usage.
  4. const { RetryPolicy } = require('../retry');
  5. // --- split to files --- //
  6. /**
  7. * @typedef {RetryPolicyContext} TokenExpiredRetryPolicyContext
  8. * @property {string} resumeRecordFilePath
  9. * @property {'v1' | 'v2' | string} uploadApiVersion
  10. */
  11. /**
  12. * @class
  13. * @extends RetryPolicy
  14. * @param {Object} options
  15. * @param {string} options.uploadApiVersion
  16. * @param {function} options.recordDeleteHandler
  17. * @param {function} options.recordExistsHandler
  18. * @param {number} [options.maxRetryTimes]
  19. * @constructor
  20. */
  21. function TokenExpiredRetryPolicy (options) {
  22. this.id = Symbol(this.constructor.name);
  23. this.uploadApiVersion = options.uploadApiVersion;
  24. this.recordDeleteHandler = options.recordDeleteHandler;
  25. this.recordExistsHandler = options.recordExistsHandler;
  26. this.maxRetryTimes = options.maxRetryTimes || 1;
  27. }
  28. TokenExpiredRetryPolicy.prototype = Object.create(RetryPolicy.prototype);
  29. TokenExpiredRetryPolicy.prototype.constructor = TokenExpiredRetryPolicy;
  30. /**
  31. * @param {Object} context
  32. * @returns {Promise<void>}
  33. */
  34. TokenExpiredRetryPolicy.prototype.initContext = function (context) {
  35. context[this.id] = {
  36. retriedTimes: 0,
  37. uploadApiVersion: this.uploadApiVersion
  38. };
  39. return Promise.resolve();
  40. };
  41. /**
  42. * @param {Object} context
  43. * @returns {boolean}
  44. */
  45. TokenExpiredRetryPolicy.prototype.shouldRetry = function (context) {
  46. const {
  47. retriedTimes,
  48. uploadApiVersion
  49. } = context[this.id];
  50. if (
  51. retriedTimes >= this.maxRetryTimes ||
  52. !this.recordExistsHandler()
  53. ) {
  54. return false;
  55. }
  56. if (!context.result) {
  57. return false;
  58. }
  59. if (uploadApiVersion === 'v1' &&
  60. context.result.resp.statusCode === 701
  61. ) {
  62. return true;
  63. }
  64. if (uploadApiVersion === 'v2' &&
  65. context.result.resp.statusCode === 612
  66. ) {
  67. return true;
  68. }
  69. return false;
  70. };
  71. /**
  72. * @param {Object} context
  73. * @returns {Promise<void>}
  74. */
  75. TokenExpiredRetryPolicy.prototype.prepareRetry = function (context) {
  76. context[this.id].retriedTimes += 1;
  77. return new Promise(resolve => {
  78. if (!this.recordExistsHandler()) {
  79. resolve();
  80. return;
  81. }
  82. this.recordDeleteHandler();
  83. resolve();
  84. });
  85. };
  86. exports.TokenExpiredRetryPolicy = TokenExpiredRetryPolicy;
  87. /**
  88. * @class
  89. * @extends RetryPolicy
  90. * @constructor
  91. */
  92. function AccUnavailableRetryPolicy () {
  93. }
  94. AccUnavailableRetryPolicy.prototype = Object.create(RetryPolicy.prototype);
  95. AccUnavailableRetryPolicy.prototype.constructor = AccUnavailableRetryPolicy;
  96. AccUnavailableRetryPolicy.prototype.initContext = function (context) {
  97. return Promise.resolve();
  98. };
  99. AccUnavailableRetryPolicy.prototype.isAccNotAvailable = function (context) {
  100. try {
  101. return context.result.resp.statusCode === 400 &&
  102. context.result.resp.data.error.includes('transfer acceleration is not configured on this bucket');
  103. } catch (_err) {
  104. return false;
  105. }
  106. };
  107. AccUnavailableRetryPolicy.prototype.shouldRetry = function (context) {
  108. if (!context.result) {
  109. return false;
  110. }
  111. if (!context.alternativeServiceNames.length) {
  112. return false;
  113. }
  114. const [nextServiceName] = context.alternativeServiceNames;
  115. if (
  116. !context.region.services[nextServiceName] ||
  117. !context.region.services[nextServiceName].length
  118. ) {
  119. return false;
  120. }
  121. return this.isAccNotAvailable(context);
  122. };
  123. AccUnavailableRetryPolicy.prototype.prepareRetry = function (context) {
  124. if (!context.alternativeServiceNames.length) {
  125. return Promise.reject(new Error(
  126. 'No alternative service available.'
  127. ));
  128. }
  129. context.serviceName = context.alternativeServiceNames.shift();
  130. [context.endpoint, ...context.alternativeEndpoints] = context.region.services[context.serviceName];
  131. if (!context.endpoint) {
  132. return Promise.reject(new Error(
  133. 'No alternative endpoint available.'
  134. ));
  135. }
  136. return Promise.resolve();
  137. };
  138. exports.AccUnavailableRetryPolicy = AccUnavailableRetryPolicy;
  139. /**
  140. * @param {Error} err
  141. * @param {string} msg
  142. */
  143. function getNoNeedRetryError (err, msg) {
  144. err.message = msg + '\n' + err.message;
  145. err.noNeedRetry = true;
  146. return err;
  147. }
  148. exports.getNoNeedRetryError = getNoNeedRetryError;
  149. /**
  150. * @param fn
  151. * @returns {(function(...[*]): (*|undefined))|*}
  152. */
  153. function wrapTryCallback (fn) {
  154. if (typeof fn !== 'function') {
  155. return () => {};
  156. }
  157. return (...args) => {
  158. try {
  159. return fn(...args);
  160. } catch (err) {
  161. console.warn(
  162. 'WARNING:\n' +
  163. 'qiniu SDK will migrate API to Promise style gradually.\n' +
  164. 'The callback style will not be removed for now,\n' +
  165. 'but you should catch your error in your callback function itself'
  166. );
  167. console.error(err);
  168. }
  169. };
  170. }
  171. /**
  172. * Compatible with callback style
  173. * Could be removed when make break changes.
  174. */
  175. function handleReqCallback (responseWrapperPromise, callbackFunc) {
  176. if (typeof callbackFunc !== 'function') {
  177. return;
  178. }
  179. const wrappedCallback = wrapTryCallback(callbackFunc);
  180. responseWrapperPromise
  181. .then(({ data, resp }) => {
  182. wrappedCallback(null, data, resp);
  183. })
  184. .catch(err => {
  185. wrappedCallback(err, null, err.resp);
  186. });
  187. }
  188. exports.handleReqCallback = handleReqCallback;