3
0
Fork 0

Added project

This commit is contained in:
Willem Cazander 2022-11-13 01:46:38 +01:00
parent fe9aa14dfd
commit 2d73cc8845
186 changed files with 21174 additions and 0 deletions

View file

@ -0,0 +1,291 @@
var XDeviceEncryption = require('./xdevice-encryption');
var Mongoose = require('mongoose');
var XSystemState = Mongoose.model( 'xsystem-state' );
var XNode = Mongoose.model( 'xnode' );
var XNodeBase = Mongoose.model( 'xnode-base' );
var XNodeBaseCommand = Mongoose.model( 'xnode-base-command' );
var XNodeData = Mongoose.model( 'xnode-data' );
var XNodeDataValue = Mongoose.model( 'xnode-data-value' );
var Async = require('async');
var Winston = require('winston');
var Log = Winston.loggers.get('main');
var createXnodeBase = function(created_ip,callbackResult) {
Async.series({
cnt_base_net_id: function(callback) {
XSystemState.incHexByName('_a_seq_base_net_id', function(err, xprop) {
callback(err,xprop.value);
});
},
cnt_base_net_key: function(callback){
XSystemState.incHexByName('_a_seq_base_net_key', function(err, xprop) {
callback(err,xprop.value);
});
},
cnt_base_net_mac: function(callback){
XSystemState.incHexByName('_a_seq_base_net_mac', function(err, xprop) {
callback(err,xprop.value);
});
},
cnt_base_rf_key: function(callback){
XSystemState.incHexByName('_a_seq_base_rf_key', function(err, xprop) {
callback(err,xprop.value);
});
}
},
function(err, result) {
if (err) {
callbackResult(err);
return;
}
var xnodeBase = new XNodeBase();
xnodeBase.created_ip = created_ip;
xnodeBase.net_id = result.cnt_base_net_id;
xnodeBase.net_key = result.cnt_base_net_key;
xnodeBase.net_mac = result.cnt_base_net_mac;
xnodeBase.rf_key = result.cnt_base_rf_key;
xnodeBase.init_index = 0;
xnodeBase.save(function(err,xnodeBase) {
Log.debug("XDeviceConnectorA.createXnodeBase _id="+xnodeBase._id+" net_id="+xnodeBase.net_id);
callbackResult(err,xnodeBase);
});
});
}
var handleInit = function(req,res,next) {
Log.debug('XDeviceConnectorA.handleInit');
var net_id = req.body.ni;
if (net_id == 0) {
createXnodeBase(req.ip,function(err,xnodeBase) {
if (err) { return next(err); }
Log.info('XDeviceConnectorA.handleInit response: Xinet_id '+xnodeBase.net_id);
res.send('Xinet_id '+xnodeBase.net_id+'\n');
});
} else {
XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) {
if (err) { return next(err); }
if (xnodeBase == null) {
Log.warn('XDeviceConnectorA.handleInit illegal net_id='+req.body.ni);
res.send('X');
return;
}
if (xnodeBase.init_index > 4) {
Log.error('initXnode stateError, device was already init-ited.');
res.send('XXreboot');
return;
}
xnodeBase.init_index++;
xnodeBase.save(function(err) {
var result;
if (xnodeBase.init_index == 1) {
result = 'Xinet_key '+xnodeBase.net_key;
} else if (xnodeBase.init_index == 2) {
result = 'Xinet_mac '+xnodeBase.net_mac;
} else if (xnodeBase.init_index == 3) {
result = 'Xirf_key '+xnodeBase.rf_key;
} else if (xnodeBase.init_index == 4) {
result = 'Xireboot';
XNodeBaseCommand.insert(net_id,'help',req.ip,next); // trigger node data on next ping :)
} else {
result = 'X'; // code error
}
Log.info('XDeviceConnectorA.initXnode response net_id='+xnodeBase.net_id+' step='+xnodeBase.init_index+' reply='+result);
res.send(result);
});
});
}
};
var replyCommand = function(req,res,next) {
XNodeBaseCommand.findOpenByNetId(req.body.ni, function ( err, data ) {
if (err) { return next(err); }
if (data.length > 0) {
Log.debug('XDeviceConnectorA.replyCommand send cmd: '+data[0].command);
data[0].send_date = new Date();
data[0].save(function(err) {
if (err) { return next(err); }
res.send('XX'+data[0].command);
});
} else {
res.send('X');
}
});
}
var logData = function(xnode,data_raw,data_text,req) {
var xdata = new XNodeData();
xdata.remote_ip = req.ip;
xdata.node_id = xnode.node_id;
xdata.net_id = req.body.ni;
xdata.data_raw = data_raw;
xdata.data_text = data_text;
xdata.save(function(err,xdata) {
if (err) { return next(err); }
Log.debug("XDeviceConnectorA.logData _id="+xdata._id+" net_id="+xdata.net_id+" node_id="+xdata.node_id+" data_text.length="+xdata.data_text.length);
});
}
var logDataValue = function(xnode,data_text,req, next) {
if (data_text.indexOf('help') > 0) {
return; // done't save help cmds as values.
}
if (data_text.indexOf('#ERR') > 0) {
return; // done't save errors.
}
var data_lines = data_text.split('\n');
for(var i = 0; i < data_lines.length; i ++) {
var data_line = data_lines[i];
var data_rows = data_line.split('=');
var data_name = data_rows[0];
var data_value = data_rows[1];
if (data_name.length == 0) {
continue;
}
xval = new XNodeDataValue();
xval.net_id = xnode.net_id;
xval.node_id = xnode.node_id;
xval.name = data_name;
xval.value = data_value;
xval.save(function(err,xval) {
if (err) { return next(err); }
Log.debug("XDeviceConnectorA.logDataValue _id="+xval._id+" net_id="+xval.net_id+" node_id="+xval.node_id+" name="+xval.name+" value="+xval.value);
});
}
}
var logRxCount = function(xnode,data_text,next) {
xnode.rx_date=new Date();
xnode.rx_requests++;
xnode.rx_bytes=data_text.length + xnode.rx_bytes;
xnode.save(function(err,xnode) {
if (err) { return next(err); }
Log.debug("XDeviceConnectorA.logRxCount _id="+xnode._id+" rx_requests="+xnode.rx_requests);
});
}
var updateMetaInfo = function(xnode,req, next) {
if (xnode.info_date == null) {
xnode.info_date = new Date(new Date().getTime() - 60*60*1000 - 1000); // triggers update
}
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
if (dateLastHour.getTime() > xnode.info_date.getTime() ) {
if (xnode.node_id == 1) {
XNodeBaseCommand.insert(xnode.net_id,'sys_info',req.ip, next);
XNodeBaseCommand.insert(xnode.net_id,'rf_info',req.ip, next);
XNodeBaseCommand.insert(xnode.net_id,'net_info',req.ip, next);
XNodeBaseCommand.insert(xnode.net_id,'net_info_eth0',req.ip, next);
} else {
Log.debug("todo");
//XNodeBaseCommand.insert(xnode.net_id,'@2 sys_info',req.ip, next);
//XNodeBaseCommand.insert(xnode.net_id,'@2 rf_info',req.ip, next);
}
xnode.info_date = new Date();
xnode.save(function(err,xsat) {
if (err) { return next(err); }
Log.debug("XDeviceConnectorA.updateMetaInfo _id="+xnode._id);
});
}
}
var handleDataNode = function(xnode,req,res,next) {
var net_id = req.body.ni;
var node_id = req.body.nn;
var data_raw = req.body.nd;
Log.debug('XDeviceConnectorA.handleDataNode ni='+xnode.net_id);
// log.debug('XDeviceConnectorA.handleData TODO FIX XXTEA');
// var result = XDeviceEncryption.xxteaDecrypt(req.body.nd,xnode.hw_net_key);
// log.debug('XDeviceConnectorA.handleData xxteaDecrypt='+result+' hw_net_key='+xnode.hw_net_key);
var data_text = data_raw;
logRxCount (xnode,data_text,next);
logData (xnode,data_raw,data_text,req);
logDataValue (xnode,data_text, req, next);
updateMetaInfo (xnode,req, next);
replyCommand (req,res,next);
}
var handleData = function(req,res,next) {
var net_id = req.body.ni;
var node_id = req.body.nn;
if (net_id == '000000000000') {
Log.warn('XDeviceConnectorA.handleData zero net_id='+net_id);
res.send('X');
return;
}
if (node_id == 0) {
Log.warn('XDeviceConnectorA.handleData zero node_id='+node_id);
res.send('X');
return;
}
Log.debug('XDeviceConnectorA.handleData ni='+net_id+' nn='+node_id);
XNode.findByNetIdAndNodeId(net_id,node_id,function(err,xnode) {
if (err) { return next(err); }
if (xnode == null) {
Log.debug('XDeviceConnectorA.handleData creating new XNode.');
xnode = new XNode();
xnode.net_id = net_id;
xnode.node_id = node_id;
xnode.save(function(err) {
if (err) { return next(err); }
handleDataNode(xnode,req,res,next);
});
} else {
handleDataNode(xnode,req,res,next);
}
});
}
var handlePing = function(req,res,next) {
var net_id = req.body.ni;
if (net_id == '000000000000') {
Log.debug('XDeviceConnectorA.handlePing zero net_id='+net_id);
res.send('X');
return;
}
Log.debug('XDeviceConnectorA.handlePing net_id='+net_id);
XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) {
if (err) { return next(err); }
if (xnodeBase == null) {
Log.warn('XDeviceConnectorA.handlePing illegal net_id='+net_id);
res.send('X');
return;
}
xnodeBase.ping_counter++;
xnodeBase.ping_last_date=new Date();
xnodeBase.save(function(err) {
if (err) { return next(err); }
if (req.body.rc == 0) {
res.send('X'); // no cmd on first ping.
} else {
replyCommand(req,res,next);
}
});
});
}
exports.deviceControl = function(req, res, next) {
var postType = req.body.pt;
var url = req.originalUrl || req.url;
var ip = req.ip;
Log.debug('POST '+url+' ip='+ip+' pt='+postType+' rc='+req.body.rc+' ni='+req.body.ni);
if (postType == 'i') {
handleInit(req,res,next);
return;
}
if (postType == 'p') {
handlePing(req,res,next);
return;
}
if (postType == 'd') {
handleData(req,res,next);
return;
}
Log.warn('XDeviceConnectorA.deviceControl unknown postType='+postType);
res.send('X');
}

View file

@ -0,0 +1,120 @@
var winston = require('winston');
var log = winston.loggers.get('main');
var delta = 0x9E3779B9;
var XXTEA_NUM_ROUNDS = 32;
//var xxxteaEncrypt = function(unsigned long v[2]) {
// unsigned int i;
// unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
// for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
// v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
// sum += delta;
// v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
// }
// v[0]=v0; v[1]=v1;
//}
var xxxteaDecrypt = function(vArray,keyBuff) {
log.debug('XDeviceEncryption.xxxteaDecrypt vArray='+JSON.stringify(vArray)+' keyBuff='+JSON.stringify(keyBuff));
var v0=vArray.v0;
var v1=vArray.v1;
log.debug('XDeviceEncryption.xxxteaDecrypt start v0='+v0.toString(16)+' v1='+v1.toString(16));
var delta=0x9E3779B9
var sum=delta*XXTEA_NUM_ROUNDS;
for (var i=0; i < XXTEA_NUM_ROUNDS; i++) {
v1 -= (((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + keyBuff.readUInt32BE((sum>>>11) & 3));
var v1Org = v1;
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + keyBuff.readUInt32BE(sum & 3));
//log.debug('XDeviceEncryption.xxxteaDecrypt v0='+v0.toString(16)+' v1='+v1.toString(16));
if (v0 < 0) { v0 = Math.pow(2,32) + v0; }
if (v0 > Math.pow(2,32)) { v0 = v0 - Math.pow(2,32); }
if (v1 < 0) { v1 = Math.pow(2,32) + v1; }
if (v1 > Math.pow(2,32)) { v1 = v1 - Math.pow(2,32); }
}
//v0 = v0 & 0xFFFFFFFF;
//v1 = v1 & 0xFFFFFFFF;
var result = {v0: v0,v1: v1};
log.debug('XDeviceEncryption.xxxteaDecrypt result='+JSON.stringify(result));
return result;
}
// public static method encrypt
exports.xxteaEncrypt = function(string, key) {
log.debug('XDeviceEncryption.xxteaEncrypt key='+key+' data='+string);
if (string.length == 0) {
return('');
}
//var v = strToLongs(Utf8.encode(string));
//var k = strToLongs(Utf8.encode(key).slice(0,16));
var v = buffToLongs(new Buffer(string, 'hex'));
var k = buffToLongs(new Buffer(key, 'hex'));
//if (v.length <= 1) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding a null
var n = v.length;
// ---- <TEA coding> ----
var z = v[n-1], y = v[0], delta = 0x9E3779B9;
var mx, e, q = Math.floor(6 + 52/n), sum = 0;
while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word
sum += delta;
e = sum>>>2 & 3;
for (var p = 0; p < n; p++) {
y = v[(p+1)%n];
mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
z = v[p] += mx;
}
}
// ---- </TEA> ----
var buff = longsToBuff(v);
return buff.toString('ascii');
}
exports.xxteaDecrypt = function(data, key) {
log.debug('XDeviceEncryption.xxteaDecrypt key='+key+' data='+data);
if (data.length == 0) {
return('');
}
var d = new Buffer(data, 'hex');
var k = new Buffer(key, 'hex');
var n = d.length;
var r = new Buffer(n);
log.debug('XDeviceEncryption.xxteaDecrypt dataBuffer='+d.toString('hex'));
// ---- <TEA decoding> ----
for (var i=0;i<n/4-1;i=i+2) {
//log.debug('XDeviceEncryption.xxteaDecrypt n='+n+' i='+i+' c='+(i*4)+' cc='+(i*4+1)+' r='+d.readUInt32LE(i*4).toString(16)+' r1='+d.readUInt32BE(i*4).toString(16));
var ed = {v0: d.readUInt32BE(i*4),v1: d.readUInt32BE((i+1)*4)};
var dd = xxxteaDecrypt(ed,k);
r.writeUInt32BE(dd.v0,i*4);
r.writeUInt32BE(dd.v1,(i+1)*4);
}
return r.toString('ascii');
//var plaintext = longsToStr(v);
//plaintext = plaintext.replace(/\0+$/,'');
//return plaintext;
//return new Buffer(plaintext,'utf8').toString('ascii');
//var plaintext = longsToStr(v);
//plaintext = plaintext.replace(/\0+$/,'');// strip trailing null chars resulting from filling 4-char blocks:
//return Utf8.decode(plaintext);
}

View file

