UNPKG

antfarm

Version:

File automation framework for ants.

261 lines (232 loc) 8.06 kB
import {Environment} from "../environment/environment"; import { Nest } from "./nest"; import { FileJob } from "./../job/fileJob"; import { FolderJob } from "./../job/folderJob"; import {Job} from "../job/job"; const node_watch = require("node-watch"), fs = require("fs"), path_mod = require("path"), tmp = require("tmp"), mkdirp = require("mkdirp"), _ = require("lodash"); /** * A folder nest is a nest which contains a backing folder at a specific _path. If the folder does not exist, * antfarm can optionally create it. */ export class FolderNest extends Nest { protected path: string; protected allowCreate: boolean; protected heldJobs: (FileJob|FolderJob)[]; constructor(e: Environment, path?: string, allowCreate?: boolean) { let nest_name = path_mod.basename(path); super(e, nest_name); this.allowCreate = allowCreate; this.checkDirectorySync(path); this.path = path; this.heldJobs = []; } /** * Check if the _path for the backing folder is created. If not, optionally create it. * @param directory */ protected checkDirectorySync(directory) { let fn = this; try { fs.statSync(directory); } catch (e) { if (fn.allowCreate) { mkdirp.sync(directory); fn.e.log(1, `Directory "${directory}" was created since it did not already exist.`, this); } else { fn.e.log(3, `Directory "${directory}" did not exist and was not created.`, this); } } } /** * Function that creates and arrives new jobs. Can produce file or folder jobs. * @param path * @param arrive * @returns {FolderJob|FileJob} */ protected createJob(path: string, arrive = true) { let fl = this; let job; // Verify file still exists, node-watch fires on any change, even delete try { fs.accessSync(path, fs.F_OK); // Check job is folder let path_stats = fs.lstatSync(path); if (path_stats.isDirectory()) { job = new FolderJob(fl.e, path); job.createFiles(function(){ if (arrive) { // Trigger arrived fl.arrive(job); } }); } else if (path_stats.isFile()) { job = new FileJob(fl.e, path); if (arrive) { // Trigger arrived fl.arrive(job); } } else { throw "Path is not a file or folder!"; } } catch (e) { // It isn't accessible fl.e.log(0, "Job creation ignored because file did not exist.", fl); } return job; } /** * Checks whether a _path starts with or contains a hidden file or a folder. * @param path {string} The _path of the file that needs to be validated. * returns {boolean} - `true` if the source is blacklisted and otherwise `false`. */ protected isUnixHiddenPath (path: string) { return (/(^|\/)\.[^\/\.]/g).test(path); }; /** * Initial load of the contents of the directory. * @param hold {boolean} Optional flag to hold jobs found. */ public load(hold: boolean = false): void { let fl = this; fs.readdir(fl.path, (err, items) => { if (items) { items = items.filter(item => !(/(^|\/)\.[^\/\.]/g).test(item)); items.forEach((filename) => { let filepath = fl.path + path_mod.sep + filename; let job; if (hold === false) { fl.createJob(filepath, true); // Arrives as well } else { job = fl.createJob(filepath, false); fl.holdJob(job); } }); } }); } /** * Watches the folder. * @param hold {boolean} Optional flag to hold jobs found. */ public watch(hold: boolean = false): void { let fl = this; let watch_options = { recursive: false }; node_watch(fl.path, watch_options, function (filepath) { if (!fl.isUnixHiddenPath(filepath)) { let job; if (hold === false) { job = fl.createJob(filepath, true); // Arrives as well } else { job = fl.createJob(filepath, false); fl.holdJob(job); } } else { fl.e.log(2, `Hidden file "${filepath}" ignored.`, fl); } }); } /** * Watches and holds jobs found. */ public watchHold(): void { let fl = this; fl.load(true); fl.watch(true); } /** * Arrive function that calls the super. * @param job */ public arrive(job: FileJob) { super.arrive(job); } /** * Picks up a job from another nest. * @param job * @param callback Callback is given the job in its parameter. */ public take(job: FileJob, callback: any) { // the other nest that this is taking from should provide a temporary location or local _path of the job let new_path = `${this.path}/${job.basename}`; fs.renameSync(job.path, new_path); job.path = new_path; callback(job); } /** * Loads jobs that have piled up in the nest if it was not watched. * No longer used. * @returns {Array} Array of jobs */ public getUnwatchedJobs() { let fl = this; let jobs = []; let fileArray = fs.readdirSync(fl.path); let items = fileArray.filter(item => !(/(^|\/)\.[^\/\.]/g).test(item)); items.forEach((filename) => { let filepath = fl.path + path_mod.sep + filename; let job = fl.createJob(filepath, false); jobs.push(job); // fl.holdJob(job); }); return jobs; } /** * Returns all held jobs. * @returns {(FileJob|FolderJob)[]} */ public getHeldJobs() { return this.heldJobs; } /** * Adds job to array of held jobs. * @param job */ protected holdJob(job: (FileJob|FolderJob)) { this.heldJobs.push(job); } /** * Get a held job with a job id. Removes it from the held job queue, * so you should move it out of the folder after using this. * @param jobId * @returns {FileJob|FolderJob} * #### Example * ```js * var tunnel = af.createTunnel("Checkpoint example"); * var webhook = af.createWebhookNest(["test", "example"], "get"); * var holding_folder = af.createAutoFolderNest(["test", "checkpoint"]); * * var im = webhook.getInterfaceManager(); * * // Watch for jobs, hold, and provide to the interface. * im.checkNest(holding_folder); * tunnel.watch(webhook); * * tunnel.run(function(job, nest){ * // Get the job_id from the webhook request * var job_id = job.getParameter("job_id"); * // Get the held job from the holding folder * var checkpoint_job = holding_folder.getHeldJob(job_id); * // Move somewhere else * checkpoint_job.move(af.createAutoFolderNest(["test", "outfolder"])); * }); * ``` */ public getHeldJob(jobId: string) { let f = this; let job = _.find(f.getHeldJobs(), (j) => j.getId() === jobId ); let jobIndex = _.findIndex(f.getHeldJobs(), (j) => j.getId() === jobId ); if (!job) { f.e.log(3, `Job ID ${jobId} could not be found in the ${f.getHeldJobs().length} pending held jobs.`, f); } else { f.heldJobs.splice(jobIndex, 1); } return job; } }