2 * Copyright 2013, 2014 IBM Corp.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 var fs = require('fs');
18 var when = require('when');
19 var nodeFn = require('when/node/function');
20 var keys = require('when/keys');
21 var util = require('util');
22 var fspath = require("path");
23 var mkdirp = require("mkdirp");
25 var promiseDir = nodeFn.lift(mkdirp);
32 var oldCredentialsFile;
36 var globalSettingsFile;
38 function listFiles(dir) {
42 return nodeFn.call(fs.readdir, dir).then(function (contents) {
43 contents.sort().forEach(function(fn) {
44 var stats = fs.lstatSync(dir+"/"+fn);
45 if (stats.isDirectory()) {
47 dirs[fn] = listFiles(dir+"/"+fn)
49 files.push(fn.split(".")[0]);
53 if (dirCount > 0) { result.d = keys.all(dirs); }
54 if (files.length > 0) { result.f = when.resolve(files); }
55 return keys.all(result);
59 function getFileMeta(root,path) {
60 var fn = fspath.join(root,path);
61 var fd = fs.openSync(fn,"r");
62 var size = fs.fstatSync(fd).size;
67 var buffer = Buffer(length);
69 read+=fs.readSync(fd,buffer,0,length);
70 var data = remaining+buffer.toString();
71 var parts = data.split("\n");
72 remaining = parts.splice(-1);
73 for (var i=0;i<parts.length;i+=1) {
74 var match = /^\/\/ (\w+): (.*)/.exec(parts[i]);
76 meta[match[1]] = match[2];
87 function getFileBody(root,path) {
89 var fn = fspath.join(root,path);
90 var fd = fs.openSync(fn,"r");
91 var size = fs.fstatSync(fd).size;
96 var buffer = Buffer(length);
98 var thisRead = fs.readSync(fd,buffer,0,length);
101 var data = remaining+buffer.slice(0,thisRead).toString();
102 var parts = data.split("\n");
103 remaining = parts.splice(-1)[0];
104 for (var i=0;i<parts.length;i+=1) {
105 if (! /^\/\/ \w+: /.test(parts[i])) {
107 body += parts[i]+"\n";
110 if (! /^\/\/ \w+: /.test(remaining)) {
117 body += buffer.slice(0,thisRead).toString();
124 var localfilesystem = {
125 init: function(_settings) {
126 settings = _settings;
127 userDir = settings.userDir || process.env.NODE_RED_HOME;
129 if (settings.flowFile) {
130 flowsFile = settings.flowFile;
131 flowsFullPath = flowsFile;
133 flowsFile = 'flows_'+require('os').hostname()+'.json';
134 flowsFullPath = fspath.join(userDir,flowsFile);
136 var fsext = fspath.extname(flowsFile);
137 credentialsFile = fspath.join(userDir,fspath.basename(flowsFile,fsext)+"_cred"+fsext);
138 oldCredentialsFile = fspath.join(userDir,"credentials.json");
139 flowsPrev = fspath.join(userDir,"flows.backup");
141 libDir = fspath.join(userDir,"lib");
142 libFlowsDir = fspath.join(libDir,"flows");
145 globalSettingsFile = fspath.join(userDir,".config.json");
147 return promiseDir(libFlowsDir);
150 getFlows: function() {
151 var defer = when.defer();
152 fs.exists(flowsFullPath, function(exists) {
154 util.log("[red] Loading flows : "+flowsFile);
155 defer.resolve(nodeFn.call(fs.readFile,flowsFullPath,'utf8').then(function(data) {
156 return JSON.parse(data);
159 util.log("[red] Flows file not found : "+flowsFile );
163 return defer.promise;
166 saveFlows: function(flows) {
167 if (fs.existsSync(flowsFullPath)) {
168 fs.renameSync(flowsFullPath,flowsPrev);
173 if (settings.flowFilePretty) {
174 flowData = JSON.stringify(flows,null,4);
176 flowData = JSON.stringify(flows);
178 console.log("Writing to file:" + flowsFullPath);
179 return nodeFn.call(fs.writeFile, flowsFullPath, flowData);
182 getCredentials: function() {
183 var defer = when.defer();
184 fs.exists(credentialsFile, function(exists) {
186 defer.resolve(nodeFn.call(fs.readFile, credentialsFile, 'utf8').then(function(data) {
187 return JSON.parse(data)
190 fs.exists(oldCredentialsFile, function(exists) {
192 defer.resolve(nodeFn.call(fs.readFile, oldCredentialsFile, 'utf8').then(function(data) {
193 return JSON.parse(data)
201 return defer.promise;
204 saveCredentials: function(credentials) {
206 if (settings.flowFilePretty) {
207 credentialData = JSON.stringify(credentials,null,4);
209 credentialData = JSON.stringify(credentials);
212 return nodeFn.call(fs.writeFile, credentialsFile, credentialData)
215 getSettings: function() {
216 if (fs.existsSync(globalSettingsFile)) {
217 return nodeFn.call(fs.readFile,globalSettingsFile,'utf8').then(function(data) {
220 return JSON.parse(data);
222 util.log("[red] Corrupted config detected - resetting");
230 return when.resolve({});
232 saveSettings: function(settings) {
233 return nodeFn.call(fs.writeFile,globalSettingsFile,JSON.stringify(settings,null,1),'utf8');
237 getAllFlows: function() {
238 return listFiles(libFlowsDir);
241 getFlow: function(fn) {
242 var defer = when.defer();
243 var file = fspath.join(libFlowsDir,fn+".json");
244 fs.exists(file, function(exists) {
246 defer.resolve(nodeFn.call(fs.readFile,file,'utf8'));
251 return defer.promise;
254 saveFlow: function(fn,data) {
255 var file = fspath.join(libFlowsDir,fn+".json");
256 return promiseDir(fspath.dirname(file)).then(function () {
257 return nodeFn.call(fs.writeFile, file, data);
261 getLibraryEntry: function(type,path) {
262 var root = fspath.join(libDir,type);
263 var rootPath = fspath.join(libDir,type,path);
264 return promiseDir(root).then(function () {
265 return nodeFn.call(fs.lstat, rootPath).then(function(stats) {
266 if (stats.isFile()) {
267 return getFileBody(root,path);
269 if (path.substr(-1) == '/') {
270 path = path.substr(0,path.length-1);
272 return nodeFn.call(fs.readdir, rootPath).then(function(fns) {
275 fns.sort().filter(function(fn) {
276 var fullPath = fspath.join(path,fn);
277 var absoluteFullPath = fspath.join(root,fullPath);
279 var stats = fs.lstatSync(absoluteFullPath);
280 if (stats.isDirectory()) {
283 var meta = getFileMeta(root,fullPath);
289 return dirs.concat(files);
295 saveLibraryEntry: function(type,path,meta,body) {
296 var fn = fspath.join(libDir, type, path);
298 for (var i in meta) {
299 if (meta.hasOwnProperty(i)) {
300 headers += "// "+i+": "+meta[i]+"\n";
303 return promiseDir(fspath.dirname(fn)).then(function () {
304 nodeFn.call(fs.writeFile, fn, headers+body);
309 module.exports = localfilesystem;