@ -0,0 +1,123 @@
var logger = require('winston').loggers.get('main');
var clone = require('clone');
var mongoose = require('mongoose');
var validate = require('validate.io');
var tcrudField = require('./tcrud-field');
var buildConfig = require('./build-config');
function autoFieldType(fieldMeta,fieldType) {
if (!fieldMeta) {
throw new Error('no fieldMeta');
}
if (fieldType && fieldType.length != 0) {
return fieldType;
}
if (fieldMeta.type == Date) {
return 'date';
}
return 'text';
}
exports.buildFields = function(modelMeta) {
if (!modelMeta) {
throw new Error('no modelMeta');
}
var tfields = {};
var keys = Object.keys(modelMeta);
for (i = 0; i < keys.length; i++) {
var key = keys[i];
var value = modelMeta[key];
var tfield = null;
if (key && value && value.tfield) {
//console.log('tfield model cloned');
tfield = clone(value.tfield);
tfield.tid = key;
tfield.tname = tcrudField.autoFieldName(key,tfield.tname);
tfield.type = autoFieldType(value,tfield.ttype);
} else if (key && value) {
//console.log('tfield model auto created');
tfield = tcrudField.newInstance(key);
tfield.tname = tcrudField.autoFieldName(key);
tfield.type = autoFieldType(value);
}
if (tfield.tvalidate && tfield.tvalidate.io) {
//console.log('tfield validate rule: '+tfield.tvalidate.io);
}
tcrudField.fillDefaults(tfield);
tfields[tfield.tid] = tfield;
}
return tfields;
}
function ss(valueRule) {
return function (value, response) {
response(validate(valueRule,value));
};
}
exports.createModelValidators = function (modelSchema,modelFields) {
if (!modelSchema) {
throw new Error('no modelSchema');
}
if (!modelFields) {
throw new Error('no modelFields');
}
var keys = Object.keys(modelFields);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var tfield = modelFields[key];
if (!tfield.tvalidate) {
continue;
}
if (!tfield.tvalidate.io) {
continue;
}
modelSchema.path(tfield.tid).validate(ss(tfield.tvalidate.io), '{PATH} validation failed: '+tfield.tvalidate.io);
}
}
exports.buildStatics = function(modelFields,modelStatics) {
if (!modelFields) {
throw new Error('no modelFields');
}
if (!modelStatics) {
modelStatics = {};
}
modelStatics['ff_tcrud_fields'] = modelFields;
return modelStatics;
}
exports.buildTCrudModel = function(mongoose,tcrudParent,name) {
var model = mongoose.model(name);
var tcrud = buildConfig.createTCrud(tcrudParent,name);
var tfields = model['ff_tcrud_fields'];
if (tfields) {
tcrud.tmeta.tfields = tfields;
}
tcrud.tmodel = name;
//tcrud.tbackend = 'mongoose';
return tcrud;
}
exports.buildTCrudModels = function(mongoose,tcrudParent) {
var result = [];
var modelNames = mongoose.connection.modelNames();
for (var i = 0; i < modelNames.length; i++) {
result.push(exports.buildTCrudModel(mongoose,tcrudParent,modelNames[i]))
}
return result;
}
// ----- wrappers
exports.buildStaticsModel = function(modelMeta,modelStatics) {
return exports.buildStatics(exports.buildFields(modelMeta),modelStatics);
}
exports.buildStaticsModelValidated = function(modelMeta,modelSchema,modelStatics) {
var modelFields = exports.buildFields(modelMeta);
exports.createModelValidators(modelSchema,modelFields);
return exports.buildStatics(modelFields,modelStatics);
}

View file

@ -0,0 +1,16 @@
var logger = require('winston').loggers.get('main');
var clone = require('clone');
var tcrud = require('./tcrud');
var tcrudField = require('./tcrud-field');
exports.createTCrudRoot = function() {
return tcrud.newInstance('root');
}
exports.createTCrud = function(parent, id) {
var result = tcrud.newInstance(id);
parent.tchilds.push(result);
result.tparent = parent;
return result;
}

View file

@ -0,0 +1,95 @@
var logger = require('winston').loggers.get('main');
var clone = require('clone');
var tcrud = require('./tcrud');
var tcrudView = require('./tcrud-view');
exports.createBaseApiUri = function(tview, tech, action) {
var uriView = tview.tslug;
var uriTech = tview.tmeta.texport[tech].tslug;
var uriAction = '';
if (action) {
uriAction = '/' + tview[action].texport[tech].tslug;
}
//logger.info('createBaseApiUri uriTech: '+uriTech+' uriView: '+uriView+' uriAction: '+uriAction);
if (tview.tmeta.tserver.tpopfix) {
return uriTech + '/' + uriView + uriAction;
} else {
return uriView + '/' + uriTech + uriAction;
}
};
function allowSlugSlash(tcrud) {
var result = true;
if (tcrud.tparent) {
result = allowSlugSlash(tcrud.tparent);
if (!result) {
return result;
}
}
if (tcrud.tcount.tslug === '') {
return 'tcount';
}
if (tcrud.tlist.tslug === '') {
return 'tlist';
}
if (tcrud.tcreate.tslug === '') {
return 'tcreate';
}
if (tcrud.tread.tslug === '') {
return 'tread';
}
if (tcrud.tedit.tslug === '') {
return 'tedit';
}
if (tcrud.tdelete.tslug === '') {
return 'tdelete';
}
// if (tcrud.tverify.tslug === '') {
//return false;
// }
return null;
}
function createTCrudViewSlug(tcrud) {
var uriViewSlash = '/';
var slug = uriViewSlash + tcrud.tslug;
if (!tcrud.tenable || !tcrud.tparent) {
slug = '';
}
if (tcrud.tparent) {
return createTCrudViewSlug(tcrud.tparent)+slug;
}
return slug;
}
var fetchEmptyRoles = function() {
return function (callback) {
callback(null,[]);
};
}
exports.createTCrudView = function(tcrud,xrollesCallback) {
if (!tcrud) {
throw new Error('no tcrud');
}
if (!xrollesCallback) {
xrollesCallback = fetchEmptyRoles;
}
var tview = tcrudView.newInstance(tcrud);
tview.tslug = createTCrudViewSlug(tcrud).substring(1);
/*
var uriViewSlashAllow = allowSlugSlash(tcrud);
if (uriViewSlashAllow !== null) {
uriViewSlash = '_';
console.log('detected crud actions with empty tslug; deploying in list mode slash; '+uriViewSlash+' in: '+uriViewSlashAllow+' of: '+tcrud.xid);
tview.tslug = buildSlug(uriViewSlash,tcrud).substring(1);
} else {
tview.tslug = buildSlug(uriViewSlash,tcrud);
}
*/
return tview;
}

View file

@ -0,0 +1,338 @@
var logger = require('winston').loggers.get('main');
var clone = require('clone');
var fs = require('fs');
var ejs = require('ejs');
var xmlmapping = require('xml-mapping');
var rawbody = require('raw-body');
var typeis = require('type-is');
var mcrud = require('crud-mongoose');
var ncrud = require('node-crud');
var mongoose = require('mongoose');
var buildView = require('./build-view');
exports.bodyParserXml = function() {
return function(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
if (!typeis(req, 'xml')) return next();
// flag as parsed
req._body = true;
// parse
rawbody(req, {
limit: options.limit || '100kb',
length: req.headers['content-length'],
encoding: 'utf8'
}, function (err, buf) {
if (err) return next(err);
if (0 == buf.length) {
return next(error(400, 'invalid xml, empty body'));
}
try {
req.body = xmlmapping.dump(buf/*, options.reviver*/);
} catch (err){
err.body = buf;
err.status = 400;
return next(err);
}
next();
})
}
}
var renderTemplateDataRead = function(tview, exportType, contentType, model, projection) {
return function(data, query, cb) {
var res = this.response;
res.set('Content-Type', contentType);
var cursor, fields;
if (query.hasOwnProperty('fields')) {
fields = query.fields;
delete query.fields;
}
delete query.export;
cursor = model.findOne(query);
cursor.select(mcrud.tools.select(projection, fields));
cursor.lean().exec(function(err,doc) {
if (err) {
cb(err || 'error in stream');
return;
}
if (doc == null) {
cb('no data'); // TODO: error is still in json...
return;
}
//var templateReadHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-header.ejs', 'utf8');
var templateReadRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-record.ejs', 'utf8');
//var templateReadFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-footer.ejs', 'utf8');
res.write(ejs.render(templateReadRecord,{
tview: tview,
record: doc,
}));
res.end();
//cb(); // FIXME
});
}
}
var renderTemplateDataList = function(tview, exportType, contentType) {
return function(res, cursor, cb) {
res.set('Content-Type', contentType);
var templateHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-header.ejs', 'utf8');
var templateRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-record.ejs', 'utf8');
var templateFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-footer.ejs', 'utf8');
res.write(ejs.render(templateHeader,{
tview: tview,
}));
cursor.stream()
.on('data', function(doc) {
res.write(ejs.render(templateRecord,{
tview: tview,
record: doc,
}));
})
.on('error', function(e) {
cb(e || 'error in stream');
})
.on('close', function() {
res.write(ejs.render(templateFooter,{
tview: tview,
}));
res.end();
cb();
});
};
}
exports.injectExportFormat = function(apiBase) {
return function ( req, res, next ) {
if (req.url.indexOf(apiBase) >= 0) {
if (req.url.indexOf('xml') > 0) {
req.query['export'] = 'xml';
} else if (req.url.indexOf('csv') > 0) {
req.query['export'] = 'csv';
} else if (req.url.indexOf('rss') > 0) {
req.query['export'] = 'rss';
}
if (req.url.indexOf('json') == 0) {
console.log('inject export type: '+req.query['export']);
}
}
next();
};
}
var _ = require('underscore');
var filterQueryList = function (model) {
return mcrud.parseQuery()
.defaults({ limit: '10' })
.overrides({})
.maxes({ limit: 1000 });
//.removes()
}
var filterDataUpdate = function (model) {
return mcrud.parseData()
overrides({});
//.removes('auth')
//.overrides({ updated: Date.now })
//.defaults({ 'info.gender': 'M' }))
}
function allowCrudType(tview,tcrudType) {
return tview[tcrudType].tenable; // todo add roles
}
//var rssXNodeMap = function(link,feed,data) {
// feed.addNewItem(data.net_id, link+'/ui/XNode/read/'+data._id, data.changed_data, data.net_id+' id', {});
//}
var sendRedirect = function (location) {
if (!location) {
throw new Error('no location');
}
return function(req, res) {
res.redirect(location);
};
};
var renderCrudView = function (tview) {
return function (req, res, next) {
var result = {
tview: tview,
}
res.json({
data: result
});
};
}
var renderCrudController = function (tview, thtmlPrefix, tapiPrefix) {
return function (req, res, next) {
res.set('Content-Type', 'text/javascript');
res.render('node-ff-tcrud/angular/controller',{
tview: tview,
thtmlPrefix: thtmlPrefix,
tapiPrefix: tapiPrefix,
});
};
}
var renderCrudTemplate = function (tview,paction) {
return function (req, res, next) {
res.render('node-ff-tcrud/angular/'+paction+'/'+req.params.action,{
tview: tview,
});
};
}
var buildCrud = function (server,tcrud) {
if (!tcrud.tenable || !tcrud.tmodel) {
logger.info('disabled server: '+tcrud.tid);
return;
}
var tview = buildView.createTCrudView(tcrud /*, fetchCrudRoles()*/);
var model = mongoose.model( tcrud.tmodel );
// Export tdebug
var uriDebug = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json') + '/_debug/';
var tcrudClone = clone(tcrud);
tcrudClone.tparent = null; // rm loop: tparent.tchilds[] = this
server.get(uriDebug + 'tview', renderCrudView(tview));
server.get(uriDebug + 'tcrud', renderCrudView(tcrudClone));
if (_.contains(tview.tmeta.tserver.texports,'json')) {
if (allowCrudType(tview,'tlist')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tlist')).Read()
.pipe(filterQueryList(model))
.pipe(mcrud.findAll(model).stream());
}
if (allowCrudType(tview,'tcreate')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcreate')).Create()
.pipe(mcrud.createNew(model));
}
if (allowCrudType(tview,'tread')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tread') + '/:_id').Read()
.pipe(mcrud.findOne(model));
}
if (allowCrudType(tview,'tedit')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tedit') + '/:_id').Update()
.pipe(filterDataUpdate(model))
.pipe(mcrud.updateOne (model));
}
if (allowCrudType(tview,'tdelete')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tdelete') +'/:_id').Delete()
.pipe(mcrud.removeOne(model));
}
if (allowCrudType(tview,'tcount')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcount')).Read()
.pipe(filterQueryList(model))
.pipe(mcrud.findAll(model).stream());
}
if (allowCrudType(tview,'tverify')) {
ncrud.entity(buildView.createBaseApiUri(tview,'json','tverify') + '/:_id').Update()
.pipe(mcrud.findOne(model));
}
}
if (_.contains(tview.tmeta.tserver.texports,'xml')) {
if (allowCrudType(tview,'tlist')) {
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tlist')).Read()
.pipe(filterQueryList(model))
.pipe(mcrud.findAll(model).stream().exports({ xml: renderTemplateDataList(tview,'xml','text/xml') }));
}
if (allowCrudType(tview,'tcreate')) {
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tcreate')).Create()
.pipe(mcrud.createNew(model));
}
if (allowCrudType(tview,'tread')) {
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tread') +'/:_id').Read()
.pipe(renderTemplateDataRead(tview,'xml','text/xml',model));
}
if (allowCrudType(tview,'tedit')) {
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tedit')+'/:_id').Update()
.pipe(filterDataUpdate(model))
.pipe(mcrud.updateOne (model));
}
if (allowCrudType(tview,'tdelete')) {
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tdelete')+'/:_id').Delete()
.pipe(mcrud.removeOne (model));
}
}
if (_.contains(tview.tmeta.tserver.texports,'csv')) {
if (allowCrudType(tview,'tlist')) {
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tlist')).Read()
.pipe(filterQueryList(model))
.pipe(mcrud.findAll(model).stream().exports({ csv: renderTemplateDataList(tview,'csv','text/csv') }));
}
if (allowCrudType(tview,'tread')) {
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tread') +'/:_id').Read()
.pipe(renderTemplateDataRead(tview,'csv','text/csv',model));
}
}
if (_.contains(tview.tmeta.tserver.texports,'rss')) {
if (allowCrudType(tview,'tlist')) {
ncrud.entity(buildView.createBaseApiUri(tview,'rss','tlist')).Read()
.pipe(mcrud.parseQuery()
.defaults({ limit: '10' })
.maxes({ limit: 50 })
)
.pipe(mcrud.findAll(model)
.stream()
.exports({ rss: renderTemplateDataList(tview,'rss','text/xml') })
);
}
//.exports({ rss: exports.exportRss('todo',tview.xid,rssXNodeMap) })
}
if (_.contains(tview.tmeta.tserver.texports,'angular')) {
var uriPrefix = tcrud.tmeta.tserver.tslug + '/' + buildView.createBaseApiUri(tview,'angular');
var thtmlPrefix = uriPrefix + '/' + tview.tmeta.texport.angular.thtml;
var tapiPrefix = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json');
//server.get('/ui/include/crud/:name/:action', XViewInclude.renderTemplateCrud);
//server.get('/ui/include/js/controller/:name', XViewInclude.renderCrudController);
server.get(uriPrefix + '/thtml/crud/:action', renderCrudTemplate(tview,'thtml/crud/'));
server.get(uriPrefix + '/controller.js', renderCrudController(tview,thtmlPrefix,tapiPrefix));
//server.get(uriPrefix + '/service.js', renderCrudService(tview))
}
}
function walkViews(server,tcrud) {
//logger.debug('walk views: '+tcrud.tid);
if (tcrud.tparent) {
buildCrud(server,tcrud);
}
for (var i = 0; i < tcrud.tchilds.length; i++) {
walkViews(server,tcrud.tchilds[i]);
}
}
function buildCrudApi(server) { // todo add return function
troot = server.get('ff_root_tcrud_view');
walkViews(server,troot);
server.use(exports.injectExportFormat(troot.tmeta.tserver.tslug));
server.use(exports.bodyParserXml());
ncrud.launch(server,{
base: troot.tmeta.tserver.tslug,
cors: false,
timeoute: 10e3
});
}
module.exports = buildCrudApi;

