ftp.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. var __importDefault = (this && this.__importDefault) || function (mod) {
  12. return (mod && mod.__esModule) ? mod : { "default": mod };
  13. };
  14. Object.defineProperty(exports, "__esModule", { value: true });
  15. const once_1 = __importDefault(require("@tootallnate/once"));
  16. const ftp_1 = __importDefault(require("ftp"));
  17. const path_1 = require("path");
  18. const debug_1 = __importDefault(require("debug"));
  19. const notfound_1 = __importDefault(require("./notfound"));
  20. const notmodified_1 = __importDefault(require("./notmodified"));
  21. const debug = debug_1.default('get-uri:ftp');
  22. /**
  23. * Returns a Readable stream from an "ftp:" URI.
  24. */
  25. function get(parsed, opts) {
  26. return __awaiter(this, void 0, void 0, function* () {
  27. const { cache } = opts;
  28. const filepath = parsed.pathname;
  29. let lastModified = null;
  30. if (!filepath) {
  31. throw new TypeError('No "pathname"!');
  32. }
  33. const client = new ftp_1.default();
  34. client.once('greeting', (greeting) => {
  35. debug('FTP greeting: %o', greeting);
  36. });
  37. function onend() {
  38. // close the FTP client socket connection
  39. client.end();
  40. }
  41. try {
  42. opts.host = parsed.hostname || parsed.host || 'localhost';
  43. opts.port = parseInt(parsed.port || '0', 10) || 21;
  44. opts.debug = debug;
  45. if (parsed.auth) {
  46. const [user, password] = parsed.auth.split(':');
  47. opts.user = user;
  48. opts.password = password;
  49. }
  50. // await cb(_ => client.connect(opts, _));
  51. const readyPromise = once_1.default(client, 'ready');
  52. client.connect(opts);
  53. yield readyPromise;
  54. // first we have to figure out the Last Modified date.
  55. // try the MDTM command first, which is an optional extension command.
  56. try {
  57. lastModified = yield new Promise((resolve, reject) => {
  58. client.lastMod(filepath, (err, res) => {
  59. return err ? reject(err) : resolve(res);
  60. });
  61. });
  62. }
  63. catch (err) {
  64. // handle the "file not found" error code
  65. if (err.code === 550) {
  66. throw new notfound_1.default();
  67. }
  68. }
  69. if (!lastModified) {
  70. // Try to get the last modified date via the LIST command (uses
  71. // more bandwidth, but is more compatible with older FTP servers
  72. const list = yield new Promise((resolve, reject) => {
  73. client.list(path_1.dirname(filepath), (err, res) => {
  74. return err ? reject(err) : resolve(res);
  75. });
  76. });
  77. // attempt to find the "entry" with a matching "name"
  78. const name = path_1.basename(filepath);
  79. const entry = list.find(e => e.name === name);
  80. if (entry) {
  81. lastModified = entry.date;
  82. }
  83. }
  84. if (lastModified) {
  85. if (isNotModified()) {
  86. throw new notmodified_1.default();
  87. }
  88. }
  89. else {
  90. throw new notfound_1.default();
  91. }
  92. // XXX: a small timeout seemed necessary otherwise FTP servers
  93. // were returning empty sockets for the file occasionally
  94. // setTimeout(client.get.bind(client, filepath, onfile), 10);
  95. const rs = (yield new Promise((resolve, reject) => {
  96. client.get(filepath, (err, res) => {
  97. return err ? reject(err) : resolve(res);
  98. });
  99. }));
  100. rs.once('end', onend);
  101. rs.lastModified = lastModified;
  102. return rs;
  103. }
  104. catch (err) {
  105. client.destroy();
  106. throw err;
  107. }
  108. // called when `lastModified` is set, and a "cache" stream was provided
  109. function isNotModified() {
  110. if (cache && cache.lastModified && lastModified) {
  111. return +cache.lastModified === +lastModified;
  112. }
  113. return false;
  114. }
  115. });
  116. }
  117. exports.default = get;
  118. //# sourceMappingURL=ftp.js.map