diff --git a/coffee/event-poller.coffee b/coffee/event-poller.coffee index 99b4ee5..9ef67c2 100644 --- a/coffee/event-poller.coffee +++ b/coffee/event-poller.coffee @@ -32,8 +32,14 @@ log = logger.getLogger logconf log.info 'EP | Event Poller starts up' process.on 'uncaughtException', ( err ) -> - log.error 'Probably one of the event pollers created an error in a callback function!' - log.error err + # TODO we'd have to wrap the dynamic-modules module in an own child process which + # we could let crash, create log info about what dynamic module caused the crash and + # then restart the dynamic-modules module, passing the crash info to the logger of the + # rule that caused this issue. on the other hand we're just fine like this since only + # the deferred token of the corresponding rule gets eliminated if it throws an error + # and the event polling won't continue fo this rule, which is fine for us, except that + # we do not have a good way to inform the user about his error. + log.error 'Probably one of the event pollers produced an error!' # Initialize required modules (should be in cache already) db logger: log @@ -174,6 +180,7 @@ This function will loop infinitely every 10 seconds until isRunning is set to fa pollLoop = () -> # We only loop if we're running if isRunning + #FIXME CHECK IF ALREADY RUNNING! #FIXME a scheduler should go here because we are limited in setTimeout # to an integer value -> ~24 days at maximum! diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 9db798f..49380b1 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -347,14 +347,17 @@ class IndexedModules @db.smembers "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:functions", ( err, obj ) => sem = obj.length oAnswer = {} - for func in obj - fRegisterFunction = ( func ) => - ( err, obj ) => - if obj - oAnswer[ func ] = obj - if --sem is 0 - cb null, oAnswer - @db.get "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:function:#{ func }", fRegisterFunction func + if sem is 0 + cb null, oAnswer + else + for func in obj + fRegisterFunction = ( func ) => + ( err, obj ) => + if obj + oAnswer[ func ] = obj + if --sem is 0 + cb null, oAnswer + @db.get "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:function:#{ func }", fRegisterFunction func getUserArguments: ( userId, ruleId, mId, funcId, cb ) => @log.info "DB | (IdxedMods) #{ @setname }.getUserArguments( #{ userId }, #{ ruleId }, #{ mId }, #{ funcId } )" @@ -596,14 +599,14 @@ exports.getAllActivatedRuleIdsPerUser = ( cb ) => cb null, result else semaphore = obj.length - fFetchActiveUserRules = ( userId ) => - @db.smembers "user:#{ user }:active-rules", ( err, obj ) => - if obj.length > 0 - result[userId] = obj - if --semaphore is 0 - cb null, result - fFetchActiveUserRules user for user in obj - + for user in obj + fProcessAnswer = ( user ) -> + ( err, obj ) => + if obj.length > 0 + result[user] = obj + if --semaphore is 0 + cb null, result + @db.smembers "user:#{ user }:active-rules", fProcessAnswer user ### ## Users diff --git a/examples/action-invokers/converter.coffee b/examples/action-invokers/converter.coffee index 16f73b4..2f686d3 100644 --- a/examples/action-invokers/converter.coffee +++ b/examples/action-invokers/converter.coffee @@ -6,7 +6,7 @@ exports.parseTextToJSON = ( eventname, text ) -> try pushEvent - event: eventname + eventname: eventname body: JSON.parse text log "Text successfully parsed" catch e @@ -16,7 +16,7 @@ exports.parseTextToJSON = ( eventname, text ) -> # Parses objects to text exports.parseObjectToPrettyText = ( eventname, obj ) -> pushEvent - event: eventname + eventname: eventname body: JSON.stringify text, undefined, 2 @@ -30,7 +30,7 @@ exports.accumulateEvents = ( evtname, evt, sendTime ) -> if lastSend < yesterday lastSend = sTime pushEvent - event: evtname + eventname: evtname body: arrEvents arrEvents = [] @@ -56,7 +56,7 @@ fPushEvent = () -> if eventname isnt '' log "Pushing changed interval event" pushEvent - event: eventname + eventname: eventname body: event setTimeout fPushEvent, interval @@ -109,7 +109,7 @@ exports.LongLatToMeterDistance = ( latOne, longOne, latTwo, longTwo, eventname ) c = 2 * Math.atan2 Math.sqrt( a ), Math.sqrt 1 - a pushEvent - event: eventname + eventname: eventname body: latOne: latOne longOne: longOne diff --git a/examples/action-invokers/neospeech.coffee b/examples/action-invokers/neospeech.coffee index 3b75fc6..5126d66 100644 --- a/examples/action-invokers/neospeech.coffee +++ b/examples/action-invokers/neospeech.coffee @@ -101,7 +101,7 @@ pollUntilDone = ( conversionNumber, email, accountid, infoEvent ) -> if oAnsw.resultCode is '0' if oAnsw.statusCode is '4' or oAnsw.statusCode is '5' pushEvent - event: infoEvent + eventname: infoEvent body: accountid: accountid downloadUrl: oAnsw.downloadUrl diff --git a/js/event-poller.js b/js/event-poller.js index fdab541..71f80b7 100644 --- a/js/event-poller.js +++ b/js/event-poller.js @@ -40,8 +40,7 @@ Dynamic Modules log.info('EP | Event Poller starts up'); process.on('uncaughtException', function(err) { - log.error('Probably one of the event pollers created an error in a callback function!'); - return log.error(err); + return log.error('Probably one of the event pollers produced an error!'); }); db({ diff --git a/js/persistence.js b/js/persistence.js index 2799d52..88cb414 100644 --- a/js/persistence.js +++ b/js/persistence.js @@ -404,22 +404,26 @@ Persistence var fRegisterFunction, func, oAnswer, sem, _i, _len, _results; sem = obj.length; oAnswer = {}; - _results = []; - for (_i = 0, _len = obj.length; _i < _len; _i++) { - func = obj[_i]; - fRegisterFunction = function(func) { - return function(err, obj) { - if (obj) { - oAnswer[func] = obj; - } - if (--sem === 0) { - return cb(null, oAnswer); - } + if (sem === 0) { + return cb(null, oAnswer); + } else { + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + func = obj[_i]; + fRegisterFunction = function(func) { + return function(err, obj) { + if (obj) { + oAnswer[func] = obj; + } + if (--sem === 0) { + return cb(null, oAnswer); + } + }; }; - }; - _results.push(_this.db.get("" + _this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":function:" + func, fRegisterFunction(func))); + _results.push(_this.db.get("" + _this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":function:" + func, fRegisterFunction(func))); + } + return _results; } - return _results; }; })(this)); }; @@ -751,26 +755,28 @@ Persistence return function(cb) { _this.log.info("DB | Fetching all active rules"); return _this.db.smembers('users', function(err, obj) { - var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results; + var fProcessAnswer, result, semaphore, user, _i, _len, _results; result = {}; if (obj.length === 0) { return cb(null, result); } else { semaphore = obj.length; - fFetchActiveUserRules = function(userId) { - return _this.db.smembers("user:" + user + ":active-rules", function(err, obj) { - if (obj.length > 0) { - result[userId] = obj; - } - if (--semaphore === 0) { - return cb(null, result); - } - }); - }; _results = []; for (_i = 0, _len = obj.length; _i < _len; _i++) { user = obj[_i]; - _results.push(fFetchActiveUserRules(user)); + fProcessAnswer = function(user) { + return (function(_this) { + return function(err, obj) { + if (obj.length > 0) { + result[user] = obj; + } + if (--semaphore === 0) { + return cb(null, result); + } + }; + })(this); + }; + _results.push(_this.db.smembers("user:" + user + ":active-rules", fProcessAnswer(user))); } return _results; } diff --git a/package.json b/package.json index 8c6d253..cc2475c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "bunyan": "0.22.1", - "coffee-script": "1.6.3", + "coffee-script": "1.7.1", "crypto-js": "3.1.2", "express": "3.4.8", "groc": "0.6.1", @@ -18,7 +18,7 @@ "js-select": "0.6.0", "mustache": "0.8.1", "needle": "0.6.3", - "nodeunit": "0.8.4", + "nodeunit": "0.8.6", "redis": "0.10.0", "request": "2.33.0", "optimist": "0.6.1" diff --git a/unit_tests.sh b/unit_tests.sh index ffded78..6deb78f 100755 --- a/unit_tests.sh +++ b/unit_tests.sh @@ -4,6 +4,7 @@ var fs = require( 'fs' ), path = require( 'path' ), nodeunit = require( 'nodeunit' ), db = require( './js/persistence' ), + cs = require('coffee-script'), args = process.argv.slice( 2 ), fEnd = function() { console.log( 'Shutting down DB from unit_test.sh script. ' @@ -11,6 +12,9 @@ var fs = require( 'fs' ), db.shutDown(); }; +if (cs.register) { + cs.register(); +} if( args[ 0 ] !== undefined ) { var fl = path.resolve( args[ 0 ] ); if ( fs.existsSync( fl ) ) { diff --git a/webpages/handlers/coffee/forge_rule.coffee b/webpages/handlers/coffee/forge_rule.coffee index d0de8c2..52ea5df 100644 --- a/webpages/handlers/coffee/forge_rule.coffee +++ b/webpages/handlers/coffee/forge_rule.coffee @@ -54,7 +54,7 @@ domSectionSelectedActions.append $( ' ' ).attr( 'id', 'selected_actions' domSectionSelectedActions.hide() domSectionActionParameters = $( '
' ) -domSectionActionParameters.append $( '
' ).html "