View file

@ -0,0 +1,138 @@
var logger = require('winston').loggers.get('main');
var clone = require('clone');
/*
var createRouter = function(server,path) {
var router = express.Router();
router.path = path;
server.use(router.path,router);
return router;
}
*/
var walkRouteTree = function(result,stack,parent_path) {
if (parent_path == null) {
parent_path = '';
}
stack.forEach(function(middleware) {
if (middleware.route){
var path = parent_path + middleware.route.path;
for (var httpMethod in middleware.route.methods) {
var data = {
"uriPath": path,
"httpMethod": httpMethod
};
result.push(data);
}
} else if (middleware.name === 'router') {
var pp = parent_path + middleware.handle.path;
walkRouteTree(result,middleware.handle.stack,pp);
} else {
//log.info('route err: '+JSON.stringify(middleware));
}
});
return result;
}
exports.renderServerUptime = function(options) {
if (!options) {
options: {};
}
var timeBoot = new Date().getTime();
return function (req, res, next) {
var timeNow = new Date().getTime();
var result = {
time_boot: timeBoot,
time_now: timeNow,
uptime: timeNow-timeBoot
}
res.json({
data: result
});
};
};
exports.renderServerRoutes = function(server) {
if (!server) {
throw new Error('no server');
}
return function (req, res, next) {
var routeList = server.get('ff_tcrud_route_list');
if (!routeList) {
console.log('no routeList');
routeList = [];
}
var reqGroups = req.query.groups;
var groupList = [];
if (reqGroups) {
groupList = reqGroups.split(',');
}
//console.log('groups: '+reqGroups);
var result = {
all: [],
};
for (var i = 0; i < groupList.length; i++) {
var groupName = groupList[i].split('/').join('_');
result[groupName] = [];
}
groupList.sort(function(a, b) {
return a.length < b.length; // longest first as we break on first hit
});
for (i = 0; i < routeList.length; i++) {
var route = routeList[i];
var added = false;
for (var ii = 0; ii < groupList.length; ii++) {
if (route.uriPath.indexOf(groupList[ii]) > 0) {
var groupName = groupList[ii].split('/').join('_');
result[groupName].push(route);
added = true;
break;
}
}
if (!added) {
result.all.push(route);
}
}
res.json({
data: result
});
};
};
exports.buildServerRoutes = function(server) { // todo add return function
if (!server) {
throw new Error('no server');
}
var result = walkRouteTree([],server._router.stack);
result.sort(function(a, b) {
return a.uriPath.localeCompare(b.uriPath);
});
server.set('ff_tcrud_route_list',result);
};
exports.sendRedirect = function (location) {
if (!location) {
throw new Error('no location');
}
return function(req, res) {
res.redirect(location);
};
};
exports.renderTemplatePath = function (viewPath) {
if (!viewPath) {
viewPath = '';
}
return function (req, res) {
res.locals.query = req.query;
//console.log('template query keys: '+Object.keys(req.query));
var qi = req.url.indexOf('?');
if (qi === -1) {
qi = req.url.length;
}
res.render(viewPath + req.url.substring(req.route.path.length-1, qi));
};
};
exports.buildCrudApi = require('./factory-express-api');

View file

@ -0,0 +1,54 @@
'use strict';
var tcrud = {
factory: {
express: require('./factory-express'),
},
build: {
config: require('./build-config'),
view: require('./build-view'),
backend: {
mongoose: require('./build-backend-mongoose'),
},
}
};
module.exports = tcrud;
/*
//app.use(function (req, res, next) {res.locals.c_var='test';next();});
var http = require('http');
var ejs = require('ejs');
var fs = require('fs');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/xml'});
fs.readFile('placemark.ejs', 'utf8', function (err, template) {
var content = ejs.render(template,{
name:"test name",
description:"this is the description",
coordinates:"-122.0822035425683,37.42228990140251,0",
filename: __dirname + '/placemark.ejs'
});
res.write(content);
res.end()
});
}).listen(8000);
var scripts = document.getElementsByTagName("script");
var currentScriptPath = scripts[scripts.length-1].src;
console.log("currentScriptPath:"+currentScriptPath);
var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
console.log("baseUrl:"+baseUrl);
var bu2 = document.querySelector("script[src$='routes.js']");
currentScriptPath = bu2.src;
console.log("bu2:"+bu2);
console.log("src:"+bu2.src);
baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
console.log("baseUrl:"+baseUrl);
*/

View file

@ -0,0 +1,110 @@
var clone = require('clone');
var template = {
tid: null,
tname: null,
ttype: null,
tslug: null,
tvalidate: {
io: null,
},
tlist: {
tenable: true,
ttext: null,
troles: [],
},
tread: {
tenable: true,
ttext: null,
troles: [],
},
tedit: {
tenable: true,
ttext: null,
troles: [],
},
tcreate: {
tenable: true,
ttext: null,
troles: [],
},
};
exports.autoFieldName = function (fieldKey,fieldName) {
if (fieldKey === undefined) {
throw new Error('no fieldKey');
}
if (fieldName && fieldName.length !== 0) {
return fieldName;
}
var result = '';
var names = fieldKey.split('_');
for (var i in names) {
var name = names[i];
if (name.length > 1) {
name = name.substring(0,1).toUpperCase() + name.substring(1);
}
result = result + name + ' ';
}
return result;
}
var autoFieldEnable = function(tfield,type) {
if (type === undefined) {
throw new Error('no type');
}
if (tfield[type] === undefined) {
tfield[type] = {};
}
if (tfield[type].tenable !== undefined) {
return;
}
var fieldKey = tfield.tid;
var result = true;
if ('tlist' === type) {
var name = fieldKey.toLowerCase();
if (fieldKey.indexOf('description') >= 0) {
result = false;
} else if (fieldKey.indexOf('comment') >= 0) {
result = false;
}
}
tfield[type].tenable = result;
}
exports.newInstance = function (id) {
var tfield = clone(template);
tfield.tid = id;
return tfield;
}
exports.fillDefaults = function (tfield) {
if (tfield === undefined) {
throw new Error('no tfield');
}
var tid = tfield.tid;
if (tid === undefined) {
throw new Error('no tfield.tid');
}
if (tfield.tname === undefined) {
tfield.tname = exports.autoFieldName(tid);
}
if (tfield.tname === undefined) {
tfield.tname = exports.autoFieldName(tid);
}
if (tfield.tslug === undefined) {
tfield.tslug = tid;
}
if (tfield.ttype === undefined) {
tfield.ttype = 'text';
}
if (tfield.tlist === undefined) {
tfield.tlist = {};
}
autoFieldEnable(tfield,'tlist');
autoFieldEnable(tfield,'tread');
autoFieldEnable(tfield,'tedit');
autoFieldEnable(tfield,'tcreate');
}

View file

@ -0,0 +1,204 @@
var clone = require('clone');
var tsurgeon = require('tree-surgeon');
var template = {
tid: null,
tname: null,
tplural: null,
tslug: null,
tcode: null,
tmodel: null,
tcount: {
ttext: null,
tenable: null,
texport: null,
},
tlist: {
tfields: [],
ttext: null,
tlinks: null,
tenable: null,
texport: null,
},
tread: {
tfields: [],
ttext: null,
tenable: null,
texport: null,
},
tedit: {
tfields: [],
ttext: null,
tenable: null,
texport: null,
},
tcreate: {
tfields: [],
ttext: null,
tenable: null,
texport: null,
},
tdelete: {
ttext: null,
tenable: null,
texport: null,
},
tverify: {
ttext: null,
tenable: null,
texport: null,
},
tmeta: {
tfields: null,
tvalidate: null,
tserver: null,
texport: null,
},
};
function copyByTemplate(prefix,objectDest,objectSrc,copyTemplate) {
var keys = Object.keys(copyTemplate);
var result = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = objectSrc[key];
if (!value) {
//console.log(prefix+'.'+key+' src object has no value.');
continue; // no src value
}
var templateValue = copyTemplate[key];
if (templateValue === null) {
if (objectDest[key] !== null) {
//console.log(prefix+'.'+key+' has own value: '+objectDest[key]);
continue;
} else {
//console.log(prefix+'.'+key+' copy value: '+value);
objectDest[key] = clone(value);
}
} else {
//console.log(prefix+'.'+key+' going deeper');
copyByTemplate(prefix+'.'+key,objectDest[key],value,templateValue)
}
}
}
function addFilteredFields(tview,type,tcrud) {
result = [];
var keys = Object.keys(tcrud.tmeta.tfields);
var result = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var tfield = tcrud.tmeta.tfields[key];
if (tfield[type]) {
if (!tfield[type].tenable) {
//console.log('------------- type: ' + type + ' key: ' + key + ' res: ' + tfield[type].tenable)
continue;
}
}
result.push(key); // default is true..
}
tview[type].tfields = result;
}
function forceLookupKeySimple() {
var low = 100000;
var high = 999999;
return Math.floor(Math.random() * (high - low + 1) + low).toString(16).toUpperCase();
}
function forceLookupTFields(tview) {
var keys = Object.keys(tview.tmeta.tfields);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var keyNew = 'FTL_' +forceLookupKeySimple() + '_' + key.substring(key.length/3,key.length/3*2); // no....its; Force template lookup
var tfield = tview.tmeta.tfields[key];
tview.tmeta.tfields[key] = undefined;
tview.tmeta.tfields[keyNew] = tfield;
var ckeys = Object.keys(tview);
for (var ii = 0; ii < ckeys.length; ii++) {
var ckey = ckeys[ii];
if (ckey === 'tmeta') {
continue;
}
var obj = tview[ckey];
if (obj && obj.tfields) {
var tfieldsNew = [];
for (var iii = 0; iii < obj.tfields.length; iii++) {
var tkey = obj.tfields[iii];
if (tkey === key) {
tfieldsNew.push(keyNew);
} else {
tfieldsNew.push(tkey);
}
}
obj.tfields = tfieldsNew;
}
}
}
}
function formatValuePart(value,replaceChar,splitChar,partFn) {
var result = '';
var parts = value.split(splitChar);
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part.length > 1) {
result += partFn(part);
} else {
result += part;
}
if (i < parts.length - 1) {
result += replaceChar;
}
}
return result;
}
function formatValue(value,removeChars,replaceChar,partFn) {
for (var i = 0; i < removeChars.length; i++) {
value = formatValuePart(value,replaceChar,removeChars[i],partFn);
}
return value;
}
exports.newInstance = function (tcrud) {
var tview = clone(template);
var tid = tcrud.tid;
tview.tid = tid;
copyByTemplate('tview',tview,tcrud,template);
//console.info('TCrudView.tslug: '+tview.tslug);
if (!tview.tslug) {
tview.tslug = formatValue(tid,['.',',','/','=','&','?',' '],'', function (part) {
return part; // todo use fully correct uri removeal and escaping.
})
//console.info('TCrudView.tslug auto: '+tview.tslug);
}
if (!tview.tname) {
tview.tname = formatValue(tid,['_','-','.',','],' ', function (part) {
return part.substring(0,1).toUpperCase()+part.substring(1).toLowerCase();
});
}
if (!tview.tcode) {
tview.tcode = formatValue(tid,[' ','_','-','.',','],'',function (part) {
return part.toLowerCase();
});
}
if (!tview.tplural) {
tview.tplural = tview.tname + 's';
}
addFilteredFields(tview,'tlist',tcrud);
addFilteredFields(tview,'tread',tcrud);
addFilteredFields(tview,'tedit',tcrud);
addFilteredFields(tview,'tcreate',tcrud);
forceLookupTFields(tview);
return tview;
}

View file

