auto-deploy/ftp/ftp-deploy.js

199 lines
6.6 KiB
JavaScript

"use strict";
const upath = require("upath");
const util = require("util");
const events = require("events");
const Promise = require("bluebird");
const fs = require("fs");
var PromiseFtp = require("@dllcnx/promise-ftp");
var PromiseSftp = require("ssh2-sftp-client");
const lib = require("./lib");
/* interim structure
{
'/': ['test-inside-root.txt'],
'folderA': ['test-inside-a.txt'],
'folderA/folderB': ['test-inside-b.txt'],
'folderA/folderB/emptyC': [],
'folderA/folderB/emptyC/folderD': ['test-inside-d-1.txt', 'test-inside-d-2.txt']
}
*/
const FtpDeployer = function () {
// The constructor for the super class.
events.EventEmitter.call(this);
this.ftp = null;
this.eventObject = {
totalFilesCount: 0,
transferredFileCount: 0,
filename: "",
};
this.makeAllAndUpload = function (remoteDir, filemap) {
let keys = Object.keys(filemap);
return Promise.mapSeries(keys, (key) => {
// console.log("Processing", key, filemap[key]);
return this.makeAndUpload(remoteDir, key, filemap[key]);
});
};
this.makeDir = function (newDirectory) {
if (newDirectory === "/") {
return Promise.resolve("unused");
} else {
return this.ftp.mkdir(newDirectory, true);
}
};
// Creates a remote directory and uploads all of the files in it
// Resolves a confirmation message on success
this.makeAndUpload = (config, relDir, fnames) => {
let newDirectory = upath.join(config.remoteRoot, relDir);
return this.makeDir(newDirectory, true).then(() => {
// console.log("newDirectory", newDirectory);
return Promise.mapSeries(fnames, (fname) => {
let tmpFileName = upath.join(config.localRoot, relDir, fname);
let tmp = fs.readFileSync(tmpFileName);
this.eventObject["filename"] = upath.join(relDir, fname);
this.emit("uploading", this.eventObject);
return this.ftp
.put(tmp, upath.join(config.remoteRoot, relDir, fname))
.then(() => {
this.eventObject.transferredFileCount++;
this.emit("uploaded", this.eventObject);
return Promise.resolve("uploaded " + tmpFileName);
})
.catch((err) => {
this.eventObject["error"] = err;
this.emit("upload-error", this.eventObject);
// if continue on error....
return Promise.reject(err);
});
});
});
};
// connects to the server, Resolves the config on success
this.connect = (config) => {
this.ftp = config.sftp ? new PromiseSftp() : new PromiseFtp();
// sftp client does not provide a connection status
// so instead provide one ourselfs
if (config.sftp) {
this.connectionStatus = "disconnected";
this.ftp.on("end", this.handleDisconnect);
this.ftp.on("close", this.handleDisconnect);
}
return this.ftp
.connect(config)
.then((serverMessage) => {
this.emit("log", "Connected to: " + config.host);
this.emit("log", "Connected: Server message: " + serverMessage);
// sftp does not provide a connection status
// so instead provide one ourself
if (config.sftp) {
this.connectionStatus = "connected";
}
return config;
})
.catch((err) => {
return Promise.reject({
code: err.code,
message: "connect: " + err.message,
});
});
};
this.getConnectionStatus = () => {
// only ftp client provides connection status
// sftp client connection status is handled using events
return typeof this.ftp.getConnectionStatus === "function"
? this.ftp.getConnectionStatus()
: this.connectionStatus;
};
this.handleDisconnect = () => {
this.connectionStatus = "disconnected";
};
// creates list of all files to upload and starts upload process
this.checkLocalAndUpload = (config) => {
try {
let filemap = lib.parseLocal(
config.include,
config.exclude,
config.localRoot,
"/"
);
// console.log(filemap);
this.emit(
"log",
"Files found to upload: " + JSON.stringify(filemap)
);
this.eventObject["totalFilesCount"] = lib.countFiles(filemap);
return this.makeAllAndUpload(config, filemap);
} catch (e) {
return Promise.reject(e);
}
};
// Deletes remote directory if requested by config
// Returns config
this.deleteRemote = (config) => {
if (config.deleteRemote) {
return lib
.deleteDir(this.ftp, config.remoteRoot)
.then(() => {
this.emit("log", "Deleted directory: " + config.remoteRoot);
return config;
})
.catch((err) => {
this.emit(
"log",
"Deleting failed, trying to continue: " +
JSON.stringify(err)
);
return Promise.resolve(config);
});
}
return Promise.resolve(config);
};
this.deploy = function (config, cb) {
return lib
.checkIncludes(config)
.then(lib.getPassword)
.then(this.connect)
.then(this.deleteRemote)
.then(this.checkLocalAndUpload)
.then((res) => {
this.ftp.end();
if (typeof cb == "function") {
cb(null, res);
} else {
return Promise.resolve(res);
}
})
.catch((err) => {
console.log("Err", err.message);
if (this.ftp && this.getConnectionStatus() != "disconnected")
this.ftp.end();
if (typeof cb == "function") {
cb(err, null);
} else {
return Promise.reject(err);
}
});
};
};
util.inherits(FtpDeployer, events.EventEmitter);
module.exports = FtpDeployer;