UNPKG

prisme-flow

Version:

prisme platform flow engine

213 lines (187 loc) 6.11 kB
/** * Created by prisme.io on 09/06/2017. */ // Node for Node-Red that lists all files from a given start folder // with an optionally specified file extension. //var fs = require('fs') var path = require('path') var readdirp = require('readdirp') // Module name must match this nodes html file var moduleName = 'fs-file-lister' module.exports = function(RED) { 'use strict' // The main node definition - most things happen in here function nodeGo(config) { // Create a RED node RED.nodes.createNode(this, config) // copy "this" object in case we need it in context of callbacks of other functions. var node = this // Store local copies of the node configuration (as defined in the .html) node.topic = config.topic node.name = config.name node.start = config.start node.pattern = config.pattern node.path = config.path node.single = config.single node.depth = config.depth node.stat = config.stat // Make sure the parameters are strings if ( (typeof node.start !== 'string') || (typeof node.pattern !== 'string') ) { node.error('Either Folder or Ext is not a string, cannot process. Folder: ' + node.start + ', Pattern: ' + node.ext) return } // respond to inputs.... node.on('input', function(msg) { // Keep the original topic and payload msg.topic = msg.topic msg.origPayload = msg.payload // Output the nodes config msg.config = { 'start': node.start, 'pattern': node.pattern, 'path': node.path, 'single': node.single, 'depth': node.depth, 'stat': node.stat } // override config if passed suitable payload if ( (typeof msg.payload === 'object') && ('start' in msg.payload) ) { if ( validFolderName(msg.payload.start) ) { node.start = msg.payload.start } } if ( (typeof msg.payload === 'object') && ('pattern' in msg.payload) ) { if ( (typeof msg.payload.pattern === 'string') && (msg.payload.pattern.length < 1024) ) { node.pattern = msg.payload.pattern } } // Keep count of files found var totalFiles = 0 var options = {} options.root = path.join(node.start), options.fileFilter = node.pattern options.entryType = 'files' if ( node.depth > -1 ) { options.depth = Number(node.depth) } var arrayOut = [] // Recursively read the folder using the stream API readdirp(options) // Called if a found entry cannot be accessed (e.g. permissions) .on('warn', function (err) { node.warn('File could not be accessed', err) }) // Fatal error .on('error', function (err) { node.error('Error processing folder listing', err) }) // called for each entry found .on('data', function (entry) { var file = entry.name // Do we want just the file name output or the full path? if ( node.path ) { file = entry.fullPath } // Do we want to include file stats? if ( node.stat ) { file = {name: file} file.stat = { size: entry.stat.size, created: entry.stat.ctime, changed: entry.stat.mtime, accessed: entry.stat.atime, uid: entry.stat.uid, gid: entry.stat.gid, mode: '0x' + entry.stat.mode.toString(16) } } // If only single output if ( node.single ) { // accumulate the output array (send later on end) arrayOut.push(file) } else { // or send each file as separate msg node.status({fill:'green',shape:'dot',text:'# files ' + ++totalFiles}) msg.payload = file //msg.debug = entry node.send( msg ) } }) // called when all entries have been output .on('end', function () { // Send a single msg if arrayOut contains anything if ( arrayOut.length > 0 ) { node.status({fill:'blue',shape:'dot',text:'# files ' + arrayOut.length}) msg.payload = arrayOut node.send(msg) } }) /* // Async read the folder fs.readdir(node.start, function (err, files) { if (err) { node.error('Oops! Folder does not exist: ' + node.start, err) return } totalFiles = files.length node.status({fill:'blue',shape:'dot',text:filteredFiles + '/' + totalFiles}) var arrayOut = [] // Any error in here will crash Node-Red!! So catch them instead try { files // calls the given callback func for each file, will only pass names where fn returns true .filter( function (file) { var len = node.ext.length if (len === 0) return true // Returns TRUE only if the file name ends in the given extension return file.substr(0-len) === node.ext }) .forEach( function (file) { if ( node.path ) { file = path.join(node.start, file) } // If only single output if ( node.single ) { // accumulate the output array (send later) arrayOut.push(file) } else { // or send each file as separate msg msg.payload = file node.send( msg ) } }) } catch (err) { node.error('Ouch! Something went badly wrong processing the files list', err) return } // Send a single msg if arrayOut contains anything if ( arrayOut.length > 0 ) { msg.payload = arrayOut node.send(msg) } }) // --- End of readdir callback --- // */ }) // --- End of node input fn --- // // Tidy up if we need to //node.on("close", function() { // Called when the node is shutdown - eg on redeploy. // Allows ports to be closed, connections dropped etc. // eg: node.client.disconnect(); //}); } // --- End of fnFileLister --- // // Check if a folder name is safe function validFolderName(folder) { var isValid = true if ( typeof folder !== 'string' ) { isValid = false } else { if ( folder.length > 1023 ) { isValid = false } } return isValid } // --- End of validFolderName function --- // // Register the node by name. This must be called before overriding any of the // Node functions. RED.nodes.registerType(moduleName, nodeGo) } // ---- End of Mobule ---- //