@ -0,0 +1,230 @@
var clone = require('clone');
var template = {
tid: null,
tname: null,
tplural: null,
tslug: null,
tmodel: null,
tenable: true,
tparam: null,
troles: [],
tparent: null,
tchilds: [],
tlist: {
tenable: true,
ttext: 'Listing of ..',
troles: [],
tserver: {
tpipe: {
query: {
defaults: { limit: '10' },
maxes: { limit: 50 },
},
},
},
texport: {
json: {
tslug: 'list',
},
xml: {
tslug: 'list',
},
rss: {
tslug: 'list',
},
csv: {
tslug: 'list',
},
angular: {
tslug: 'list',
thtml: 'crud/list',
tcontroller: {
prefix: 'tcrudAuto',
postfix: 'ListCntr',
argu: '$scope, $http, $location, $routeParams',
},
tlinks: {
'DataTODO':'/ui/XNodeData/list/XNode/{{row.net_id}}/{{row.net_id}}',
},
},
},
},
tcreate: {
tenable: true,
ttext: null,
troles: [],
texport: {
json: {
tslug: 'create',
},
xml: {
tslug: 'create',
},
angular: {
tslug: 'create',
thtml: 'crud/create',
tcontroller: {
prefix: 'tcrudAuto',
postfix: 'CreateCntr',
argu: '$scope, $http, $location, $routeParams',
},
},
},
},
tedit: {
tenable: true,
ttext: null,
troles: [],
texport: {
json: {
tslug: 'edit',
},
xml: {
tslug: 'edit',
},
angular: {
tslug: 'edit',
thtml: 'crud/edit',
tcontroller: {
prefix: 'tcrudAuto',
postfix: 'EditCntr',
argu: '$scope, $http, $location, $routeParams',
},
},
},
},
tread: {
tenable: true,
ttext: null,
troles: [],
tslug: '',
texport: {
json: {
tslug: 'read',
},
xml: {
tslug: 'read',
},
csv: {
tslug: 'read',
},
angular: {
tslug: 'read',
thtml: 'crud/read',
troute: {
},
tcontroller: {
prefix: 'tcrudAuto',
postfix: 'ReadCntr',
argu: '$scope, $http, $location, $routeParams',
},
},
},
},
tdelete: {
tenable: true,
ttext: null,
troles: [],
texport: {
json: {
tslug: 'delete',
},
xml: {
tslug: 'delete',
},
angular: {
tslug: 'delete',
thtml: 'crud/delete',
tcontroller: {
prefix: 'tcrudAuto',
postfix: 'DeleteCntr',
argu: '$scope, $http, $location, $routeParams',
},
},
},
},
tcount: {
tenable: true,
ttext: 'Count records',
troles: [],
texport: {
json: {
tslug: 'list-count',
},
xml: {
tslug: 'list-count',
},
csv: {
tslug: 'list-count',
},
},
},
tverify: {
tenable: true,
ttext: 'Verify data',
troles: [],
texport: {
json: {
tslug: 'verify',
},
xml: {
tslug: 'verify',
},
csv: {
tslug: 'verify',
},
},
},
ttemplate: {
tid: '_id',
tname: '_id',
tdescription: '_id',
},
tmeta: {
troles: [],
tfields: {},
tvalidate: {
io: { 'admin_role': 'object|properties[test]' },
},
tserver: {
thost: 'http://localhost:8080/',
tslug: '/api',
tpopfix: true,
texports: ['json','xml','csv','rss','angular'],
},
texport: {
json: {
tslug: 'json',
},
xml: {
tslug: 'xml',
},
csv: {
tslug: 'csv',
},
rss: {
tslug: 'rss',
itemTitle: '$data._id',
itemLink: '$siteLink/ui/$modelUri/read/$[\'data._id\']',
itemDate: '',
itemDescription: '',
//itemFields: '',
},
angular: {
tslug: 'angular',
tbase: '/ui',
thtml: 'thtml',
},
},
},
};
exports.newInstance = function (tid) {
var tcrud = clone(template);
tcrud.tid = tid;
tcrud.tslug = tid; // view fills more defaults.
return tcrud;
}

View file

@ -0,0 +1,8 @@
$scope.<%= taction %>None = function () {
<% if (tview.tlist) { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
<% } else { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
<% } %>
}

View file

@ -0,0 +1,5 @@
$routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview[taction].texport.angular.tslug %><%= routeEnd %>', {
templateUrl: '<%= thtmlPrefix %>/<%= tview[taction].texport.angular.thtml %>',
controller: <%= tview[taction].texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview[taction].texport.angular.tcontroller.postfix %>
});

View file

@ -0,0 +1,99 @@
'use strict';
// Auto generated controller mapping for: <%= tview.tid %>
crudRouteInit.push(<%= tview.tcode %>Init);
function <%= tview.tcode %>Init($routeProvider, $locationProvider) {
<% if (tview.tlist) { %>
$routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/', {
redirectTo: '<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>'
});
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tlist', routeEnd: ''}); %>
<% } %>
<% if (tview.tcreate) { %>
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tcreate', routeEnd: ''}); %>
<% } %>
<% if (tview.tedit) { %>
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tedit', routeEnd: '/:id'}); %>
<% } %>
<% if (tview.tread) { %>
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tread', routeEnd: '/:id'}); %>
<% } %>
<% if (tview.tdelete) { %>
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tdelete', routeEnd: '/:id'}); %>
<% } %>
}
<% if (tview.tlist) { %>
function <%= tview.tlist.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tlist.texport.angular.tcontroller.postfix %>(<%= tview.tlist.texport.angular.tcontroller.argu %>) {
$http.get('<%= tapiPrefix %>/<%= tview.tlist.texport.json.tslug %>').success(function(data, status, headers, config) {
$scope.data = data.data;
});
}
<% } %>
<% if (tview.tcreate) { %>
function <%= tview.tcreate.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tcreate.texport.angular.tcontroller.postfix %>(<%= tview.tcreate.texport.angular.tcontroller.argu %>) {
$scope.data = {};
$scope.tcreateData = function () {
$http.post('<%= tapiPrefix %>/<%= tview.tcreate.texport.json.tslug %>', $scope.data).success(function(data) {
<% if (tview.tlist) { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
<% } else { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
<% } %>
});
}
<%- include('controller-action-none', {tview: tview,taction: 'tcreate'}); %>
}
<% } %>
<% if (tview.tread) { %>
function <%= tview.tread.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tread.texport.angular.tcontroller.postfix %>(<%= tview.tread.texport.angular.tcontroller.argu %>) {
$scope.data = {};
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
$scope.data = data.data;
});
<%- include('controller-action-none', {tview: tview,taction: 'tread'}); %>
}
<% } %>
<% if (tview.tedit) { %>
function <%= tview.tedit.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tedit.texport.angular.tcontroller.postfix %>(<%= tview.tedit.texport.angular.tcontroller.argu %>) {
$scope.data = {};
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
$scope.data = data.data;
});
$scope.teditData = function () {
$http.put('<%= tapiPrefix %>/<%= tview.tedit.texport.json.tslug %>/' + $routeParams.id, $scope.data ).success(function(data) {
<% if (tview.tread) { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.texport.angular.tslug %>/' + $routeParams.id);
<% } else { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
<% } %>
});
}
<%- include('controller-action-none', {tview: tview,taction: 'tedit'}); %>
}
<% } %>
<% if (tview.tdelete) { %>
function <%= tview.tdelete.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tdelete.texport.angular.tcontroller.postfix %>(<%= tview.tdelete.texport.angular.tcontroller.argu %>) {
$scope.data = {};
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
$scope.data = data.data;
});
$scope.tdeleteData = function () {
$http.delete('<%= tapiPrefix %>/<%= tview.tdelete.texport.json.tslug %>/'+ $routeParams.id, $scope.data).success(function(data) {
<% if (tview.tlist) { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
<% } else { %>
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
<% } %>
});
}
<%- include('controller-action-none', {tview: tview,taction: 'tdelete'}); %>
}
<% } %>

View file

@ -0,0 +1,20 @@
<h2>Create <%= tview.tname %></h2>
<div class="row">
<div class="col-lg-8">
<form role="form">
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
<div class="form-group">
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="form-control"></input>
</div>
<% }) %>
<button type="submit" class="btn btn-default" ng-click="tcreateData()">Submit</button>
<button type="submit" class="btn btn-default" ng-click="tcreateNone()">Cancel</button>
</form>
</div>
<div class="col-lg-4"></div>
</div>
<!--
06 308 500 37
-->

View file

@ -0,0 +1,6 @@
<h2>Delete <%= tview.tname %></h2>
<div>
<p>Are you sure you want to delete this <%= tview.tname %> {{data._id}} ?</p>
<button ng-click="tdeleteData()">Yes</button> | -
<button ng-click="tdeleteNone()">No thanks</button>
<div>

View file

@ -0,0 +1,16 @@
<h2> Edit <%= tview.tname %></h2>
<div class="row">
<div class="col-lg-8">
<form role="form">
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
<div class="form-group">
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="form-control"></input>
</div>
<% }) %>
<button type="submit" class="btn btn-default" ng-click="teditData()">Submit</button>
<button type="submit" class="btn btn-default" ng-click="teditNone()">Cancel</button>
</form>
<div class="col-lg-4"></div>
</div>

View file

@ -0,0 +1,50 @@
<p>There are {{data.length}} <%= tview.tplural %></p>
<% if (tview.tcreate) { %>
<p>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tcreate.texport.angular.tslug %>">Create New</a>
</p>
<% } %>
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<% if (tview.tread) { %><th>Open</th><% } %>
<% if (tview.tedit) { %><th>Edit</th><% } %>
<% if (tview.tdelete) { %><th>Delete</th><% } %>
<% tview.tlist.tfields.forEach(function (fieldKey) { %>
<th><%= tview.tmeta.tfields[fieldKey].tname %></th>
<% }) %>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in data">
<% if (tview.tread) { %>
<td>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.texport.angular.tslug %>/{{row._id}}">Read</a>
</td>
<% } %>
<% if (tview.tedit) { %>
<td>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tedit.texport.angular.tslug %>/{{row._id}}">Edit</a>
</td>
<% } %>
<% if (tview.tdelete) { %>
<td>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tdelete.texport.angular.tslug %>/{{row._id}}">Delete</a>
</td>
<% } %>
<% tview.tlist.tfields.forEach(function (fieldKey) { %>
<td>{{row.<%= tview.tmeta.tfields[fieldKey].tid %>}}</td>
<% }) %>
</tr>
</tbody>
</table>
</div>
<% if (tview.tcreate) { %>
<p>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tcreate.texport.angular.tslug %>">Create New</a>
</p>
<% } %>

View file

@ -0,0 +1,19 @@
<section>
<h2> {{data._id}} </h2>
<% if (tview.tedit) { %>
<p>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tedit.texport.angular.tslug %>/{{data._id}}">Edit</a>
</p>
<% } %>
<% if (tview.tdelete) { %>
<p>
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tdelete.texport.angular.tslug %>/{{data._id}}">Delete</a>
</p>
<% } %>
<% tview.tread.tfields.forEach(function (fieldKey) { %>
<p><%= tview.tmeta.tfields[fieldKey].tname %>: {{data.<%= tview.tmeta.tfields[fieldKey].tid %>}}</p>
<% }) %>
<p>
<button ng-click="treadNone()">Back</button>
</p>
<sector>

View file

@ -0,0 +1 @@
# CSV: <%= tview.tid %>

View file

@ -0,0 +1 @@
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %>

View file

@ -0,0 +1 @@
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %>

View file

@ -0,0 +1 @@
</<%= tview.tid %>List>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<<%= tview.tid %>List>

View file

@ -0,0 +1,5 @@
<<%= tview.tid %>>
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
<% }) %>
</<%= tview.tid %>>

View file

@ -0,0 +1,2 @@
</<%= tview.tid %>List>
</data>

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<data>
<<%= tview.tid %>List>

View file

@ -0,0 +1,5 @@
<<%= tview.tid %>>
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
<% }) %>
</<%= tview.tid %>>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<data>
<<%= tview.tid %>>
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
<% }) %>
</<%= tview.tid %>>
</data>

View file

