| /** |
| * Copyright 2013, 2014 IBM Corp. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| **/ |
| |
| var fs = require('fs'); |
| var when = require('when'); |
| var nodeFn = require('when/node/function'); |
| var keys = require('when/keys'); |
| var util = require('util'); |
| var fspath = require("path"); |
| var mkdirp = require("mkdirp"); |
| |
| var promiseDir = nodeFn.lift(mkdirp); |
| |
| var settings; |
| var flowsFile; |
| var flowsFullPath; |
| var flowsPrev; |
| var credentialsFile; |
| var oldCredentialsFile; |
| var userDir; |
| var libDir; |
| var libFlowsDir; |
| var globalSettingsFile; |
| |
| function listFiles(dir) { |
| var dirs = {}; |
| var files = []; |
| var dirCount = 0; |
| return nodeFn.call(fs.readdir, dir).then(function (contents) { |
| contents.sort().forEach(function(fn) { |
| var stats = fs.lstatSync(dir+"/"+fn); |
| if (stats.isDirectory()) { |
| dirCount += 1; |
| dirs[fn] = listFiles(dir+"/"+fn) |
| } else { |
| files.push(fn.split(".")[0]); |
| } |
| }) |
| var result = {}; |
| if (dirCount > 0) { result.d = keys.all(dirs); } |
| if (files.length > 0) { result.f = when.resolve(files); } |
| return keys.all(result); |
| }) |
| } |
| |
| function getFileMeta(root,path) { |
| var fn = fspath.join(root,path); |
| var fd = fs.openSync(fn,"r"); |
| var size = fs.fstatSync(fd).size; |
| var meta = {}; |
| var read = 0; |
| var length = 10; |
| var remaining = ""; |
| var buffer = Buffer(length); |
| while(read < size) { |
| read+=fs.readSync(fd,buffer,0,length); |
| var data = remaining+buffer.toString(); |
| var parts = data.split("\n"); |
| remaining = parts.splice(-1); |
| for (var i=0;i<parts.length;i+=1) { |
| var match = /^\/\/ (\w+): (.*)/.exec(parts[i]); |
| if (match) { |
| meta[match[1]] = match[2]; |
| } else { |
| read = size; |
| break; |
| } |
| } |
| } |
| fs.closeSync(fd); |
| return meta; |
| } |
| |
| function getFileBody(root,path) { |
| var body = ""; |
| var fn = fspath.join(root,path); |
| var fd = fs.openSync(fn,"r"); |
| var size = fs.fstatSync(fd).size; |
| var scanning = true; |
| var read = 0; |
| var length = 50; |
| var remaining = ""; |
| var buffer = Buffer(length); |
| while(read < size) { |
| var thisRead = fs.readSync(fd,buffer,0,length); |
| read += thisRead; |
| if (scanning) { |
| var data = remaining+buffer.slice(0,thisRead).toString(); |
| var parts = data.split("\n"); |
| remaining = parts.splice(-1)[0]; |
| for (var i=0;i<parts.length;i+=1) { |
| if (! /^\/\/ \w+: /.test(parts[i])) { |
| scanning = false; |
| body += parts[i]+"\n"; |
| } |
| } |
| if (! /^\/\/ \w+: /.test(remaining)) { |
| scanning = false; |
| } |
| if (!scanning) { |
| body += remaining; |
| } |
| } else { |
| body += buffer.slice(0,thisRead).toString(); |
| } |
| } |
| fs.closeSync(fd); |
| return body; |
| } |
| |
| var localfilesystem = { |
| init: function(_settings) { |
| settings = _settings; |
| userDir = settings.userDir || process.env.NODE_RED_HOME; |
| |
| if (settings.flowFile) { |
| flowsFile = settings.flowFile; |
| flowsFullPath = flowsFile; |
| } else { |
| flowsFile = 'flows_'+require('os').hostname()+'.json'; |
| flowsFullPath = fspath.join(userDir,flowsFile); |
| } |
| var fsext = fspath.extname(flowsFile); |
| credentialsFile = fspath.join(userDir,fspath.basename(flowsFile,fsext)+"_cred"+fsext); |
| oldCredentialsFile = fspath.join(userDir,"credentials.json"); |
| flowsPrev = fspath.join(userDir,"flows.backup"); |
| |
| libDir = fspath.join(userDir,"lib"); |
| libFlowsDir = fspath.join(libDir,"flows"); |
| |
| |
| globalSettingsFile = fspath.join(userDir,".config.json"); |
| |
| return promiseDir(libFlowsDir); |
| }, |
| |
| getFlows: function() { |
| var defer = when.defer(); |
| fs.exists(flowsFullPath, function(exists) { |
| if (exists) { |
| util.log("[red] Loading flows : "+flowsFile); |
| defer.resolve(nodeFn.call(fs.readFile,flowsFullPath,'utf8').then(function(data) { |
| return JSON.parse(data); |
| })); |
| } else { |
| util.log("[red] Flows file not found : "+flowsFile ); |
| defer.resolve([]); |
| } |
| }); |
| return defer.promise; |
| }, |
| |
| saveFlows: function(flows) { |
| if (fs.existsSync(flowsFullPath)) { |
| fs.renameSync(flowsFullPath,flowsPrev); |
| } |
| |
| var flowData; |
| |
| if (settings.flowFilePretty) { |
| flowData = JSON.stringify(flows,null,4); |
| } else { |
| flowData = JSON.stringify(flows); |
| } |
| console.log("Writing to file:" + flowsFullPath); |
| return nodeFn.call(fs.writeFile, flowsFullPath, flowData); |
| }, |
| |
| getCredentials: function() { |
| var defer = when.defer(); |
| fs.exists(credentialsFile, function(exists) { |
| if (exists) { |
| defer.resolve(nodeFn.call(fs.readFile, credentialsFile, 'utf8').then(function(data) { |
| return JSON.parse(data) |
| })); |
| } else { |
| fs.exists(oldCredentialsFile, function(exists) { |
| if (exists) { |
| defer.resolve(nodeFn.call(fs.readFile, oldCredentialsFile, 'utf8').then(function(data) { |
| return JSON.parse(data) |
| })); |
| } else { |
| defer.resolve({}); |
| } |
| }); |
| } |
| }); |
| return defer.promise; |
| }, |
| |
| saveCredentials: function(credentials) { |
| var credentialData; |
| if (settings.flowFilePretty) { |
| credentialData = JSON.stringify(credentials,null,4); |
| } else { |
| credentialData = JSON.stringify(credentials); |
| } |
| |
| return nodeFn.call(fs.writeFile, credentialsFile, credentialData) |
| }, |
| |
| getSettings: function() { |
| if (fs.existsSync(globalSettingsFile)) { |
| return nodeFn.call(fs.readFile,globalSettingsFile,'utf8').then(function(data) { |
| if (data) { |
| try { |
| return JSON.parse(data); |
| } catch(err) { |
| util.log("[red] Corrupted config detected - resetting"); |
| return {}; |
| } |
| } else { |
| return {}; |
| } |
| }); |
| } |
| return when.resolve({}); |
| }, |
| saveSettings: function(settings) { |
| return nodeFn.call(fs.writeFile,globalSettingsFile,JSON.stringify(settings,null,1),'utf8'); |
| }, |
| |
| |
| getAllFlows: function() { |
| return listFiles(libFlowsDir); |
| }, |
| |
| getFlow: function(fn) { |
| var defer = when.defer(); |
| var file = fspath.join(libFlowsDir,fn+".json"); |
| fs.exists(file, function(exists) { |
| if (exists) { |
| defer.resolve(nodeFn.call(fs.readFile,file,'utf8')); |
| } else { |
| defer.reject(); |
| } |
| }); |
| return defer.promise; |
| }, |
| |
| saveFlow: function(fn,data) { |
| var file = fspath.join(libFlowsDir,fn+".json"); |
| return promiseDir(fspath.dirname(file)).then(function () { |
| return nodeFn.call(fs.writeFile, file, data); |
| }); |
| }, |
| |
| getLibraryEntry: function(type,path) { |
| var root = fspath.join(libDir,type); |
| var rootPath = fspath.join(libDir,type,path); |
| return promiseDir(root).then(function () { |
| return nodeFn.call(fs.lstat, rootPath).then(function(stats) { |
| if (stats.isFile()) { |
| return getFileBody(root,path); |
| } |
| if (path.substr(-1) == '/') { |
| path = path.substr(0,path.length-1); |
| } |
| return nodeFn.call(fs.readdir, rootPath).then(function(fns) { |
| var dirs = []; |
| var files = []; |
| fns.sort().filter(function(fn) { |
| var fullPath = fspath.join(path,fn); |
| var absoluteFullPath = fspath.join(root,fullPath); |
| if (fn[0] != ".") { |
| var stats = fs.lstatSync(absoluteFullPath); |
| if (stats.isDirectory()) { |
| dirs.push(fn); |
| } else { |
| var meta = getFileMeta(root,fullPath); |
| meta.fn = fn; |
| files.push(meta); |
| } |
| } |
| }); |
| return dirs.concat(files); |
| }); |
| }); |
| }); |
| }, |
| |
| saveLibraryEntry: function(type,path,meta,body) { |
| var fn = fspath.join(libDir, type, path); |
| var headers = ""; |
| for (var i in meta) { |
| if (meta.hasOwnProperty(i)) { |
| headers += "// "+i+": "+meta[i]+"\n"; |
| } |
| } |
| return promiseDir(fspath.dirname(fn)).then(function () { |
| nodeFn.call(fs.writeFile, fn, headers+body); |
| }); |
| } |
| }; |
| |
| module.exports = localfilesystem; |