Required Parameters:

" +domSectionActionParameters.append $( '
' ).html "

Required User-specific Data:

" domSectionActionParameters.append $( '
' ).attr( 'id', 'action_invoker_params' ) domSectionActionParameters.append $( '
' ).html "

" domSectionActionParameters.hide() @@ -254,7 +254,7 @@ fDisplayEventParams = ( id ) -> tr.append $( '
' ).text( ' : ' ).append inp table.append tr if i > 0 - $( '#event_poller_params' ).html 'Required Global Parameters:' + $( '#event_poller_params' ).html 'Required User-specific Data:' $( '#event_poller_params' ).append table fFillEventParams id @@ -286,7 +286,7 @@ fFetchEventFunctionArgs = ( arrName ) -> oParams = JSON.parse data.message if oParams[ arrName[ 1 ] ] if oParams[ arrName[ 1 ] ].length > 0 - $( '#event_poller_params' ).append $( "" ).text 'Required Function Parameters:' + $( '#event_poller_params' ).append $( "" ).text 'Required Rule-specific Data:' table = $( '' ).appendTo $( '#event_poller_params' ) for functionArgument in oParams[ arrName[ 1 ] ] tr = $( '' ).attr( 'class', 'funcMappings' ).appendTo table @@ -492,8 +492,8 @@ fOnLoad = () -> name = decodeURIComponent oParams.eventname $( '#input_id' ).val "My '#{ name }' Rule" fPrepareEventType 'Custom Event', () -> - $( '#input_eventname' ).val name - $( '#input_eventname' ).focus() + $( 'input', domInputEventName ).val name + $( 'input', domInputEventName ).focus() editor.setValue "[\n\n]" # For now we don't prepare conditions when 'webhook' @@ -722,44 +722,44 @@ fOnLoad = () -> $( '#input_id' ).val oRule.id # Event - fPrepareEventType oRule.eventtype - switch oRule.eventtype - when 'Event Poller' - $( '#select_event' ).val oRule.eventname - if $( '#select_event' ).val() isnt '' - fFetchEventParams oRule.eventname - $( '#input_event' ).val oRule.eventname - d = new Date oRule.eventstart - mins = d.getMinutes() - if mins.toString().length is 1 - mins = '0' + mins - $( '#input_start', domInputEventTiming ).val d.getHours() + ':' + mins - $( '#input_interval', domInputEventTiming ).val oRule.eventinterval + fPrepareEventType oRule.eventtype, () -> - else - window.scrollTo 0, 0 - $( '#info' ).text 'Error loading Rule: Your Event Poller does not exist anymore!' - $( '#info' ).attr 'class', 'error' + switch oRule.eventtype + when 'Event Poller' + $( 'select', domSelectEventPoller ).val oRule.eventname + if $( 'select', domSelectEventPoller ).val() is oRule.eventname + fFetchEventParams oRule.eventname + d = new Date oRule.eventstart + mins = d.getMinutes() + if mins.toString().length is 1 + mins = '0' + mins + $( '#input_start', domInputEventTiming ).val d.getHours() + ':' + mins + $( '#input_interval', domInputEventTiming ).val oRule.eventinterval - when 'Webhook' - $( '#select_eventhook' ).val oRule.eventname + else + window.scrollTo 0, 0 + $( '#info' ).text 'Error loading Rule: Your Event Poller does not exist anymore!' + $( '#info' ).attr 'class', 'error' - if $( '#select_eventhook' ).val() is '' - window.scrollTo 0, 0 - $( '#info' ).text 'Your Webhook does not exist anymore!' - $( '#info' ).attr 'class', 'error' + when 'Webhook' + $( 'select', domSelectWebhook ).val oRule.eventname - when 'Custom Event' - $( '#input_eventname' ).val oRule.eventname + if $( 'select', domSelectWebhook ).val() is oRule.eventname + window.scrollTo 0, 0 + $( '#info' ).text 'Your Webhook does not exist anymore!' + $( '#info' ).attr 'class', 'error' - # Conditions - editor.setValue JSON.stringify oRule.conditions, undefined, 2 + when 'Custom Event' + $( 'input', domInputEventName ).val oRule.eventname - # Actions - domSectionSelectedActions.show() - for action in oRule.actions - arrName = action.split ' -> ' - fAddSelectedAction action + # Conditions + editor.setValue JSON.stringify oRule.conditions, undefined, 2 + + # Actions + domSectionSelectedActions.show() + for action in oRule.actions + arrName = action.split ' -> ' + fAddSelectedAction action fail: ( err ) -> if err.responseText is '' diff --git a/webpages/handlers/js/forge_rule.js b/webpages/handlers/js/forge_rule.js index 289023f..e55f926 100644 --- a/webpages/handlers/js/forge_rule.js +++ b/webpages/handlers/js/forge_rule.js @@ -73,7 +73,7 @@ domSectionActionParameters = $('
'); - domSectionActionParameters.append($('
').html("