@ -0,0 +1,75 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
net_id: {
type: String,
index: { unique: false },
tfield: {
tvalidate: { io: 'string' },
},
},
command: {
type: String,
tfield: {
tvalidate: { io: 'string' },
},
},
insert_ip: {
type: String,
tfield: {
tvalidate: { io: 'string' },
},
},
insert_date: {
type: Date,
default: Date.now,
tfield: {
tlist: { tenable: false },
},
},
send_date: {
type: Date
},
done_date: {
type: Date
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findByNetIdLimit10: function (net_id, callback) {
logger.debug(modelBackend+'.findByNetId net_id='+net_id);
this.find({net_id:net_id}).sort('-insert_date').limit(10).exec(callback);
},
findOpenByNetId: function (net_id, callback) {
logger.debug(modelBackend+'.findOpenByNetId net_id='+net_id);
this.find({net_id:net_id}).where('send_date',null).sort('insert_date').limit(1).exec(callback);
},
findOpenCommandLimit5: function (callback) {
logger.debug(modelBackend+'.findOpenCommands');
var dateLastHour = new Date(new Date().getTime() - 30*60*1000); // soft limit on long open errors.
this.find({insert_date: { $gt: dateLastHour}}).where('send_date',null).sort('insert_date').limit(5).exec(callback);
},
findSendCommandLimit5: function (callback) {
logger.debug(modelBackend+'.findSendCommands');
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
this.find({send_date: { $gt: dateLastHour}}).sort('-insert_date').limit(5).exec(callback);
},
insert: function (net_id,command,insert_ip, next) {
var xcmd = new this();
xcmd.net_id = net_id;
xcmd.command = command;
xcmd.insert_ip = insert_ip;
xcmd.save(function(err,xcmd) {
if (err) { return next(err); }
logger.debug(modelBackend+'.insert _id='+xcmd._id+' net_id='+xcmd.net_id);
});
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,98 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
net_id: {
type: String,
index: { unique: true },
tfield: {
tvalidate: { io: 'string' },
},
},
net_key: {
type: String,
tfield: {
tvalidate: { io: 'string' },
tlist: { tenable: false },
},
},
net_mac: {
type: String,
tcrud: {
tname: 'Net MAC',
tlist: { tenable: false },
}
},
rf_key: {
type: String,
tfield: {
tname: 'RF Key',
tlist: { tenable: false },
}
},
init_index: {
type: Number,
tfield: {
tlist: { tenable: false },
}
},
ping_counter: {
type: Number,
default: 0,
tfield: {
tname: 'Ping #'
}
},
ping_last_date: {
type: Date,
index: { unique: true, sparse: true }
},
ping_rtt: {
type: Number,
default: 0,
tfield: {
tname: 'Ping RTT'
}
},
changed_date: {
type: Date,
default: Date.now,
tfield: {
tlist: { tenable: false },
}
},
created_date: {
type: Date,
default: Date.now,
tfield: {
tlist: { tenable: false },
}
},
created_ip: {
type: String,
tfield: {
tvalidate: { io: 'string' },
},
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findOneByNetId: function (net_id, callback) {
logger.debug(modelBackend+'.findByNetId net_id='+net_id);
this.findOne({net_id:net_id}).exec(callback);
},
findLastPingLimit5: function (callback) {
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
logger.debug(modelBackend+'.findLastPinged lastDate: '+dateLastHour);
this.find({}).where('ping_last_date').gt(dateLastHour).sort('-ping_last_date').limit(5).exec(callback);
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,59 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
/*
uuid: {
type: String,
index: { unique: true },
tfield: {
tvalidate: { io: 'string' },
},
},
*/
node_id: {
type: Number,
index: { unique: false },
tfield: {
tvalidate: { io: 'number' },
},
},
insert_date: {
type: Date,
index: { unique: false },
default: Date.now,
},
name: {
type: String,
index: { unique: false },
tfield: {
tvalidate: { io: 'string' },
},
},
value: {
type: String,
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findLastAddedLimit5: function (callback) {
logger.debug(modelBackend+'.findLastAddedLimit5');
this.find({}).sort('-insert_date').limit(5).exec(callback);
},
findByNetIdAndNodeId: function (net_id,node_id, callback) {
logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id);
this
.aggregate({ $match: { net_id:net_id ,node_id:node_id }})
.group({ _id: "$name", value: { $min : "$value" } })
.sort("_id")
.exec(callback);
//this.find({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback);
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,53 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
//node : {type : Schema.ObjectId, ref : 'XNode'}
node_id: {
type: Number,
index: { unique: false },
tfield: {
tvalidate: { io: 'number' },
},
},
data_raw: {
type: String,
tfield: {
ttype: 'textarea',
tvalidate: { io: 'string' },
tlist: { tenable: false },
}
},
data_text: {
type: String,
tfield: {
tvalidate: { io: 'number' },
ttype: 'textarea',
}
},
remote_ip: {
type: String,
tfield: {
tname: 'Remote IP',
tvalidate: { io: 'ip_address' },
tlist: { tenable: false },
}
},
insert_date: {
type: Date, default: Date.now,
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findLastLimit5: function (callback) {
logger.debug(modelBackend+'.findLastLimit5');
this.find({}).sort('-insert_date').limit(5).exec(callback);
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,98 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
net_id: {
type: String,
index: { unique: false },
tfield: {
tvalidate: { io: 'string' },
},
},
node_id: {
type: Number,
index: { unique: false },
tfield: {
tvalidate: { io: 'number' },
},
},
insert_date: {
type: Date,
index: { unique: false },
default: Date.now,
tfield: {
tlist: { tenable: false },
}
},
info_date: {
type: Date,
tfield: {
tlist: { tenable: false },
}
},
name: {
type: String,
},
description: {
type: String,
tfield: {
tlist: { tenable: false },
}
},
gps_latitude: {
type: Number,
tfield: {
tname: 'Latitude',
tlist: { tenable: false },
}
},
gps_longitude: {
type: Number,
tfield: {
tname: 'Longitude',
tlist: { tenable: false },
}
},
rx_bytes: {
type: Number,
default: 0,
tfield: {
tname: 'RX bytes'
}
},
rx_requests: {
type: Number,
default: 0,
tfield: {
tname: 'RX req#'
}
},
rx_date: {
type: Date,
index: { unique: false },
default: Date.now,
tfield: {
tname: 'RX Date'
}
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findByNetId: function (net_id, callback) {
logger.debug(modelBackend+'.findByNetId net_id='+net_id+"");
this.find({net_id:net_id}).sort('insert_date').exec(callback);
},
findByNetIdAndNodeId: function (net_id,node_id, callback) {
logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id);
this.findOne({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback);
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,35 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
_id: {
type: String,
tfield: {
tname: 'SID',
ttype: 'textarea'
}
},
session: {
type: String,
tfield: {
ttype: 'textarea'
}
},
expires: {
type: Date,
},
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findLastChangedLimit5: function (callback) {
logger.debug(modelBackend+'.findLastChangedLimit5');
this.find({}).sort('-changed_date').limit(5).exec(callback);
},
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,146 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
name: {
type: String,
trim: true,
index: { unique: true },
tfield: {
tvalidate: { io: 'string' },
},
},
type: {
type: String,
trim: true,
index: { unique: false },
tfield: {
tvalidate: { io: 'string' },
},
},
value: {
type: String,
trim: true,
tfield: {
xtype: 'textarea',
tvalidate: { io: 'string' },
},
},
description: {
type: String,
trim: true,
tfield: {
ttype: 'textarea',
tvalidate: { io: 'string' },
},
},
changed_date: {
type: Date,
default: Date.now,
tfield: {
tlist: { tenable: false },
},
},
created_date: {
type: Date,
default: Date.now,
tfield: {
tlist: { tenable: false },
},
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findLastChangedLimit5: function (callback) {
logger.debug(modelBackend+'.findLastChangedLimit5');
this.find({}).sort('-changed_date').limit(5).exec(callback);
},
findOneByName: function (name, callback) {
logger.debug(modelBackend+'.findByName name='+name);
this.findOne({name:name}).exec(callback);
},
ensureExcists: function (name, type, defaultValue, description, callback) {
this.findOneByName(name, function(err, xprop) {
if (err) {
callback(err);
return;
}
if (xprop == null) {
logger.debug(modelBackend+'.getByName create name='+name+' defaultValue='+defaultValue);
var model = mongoose.model(modelName);
xprop = new model();
xprop.name = name;
xprop.type = type;
xprop.value = defaultValue;
xprop.description = description;
xprop.save(function(err,xprop) {
if (callback) {
callback(err, xprop);
}
});
} else {
logger.debug(modelBackend+'.getByName fetched name='+name);
if (callback) {
callback(null, xprop);
}
}
});
},
setByName: function (name, value, callback) {
this.findOneByName(name, function(err, xprop) {
if (err) { throw err }
logger.debug(modelBackend+'.setByName name='+name+' valueNew='+value+' valueOld='+xprop.value);
xprop.value = value;
xprop.save(function(err) {
callback(err, xprop);
});
});
},
incByName: function (name, callback) {
this.findOneByName(name, function(err, xprop) {
if (err) { throw err }
xprop.value++;
logger.debug(modelBackend+'.incByName name='+name+' value='+xprop.value);
xprop.save(function(err) {
callback(err, xprop);
});
});
},
incHexByName: function (name, callback) {
this.findOneByName(name, function(err, xprop) {
// DIY inc per 8 chars as JS goes to ~14chars before zering the rest.
var v = xprop.value;
var r = '';
var inc = true;
for (var i=0;i<v.length/8;i++) {
var sv = v.substring(v.length-(i*8)-8,v.length-(i*8));
var svNum = parseInt(sv, 16);
if (inc) {
svNum++;
inc = false;
}
if (svNum == (1+0xFFFFFFFF)) {
svNum = 0;
inc = true;
}
sv = svNum.toString(16).toUpperCase();
while (i<((v.length/8)-1) && sv.length < 8) {
sv = '0' + sv;
}
r = sv + r;
}
xprop.value = r; ///(parseInt(xprop.value, 16)+1).toString(16).toUpperCase();
logger.debug(modelBackend+'.incHexByName name='+name+' value='+xprop.value);
xprop.save(function(err) {
callback(err, xprop);
});
});
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,46 @@
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
var modelName = __filename.split('/').pop().split('.')[0];
var modelBackend = modelName.split('-').join('_');
var modelMeta = {
username: {
type: String,
trim: true,
index: { unique: true },
tfield: {
tvalidate: { io: 'string' },
},
},
password: {
type: String
},
active: {
type: Boolean,
default: true
},
changed_date: {
type: Date,
default: Date.now
},
created_date: {
type: Date,
default: Date.now
}
};
var modelSchema = new mongoose.Schema(modelMeta);
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
findLastChangedLimit5: function (callback) {
logger.debug(modelBackend+'.findLastChangedLimit5');
this.find({}).sort('-changed_date').limit(5).exec(callback);
},
findOneByUsername: function (username, callback) {
logger.debug(modelBackend+'.findByName username='+username);
this.findOne({username:username}).exec(callback);
}
});
module.exports = mongoose.model(modelName, modelSchema, modelBackend);

View file

@ -0,0 +1,38 @@
var favicon = require('static-favicon');
var morgan = require('morgan')
var cookieParser = require('cookie-parser')
var bodyParser = require('body-parser');
var express = require('express');
var tcrud = require('./lib/node-ff-tcrud');
var xdeviceA = require('./device/xdevice-connector-a');
var renderIndex = function(server) {
return function (req, res, next) {
res.render('index', {
pageTitle: server.get('config').application.index.pageTitle,
pageKeywords: server.get('config').application.index.pageKeywords,
pageCssFiles: server.get('ff_assets_css'),
pageJsFiles: server.get('ff_assets_js'),
});
}
}
exports.initConfig = function(server,config) {
server.use(favicon());
server.use(morgan(config.options.morgan.logLevel));
server.use(cookieParser(config.options.cookieParser.secretKey));
server.use(bodyParser.json());
server.use(bodyParser.urlencoded());
server.post('/_a', xdeviceA.deviceControl);
tcrud.factory.express.buildCrudApi(server);
server.get('/api/json/server/uptime', tcrud.factory.express.renderServerUptime());
server.get('/api/json/server/routes', tcrud.factory.express.renderServerRoutes(server));
server.get('/', tcrud.factory.express.sendRedirect('/ui'));
server.get('/ui', renderIndex(server));
server.get('/ui/thtml/*', tcrud.factory.express.renderTemplatePath('thtml/'));
server.get('/ui/*', renderIndex(server)); // must be last; for HTML5 history
}

View file

@ -0,0 +1,44 @@
{
"name": "xnode-debug-server",
"description": "XNode Debug Server",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node server.js",
"size": "npm run-script size-json;npm run-script size-html;npm run-script size-code",
"size-code": "find . -type f -name '*.js' |egrep -v '/node_modules|/lib' | xargs wc -l",
"size-json": "find . -type f -name '*.json' |egrep -v '/node_modules|/lib' | xargs wc -l",
"size-html": "find . -type f -name '*.ejs' |egrep -v '/node_modules|/lib' | xargs wc -l"
},
"dependencies": {
"async": "~0.9.0",
"body-parser": "~1.0.1",
"bootstrap": "3.3.2",
"clone": "^1.0.0",
"connect-mongo": "^0.7.0",
"cookie-parser": "^1.0.1",
"crud-mongoose": "^1.0.10",
"ejs": "^2.3.1",
"errorhandler": "^1.1.1",
"express": "^4.11.0",
"express-session": "^1.10.3",
"fetch": "^0.3.6",
"flot": "0.8.0-alpha",
"fs-extra": "^0.16.3",
"mongoose": "~3.8.13",
"morgan": "~1.1.1",
"node-crud": "2.0.8",
"node-ff-assets": "^0.2.4",
"raw-body": "1.2.2",
"static-favicon": "~1.0.0",
"tree-surgeon": "0.0.13",
"type-is": "1.1.0",
"underscore": "^1.8.2",
"validate.io": "^1.5.0",
"winston": "~0.7.3",
"xml-mapping": "~1.6.1"
},
"devDependencies": {
"mocha-jshint": "0.0.9"
}
}

View file

@ -0,0 +1,27 @@
{
"linkMapping" : {
"/static/module/bootstrap/": "node_modules/bootstrap/dist/",
"/static/module/flot/": "node_modules/flot/",
"/static/": "www_static/"
},
"css": {
"linkTarget": "/static/css/lib/assets.css",
"linkSources": [
"/static/module/bootstrap/css/bootstrap.css"
]
},
"js": {
"linkTarget": "/static/js/lib/assets.js",
"linkSources": [
"/static/js/lib/jquery-2.1.3/jquery.js@http://code.jquery.com/jquery-2.1.3.js",
"/static/module/bootstrap/js/bootstrap.js",
"/static/module/flot/jquery.flot.js",
"/static/module/flot/jquery.flot.resize.js",
"/static/module/flot/jquery.flot.pie.js",
"/static/js/lib/angularjs-1.4.0-b4/angular.js@https://code.angularjs.org/1.4.0-beta.4/angular.js",
"/static/js/lib/angularjs-1.4.0-b4/angular-route.js@https://code.angularjs.org/1.4.0-beta.4/angular-route.js",
"/static/js/lib/angularjs-1.4.0-b4/angular-resource.js@https://code.angularjs.org/1.4.0-beta.4/angular-resource.js",
"/static/js/lib/angularjs-1.4.0-b4/angular-touch.js@https://code.angularjs.org/1.4.0-beta.4/angular-touch.js"
]
}
}

View file

@ -0,0 +1,71 @@
module.exports = {
winston: {
console: {
level: 'debug',
silent: false,
colorize: true,
timestamp: null
},
file: {
level: 'info',
silent: false,
colorize: false,
json: false,
//timestamp: null,
//maxFiles: 100,
//maxsize: 1024*1024*1024,
filename: 'www_logs/server.log'
}
},
mongo: {
url: process.env.MONGO_URL || 'mongodb://localhost:27017/xnode-debug-server',
options : {
//user: 'myUserName',
//pass: 'myPassword',
db: {
fsync: false,
journal: false,
native_parser: true,
forceServerObjectId: true
},
server: {
poolSize: 4,
socketOptions: {
connectTimeoutMS: 500,
keepAlive: 1,
auto_reconnect: true
}
}
}
},
server: {
httpPort: process.env.HTTP_PORT || 8008,
httpTrustProxy: true,
sessionSecret: 'xensitXDS',
sessionTTL: 14 * 24 * 60 * 60, // = 14 days. Default
},
application: {
name: 'Xensit Debug Server',
index: {
pageTitle: 'Xensit Debug Server',
pageKeywords: 'xnode,sensor,data,weather,wireless',
},
},
options: {
static: {
maxAge: 86400000
},
morgan: {
logLevel: process.env.LOG_MORGAN || 'dev'
},
cookieParser: {
secretKey: 'DeBugMe@11'
},
rss: {
link: 'http://localhost:8008',
author: 'Xensit',
options: {
}
}
}
};

View file

@ -0,0 +1,102 @@
'use strict';
var logger = require('winston').loggers.get('main');
var mongoose = require('mongoose');
var async = require('async');
var fs = require('fs');
var tcrud = require('./node_lib/lib/node-ff-tcrud');
var assets = require('node-ff-assets');
var xsystemState = mongoose.model( 'xsystem-state' );
function walkTree(builderConfigJs,server,crud) {
if (crud.tparent && crud.tenable && crud.tmodel) {
var localPort = server.get('config').server.httpPort;
var tview = tcrud.build.view.createTCrudView(crud/*, fetchCrudRoles()*/);
var base = troot.tmeta.tserver.tslug + '/' + tcrud.build.view.createBaseApiUri(tview,'angular');
var assetLink = '/static/js/lib/tcrud/'+tview.tslug+'/controller.js@@http://localhost:'+localPort+base+'/controller.js';
//console.log('asssetLinkDyna; '+assetLink);
builderConfigJs.linkSources.push(assetLink);
}
for (var i = 0; i < crud.tchilds.length; i++) {
walkTree(builderConfigJs,server,crud.tchilds[i]);
}
}
function pushDynamicLinkSourcesJs(builderConfigJs,server) {
return function(callback) {
// Extend js list with crud entries
troot = server.get('ff_root_tcrud_view');
walkTree(builderConfigJs,server,troot);
callback();
};
}
function buildAssets(server,callbackDone) {
var singleResult = 'false' !== process.env.DEV_ASSETS_SINGLE_RESULT;
var assetsConfig = require('./server-assets.json');
assets.build({
assets: {
js: {
configCreate: assets.factory.builder.configCreate.fromJSON(assetsConfig,'js'),
configFill: function (config, callback) {
async.series([
assets.factory.lib.async.pushLinkSources(config, '/static/js/', 'www_static/js/'),
assets.factory.lib.async.pushLinkSources(config, '/static/js/controller/', 'www_static/js/controller/'),
pushDynamicLinkSourcesJs(config,server),
],callback);
},
},
css: {
configCreate: assets.factory.builder.configCreate.fromJSON(assetsConfig,'css'),
configFill: function (config, callback) {
async.series([
assets.factory.lib.async.pushLinkSources(config, '/static/css/', 'www_static/css/'),
],callback);
},
//assemblerCreate: function (assemblerConfig, callback) {
// callback(null,new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileMinify()));
//},
},
},
// assemblerCreate: assets.factory.builder.assemblerCreate.readFileRegex(),
assemblerFill: function (assembler, callback) {
var serverResultKey = 'ff_assets_'+assembler.config.assetType;
assembler.on ('log', assets.factory.assembler.event.log.winston(logger,assembler.config.assetType));
assembler.on ('result', assets.factory.assembler.event.result.objectSet(server,serverResultKey));
assembler.config.linkTargetSingleResult = singleResult;
callback();
},
},callbackDone);
}
var initServerStateValue = function(server,type,name,defaultValue,description) {
xsystemState.ensureExcists(name,type,defaultValue,description,function(err,data) {
if (err) { throw err }
logger.info('state checked: '+data.name);
});
}
exports.build = function(server) {
buildAssets(server,function(err) {
if (err) {
logger.info('Server init failed: '+err);
return;
}
logger.info('Server init done.');
// init other stuff...
initServerStateValue(server,'_a','_a_seq_base_net_id', '1F2E3D4C5B6A','XNode Base net_id sequence');
initServerStateValue(server,'_a','_a_seq_base_net_key' ,'9A2EE3A293486E9FE73D77EFC8087D2F','XNode Base net_key sequence')
initServerStateValue(server,'_a','_a_seq_base_net_mac', '7469694D33B1','XNode Base net_mac sequence')
initServerStateValue(server,'_a','_a_seq_base_rf_key', '1A2B93586E9F170D72EFC8FE72D53A9F','XNode Base rf_key sequence');
initServerStateValue(server,'xds','xds_boot_date',new Date().getTime(),'Server Last boot date');
initServerStateValue(server,'xds','xds_boot_count','0','Server Boot Counter');
setTimeout(function() {
xsystemState.incByName('xds_boot_count',function(err,data) {});
xsystemState.setByName('xds_boot_date',new Date().getTime(),function(err,data) {});
}, 500);
});
}

View file

@ -0,0 +1,115 @@
// server.js
var config = require('./server-config');
var winston = require('winston');
winston.loggers.add('main',config.winston);
var log = winston.loggers.get('main');
var express = require('express');
var path = require('path');
var fs = require('fs');
var mongoose = require('mongoose');
var expressSession = require('express-session');
var mongoStore = require('connect-mongo')(expressSession);
var tcrud = require('./node_lib/lib/node-ff-tcrud');
function startMongoose(callback) {
log.info('Starting '+config.application.name);
log.info('Connecting to: ' + config.mongo.url);
mongoose.connection.on('error', callback);
mongoose.connection.on('connected', callback);
mongoose.connect(config.mongo.url,config.mongo.options);
}
function startMongooseModels(server,callback) {
var modelsCount = 0;
var modelsPath = __dirname + '/node_lib/model';
fs.readdirSync(modelsPath).forEach(function (file) {
if (~file.indexOf('.js')) {
log.debug('Loading mongoose model: '+file);
require(modelsPath + '/' + file);
modelsCount++;
}
});
log.info('Loaded mongoose models: '+modelsCount);
var crudRoot = tcrud.build.config.createTCrudRoot();
var crudAdmin = tcrud.build.config.createTCrud(crudRoot,'admin');
crudAdmin.troles.push('admin');
//crudAdmin.tenable = false;
var crudAdminModels = tcrud.build.backend.mongoose.buildTCrudModels(mongoose,crudAdmin);
log.info('crud admin models created: '+crudAdminModels.length);
//var crudAdminNodeBaseCmd = crudAdmin
server.set('ff_root_tcrud_view',crudRoot);
callback();
}
// Build Server
function createServerSync() {
var server = express();
server.disable('x-powered-by');
server.set('config', config);
server.set('trust proxy', config.server.httpTrustProxy);
server.set('views', [path.join(__dirname, 'www_views'),path.join(__dirname, 'node_lib/lib/www_views')]);
server.set('view engine', 'ejs');
server.use('/static',express.static(path.join(__dirname,'www_static'),config.options.static));
server.use('/static/module/bootstrap',express.static(path.join(__dirname,'node_modules/bootstrap/dist'),config.options.static));
server.use('/static/module/flot',express.static(path.join(__dirname,'node_modules/flot'),config.options.static));
// Add Server session support
// server.use(expressSession({
// secret: config.server.sessionSecret,
// store: new mongoStore({
// mongooseConnection: mongoose.connection,
// collection: 'xsystem_session',
// ttl: server.sessionTTL,
// })
// }));
return server;
}
function configServer(server,callback) {
// Add Server config and routing
var router = require('./node_lib/server-build');
router.initConfig(server,config);
// Store router list for server/routes page
tcrud.factory.express.buildServerRoutes(server);
// Auto build site assets
var ServerInit = require('./server-init');
ServerInit.build(server);
// Test
//var test = require('./node_lib/device/xdevice-encryption');
//log.info('testA='+test.xxteaDecrypt('D57408F9D7F10917AFE9AA92C8051450','9A2EE3A293486E9FE73D77EFC8087D31'));
//log.info('testA='+test.xxteaDecrypt('9A2EE3A293486E9F','D57408F9D7F10917AFE9AA92C8051450'));
//log.info('testB=rf_fail=1');
//log.info('testC='+test.xxteaDecrypt('944DF85BAEE43DC0D7914910D2B69547','9A2EE3A293486E9F'));
callback();
}
function startServer(server) {
server.listen(config.server.httpPort);
log.info('Started '+config.application.name+' on port: ' + config.server.httpPort);
}
startMongoose(function(err) {
if (err) { throw err };
server = createServerSync();
startMongooseModels(server,function(err) {
if (err) { throw err };
configServer(server,function(err) {
if (err) { throw err };
startServer(server)
});
});
});
module.exports = {
version: 'development'
};

View file

@ -0,0 +1,149 @@
body {
margin-top: 100px;
background-color: #222;
}
@media(min-width:768px) {
body {
margin-top: 50px;
}
}
#wrapper {
padding-left: 0;
}
#page-wrapper {
width: 100%;
padding: 0;
background-color: #fff;
}
.huge {
font-size: 50px;
line-height: normal;
}
@media(min-width:768px) {
#wrapper {
padding-left: 225px;
}
#page-wrapper {
padding: 10px;
}
}
/* Top Navigation */
.top-nav {
padding: 0 15px;
}
.top-nav>li {
display: inline-block;
float: left;
}
.top-nav>li>a {
padding-top: 15px;
padding-bottom: 15px;
line-height: 20px;
color: #999;
}
.top-nav>li>a:hover,
.top-nav>li>a:focus,
.top-nav>.open>a,
.top-nav>.open>a:hover,
.top-nav>.open>a:focus {
color: #fff;
background-color: #000;
}
.top-nav>.open>.dropdown-menu {
float: left;
position: absolute;
margin-top: 0;
border: 1px solid rgba(0,0,0,.15);
border-top-left-radius: 0;
border-top-right-radius: 0;
background-color: #fff;
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
box-shadow: 0 6px 12px rgba(0,0,0,.175);
}
.top-nav>.open>.dropdown-menu>li>a {
white-space: normal;
}
ul.message-dropdown {
padding: 0;
max-height: 250px;
overflow-x: hidden;
overflow-y: auto;
}
li.message-preview {
width: 275px;
border-bottom: 1px solid rgba(0,0,0,.15);
}
li.message-preview>a {
padding-top: 15px;
padding-bottom: 15px;
}
li.message-footer {
margin: 5px 0;
}
ul.alert-dropdown {
width: 200px;
}
/* Side Navigation */
@media(min-width:768px) {
.side-nav {
position: fixed;
top: 51px;
left: 225px;
width: 225px;
margin-left: -225px;
border: none;
border-radius: 0;
overflow-y: auto;
background-color: #222;
}
.side-nav>li>a {
width: 225px;
}
.side-nav li a:hover,
.side-nav li a:focus {
outline: none;
background-color: #000 !important;
}
}
.side-nav>li>ul {
padding: 0;
}
.side-nav>li>ul>li>a {
display: block;
padding: 10px 15px 10px 38px;
text-decoration: none;
color: #999;
}
.side-nav>li>ul>li>a:hover {
color: #fff;
}
.huge {
font-size: 40px;
}

View file

@ -0,0 +1,11 @@
.flot-chart {
display: block;
height: 400px;
}
.flot-chart-content {
width: 100%;
height: 100%;
}

View file

@ -0,0 +1,56 @@
.panel-green {
border-color: #5cb85c;
}
.panel-green .panel-heading {
border-color: #5cb85c;
color: #fff;
background-color: #5cb85c;
}
.panel-green a {
color: #5cb85c;
}
.panel-green a:hover {
color: #3d8b3d;
}
.panel-red {
border-color: #d9534f;
}
.panel-red .panel-heading {
border-color: #d9534f;
color: #fff;
background-color: #d9534f;
}
.panel-red a {
color: #d9534f;
}
.panel-red a:hover {
color: #b52b27;
}
.panel-yellow {
border-color: #f0ad4e;
}
.panel-yellow .panel-heading {
border-color: #f0ad4e;
color: #fff;
background-color: #f0ad4e;
}
.panel-yellow a {
color: #f0ad4e;
}
.panel-yellow a:hover {
color: #df8a13;
}

View file

@ -0,0 +1,54 @@
#wrapper {
padding-right: 0px;
padding-left: 0px;
}
.side-nav {
right: 0px;
left: 0px;
}
.btn {
margin-right: 10px;
}
.navbar-footer {
margin-left: 45%;
}
.navbar-toggle {
display: none;
}
.navbar-brand {
background-color: #2CABE1;
}
.navbar-inverse .navbar-brand {
color: #FFFFFF;
}
.navbar-inverse .navbar-brand:focus {
outline: none;
}
.navbar-inverse .navbar-brand:hover {
background-color: #FF9A28;
outline: none;
}
.navbar-inverse {
background-color: #2CABE1;
}
#menuLogo {
position: absolute;
top: 47px;
right: 0px;
background: url("../img/xensit-sm.png") 50% 0px no-repeat transparent !important;
height: 77px;
width: 212px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

@ -0,0 +1,13 @@
pageRouteInit.push(function ($routeProvider, $locationProvider) {
$routeProvider.when('/ui/server/about', {
templateUrl: '/ui/thtml/server/about',
controller: XPageServerAbout
});
});
function XPageServerAbout($scope, $http) {
//$http.get('/api/posts').success(function(data, status, headers, config) {
// $scope.posts = data.posts;
//});
}

View file

@ -0,0 +1,14 @@
pageRouteInit.push(function ($routeProvider, $locationProvider) {
$routeProvider.when('server/dash', {
templateUrl: '/ui/thtml/server/dash',
controller: XPageServerDash
});
});
function XPageServerDash($scope, $http) {
//$http.get('/api/posts').success(function(data, status, headers, config) {
// $scope.posts = data.posts;
//});
}

View file

@ -0,0 +1,13 @@
pageRouteInit.push(function ($routeProvider, $locationProvider) {
$routeProvider.when('/ui', {
templateUrl: '/ui/thtml/server/index',
controller: XPageServerIndex
});
});
function XPageServerIndex($scope, $http) {
//$http.get('/api/posts').success(function(data, status, headers, config) {
// $scope.posts = data.posts;
//});
}

View file

@ -0,0 +1,26 @@
pageRouteInit.push(function ($routeProvider, $locationProvider) {
$routeProvider.when('/ui/server/routes', {
redirectTo: '/ui/server/routes/tech',
});
$routeProvider.when('/ui/server/routes/tech', {
templateUrl: '/ui/thtml/server/routes?group1=all,rss,json&group2=csv,xml,ui,angular',
controller: XPageServerTechRoutes,
});
$routeProvider.when('/ui/server/routes/model', {
templateUrl: '/ui/thtml/server/routes?group1=xnode,xnode_base,xnode-base-command&group2=xnode-data,xnode-data-value,xsystem-state,all',
controller: XPageServerModelRoutes,
});
});
function XPageServerTechRoutes($scope, $http) {
$http.get('/api/json/server/routes?groups=json,xml,rss,csv,ui,angular').success(function(data, status, headers, config) {
$scope.serverRoutes = data.data;
});
}
function XPageServerModelRoutes($scope, $http) {
$http.get('/api/json/server/routes?groups=xnode,xnode-base,xnode-base-command,xnode-data,xnode-data-value,system-state').success(function(data, status, headers, config) {
$scope.serverRoutes = data.data;
});
}

View file

@ -0,0 +1,9 @@
'use strict';
angular.module('xdsUI.directives', []).
directive('appVersion', ['version', function(version) {
return function(scope, elm, attrs) {
elm.text(version);
};
}]);

View file

@ -0,0 +1,9 @@
'use strict';
angular.module('xdsUI.filters', []).
filter('interpolate', ['version', function(version) {
return function(text) {
return String(text).replace(/\%VERSION\%/mg, version);
}
}]);

View file

@ -0,0 +1,5 @@
'use strict';
angular.module('xdsUI.services', []).
value('version', '0.1');

View file

@ -0,0 +1,27 @@
'use strict';
var crudRouteInit = [];
var pageRouteInit = [];
angular.module('xdsUI', ['ngRoute','xdsUI.filters', 'xdsUI.services', 'xdsUI.directives']).
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
// init page controllers
for (var i = 0; i < pageRouteInit.length; i++) {
pageRouteInit[i]($routeProvider, $locationProvider);
}
// init crud controllers
for (var i = 0; i < crudRouteInit.length; i++) {
crudRouteInit[i]($routeProvider, $locationProvider);
}
//$routeProvider.otherwise("/404", {
// templateUrl: "partials/404.html",
// controller: "PageCtrl"
//});
$routeProvider.otherwise({ redirectTo: '/ui' });
// todo: add ie9 warning, base kills svg url property
$locationProvider.html5Mode({enabled: true, requireBase: false});
}]);

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en" ng-app="xdsUI">
<head>
<title><%= pageTitle %></title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="keywords" content="<%= pageKeywords %>">
<% if (pageCssFiles.length) { %><% pageCssFiles.forEach(function (cssFile) { %><link rel="stylesheet" href="<%= cssFile %>"><% }) %><% } %>
</head>
<body>
<div id="wrapper">
<div ng-include="'/ui/thtml/layout/header'"></div>
<div id="page-wrapper">
<div id="container-fluid">
<div ng-view></div>
</div>
</div>
</div>
<div ng-include="'/ui/thtml/layout/footer'"></div>
<% if (pageJsFiles.length) { %><% pageJsFiles.forEach(function (jsFile) { %><script src="<%= jsFile %>"></script><% }) %><% } %>
</body>
</html>

