base.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. "use strict";
  2. var _interopRequireWildcard = require("@babel/runtime-corejs2/helpers/interopRequireWildcard");
  3. var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
  4. var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
  5. _Object$defineProperty(exports, "__esModule", {
  6. value: true
  7. });
  8. exports["default"] = exports.RETRY_CODE_LIST = exports.FREEZE_CODE_LIST = exports.DEFAULT_CHUNK_SIZE = void 0;
  9. var _iterator = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/symbol/iterator"));
  10. var _symbol = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/symbol"));
  11. var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
  12. var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
  13. var _errors = require("../errors");
  14. var utils = _interopRequireWildcard(require("../utils"));
  15. var __assign = void 0 && (void 0).__assign || function () {
  16. __assign = _assign["default"] || function (t) {
  17. for (var s, i = 1, n = arguments.length; i < n; i++) {
  18. s = arguments[i];
  19. for (var p in s) {
  20. if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
  21. }
  22. }
  23. return t;
  24. };
  25. return __assign.apply(this, arguments);
  26. };
  27. var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
  28. function adopt(value) {
  29. return value instanceof P ? value : new P(function (resolve) {
  30. resolve(value);
  31. });
  32. }
  33. return new (P || (P = _promise["default"]))(function (resolve, reject) {
  34. function fulfilled(value) {
  35. try {
  36. step(generator.next(value));
  37. } catch (e) {
  38. reject(e);
  39. }
  40. }
  41. function rejected(value) {
  42. try {
  43. step(generator["throw"](value));
  44. } catch (e) {
  45. reject(e);
  46. }
  47. }
  48. function step(result) {
  49. result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
  50. }
  51. step((generator = generator.apply(thisArg, _arguments || [])).next());
  52. });
  53. };
  54. var __generator = void 0 && (void 0).__generator || function (thisArg, body) {
  55. var _ = {
  56. label: 0,
  57. sent: function sent() {
  58. if (t[0] & 1) throw t[1];
  59. return t[1];
  60. },
  61. trys: [],
  62. ops: []
  63. },
  64. f,
  65. y,
  66. t,
  67. g;
  68. return g = {
  69. next: verb(0),
  70. "throw": verb(1),
  71. "return": verb(2)
  72. }, typeof _symbol["default"] === "function" && (g[_iterator["default"]] = function () {
  73. return this;
  74. }), g;
  75. function verb(n) {
  76. return function (v) {
  77. return step([n, v]);
  78. };
  79. }
  80. function step(op) {
  81. if (f) throw new TypeError("Generator is already executing.");
  82. while (_) {
  83. try {
  84. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  85. if (y = 0, t) op = [op[0] & 2, t.value];
  86. switch (op[0]) {
  87. case 0:
  88. case 1:
  89. t = op;
  90. break;
  91. case 4:
  92. _.label++;
  93. return {
  94. value: op[1],
  95. done: false
  96. };
  97. case 5:
  98. _.label++;
  99. y = op[1];
  100. op = [0];
  101. continue;
  102. case 7:
  103. op = _.ops.pop();
  104. _.trys.pop();
  105. continue;
  106. default:
  107. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
  108. _ = 0;
  109. continue;
  110. }
  111. if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
  112. _.label = op[1];
  113. break;
  114. }
  115. if (op[0] === 6 && _.label < t[1]) {
  116. _.label = t[1];
  117. t = op;
  118. break;
  119. }
  120. if (t && _.label < t[2]) {
  121. _.label = t[2];
  122. _.ops.push(op);
  123. break;
  124. }
  125. if (t[2]) _.ops.pop();
  126. _.trys.pop();
  127. continue;
  128. }
  129. op = body.call(thisArg, _);
  130. } catch (e) {
  131. op = [6, e];
  132. y = 0;
  133. } finally {
  134. f = t = 0;
  135. }
  136. }
  137. if (op[0] & 5) throw op[1];
  138. return {
  139. value: op[0] ? op[1] : void 0,
  140. done: true
  141. };
  142. }
  143. };
  144. var __read = void 0 && (void 0).__read || function (o, n) {
  145. var m = typeof _symbol["default"] === "function" && o[_iterator["default"]];
  146. if (!m) return o;
  147. var i = m.call(o),
  148. r,
  149. ar = [],
  150. e;
  151. try {
  152. while ((n === void 0 || n-- > 0) && !(r = i.next()).done) {
  153. ar.push(r.value);
  154. }
  155. } catch (error) {
  156. e = {
  157. error: error
  158. };
  159. } finally {
  160. try {
  161. if (r && !r.done && (m = i["return"])) m.call(i);
  162. } finally {
  163. if (e) throw e.error;
  164. }
  165. }
  166. return ar;
  167. };
  168. var __spread = void 0 && (void 0).__spread || function () {
  169. for (var ar = [], i = 0; i < arguments.length; i++) {
  170. ar = ar.concat(__read(arguments[i]));
  171. }
  172. return ar;
  173. };
  174. var DEFAULT_CHUNK_SIZE = 4; // 单位 MB
  175. // code 信息地址 https://developer.qiniu.com/kodo/3928/error-responses
  176. exports.DEFAULT_CHUNK_SIZE = DEFAULT_CHUNK_SIZE;
  177. var FREEZE_CODE_LIST = [0, 502, 503, 504, 599]; // 将会冻结当前 host 的 code
  178. exports.FREEZE_CODE_LIST = FREEZE_CODE_LIST;
  179. var RETRY_CODE_LIST = __spread(FREEZE_CODE_LIST, [612]); // 会进行重试的 code
  180. exports.RETRY_CODE_LIST = RETRY_CODE_LIST;
  181. var GB = Math.pow(1024, 3);
  182. var Base =
  183. /** @class */
  184. function () {
  185. function Base(options, handlers, hostPool, logger) {
  186. this.hostPool = hostPool;
  187. this.logger = logger;
  188. this.aborted = false;
  189. this.retryCount = 0;
  190. this.xhrList = [];
  191. this.config = options.config;
  192. logger.info('config inited.', this.config);
  193. this.putExtra = __assign({
  194. fname: ''
  195. }, options.putExtra);
  196. logger.info('putExtra inited.', this.putExtra);
  197. this.key = options.key;
  198. this.file = options.file;
  199. this.token = options.token;
  200. this.onData = handlers.onData;
  201. this.onError = handlers.onError;
  202. this.onComplete = handlers.onComplete;
  203. try {
  204. var putPolicy = utils.getPutPolicy(this.token);
  205. this.bucketName = putPolicy.bucketName;
  206. this.assessKey = putPolicy.assessKey;
  207. } catch (error) {
  208. logger.error('get putPolicy from token failed.', error);
  209. this.onError(error);
  210. }
  211. } // 检查并更新 upload host
  212. Base.prototype.checkAndUpdateUploadHost = function () {
  213. return __awaiter(this, void 0, void 0, function () {
  214. var newHost;
  215. return __generator(this, function (_a) {
  216. switch (_a.label) {
  217. case 0:
  218. // 从 hostPool 中获取一个可用的 host 挂载在 this
  219. this.logger.info('get available upload host.');
  220. return [4
  221. /*yield*/
  222. , this.hostPool.getUp(this.assessKey, this.bucketName, this.config.upprotocol)];
  223. case 1:
  224. newHost = _a.sent();
  225. if (newHost == null) {
  226. throw new _errors.QiniuError(_errors.QiniuErrorName.NotAvailableUploadHost, 'no available upload host.');
  227. }
  228. if (this.uploadHost != null && this.uploadHost.host !== newHost.host) {
  229. this.logger.warn("host switches from " + this.uploadHost.host + " to " + newHost.host + ".");
  230. } else {
  231. this.logger.info("use host " + newHost.host + ".");
  232. }
  233. this.uploadHost = newHost;
  234. return [2
  235. /*return*/
  236. ];
  237. }
  238. });
  239. });
  240. }; // 检查并解冻当前的 host
  241. Base.prototype.checkAndUnfreezeHost = function () {
  242. this.logger.info('check unfreeze host.');
  243. if (this.uploadHost != null && this.uploadHost.isFrozen()) {
  244. this.logger.warn(this.uploadHost.host + " will be unfrozen.");
  245. this.uploadHost.unfreeze();
  246. }
  247. }; // 检查并更新冻结当前的 host
  248. Base.prototype.checkAndFreezeHost = function (error) {
  249. this.logger.info('check freeze host.');
  250. if (error instanceof _errors.QiniuRequestError && this.uploadHost != null) {
  251. if (FREEZE_CODE_LIST.includes(error.code)) {
  252. this.logger.warn(this.uploadHost.host + " will be temporarily frozen.");
  253. this.uploadHost.freeze();
  254. }
  255. }
  256. };
  257. Base.prototype.handleError = function (error) {
  258. this.logger.error(error.message);
  259. this.onError(error);
  260. };
  261. /**
  262. * @returns Promise 返回结果与上传最终状态无关,状态信息请通过 [Subscriber] 获取。
  263. * @description 上传文件,状态信息请通过 [Subscriber] 获取。
  264. */
  265. Base.prototype.putFile = function () {
  266. return __awaiter(this, void 0, void 0, function () {
  267. var result, err_1, notReachRetryCount, needRetry;
  268. return __generator(this, function (_a) {
  269. switch (_a.label) {
  270. case 0:
  271. this.aborted = false;
  272. if (!this.putExtra.fname) {
  273. this.logger.info('use file.name as fname.');
  274. this.putExtra.fname = this.file.name;
  275. }
  276. if (this.file.size > 10000 * GB) {
  277. this.handleError(new _errors.QiniuError(_errors.QiniuErrorName.InvalidFile, 'file size exceed maximum value 10000G'));
  278. return [2
  279. /*return*/
  280. ];
  281. }
  282. if (this.putExtra.customVars) {
  283. if (!utils.isCustomVarsValid(this.putExtra.customVars)) {
  284. this.handleError(new _errors.QiniuError(_errors.QiniuErrorName.InvalidCustomVars, // FIXME: width => with
  285. 'customVars key should start width x:'));
  286. return [2
  287. /*return*/
  288. ];
  289. }
  290. }
  291. if (this.putExtra.metadata) {
  292. if (!utils.isMetaDataValid(this.putExtra.metadata)) {
  293. this.handleError(new _errors.QiniuError(_errors.QiniuErrorName.InvalidMetadata, 'metadata key should start with x-qn-meta-'));
  294. return [2
  295. /*return*/
  296. ];
  297. }
  298. }
  299. _a.label = 1;
  300. case 1:
  301. _a.trys.push([1, 4,, 5]);
  302. this.uploadAt = new Date().getTime();
  303. return [4
  304. /*yield*/
  305. , this.checkAndUpdateUploadHost()];
  306. case 2:
  307. _a.sent();
  308. return [4
  309. /*yield*/
  310. , this.run()];
  311. case 3:
  312. result = _a.sent();
  313. this.onComplete(result.data);
  314. this.checkAndUnfreezeHost();
  315. this.sendLog(result.reqId, 200);
  316. return [2
  317. /*return*/
  318. ];
  319. case 4:
  320. err_1 = _a.sent();
  321. if (this.aborted) {
  322. this.logger.warn('upload is aborted.');
  323. this.sendLog('', -2);
  324. return [2
  325. /*return*/
  326. ];
  327. }
  328. this.clear();
  329. this.logger.error(err_1);
  330. if (err_1 instanceof _errors.QiniuRequestError) {
  331. this.sendLog(err_1.reqId, err_1.code); // 检查并冻结当前的 host
  332. this.checkAndFreezeHost(err_1);
  333. notReachRetryCount = ++this.retryCount <= this.config.retryCount;
  334. needRetry = RETRY_CODE_LIST.includes(err_1.code); // 以下条件满足其中之一则会进行重新上传:
  335. // 1. 满足 needRetry 的条件且 retryCount 不为 0
  336. // 2. uploadId 无效时在 resume 里会清除本地数据,并且这里触发重新上传
  337. if (needRetry && notReachRetryCount) {
  338. this.logger.warn("error auto retry: " + this.retryCount + "/" + this.config.retryCount + ".");
  339. this.putFile();
  340. return [2
  341. /*return*/
  342. ];
  343. }
  344. }
  345. this.onError(err_1);
  346. return [3
  347. /*break*/
  348. , 5];
  349. case 5:
  350. return [2
  351. /*return*/
  352. ];
  353. }
  354. });
  355. });
  356. };
  357. Base.prototype.clear = function () {
  358. this.xhrList.forEach(function (xhr) {
  359. xhr.onreadystatechange = null;
  360. xhr.abort();
  361. });
  362. this.xhrList = [];
  363. this.logger.info('cleanup uploading xhr.');
  364. };
  365. Base.prototype.stop = function () {
  366. this.logger.info('aborted.');
  367. this.clear();
  368. this.aborted = true;
  369. };
  370. Base.prototype.addXhr = function (xhr) {
  371. this.xhrList.push(xhr);
  372. };
  373. Base.prototype.sendLog = function (reqId, code) {
  374. var _a, _b;
  375. this.logger.report({
  376. code: code,
  377. reqId: reqId,
  378. remoteIp: '',
  379. upType: 'jssdk-h5',
  380. size: this.file.size,
  381. time: Math.floor(this.uploadAt / 1000),
  382. port: utils.getPortFromUrl((_a = this.uploadHost) === null || _a === void 0 ? void 0 : _a.getUrl()),
  383. host: utils.getDomainFromUrl((_b = this.uploadHost) === null || _b === void 0 ? void 0 : _b.getUrl()),
  384. bytesSent: this.progress ? this.progress.total.loaded : 0,
  385. duration: Math.floor((new Date().getTime() - this.uploadAt) / 1000)
  386. });
  387. };
  388. Base.prototype.getProgressInfoItem = function (loaded, size, fromCache) {
  389. return __assign({
  390. size: size,
  391. loaded: loaded,
  392. percent: loaded / size * 100
  393. }, fromCache == null ? {} : {
  394. fromCache: fromCache
  395. });
  396. };
  397. return Base;
  398. }();
  399. var _default = Base;
  400. exports["default"] = _default;