Required Parameters:

")); + domSectionActionParameters.append($('
').html("

Required User-specific Data:

")); domSectionActionParameters.append($('
').attr('id', 'action_invoker_params')); @@ -297,7 +297,7 @@ table.append(tr); } if (i > 0) { - $('#event_poller_params').html('Required Global Parameters:'); + $('#event_poller_params').html('Required User-specific Data:'); $('#event_poller_params').append(table); return fFillEventParams(id); } @@ -347,7 +347,7 @@ oParams = JSON.parse(data.message); if (oParams[arrName[1]]) { if (oParams[arrName[1]].length > 0) { - $('#event_poller_params').append($("").text('Required Function Parameters:')); + $('#event_poller_params').append($("").text('Required Rule-specific Data:')); } table = $('
').appendTo($('#event_poller_params')); _ref = oParams[arrName[1]]; @@ -619,8 +619,8 @@ name = decodeURIComponent(oParams.eventname); $('#input_id').val("My '" + name + "' Rule"); fPrepareEventType('Custom Event', function() { - $('#input_eventname').val(name); - $('#input_eventname').focus(); + $('input', domInputEventName).val(name); + $('input', domInputEventName).focus(); return editor.setValue("[\n\n]"); }); break; @@ -881,51 +881,52 @@ }) }, done: function(data) { - var action, arrName, d, mins, oRule, _j, _len1, _ref, _results; + var oRule; oRule = JSON.parse(data.message); if (oRule) { $('#input_id').val(oRule.id); - fPrepareEventType(oRule.eventtype); - switch (oRule.eventtype) { - case 'Event Poller': - $('#select_event').val(oRule.eventname); - if ($('#select_event').val() !== '') { - fFetchEventParams(oRule.eventname); - $('#input_event').val(oRule.eventname); - d = new Date(oRule.eventstart); - mins = d.getMinutes(); - if (mins.toString().length === 1) { - mins = '0' + mins; + return fPrepareEventType(oRule.eventtype, function() { + var action, arrName, d, mins, _j, _len1, _ref, _results; + switch (oRule.eventtype) { + case 'Event Poller': + $('select', domSelectEventPoller).val(oRule.eventname); + if ($('select', domSelectEventPoller).val() === oRule.eventname) { + fFetchEventParams(oRule.eventname); + d = new Date(oRule.eventstart); + mins = d.getMinutes(); + if (mins.toString().length === 1) { + mins = '0' + mins; + } + $('#input_start', domInputEventTiming).val(d.getHours() + ':' + mins); + $('#input_interval', domInputEventTiming).val(oRule.eventinterval); + } else { + window.scrollTo(0, 0); + $('#info').text('Error loading Rule: Your Event Poller does not exist anymore!'); + $('#info').attr('class', 'error'); } - $('#input_start', domInputEventTiming).val(d.getHours() + ':' + mins); - $('#input_interval', domInputEventTiming).val(oRule.eventinterval); - } else { - window.scrollTo(0, 0); - $('#info').text('Error loading Rule: Your Event Poller does not exist anymore!'); - $('#info').attr('class', 'error'); - } - break; - case 'Webhook': - $('#select_eventhook').val(oRule.eventname); - if ($('#select_eventhook').val() === '') { - window.scrollTo(0, 0); - $('#info').text('Your Webhook does not exist anymore!'); - $('#info').attr('class', 'error'); - } - break; - case 'Custom Event': - $('#input_eventname').val(oRule.eventname); - } - editor.setValue(JSON.stringify(oRule.conditions, void 0, 2)); - domSectionSelectedActions.show(); - _ref = oRule.actions; - _results = []; - for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { - action = _ref[_j]; - arrName = action.split(' -> '); - _results.push(fAddSelectedAction(action)); - } - return _results; + break; + case 'Webhook': + $('select', domSelectWebhook).val(oRule.eventname); + if ($('select', domSelectWebhook).val() === oRule.eventname) { + window.scrollTo(0, 0); + $('#info').text('Your Webhook does not exist anymore!'); + $('#info').attr('class', 'error'); + } + break; + case 'Custom Event': + $('input', domInputEventName).val(oRule.eventname); + } + editor.setValue(JSON.stringify(oRule.conditions, void 0, 2)); + domSectionSelectedActions.show(); + _ref = oRule.actions; + _results = []; + for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { + action = _ref[_j]; + arrName = action.split(' -> '); + _results.push(fAddSelectedAction(action)); + } + return _results; + }); } }, fail: function(err) {