View file

@ -0,0 +1,7 @@
<div>
<h1>400</h1>
<h2>Page Not Found</h2>
<pre>
Please check you url.
</pre>
</div>

View file

@ -0,0 +1,7 @@
<div>
<h1>500</h1>
<h2>Server Error</h2>
<pre>
Sorry server at fault.
</pre>
</div>

View file

@ -0,0 +1,7 @@
<nav class="navbar">
<div class="navbar-footer">
<a href="/ui/">Home</a> | -
<a href="/ui/server/about">About</a> | -
<a href="/ui/server/routes">Routes<a/>
</div>
</nav>

View file

@ -0,0 +1,16 @@
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/ui/">Home</a>
<a class="navbar-brand" href="/ui/admin/xnode/list">XNodes</a>
<a class="navbar-brand" href="/ui/admin/xnode-base/list">XNodeBase</a>
<a class="navbar-brand" href="/ui/admin/xsystem-state/list">XSysState</a>
<a class="navbar-brand" href="/ui/admin/xsystem-session/list">XSysSession</a>
</div>
<div id="menuLogo"></div>
</nav>

View file

@ -0,0 +1,5 @@
<div>
<h2>About</h2>
<p>Testing debug server for xensit xnodes.</p>
<p>Internal use only.</p>
</div>

