mirror of
https://github.com/Hopiu/webapi-eca.git
synced 2026-03-17 06:20:23 +00:00
changed event data to payload, worked on user sessions, mobile location event pusher webpage added
This commit is contained in:
parent
b3de695b07
commit
89fc5d26a1
9 changed files with 207 additions and 103 deletions
3
config/users.json
Normal file
3
config/users.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"dominic": "test"
|
||||
}
|
||||
|
|
@ -33,6 +33,14 @@ function loadConfigFile(relPath) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer true if the config file is ready, else false
|
||||
*/
|
||||
exports.isReady = function() {
|
||||
if(config) return true;
|
||||
else return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch a property from the configuration
|
||||
* @param {String} prop
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ exports = module.exports = function(args) {
|
|||
|
||||
/**
|
||||
* ### encrypt
|
||||
* this is used to decrypt
|
||||
* @param {String} plainText
|
||||
*/
|
||||
function encrypt(plainText) {
|
||||
if(!plainText) return null;
|
||||
|
|
@ -56,13 +58,13 @@ function encrypt(plainText) {
|
|||
/**
|
||||
* ### decrypt
|
||||
*/
|
||||
function decrypt(crypticText) {
|
||||
function decrypt(crypticText, id) {
|
||||
if(!crypticText) return null;
|
||||
try {
|
||||
var deciph = crypto.createDecipher('aes-256-cbc', crypto_key);
|
||||
return deciph.update(crypticText, 'base64', 'utf8') + deciph.final('utf8');
|
||||
} catch (err) {
|
||||
log.error('DB', 'in decrypting: ' + err);
|
||||
log.error('DB', 'in decrypting "' + id + '": ' + err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +181,9 @@ exports.storeActionModuleAuth = function(id, data) {
|
|||
* @param {function} callback the callback to receive the answer (err, obj)
|
||||
*/
|
||||
exports.getActionModuleAuth = function(id, callback) {
|
||||
if(callback && db) db.get('action_module_' + id + '_auth', function(err, txt) { callback(err, decrypt(txt)); });
|
||||
if(callback && db) db.get('action_module_' + id + '_auth', function(id) {
|
||||
return function(err, txt) { callback(err, decrypt(txt, 'action_module_' + id + '_auth')); };
|
||||
}(id));
|
||||
};
|
||||
|
||||
// ## Event Modules
|
||||
|
|
@ -235,7 +239,9 @@ exports.storeEventModuleAuth = function(id, data) {
|
|||
// @param {String} id the module id
|
||||
// @param {function} callback the callback to receive the answer (err, obj)
|
||||
exports.getEventModuleAuth = function(id, callback) {
|
||||
if(callback) db.get('event_module_' + id +'_auth', function(err, txt) { callback(err, decrypt(txt)); });
|
||||
if(callback) db.get('event_module_' + id +'_auth', function(id) {
|
||||
return function(err, txt) { callback(err, decrypt(txt, 'event_module_' + id + '_auth')); };
|
||||
}(id));
|
||||
};
|
||||
|
||||
// ## Rules
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ function checkEvent(evt) {
|
|||
for(var rn in listRules) {
|
||||
//TODO this needs to get depth safe, not only data but eventually also
|
||||
// on one level above (eventid and other meta)
|
||||
if(listRules[rn].event === evt.event && validConditions(evt.data, listRules[rn])) {
|
||||
if(listRules[rn].event === evt.event && validConditions(evt.payload, listRules[rn])) {
|
||||
log.print('EN', 'Rule "' + rn + '" fired');
|
||||
actions = actions.concat(listRules[rn].actions);
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ function invokeAction(evt, action) {
|
|||
var srvc = listActionModules[arrModule[0]];
|
||||
if(srvc && srvc[arrModule[1]]) {
|
||||
//FIXME preprocessing not only on data
|
||||
preprocessActionArguments(evt.data, action.arguments, actionargs);
|
||||
preprocessActionArguments(evt.payload, action.arguments, actionargs);
|
||||
try {
|
||||
if(srvc[arrModule[1]]) srvc[arrModule[1]](actionargs);
|
||||
} catch(err) {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ function checkRemotes() {
|
|||
process.send({
|
||||
event: p,
|
||||
eventid: 'polled_' + eId++,
|
||||
data: obj
|
||||
payload: obj
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// # HTTP Listener
|
||||
// Isso
|
||||
// HTTP Listener
|
||||
// =============
|
||||
//
|
||||
// Handles the HTTP requests to the server at the port specified by the [config](config.html) file.
|
||||
|
||||
'use strict';
|
||||
|
||||
var path = require('path'),
|
||||
|
|
@ -10,12 +13,18 @@ var path = require('path'),
|
|||
log = require('./logging'),
|
||||
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)',
|
||||
db_port, http_port, server,
|
||||
adminHandler, eventHandler;
|
||||
eventHandler, userHandler;
|
||||
|
||||
/*
|
||||
* The module needs to be called as a function to initialize it.
|
||||
* After that it fetches the http\_port, db\_port & sess\_sec properties
|
||||
* from the configuration file.
|
||||
*/
|
||||
exports = module.exports = function(args) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
var config = require('./config')(args);
|
||||
userHandler = require('./user_handler')(args);
|
||||
db_port = config.getDBPort(),
|
||||
sess_sec = config.getSessionSecret(),
|
||||
http_port = config.getHttpPort();
|
||||
|
|
@ -23,110 +32,78 @@ exports = module.exports = function(args) {
|
|||
};
|
||||
|
||||
exports.addHandlers = function(funcAdminHandler, funcEvtHandler) {
|
||||
if(!funcEvtHandler) {
|
||||
log.error('HL', 'ERROR: either port or eventHandler function not defined!');
|
||||
if(!funcAdminHandler || !funcEvtHandler) {
|
||||
log.error('HL', 'ERROR: either adminHandler or eventHandler function not defined!');
|
||||
return;
|
||||
}
|
||||
adminHandler = funcAdminHandler;
|
||||
userHandler.addHandler(funcAdminHandler);
|
||||
eventHandler = funcEvtHandler;
|
||||
|
||||
//FIXME this whole webserver requires clean approach together with session handling all over the engine.
|
||||
//One entry point, from then collecting response contents and one exit point that sends it!
|
||||
|
||||
// Add cookie support for session handling.
|
||||
app.use(express.cookieParser());
|
||||
app.use('/doc/', express.static(path.resolve(__dirname, '..', 'webpages', 'doc')));
|
||||
app.use('/mobile/', express.static(path.resolve(__dirname, '..', 'webpages', 'mobile')));
|
||||
app.use('/rulesforge/', express.static(path.resolve(__dirname, '..', 'webpages', 'rulesforge')));
|
||||
app.get('/admin', onAdminCommand);
|
||||
app.post('/pushEvents', onPushEvent);
|
||||
if(db_port) {
|
||||
app.use(express.session({
|
||||
store: new RedisStore({
|
||||
host: 'localhost',
|
||||
port: db_port,
|
||||
db: 2
|
||||
// ,
|
||||
// pass: 'RedisPASS'
|
||||
}),
|
||||
// FIXME use a secret from config
|
||||
secret: sess_sec
|
||||
}));
|
||||
log.print('HL', 'Added redis DB as session backbone');
|
||||
} else {
|
||||
app.use(express.session({secret: sess_sec}));
|
||||
log.print('HL', 'no session backbone');
|
||||
}
|
||||
if(http_port) server = app.listen(http_port); // inbound event channel
|
||||
else log.error('HL', new Error('No HTTP port found!?'));
|
||||
};
|
||||
|
||||
function answerHandler(r) {
|
||||
var response = r, hasBeenAnswered = false;
|
||||
function postAnswer(msg) {
|
||||
if(!hasBeenAnswered) {
|
||||
response.write(msg);
|
||||
response.end();
|
||||
hasBeenAnswered = true;
|
||||
}
|
||||
}
|
||||
return {
|
||||
answerSuccess: function(msg) {
|
||||
if(!hasBeenAnswered) response.writeHead(200, { "Content-Type": "text/plain" });
|
||||
postAnswer(msg);
|
||||
},
|
||||
answerError: function(msg) {
|
||||
if(!hasBeenAnswered) response.writeHead(400, { "Content-Type": "text/plain" });
|
||||
postAnswer(msg);
|
||||
},
|
||||
isAnswered: function() { return hasBeenAnswered; }
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles correct event posts, replies thank you.
|
||||
*/
|
||||
function answerSuccess(resp, msg){
|
||||
resp.writeHead(200, { "Content-Type": "text/plain" });
|
||||
resp.write(msg);
|
||||
resp.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles erroneous requests.
|
||||
* @param {Object} msg the error message to be returned
|
||||
*/
|
||||
function answerError(resp, msg) {
|
||||
resp.writeHead(400, { "Content-Type": "text/plain" });
|
||||
resp.write(msg);
|
||||
resp.end();
|
||||
}
|
||||
|
||||
//FIXME this answer handling is a very ugly hack, improve!
|
||||
function onAdminCommand(request, response) {
|
||||
var q = request.query;
|
||||
log.print('HL', 'Received admin request: ' + request.originalUrl);
|
||||
if(q.cmd) {
|
||||
adminHandler(q, answerHandler(response));
|
||||
// answerSuccess(response, 'Thank you, we try our best!');
|
||||
} else answerError(response, 'I\'m not sure about what you want from me...');
|
||||
}
|
||||
app.use(express.session({secret: sess_sec}));
|
||||
log.print('HL', 'no session backbone');
|
||||
|
||||
// ^ TODO figure out why redis backbone doesn't work. eventually the db pass has to be set in the DB?
|
||||
// } session information seems to be stored in DB but not retrieved correctly
|
||||
// } if(db_port) {
|
||||
// } app.use(express.session({
|
||||
// } store: new RedisStore({
|
||||
// } host: 'localhost',
|
||||
// } port: db_port,
|
||||
// } db: 2
|
||||
// } ,
|
||||
// } pass: null
|
||||
// } }),
|
||||
// } secret: sess_sec
|
||||
// } }));
|
||||
// } log.print('HL', 'Added redis DB as session backbone');
|
||||
// } } else {
|
||||
// } app.use(express.session({secret: sess_sec}));
|
||||
// } log.print('HL', 'no session backbone');
|
||||
// } }
|
||||
|
||||
// Redirect the requests to the appropriate handler.
|
||||
app.use('/doc/', express.static(path.resolve(__dirname, '..', 'webpages', 'doc')));
|
||||
// app.get('/mobile', userHandler.handleRequest);
|
||||
app.get('/rulesforge', userHandler.handleRequest);
|
||||
app.use('/mobile/', express.static(path.resolve(__dirname, '..', 'webpages', 'mobile')));
|
||||
// } app.use('/rulesforge/', express.static(path.resolve(__dirname, '..', 'webpages', 'rulesforge')));
|
||||
app.get('/admin', userHandler.handleRequest);
|
||||
app.post('/push_event', onPushEvent);
|
||||
if(http_port) server = app.listen(http_port); // inbound event channel
|
||||
else log.error('HL', new Error('No HTTP port found!? Nothing to listen on!...'));
|
||||
};
|
||||
|
||||
/**
|
||||
* If a request is made to the server, this function is used to handle it.
|
||||
* If a post request reaches the server, this function handles it and treats the request as a possible event.
|
||||
*/
|
||||
function onPushEvent(request, response) {
|
||||
function onPushEvent(req, resp) {
|
||||
var body = '';
|
||||
request.on('data', function (data) { body += data; });
|
||||
request.on('end', function () {
|
||||
req.on('data', function (data) { body += data; });
|
||||
req.on('end', function () {
|
||||
var obj = qs.parse(body);
|
||||
/* If required event properties are present we process the event */
|
||||
if(obj && obj.event && obj.eventid){
|
||||
answerSuccess(response, 'Thank you for the event (' + obj.event + '[' + obj.eventid + '])!');
|
||||
resp.writeHead(200, { "Content-Type": "text/plain" });
|
||||
resp.write('Thank you for the event (' + obj.event + '[' + obj.eventid + '])!');
|
||||
resp.end();
|
||||
eventHandler(obj);
|
||||
} else answerError(response, 'Your event was missing important parameters!');
|
||||
} else {
|
||||
resp.writeHead(400, { "Content-Type": "text/plain" });
|
||||
resp.write('Your event was missing important parameters!');
|
||||
resp.end();
|
||||
}
|
||||
resp.end();
|
||||
});
|
||||
}
|
||||
|
||||
exports.loadUsers = function() {
|
||||
var users = JSON.parse(require('fs').readFileSync(path.resolve(__dirname, '..', relPath)));
|
||||
for(var name in users) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
exports.shutDown = function() {
|
||||
log.print('HL', 'Shutting down HTTP listener');
|
||||
process.exit(); // This is a bit brute force...
|
||||
|
|
|
|||
12
js/server.js
12
js/server.js
|
|
@ -24,8 +24,7 @@ dog's back.
|
|||
*/
|
||||
|
||||
//FIXME server should be started via command line arguments http_port and logging level to allow proper testing
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
var path = require('path'),
|
||||
log = require('./logging'),
|
||||
procCmds = {
|
||||
'die': function() { shutDown(); }
|
||||
|
|
@ -36,7 +35,10 @@ var fs = require('fs'),
|
|||
|
||||
function init() {
|
||||
log.print('RS', 'STARTING SERVER');
|
||||
|
||||
if(!require('./config').isReady()) {
|
||||
log.error('RS', 'Config file not ready!');
|
||||
return;
|
||||
}
|
||||
if(process.argv.length > 2) {
|
||||
args.logType = parseInt(process.argv[2]) || 0 ;
|
||||
log(args);
|
||||
|
|
@ -56,12 +58,13 @@ function init() {
|
|||
'loadactions': mm.loadActionModulesFromFS,
|
||||
'loadevent': mm.loadEventModuleFromFS,
|
||||
'loadevents': mm.loadEventModulesFromFS,
|
||||
'loadusers': http_listener.loadUsers,
|
||||
'shutdown': shutDown
|
||||
};
|
||||
log.print('RS', 'Initialzing engine');
|
||||
engine.addDBLinkAndLoadActionsAndRules(db);
|
||||
log.print('RS', 'Initialzing http listener');
|
||||
http_listener.addHandlers(handleAdminCommands, engine.pushEvent);
|
||||
http_listener.addHandlers(db, handleAdminCommands, engine.pushEvent);
|
||||
log.print('RS', 'Initialzing module manager');
|
||||
mm.addHandlers(db, engine.loadActionModule, engine.addRule);
|
||||
//FIXME load actions and events, then rules, do this here, visible for everybody on the first glance
|
||||
|
|
@ -82,6 +85,7 @@ function handleAdminCommands(args, answHandler) {
|
|||
}, 2000);
|
||||
}
|
||||
|
||||
|
||||
function shutDown(args, answHandler) {
|
||||
if(answHandler) answHandler.answerSuccess('Goodbye!');
|
||||
log.print('RS', 'Received shut down command!');
|
||||
|
|
|
|||
61
js/user_handler.js
Normal file
61
js/user_handler.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
var log = require('./logging'),
|
||||
db = require('./db_interface'), adminHandler;
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
db(args);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
exports.addHandler = function(adminHandl) {
|
||||
adminHandler = adminHandl;
|
||||
};
|
||||
|
||||
exports.handleRequest = function(req, resp) {
|
||||
req.on('end', function () {
|
||||
resp.end();
|
||||
});
|
||||
if(req.session && req.session.lastPage) resp.send('You visited last: ' + req.session.lastPage);
|
||||
else resp.send('You are new!');
|
||||
// resp.end();
|
||||
log.print('UH', 'last: '+ req.session.lastPage);
|
||||
req.session.lastPage = req.originalUrl;
|
||||
log.print('UH', 'last: '+ req.session.lastPage);
|
||||
log.print('UH', 'retrieved req: '+ req.originalUrl);
|
||||
// console.log(req);
|
||||
};
|
||||
|
||||
function answerHandler(r) {
|
||||
var response = r, hasBeenAnswered = false;
|
||||
function postAnswer(msg) {
|
||||
if(!hasBeenAnswered) {
|
||||
response.write(msg);
|
||||
response.end();
|
||||
hasBeenAnswered = true;
|
||||
}
|
||||
}
|
||||
return {
|
||||
answerSuccess: function(msg) {
|
||||
if(!hasBeenAnswered) response.writeHead(200, { "Content-Type": "text/plain" });
|
||||
postAnswer(msg);
|
||||
},
|
||||
answerError: function(msg) {
|
||||
if(!hasBeenAnswered) response.writeHead(400, { "Content-Type": "text/plain" });
|
||||
postAnswer(msg);
|
||||
},
|
||||
isAnswered: function() { return hasBeenAnswered; }
|
||||
};
|
||||
};
|
||||
|
||||
//FIXME this answer handling is a very ugly hack, improve!
|
||||
function onAdminCommand(request, response) {
|
||||
var q = request.query;
|
||||
log.print('HL', 'Received admin request: ' + request.originalUrl);
|
||||
if(q.cmd) {
|
||||
adminHandler(q, answerHandler(response));
|
||||
// answerSuccess(response, 'Thank you, we try our best!');
|
||||
} else answerError(response, 'I\'m not sure about what you want from me...');
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,53 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Mobile Page</title>
|
||||
<script type="text/javascript">
|
||||
document.write("\<script src='//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js' type='text/javascript'>\<\/script>");
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif, "Times New Roman", Georgia, Serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Mobile Page</h1>
|
||||
<script>
|
||||
function displayPosition(position) {
|
||||
var lat = position.coords.latitude,
|
||||
lon = position.coords.longitude;
|
||||
$('#print').html("<table border='1'><tr><th>Timestamp</th><td>" + position.timestamp +
|
||||
"<tr><th>Latitude</th><td>" + lat + " deg</td></tr>" +
|
||||
"<tr><th>Longitude</th><td>" + lon + " deg</td></tr></table>");
|
||||
|
||||
var img_url="http://maps.googleapis.com/maps/api/staticmap?center="
|
||||
+lat+","+lon+"&zoom=15&size=400x300&sensor=false&maptype=roadmap&markers=color:orange|label:1|"+lat+","+lon;
|
||||
|
||||
document.getElementById("mapholder").innerHTML="<img src='"+img_url+"'>";
|
||||
$.post('push_event', { event: 'geoposition', eventid: 'geoposition_' + position.timestamp })
|
||||
.done(function(data) {
|
||||
$('#info').text("Sent event to engine: " + data);
|
||||
})
|
||||
.fail(function(err) {
|
||||
$('#info').text("Error: " + err);
|
||||
});
|
||||
}
|
||||
|
||||
function displayError(positionError) {
|
||||
$('#info').text('Error: ' + positionError);
|
||||
}
|
||||
|
||||
var gl = navigator.geolocation;
|
||||
|
||||
if (gl) {
|
||||
gl.getCurrentPosition(displayPosition, displayError);
|
||||
} else {
|
||||
$('#info').text('Geolocation services are not supported by your web browser.');
|
||||
}
|
||||
|
||||
</script>
|
||||
<div id="print"></div>
|
||||
<div id="mapholder"></div>
|
||||
<div id="info"></div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue