[CCSDK-28] populated the seed code for dgbuilder
[ccsdk/distribution.git] / dgbuilder / red / storage / localfilesystem.js
1 /**
2  * Copyright 2013, 2014 IBM Corp.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  **/
16
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");
24
25 var promiseDir = nodeFn.lift(mkdirp);
26
27 var settings;
28 var flowsFile;
29 var flowsFullPath;
30 var flowsPrev;
31 var credentialsFile;
32 var oldCredentialsFile;
33 var userDir;
34 var libDir;
35 var libFlowsDir;
36 var globalSettingsFile;
37
38 function listFiles(dir) {
39     var dirs = {};
40     var files = [];
41     var dirCount = 0;
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()) {
46                 dirCount += 1;
47                 dirs[fn] = listFiles(dir+"/"+fn)
48             } else {
49                 files.push(fn.split(".")[0]);
50             }
51         })
52         var result = {};
53         if (dirCount > 0) { result.d = keys.all(dirs); }
54         if (files.length > 0) { result.f = when.resolve(files); }
55         return keys.all(result);
56     })
57 }
58
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;
63     var meta = {};
64     var read = 0;
65     var length = 10;
66     var remaining = "";
67     var buffer = Buffer(length);
68     while(read < size) {
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]);
75             if (match) {
76                 meta[match[1]] = match[2];
77             } else {
78                 read = size;
79                 break;
80             }
81         }
82     }
83     fs.closeSync(fd);
84     return meta;
85 }
86
87 function getFileBody(root,path) {
88     var body = "";
89     var fn = fspath.join(root,path);
90     var fd = fs.openSync(fn,"r");
91     var size = fs.fstatSync(fd).size;
92     var scanning = true;
93     var read = 0;
94     var length = 50;
95     var remaining = "";
96     var buffer = Buffer(length);
97     while(read < size) {
98         var thisRead = fs.readSync(fd,buffer,0,length);
99         read += thisRead;
100         if (scanning) {
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])) {
106                     scanning = false;
107                     body += parts[i]+"\n";
108                 }
109             }
110             if (! /^\/\/ \w+: /.test(remaining)) {
111                 scanning = false;
112             }
113             if (!scanning) {
114                 body += remaining;
115             }
116         } else {
117             body += buffer.slice(0,thisRead).toString();
118         }
119     }
120     fs.closeSync(fd);
121     return body;
122 }
123
124 var localfilesystem = {
125     init: function(_settings) {
126         settings = _settings;
127         userDir = settings.userDir || process.env.NODE_RED_HOME;
128
129         if (settings.flowFile) {
130             flowsFile = settings.flowFile;
131             flowsFullPath = flowsFile;
132         } else {
133             flowsFile = 'flows_'+require('os').hostname()+'.json';
134             flowsFullPath = fspath.join(userDir,flowsFile);
135         }
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");
140
141         libDir = fspath.join(userDir,"lib");
142         libFlowsDir = fspath.join(libDir,"flows");
143
144         
145         globalSettingsFile = fspath.join(userDir,".config.json");
146         
147         return promiseDir(libFlowsDir);
148     },
149
150     getFlows: function() {
151         var defer = when.defer();
152         fs.exists(flowsFullPath, function(exists) {
153             if (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);
157                 }));
158             } else {
159                 util.log("[red] Flows file not found : "+flowsFile   );
160                 defer.resolve([]);
161             }
162         });
163         return defer.promise;
164     },
165
166     saveFlows: function(flows) {
167         if (fs.existsSync(flowsFullPath)) {
168             fs.renameSync(flowsFullPath,flowsPrev);
169         }
170         
171         var flowData;
172         
173         if (settings.flowFilePretty) {
174             flowData = JSON.stringify(flows,null,4);
175         } else {
176             flowData = JSON.stringify(flows);
177         }
178         console.log("Writing to file:" + flowsFullPath); 
179         return nodeFn.call(fs.writeFile, flowsFullPath, flowData);
180     },
181
182     getCredentials: function() {
183         var defer = when.defer();
184         fs.exists(credentialsFile, function(exists) {
185             if (exists) {
186                 defer.resolve(nodeFn.call(fs.readFile, credentialsFile, 'utf8').then(function(data) {
187                     return JSON.parse(data)
188                 }));
189             } else {
190                 fs.exists(oldCredentialsFile, function(exists) {
191                     if (exists) {
192                         defer.resolve(nodeFn.call(fs.readFile, oldCredentialsFile, 'utf8').then(function(data) {
193                             return JSON.parse(data)
194                         }));
195                     } else {
196                         defer.resolve({});
197                     }
198                 });
199             }
200         });
201         return defer.promise;
202     },
203
204     saveCredentials: function(credentials) {
205         var credentialData;
206         if (settings.flowFilePretty) {
207             credentialData = JSON.stringify(credentials,null,4);
208         } else {
209             credentialData = JSON.stringify(credentials);
210         }
211         
212         return nodeFn.call(fs.writeFile, credentialsFile, credentialData)
213     },
214     
215     getSettings: function() {
216         if (fs.existsSync(globalSettingsFile)) {
217             return nodeFn.call(fs.readFile,globalSettingsFile,'utf8').then(function(data) {
218                 if (data) {
219                     try {
220                         return JSON.parse(data);
221                     } catch(err) {
222                         util.log("[red] Corrupted config detected - resetting");
223                         return {};
224                     }
225                 } else {
226                     return {};
227                 }
228             });
229         }
230         return when.resolve({});
231     },
232     saveSettings: function(settings) {
233         return nodeFn.call(fs.writeFile,globalSettingsFile,JSON.stringify(settings,null,1),'utf8');
234     },
235     
236     
237     getAllFlows: function() {
238         return listFiles(libFlowsDir);
239     },
240
241     getFlow: function(fn) {
242         var defer = when.defer();
243         var file = fspath.join(libFlowsDir,fn+".json");
244         fs.exists(file, function(exists) {
245             if (exists) {
246                 defer.resolve(nodeFn.call(fs.readFile,file,'utf8'));
247             } else {
248                 defer.reject();
249             }
250         });
251         return defer.promise;
252     },
253
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);
258         });
259     },
260
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);
268                 }
269                 if (path.substr(-1) == '/') {
270                     path = path.substr(0,path.length-1);
271                 }
272                 return nodeFn.call(fs.readdir, rootPath).then(function(fns) {
273                     var dirs = [];
274                     var files = [];
275                     fns.sort().filter(function(fn) {
276                         var fullPath = fspath.join(path,fn);
277                         var absoluteFullPath = fspath.join(root,fullPath);
278                         if (fn[0] != ".") {
279                             var stats = fs.lstatSync(absoluteFullPath);
280                             if (stats.isDirectory()) {
281                                 dirs.push(fn);
282                             } else {
283                                 var meta = getFileMeta(root,fullPath);
284                                 meta.fn = fn;
285                                 files.push(meta);
286                             }
287                         }
288                     });
289                     return dirs.concat(files);
290                 });
291             });
292         });
293     },
294
295     saveLibraryEntry: function(type,path,meta,body) {
296         var fn = fspath.join(libDir, type, path);
297         var headers = "";
298         for (var i in meta) {
299             if (meta.hasOwnProperty(i)) {
300                 headers += "// "+i+": "+meta[i]+"\n";
301             }
302         }
303         return promiseDir(fspath.dirname(fn)).then(function () {
304             nodeFn.call(fs.writeFile, fn, headers+body);
305         });
306     }
307 };
308
309 module.exports = localfilesystem;