View file

@ -0,0 +1,96 @@
extends layout
block content
h1= title
div
h2 Last five node data.
table
thead
tr
th Net id
th Node Id
th Value
tbody
each row in lastData
tr
td #{row.net_id}
td #{row.node_id}
td
p #{row.insert_date}
p #{row.data_text}
div(id='split')
div(id='splitLeft')
div
h2 Last five node values.
table
thead
tr
th Net id
th Name
th Value
th insert_date
tbody
each row in lastValues
tr
td #{row.net_id}
td #{row.name}
td #{row.value}
td #{row.insert_date}
div
h2 Last five changed settings
table
thead
tr
th Name
th Value
tbody
each row in lastSettings
tr
td #{row.name}
td #{row.value}
div(id='splitRight')
div
h2 Last five pings
table
thead
tr
th Net id
th Ping Count
th Ping Last
tbody
each xnode in lastPinged
tr
td #{xnode.hw_net_id}
td #{xnode.ping_counter}
td #{xnode.ping_last_date}
div
h2 Last five open Cmds
table
thead
tr
th Net id
th Command
th Insert date
tbody
each xnode in openCommands
tr
td #{xnode.net_id}
td #{xnode.command}
td #{xnode.insert_date}
div
h2 Last five send Cmds
table
thead
tr
th Net id
th Command
th Send date
tbody
each xnode in sendCommands
tr
td #{xnode.net_id}
td #{xnode.command}
td #{xnode.send_date}

View file

@ -0,0 +1,5 @@
<div>
<h2>XNode Debug Server Home</h2>
<p>Welcome</p>
<p>Make your self at home.</p>
</div>

View file

@ -0,0 +1,17 @@
<div class="table-responsive">
<h3><%= routeGroup.toUpperCase() %></h3>
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Path</th>
<th>Method</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="route in serverRoutes['<%= routeGroup %>']">
<td>{{route.uriPath}}</td>
<td>{{route.httpMethod}}</td>
</tr>
</tbody>
</table>
</div>

View file

@ -0,0 +1,28 @@
<div>
<h2>Server Routes</h2>
<p>This page show all the nodejs express routes.</p>
<div class="row">
<% if (query.group1 && query.group2) { %>
<div class="col-lg-6">
<% query.group1.split(',').forEach(function (routeGroup) { %>
<%- include('routes-group', {routeGroup: routeGroup}); %>
<% }) %>
</div>
<div class="col-lg-6">
<% query.group2.split(',').forEach(function (routeGroup) { %>
<%- include('routes-group', {routeGroup: routeGroup}); %>
<% }) %>
</div>
<% } else if (query.group1) { %>
<div class="col-lg-12">
<% query.group1.split(',').forEach(function (routeGroup) { %>
<%- include('routes-group', {routeGroup: routeGroup}); %>
<% }) %>
</div>
<% } else { %>
<div class="col-lg-12">
<%- include('routes-group', {routeGroup: 'all'}); %>
</div>
<% } %>
</div>
</div>

View file

@ -0,0 +1,40 @@
#
# Managed debug logging
#
# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR
# Replace keywords with debug flags.
ifneq (,$(findstring NETWORK,$(DEBUG_LOGGING)))
DEBUG_NETWORK ?= -DDEBUG_NETWORK
endif
ifneq (,$(findstring RADIO,$(DEBUG_LOGGING)))
DEBUG_RADIO ?= -DDEBUG_RADIO
endif
ifneq (,$(findstring SYSTEM,$(DEBUG_LOGGING)))
DEBUG_SYSTEM ?= -DDEBUG_SYSTEM
endif
ifneq (,$(findstring SERIAL,$(DEBUG_LOGGING)))
DEBUG_SERIAL ?= -DDEBUG_SERIAL
endif
ifneq (,$(findstring SENSOR,$(DEBUG_LOGGING)))
DEBUG_SENSOR ?= -DDEBUG_SENSOR
endif
ifneq (,$(findstring ALL,$(DEBUG_LOGGING)))
DEBUG_NETWORK ?= -DDEBUG_NETWORK
DEBUG_RADIO ?= -DDEBUG_RADIO
DEBUG_SYSTEM ?= -DDEBUG_SYSTEM
DEBUG_SERIAL ?= -DDEBUG_SERIAL
DEBUG_SENSOR ?= -DDEBUG_SENSOR
endif
# Let NONE keyword override to disable.
ifeq (,$(findstring NONE,$(DEBUG_LOGGING)))
# Argragate debug flags to build.
DEBUG_FLAGS ?= \
$(DEBUG_NETWORK) \
$(DEBUG_RADIO) \
$(DEBUG_SYSTEM) \
$(DEBUG_SERIAL) \
$(DEBUG_SENSOR)
endif

View file

@ -0,0 +1,36 @@
#
# Managed libraries versions
#
# Replace libraries with versioned libraries paths.
ifneq (,$(findstring spi,$(MASTER_LIBS)))
II_SPI = $(ARD_HOME)/hardware/arduino/avr/libraries/SPI
endif
ifneq (,$(findstring rfm,$(MASTER_LIBS)))
II_RFM = ../lib-ext/rfm-69.git
endif
ifneq (,$(findstring dht,$(MASTER_LIBS)))
II_DHT = ../lib-ext/dht.git
endif
ifneq (,$(findstring ethercard,$(MASTER_LIBS)))
II_ETHERCARD = ../lib-ext/ethercard.git
endif
ifneq (,$(findstring isp-repair,$(MASTER_LIBS)))
II_ISP_REPAIR = ../lib/isp-repair
endif
ifneq (,$(findstring xnode-shared,$(MASTER_LIBS)))
II_XNODE_SHARED = ../lib/xnode-shared
endif
ifneq (,$(findstring xnode-shared-satellite,$(MASTER_LIBS)))
II_XNODE_SHARED_SATELLITE = ../lib/xnode-shared-satellite
endif
# Argragate Internal Includes to ROOT_LIBS
ROOT_LIBS = \
$(II_SPI) \
$(II_RFM) \
$(II_DHT) \
$(II_ETHERCARD) \
$(II_ISP_REPAIR) \
$(II_XNODE_SHARED) \
$(II_XNODE_SHARED_SATELLITE)

View file

@ -0,0 +1,20 @@
# Local env included makefile
# This file should be ignored in version control
# note: the ?= is so you can override those again in cmdline.
#
# Change to local arduino installation.
ARD_HOME ?= /home/willemc/devv/avr/ide/arduino-1.6.0
# Default port to isp
# PORT ?= /dev/ttyACM0
# Uncomment to have serial debug printing
# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR
# DEBUG_LOGGING ?= ALL
# Uncomment to disable lookup and this this address.
# DEBUG_NET_HISIP ?= {10,11,12,177}
# Only needed in some extreme cases where there is
# transparant http proxy filtering in the network...
# DEBUG_NET_GATE ?= {10,11,12,177}

View file

