node-red-contrib-xstorage
Version:
A Node-RED storageModule for load flows from xStorage and save flows at xStorage.
413 lines (361 loc) • 11.4 kB
JavaScript
var when = require('when');
var nodeFn = require('when/node/function');
var keys = require('when/keys');
var fs = require('fs-extra');
var fspath = require("path");
var mkdirp = fs.mkdirs;
var crypto = require('crypto');
var mc = require('./lib/mcClient.js');
var caller = {
SetConfig: mc.set,
GetConfig: mc.get,
call: mc.call,
reged: mc.reged
}
var initialFlowLoadComplete = false;
var settings;
var runtime;
var flowsFile;
var projectFile;
var flowsFullPath;
var flowsFileBackup;
var credentialsFile;
var credentialsFileBackup;
var oldCredentialsFile;
var sessionsFile;
var libDir;
var libFlowsDir;
var globalSettingsFile;
var qName;
var qCode;
var eiName;
var promiseDir = nodeFn.lift(mkdirp);
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function loadObjMMS(){
return when.promise(async function(resolve, reject){
let payload = {
type: "flow"
};
if(qCode)
payload.qcode = qCode;
else if(qName)
payload.qname = qName;
else
reject('QCODE or QNAME is required.');
while(1){
if(caller.reged() != ""){
break;
}
await new Promise(resolve => setTimeout(resolve, 500));
}
caller.call('', process.env.OBJMMS_DDN || '>svc/objstore', 'obj://get', payload).then(reply => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if(!result.Reply){
reject(result.IN.State.ErrMsg);
}else{
result = result.Reply;
}
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
result = result.Data;
if(result && result.data.flow)
resolve(result.data.flow);
else{
reject(`Flow not found: QNAME = ${qName} QCODE = ${qCode}`);
}
}
} else {
reject("Call objmms not response")
}
}).catch(err => {
console.log(err);
reject(err.message);
});
})
}
function objLoad(type, path) {
if (!initialFlowLoadComplete) {
initialFlowLoadComplete = true;
}
return when.promise(async function(resolve, reject) {
if(type == 'flows'){
loadObjMMS().then((reply)=>{
if(reply && reply.length > 0){
console.log("Flow loaded from obj-mms: QNAME = %s QCODE = %s", qName, qCode);
objSave('flows', '/', reply).then((result)=>{
console.log("Flow stored at xstorage: QNAME = %s QCODE = %s EINAME = ", qName, qCode, eiName);
resolve(reply);
}).catch((err)=>{
console.log("Flow can't store at xstorage: QNAME = %s QCODE =%s EINAME = ", qName, qCode, eiName);
console.log(err);
reject(err.message);
});
}
}).catch((err) => {
console.log("Flow can't load from obj-mms: QNAME = %s QCODE = %s", qName, qCode);
console.log(err);
let payload = {
catalog: 'flow',
idname: eiName
};
caller.GetConfig(payload).then((reply) => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
console.log("Flow load from xstorage: QNAME = %s QCODE = %s EINAME = ", qName, qCode, eiName);
if(result.result)
resolve(result.result);
else if(type == 'flows'){
resolve([]);
}
else{
resolve([]);
}
}
} else {
console.log("Flow can't load from xstorage: QNAME = %s QCODE = %s EINAME = ", qName, qCode, eiName);
reject("Call xstorage not response")
}
});
});
}else{
let idname = type;
if(path)
idname += `_${path}`;
let payload = {
catalog: type == 'flows' ? 'flow' : type,
idname: idname
};
caller.GetConfig(payload).then((reply) => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
if(result.result)
resolve(result.result);
else if(type == 'flows'){
resolve([]);
}
else{
resolve([]);
}
}
} else {
reject("Call xstorage not response")
}
});
}
});
}
function objSave(type, path, blob) { //need to check
return when.promise(function(resolve, reject) {
let idname = type;
if(path)
idname += `_${path}`;
if(type == 'flows'){
idname = eiName;
}
let payload = {
catalog: type == 'flows' ? 'flow' : type,
idname: idname,
data: blob
};
caller.SetConfig(payload).then((reply) => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
resolve('OK')
}
} else {
reject('Call xstorage not response');
}
});
});
}
var xStorage = {
init: function(_settings, _runtime) {
var promises = [];
settings = _settings;
runtime = _runtime;
if (!settings.userDir) {
try {
fs.statSync(fspath.join(process.env.NODE_RED_HOME,".config.json"));
settings.userDir = process.env.NODE_RED_HOME;
} catch(err) {
settings.userDir = fspath.join(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || process.env.NODE_RED_HOME,".node-red");
if (!settings.readOnly) {
promises.push(promiseDir(fspath.join(settings.userDir,"node_modules")));
}
}
}
if (process.env.FLOW_FILE || settings.flowFile) {
flowsFile = process.env.FBOT_FLOWFILE || settings.flowFile;
// handle Unix and Windows "C:\"
if ((flowsFile[0] == "/") || (flowsFile[1] == ":")) {
// Absolute path
flowsFullPath = flowsFile;
} else if (flowsFile.substring(0,2) === "./") {
// Relative to cwd
flowsFullPath = fspath.join(process.cwd(),flowsFile);
} else {
try {
fs.statSync(fspath.join(process.cwd(),flowsFile));
// Found in cwd
flowsFullPath = fspath.join(process.cwd(),flowsFile);
} catch(err) {
// Use userDir
flowsFullPath = fspath.join(settings.userDir,flowsFile);
}
}
} else {
flowsFile = 'flows_'+require('os').hostname()+'.json';
flowsFullPath = fspath.join(settings.userDir,flowsFile);
}
var ffExt = fspath.extname(flowsFullPath);
var ffName = fspath.basename(flowsFullPath);
var ffBase = fspath.basename(flowsFullPath,ffExt);
var ffDir = fspath.dirname(flowsFullPath);
credentialsFile = fspath.join(settings.userDir,ffBase+"_cred"+ffExt);
credentialsFileBackup = fspath.join(settings.userDir,"."+ffBase+"_cred"+ffExt+".backup");
oldCredentialsFile = fspath.join(settings.userDir,"credentials.json");
//flowsFileBackup = fspath.join(ffDir,"."+ffName+".backup");
sessionsFile = fspath.join(settings.userDir,".sessions.json");
//projectFile = fspath.join(settings.userDir,"projects.json");
libDir = fspath.join(settings.userDir,"lib");
libFlowsDir = fspath.join(libDir,"flows");
globalSettingsFile = fspath.join(settings.userDir,".config.json");
if (!settings.readOnly) {
promises.push(promiseDir(libFlowsDir));
}
qName = process.env.FBOT_QNAME;
qCode = process.env.FBOT_QCODE;
eiName = process.env.MCHAT_EINAME;
promises.push(mc.setup());
return when.all(promises);
},
getFlows: function() {
return objLoad('flows', '/');
},
saveFlows: function(flows) {
return objSave('flows', '/', flows);
},
getCredentials: function() {
return objLoad('credentials', '/');
},
saveCredentials: function(credentials) {
return objSave('credentials', '/', credentials);
},
getSettings: function() {
return objLoad('settings', '/');
},
saveSettings: function(settings) {
return objSave('settings', '/', settings);
},
getSessions: function() {
return objLoad('sessions', '/');
},
saveSessions: function(sessions) {
return objSave('sessions', '/', sessions);
},
getLibraryEntry: function(type, path) {
return when.promise(function(resolve, reject) {
let idname = 'library';
if(type)
idname += `_${type}`;
if(path)
idname += `_${path}`;
let payload = {
catalog: type,
idname: idname
}
caller.GetConfig(payload).then((reply) => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
resolve(result.result || {});
}
} else {
reject("Call xstorage not response")
}
});
});
},
saveLibraryEntry: function(type, path, meta, body) {
return when.promise(function(resolve, reject) {
let idname = type;
if(path)
idname += `_${path}`;
let payload = {
catalog: type,
idname: idname,
data: {meta : meta, body: body}
};
caller.SetConfig(payload).then((reply) => {
if (reply) {
let result;
if (typeof reply == 'object')
result = reply;
else
result = reply[0];
if (Array.isArray(result))
result = result[0];
if (result.ErrMsg != 'OK') {
reject(result.ErrMsg);
}
else if (result.ErrMsg == 'OK') {
resolve('OK')
}
} else {
reject('Call xstorage not response');
}
});
});
}
};
module.exports = xStorage;