@ -0,0 +1,284 @@
#
# Copyright 2011 Alan Burlison, alan@bleaklow.com. All rights reserved.
# Subsequently modified by Matthieu Weber, matthieu.weber@jyu.fi.
# Use is subject to license terms.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY ALAN BURLISON "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL ALAN BURLISON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# Changed some code for working without pde/ino files.
# Added extra build flag and libary support.
# wc, 2014-01-13
#
# Minor adjustments for Mac OS X and for educational purposes by Maik Schmidt,
# contact@maik-schmidt.de.
#
# Makefile for building Arduino projects outside of the Arduino environment
#
# This makefile should be included into a per-project Makefile of the following
# form:
#
# ----------
# BOARD = mega
# PORT = /dev/term/0
# INC_DIRS = ../common
# LIB_DIRS = ../libraries/Task ../../libraries/VirtualWire
# include ../../Makefile.master
# ----------
#
# Where:
# BOARD : Arduino board type, from $(ARD_HOME)/hardware/boards.txt
# PORT : USB port
# INC_DIRS : List pf directories containing header files
# LIB_DIRS : List of directories containing library source
#
# Before using this Makefile you can adjust the following macros to suit
# your environment, either by editing this file directly or by defining them in
# the Makefile that includes this one, in which case they will override the
# definitions below:
# ARD_REV : arduino software revision, e.g. 0017, 0018
# ARD_HOME : installation directory of the Arduino software.
# ARD_BIN : location of compiler binaries
# AVRDUDE : location of avrdude executable
# AVRDUDE_CONF : location of avrdude configuration file
# PROGRAMMER : avrdude programmer type
# MON_CMD : serial monitor command
# MON_SPEED : serial monitor speed
#
# Global configuration.
ARD_REV ?= 0022
ARD_HOME ?= /Applications/Arduino.app/Contents/Resources/Java
ARD_BIN ?= /usr/local/CrossPack-AVR/bin
AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude
AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf
PROGRAMMER ?= stk500v1
MON_SPEED ?= 57600
MON_CMD ?= picocom
PORT ?= /dev/tty.usbserial-A60061a3
BOARD ?= atmega328
### Nothing below here should require editing. ###
# Check for the required definitions.
ifndef BOARD
$(error $$(BOARD) not defined)
endif
ifndef PORT
$(error $$(PORT) not defined)
endif
# Version-specific settings
ARD_BOARDS = $(ARD_HOME)/hardware/arduino/avr/boards.txt
ARD_SRC_DIR = $(ARD_HOME)/hardware/arduino/avr/cores/arduino
ARD_MAIN = $(ARD_SRC_DIR)/main.cpp
# Standard macros.
SKETCH = $(notdir $(CURDIR))
BUILD_DIR = build
VPATH = $(LIB_DIRS)
# Macros derived from boards.txt
MCU := $(shell sed -n 's/$(BOARD)\.build\.mcu=\(.*\)/\1/p' < $(ARD_BOARDS))
F_CPU := $(shell sed -n 's/$(BOARD)\.build\.f_cpu=\(.*\)/\1/p' < $(ARD_BOARDS))
UPLOAD_SPEED := \
$(shell sed -n 's/$(BOARD)\.upload\.speed=\(.*\)/\1/p' < $(ARD_BOARDS))
# Build tools.
CC = $(ARD_BIN)/avr-gcc
CXX = $(ARD_BIN)/avr-g++
CXXFILT = $(ARD_BIN)/avr-c++filt
OBJCOPY = $(ARD_BIN)/avr-objcopy
OBJDUMP = $(ARD_BIN)/avr-objdump
AR = $(ARD_BIN)/avr-ar
SIZE = $(ARD_BIN)/avr-size
NM = $(ARD_BIN)/avr-nm
MKDIR = mkdir -p
RM = rm -rf
MV = mv -f
LN = ln -f
# Compiler flags.
INC_FLAGS = \
$(addprefix -I,$(INC_DIRS)) $(addprefix -I,$(LIB_DIRS)) -I$(ARD_SRC_DIR)
ARD_FLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -DARDUINO=$(ARD_REV) $(SKETCH_FLAGS)
C_CXX_FLAGS = \
-Wall -Wextra -Wundef -Wno-unused-parameter \
-fdiagnostics-show-option -g -Wa,-adhlns=$(BUILD_DIR)/$*.lst
C_FLAGS = \
$(C_CXX_FLAGS) -std=gnu99 -Wstrict-prototypes -Wno-old-style-declaration
CXX_FLAGS = $(C_CXX_FLAGS)
# Optimiser flags.
# optimise for size, unsigned by default, pack data.
# separate sections, drop unused ones, shorten branches, jumps.
# don't inline, vectorise loops. no exceptions.
# no os preamble, use function calls in prologues.
# http://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/
# http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html
OPT_FLAGS = \
-Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
-ffunction-sections -fdata-sections -Wl,--gc-sections,--relax \
-fno-inline-small-functions -fno-tree-scev-cprop -fno-exceptions \
-ffreestanding -mcall-prologues
# Build parameters.
IMAGE = $(BUILD_DIR)/$(SKETCH)
ARD_C_SRC = $(wildcard $(ARD_SRC_DIR)/*.c)
ARD_CXX_SRC = $(wildcard $(ARD_SRC_DIR)/*.cpp)
ARD_C_OBJ = $(patsubst %.c,%.o,$(notdir $(ARD_C_SRC)))
ARD_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(ARD_CXX_SRC)))
ARD_LIB = arduino
ARD_AR = $(BUILD_DIR)/lib$(ARD_LIB).a
ARD_AR_OBJ = $(ARD_AR)($(ARD_C_OBJ) $(ARD_CXX_OBJ))
ARD_LD_FLAG = -l$(ARD_LIB)
# Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
$(ARD_AR)(Tone.o) : CXX_FLAGS += -w
# Sketch libraries.
LIB_C_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.c))
LIB_CXX_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.cpp))
LIB_SRC = $(LIB_C_SRC) $(LIB_CXX_SRC)
ifneq "$(strip $(LIB4_C_SRC) $(LIB_CXX_SRC))" ""
LIB_C_OBJ = $(patsubst %.c,%.o,$(notdir $(LIB_C_SRC)))
LIB_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(LIB_CXX_SRC)))
LIB_LIB = library
LIB_AR = $(BUILD_DIR)/lib$(LIB_LIB).a
LIB_AR_OBJ = $(LIB_AR)($(LIB_C_OBJ)$(LIB_CXX_OBJ))
LIB_LD_FLAG = -l$(LIB_LIB)
endif
# Sketch PDE source.
# SKT_PDE_SRC = $(wildcard *.pde)
#ifneq "$(strip $(SKT_PDE_SRC))" ""
# SKT_PDE_OBJ = $(BUILD_DIR)/$(SKETCH)_pde.o
#endif
SKT_PDE_OBJ = $(patsubst %.cpp,%.o,$(notdir $(SKT_PDE_SRC)))
# C and C++ source.
SKT_C_SRC = $(wildcard *.c)
SKT_CXX_SRC = $(wildcard *.cpp)
ifneq "$(strip $(SKT_C_SRC) $(SKT_CXX_SRC))" ""
SKT_C_OBJ = $(patsubst %.c,%.o,$(SKT_C_SRC))
SKT_CXX_OBJ = $(patsubst %.cpp,%.o,$(SKT_CXX_SRC))
SKT_LIB = sketch
SKT_AR = $(BUILD_DIR)/lib$(SKT_LIB).a
SKT_AR_OBJ = $(SKT_AR)($(SKT_C_OBJ) $(SKT_CXX_OBJ))
#SKT_AR_OBJ = $(SKT_AR)/($(SKT_C_OBJ) $(SKT_CXX_OBJ)) // mmm: '/' rmed after make 4.0 to work
SKT_LD_FLAG = -l$(SKT_LIB)
endif
# Definitions.
define run-cc
@ $(CC) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $<
$(CC) -c $(C_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
$< -o $(BUILD_DIR)/$%
@ $(AR) rc $@ $(BUILD_DIR)/$%
@ $(RM) $(BUILD_DIR)/$%
@ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp
@ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst
endef
define run-cxx
@ $(CXX) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $<
$(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
$< -o $(BUILD_DIR)/$%
@ $(AR) rc $@ $(BUILD_DIR)/$%
@ $(RM) $(BUILD_DIR)/$%
@ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp
@ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst
endef
# Rules.
.PHONY : all clean upload monitor upload_monitor
all : $(BUILD_DIR) $(IMAGE).hex
clean :
$(RM) $(BUILD_DIR)
$(BUILD_DIR) :
$(MKDIR) $@
$(SKT_PDE_OBJ) : $(SKT_PDE_SRC)
$(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
$< -o $(BUILD_DIR)/$(SKT_PDE_OBJ)
# echo '#include <Arduino.h>' > $(BUILD_DIR)/$(SKETCH)_pde.cpp
# echo '#include "$(SKT_PDE_SRC)"' >> $(BUILD_DIR)/$(SKETCH)_pde.cpp
# $(LN) $(SKT_PDE_SRC) $(BUILD_DIR)/$(SKT_PDE_SRC)
# cd $(BUILD_DIR) && ../$(CXX) -c $(subst build/,,$(CXX_FLAGS)) \
# $(OPT_FLAGS) $(ARD_FLAGS) -I.. \
# $(patsubst -I..%,-I../..%,$(INC_FLAGS)) \
# $(SKETCH)_pde.cpp -o $(@F)
(%.o) : $(ARD_SRC_DIR)/%.c
$(run-cc)
(%.o) : $(ARD_SRC_DIR)/%.cpp
$(run-cxx)
(%.o) : %.c
$(run-cc)
(%.o) : %.cpp
$(run-cxx)
# not used
#$(BUILD_DIR)/%.d %.c
# $(run-cc-d)
#
#$(BUILD_DIR)/%.d %.cpp
# $(run-cxx-d)
#build/libsketch.a build/libarduino.a
$(IMAGE).hex : $(ARD_AR_OBJ) $(LIB_AR_OBJ) $(SKT_AR_OBJ) $(SKT_PDE_OBJ)
$(CC) $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) -L$(BUILD_DIR) \
$(BUILD_DIR)/$(SKT_PDE_OBJ) $(SKT_LD_FLAG) $(LIB_LD_FLAG) $(ARD_LD_FLAG) -lm \
-o $(IMAGE).elf
$(OBJCOPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load \
--no-change-warnings --change-section-lma .eeprom=0 $(IMAGE).elf \
$(IMAGE).eep
$(OBJCOPY) -O ihex -R .eeprom $(IMAGE).elf $(IMAGE).hex
$(OBJDUMP) -h -S $(IMAGE).elf | $(CXXFILT) -t > $(IMAGE).lst
$(SIZE) $(IMAGE).hex
# START:makemods
upload : all
- pkill -f '$(MON_CMD).*$(PORT)'
- sleep 1
- stty -f $(PORT) hupcl
- $(AVRDUDE) -V -C$(AVRDUDE_CONF) -p$(MCU) -c$(PROGRAMMER) \
-P$(PORT) -b$(UPLOAD_SPEED) -D -Uflash:w:$(IMAGE).hex:i
monitor :
$(MON_CMD) $(PORT) $(MON_SPEED)
# END:makemods
upload_monitor : upload monitor
-include $(wildcard $(BUILD_DIR)/*.dep))
# vim:ft=make

View file

@ -0,0 +1,50 @@
# Include this makefile per project
#
# Optional parameters;
# MASTER_LIBS = Simple library name list.
# MASTER_INC_DIRS = hook to include extra header files.
# MASTER_LIB_DIRS = hook to include extra libraries.
# MASTER_FLAGS = hook for extra build flags
#
ifndef SKT_PDE_SRC
$(error $$(SKT_PDE_SRC) not defined)
endif
THIS_PATH = ../lib-build/make/
INC_LOCAL = .
# Optional include an local override
-include $(THIS_PATH)/Makefile.inc.local
# Copy debug ips
ifdef DEBUG_NET_HISIP
DEBUG_NET_FLAG_HISIP = -DDEBUG_NET_HISIP=$(DEBUG_NET_HISIP)
endif
ifdef DEBUG_NET_GATE
DEBUG_NET_FLAG_GATE = -DDEBUG_NET_GATE=$(DEBUG_NET_GATE)
endif
# Add some normal defaults for root makefile
ARD_REV ?= 105
ARD_BIN ?= $(ARD_HOME)/hardware/tools/avr/bin
AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude
AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf
BOARD ?= uno
PORT ?= /dev/ttyACM0
PROGRAMMER ?= arduino
MON_SPEED ?= 115200
MON_CMD ?= picocom
ROOT_INCS = $(ARD_HOME)/hardware/arduino/avr/variants/standard/
# Include managed build parameters
include $(THIS_PATH)/Makefile.inc.debug
include $(THIS_PATH)/Makefile.inc.libs
# Create build dirs for root makefile
INC_DIRS = $(MASTER_INC_DIRS) $(ROOT_INCS) $(INC_LOCAL)
LIB_DIRS = $(MASTER_LIB_DIRS) $(ROOT_LIBS)
SKETCH_FLAGS = $(MASTER_FLAGS) $(DEBUG_NET_FLAG_HISIP) $(DEBUG_NET_FLAG_GATE) $(DEBUG_FLAGS)
# Include the root parent makefile
include $(THIS_PATH)/Makefile.inc.root

View file

@ -0,0 +1,45 @@
# Master makefile to flash tool projects
#
# Parameter;
# MASTER_FLASH_PROG = The hex file to flash
#
# Option Parameter;
# MASTER_FLASH_BOOT = The bootloader to flash
# MASTER_FLASH_PAIR_EXTRA = extra pair list of hex files to flash,
# note where the keyword optiboot get replaced by the optiboot hex file.
#
ifndef MASTER_FLASH_PROG
$(error $$(MASTER_FLASH_PROG) not defined)
endif
# Define libary includes
MASTER_LIBS = isp-repair
# Include our master
include ../lib-build/make/Makefile.master
HEX_FILE_BOOT_OPTI = $(ARD_HOME)/hardware/arduino/avr/bootloaders/optiboot/optiboot_atmega328.hex
HEX_FILE_BLINK_TEST = ../xnode-test-blink/build/xnode-test-blink.hex
# Define local variables
HEX2C = tclsh ../lib-build/tools/mega-hex2c.tcl
HEX_DATA = xnode-flashdata.generated
HEX_PAIR_BLINK = $(HEX_FILE_BOOT_OPTI) $(HEX_FILE_BLINK_TEST)
MASTER_FLASH_BOOT ?= $(HEX_FILE_BOOT_OPTI)
HEX_PAIR_MASTER = $(MASTER_FLASH_BOOT) $(MASTER_FLASH_PROG)
HEX_PAIR_EXTRA = $(subst optiboot,$(HEX_FILE_BOOT_OPTI),$(MASTER_FLASH_PAIR_EXTRA))
HEX_PAIR_LIST = $(HEX_PAIR_BLINK) $(HEX_PAIR_MASTER) $(HEX_PAIR_EXTRA)
# Hook in our local extra build targets
clean : clean-hex
$(BUILD_DIR) : $(HEX_DATA)
# Generate flashdata before compiling
$(HEX_DATA) :
$(HEX2C) $(HEX_PAIR_LIST) > $(HEX_DATA)
clean-hex :
$(RM) $(HEX_DATA)

View file

@ -0,0 +1,86 @@
#!/usr/bin/env tclsh
# Changed to byte array per file with index struct for mega version
# wc, 2014-01-13
# Generate a C include file from one or more Intel HEX files (avr-gcc output)
# jcw, 2010-04-18
# Examples:
# ./hex2c.tcl Blink.cpp.hex ATmegaBOOT_168_atmega328.hex >data_blink.h
# ./hex2c.tcl RF12demo.cpp.hex ATmegaBOOT_168_atmega328.hex >data_rf12demo.h
# ./hex2c.tcl Blink.cpp.hex optiboot_atmega328.hex >opti_blink.h
# ./hex2c.tcl RF12demo.cpp.hex optiboot_atmega328.hex >opti_rf12demo.h
if {$argv eq ""} {
puts stderr "Usage: [info script] infile.hex ?...? >outfile.h"
exit 1
}
set bytes {}
set psi 0
foreach a $argv {
set start [llength $bytes]
set mtime [clock format [file mtime $a] -format "%Y-%m-%d"]
puts stderr $a:
set fd [open $a]
while {[gets $fd line] > 0} {
if {[scan $line {:%2x%4x%2x%s} count addr type data]} {
if {$type == 0} {
if {![info exists next]} {
set first [format 0x%04X $addr]
set next $addr
}
while {$next < $addr} {
lappend bytes 255 ;# pad with unset bytes if there is a gap
incr next
}
if {$next != $addr} {
puts stderr "non-contiguous data ($next vs $addr)"
}
incr next $count
foreach {x y} [split [string range $data 0 end-2] ""] {
lappend bytes [scan $x$y %x]
}
}
}
}
incr next -$first
set f [format %-30s [file tail $a]]
lappend sections "\"$f\",\"$mtime\",progdata_$psi,$first,$start,$next"
#lappend sections "\"$mtime $f ${next}b @ $first\",$first,$start,$next"
unset next
close $fd
lappend byte_sections $bytes
set bytes {}
incr psi
}
puts "// This file was generated by hex2c.tcl on [clock format [clock seconds]]"
puts ""
puts ""
set pgi 0
foreach bs $byte_sections {
puts "const unsigned char progdata_$pgi\[] PROGMEM = {"
set out " "
foreach x $bs {
if {[string length $out$x,] > 80} {
puts $out
set out " "
}
append out $x ,
}
puts $out
puts "};"
incr pgi
}
puts ""
puts "mega_flash_data_struct sections\[] = {"
foreach x $sections {
puts " {$x},"
}
puts "};"
puts ""

171
lib-build/tools/xxtea.c Normal file
View file

@ -0,0 +1,171 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* Coding Part */
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) {
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
} while (--rounds);
} else if (n < -1) { /* Decoding Part */
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) {
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}
void convToQU32(uint32_t *v/*, int n*/,int *data,int dataOffset) {
for (int i=0;i<4;i++) {
int idx = dataOffset + i*4;
//uint32_t value = (data[idx]) + (data[idx+1] << 8) + (data[idx+2] << 16) + (data[idx+3] << 24);
uint32_t value = (data[idx+3]) + (data[idx+2] << 8) + (data[idx+1] << 16) + (data[idx+0] << 24);
printf("convToQU32 %08x \n", value);
v[i] = value;
}
}
#define XXTEA_NUM_ROUNDS 32
void xxteaDecrypt(unsigned long v[2],unsigned long net_key[4])
{
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS;
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + net_key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + net_key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
int main (int argc, char *argv[] ) {
// Arguments parsing
if ( argc != 4 ) {
printf( "usage: %s encrypt|decrypt key message\n", argv[0] ); // prog name
printf( "note: parameters are pure hex and key should be 32 chars. \n");
return 1;
}
int operation = 0;
if (strcmp("encrypt", argv[1]) == 0) {
operation = 1;
}
if (strcmp("decrypt", argv[1]) == 0) {
operation = -1;
}
if (operation == 0) {
printf( "Could not parse first argument.\n");
return 1;
}
printf( "operation: %d.\n",operation);
char* keyBuffer = argv[2];
int keyBufferLength = strlen(keyBuffer);
if (keyBufferLength != 32) {
printf( "key should by 32 chars.\n");
return 1;
}
char* messageBuffer = argv[3];
int messageBufferLength = strlen(messageBuffer);
if (messageBufferLength < 16) {
printf( "message should be minimal 16 chars.\n");
return 1;
}
// Done arguments
// Convert data
int keyData[16];
int keyDataIndex = 0;
for (int i=0;i<keyBufferLength/2;i++) {
int value;
sscanf(keyBuffer+2*i,"%02x",&value);
keyData[keyDataIndex] = value;
keyDataIndex++;
}
printf( "Key data size %d\n", keyDataIndex );
for (int i=0;i<keyDataIndex;i++) {
printf( "%02x", keyData[i] );
}
printf("\n");
int messageData[512];
int messageDataIndex = 0;
for (int i=0;i<512;i++) {
messageData[i] = 0;
}
for (int i=0;i<messageBufferLength/2;i++) {
int value;
sscanf(messageBuffer+2*i,"%02x",&value);
messageData[messageDataIndex] = value;
messageDataIndex++;
}
printf( "Message data size %d\n", messageDataIndex );
for (int i=0;i<messageDataIndex;i++) {
printf( "%02x", messageData[i] );
}
printf("\n");
uint32_t key[4];
uint32_t data[4];
convToQU32(key,keyData,0);
convToQU32(data,messageData,0);
printf("OUT-ppre: ");
for (int i=0;i<4;i++) {
printf("%08x", data[i]);
}
printf("\n");
operation = operation* (messageDataIndex/4);
printf( "word length: %d\n",operation);
//btea(data,operation,key);
xxteaDecrypt(data,key);
printf("OUT-post: ");
for (int i=0;i<4;i++) {
printf("%08x", data[i]);
}
printf("\n");
printf("OUT-AS: ");
for (int i=0;i<4;i++) {
//printf("%02x ", data[i] & 255);
//printf("%02x ", data[i] >> 8 & 255);
//printf("%02x ", data[i] >> 16 & 255);
//printf("%02x ", data[i] >> 24 & 255);
printf("%c ", data[i] & 255);
printf("%c ", data[i] >> 8 & 255);
printf("%c ", data[i] >> 16 & 255);
printf("%c ", data[i] >> 24 & 255);
}
printf("\n");
return 0;
}