diff --git a/example/amd/js/libs/postal/postal.diagnostics.js b/example/amd/js/libs/postal/postal.diagnostics.js index 638c9b9..e65e89b 100644 --- a/example/amd/js/libs/postal/postal.diagnostics.js +++ b/example/amd/js/libs/postal/postal.diagnostics.js @@ -1,27 +1,84 @@ // This is the amd module version of postal.diagnostics.js // If you need the standard lib version, go to http://github.com/ifandelse/postal.js -define(["postal", "underscore"], function(postal, _, undefined) { - +define( [ "postal", "underscore" ], function ( postal, _, undefined ) { + var filters = [], + applyFilter = function ( filter, env ) { + var match = 0, possible = 0; + _.each( filter, function ( item, key ) { + if ( env[key] ) { + possible++; + if ( _.isObject( env[key] ) && !_.isArray( env[key] ) ) { + if ( applyFilter( item, env[key] ) ) { + match++; + } + } + else { + if ( _.isEqual( env[key], item ) ) { + match++; + } + } + } + } ); + return match === possible; + }; + // this returns a callback that, if invoked, removes the wireTap - postal.diagnostics = postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { - throw "This browser or environment does not provide JSON support"; - } - try { - console.log(JSON.stringify(all)); - } - catch(exception) { + var wireTap = postal.addWireTap( function ( data, envelope ) { + if ( !filters.length || _.any( filters, function ( filter ) { + return applyFilter( filter, envelope ); + } ) ) { + if ( !JSON ) { + throw "This browser or environment does not provide JSON support"; + } try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); + console.log( JSON.stringify( envelope ) ); } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); + catch ( exception ) { + try { + var env = _.extend( {}, envelope ); + delete env.data; + console.log( JSON.stringify( env ) + "\n\t" + "JSON.stringify Error: " + exception.message ); + } + catch ( ex ) { + console.log( "Unable to parse data to JSON: " + exception ); + } } } - }); + } ); + + postal.diagnostics = { + clearFilters : function () { + filters = []; + }, + removeFilter : function ( filter ) { + filters = _.filter( filters, function ( item ) { + return !_.isEqual( item, filter ); + } ); + }, + addFilter : function ( constraint ) { + if ( !_.isArray( constraint ) ) { + constraint = [ constraint ]; + } + _.each( constraint, function( item ){ + if ( filters.length === 0 || !_.any( filters, function ( filter ) { + return _.isEqual( filter, item ); + } ) ) { + filters.push( item ); + } + }); + + }, + getCurrentFilters : function () { + return filters; + }, + removeWireTap : function () { + if ( wireTap ) { + wireTap(); + } + } + }; + + - -}); \ No newline at end of file +} ); \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.diagnostics.min.js b/example/amd/js/libs/postal/postal.diagnostics.min.js index 0033654..2b27caa 100644 --- a/example/amd/js/libs/postal/postal.diagnostics.min.js +++ b/example/amd/js/libs/postal/postal.diagnostics.min.js @@ -1 +1 @@ -define(["postal","underscore"],function(a,b,c){a.diagnostics=a.addWireTap(function(a,c){var d=b.extend(c,{data:a});if(!JSON)throw"This browser or environment does not provide JSON support";try{console.log(JSON.stringify(d))}catch(e){try{d.data="ERROR: "+e.message,console.log(JSON.stringify(d))}catch(f){console.log("Unable to parse data to JSON: "+e)}}})}) \ No newline at end of file +define(["postal","underscore"],function(a,b,c){var d=[],e=function(a,c){var d=0,f=0;return b.each(a,function(a,g){c[g]&&(f++,b.isObject(c[g])&&!b.isArray(c[g])?e(a,c[g])&&d++:b.isEqual(c[g],a)&&d++)}),d===f},f=a.addWireTap(function(a,c){if(!d.length||b.any(d,function(a){return e(a,c)})){if(!JSON)throw"This browser or environment does not provide JSON support";try{console.log(JSON.stringify(c))}catch(f){try{var g=b.extend({},c);delete g.data,console.log(JSON.stringify(g)+"\n "+"JSON.stringify Error: "+f.message)}catch(h){console.log("Unable to parse data to JSON: "+f)}}}});a.diagnostics={clearFilters:function(){d=[]},removeFilter:function(a){d=b.filter(d,function(c){return!b.isEqual(c,a)})},addFilter:function(a){b.isArray(a)||(a=[a]),b.each(a,function(a){(d.length===0||!b.any(d,function(c){return b.isEqual(c,a)}))&&d.push(a)})},getCurrentFilters:function(){return d},removeWireTap:function(){f&&f()}}}) \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.js b/example/amd/js/libs/postal/postal.js index 725294f..8ef6b5f 100644 --- a/example/amd/js/libs/postal/postal.js +++ b/example/amd/js/libs/postal/postal.js @@ -225,14 +225,25 @@ var bindingsResolver = { this.cache[topic][binding] = true; } return result; + }, + + reset: function() { + this.cache = {}; } }; var localBus = { - subscriptions: {}, - - wireTaps: new Array(0), + addWireTap: function(callback) { + var self = this; + self.wireTaps.push(callback); + return function() { + var idx = self.wireTaps.indexOf(callback); + if(idx !== -1) { + self.wireTaps.splice(idx,1); + } + }; + }, publish: function(envelope) { _.each(this.wireTaps,function(tap) { @@ -253,6 +264,19 @@ var localBus = { }); }, + reset: function() { + if( this.subscriptions ) { + _.each( this.subscriptions , function( channel ){ + _.each( channel, function( topic ){ + while( topic.length ) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + subscribe: function(subDef) { var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; @@ -278,6 +302,10 @@ var localBus = { return subDef; }, + subscriptions: {}, + + wireTaps: new Array(0), + unsubscribe: function(config) { if(this.subscriptions[config.channel][config.topic]) { var len = this.subscriptions[config.channel][config.topic].length, @@ -289,17 +317,6 @@ var localBus = { } } } - }, - - addWireTap: function(callback) { - var self = this; - self.wireTaps.push(callback); - return function() { - var idx = self.wireTaps.indexOf(callback); - if(idx !== -1) { - self.wireTaps.splice(idx,1); - } - }; } }; @@ -351,8 +368,7 @@ var publishPicker = { return new postal.channelTypes[ options.type || "local" ]( channel, topic ); } }, - sessionId = undefined, - lastSessionId = undefined; + sessionInfo = {}; // save some setup time, albeit tiny localBus.subscriptions[SYSTEM_CHANNEL] = {}; @@ -361,6 +377,13 @@ var postal = { configuration: { bus: localBus, resolver: bindingsResolver, + getSessionIdAction: function( callback ) { + callback( sessionInfo ); + }, + setSessionIdAction: function( info, callback ) { + sessionInfo = info; + callback( sessionInfo ); + }, DEFAULT_CHANNEL: DEFAULT_CHANNEL, DEFAULT_PRIORITY: DEFAULT_PRIORITY, DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER, @@ -428,19 +451,25 @@ var postal = { utils: { getSessionId: function( callback ) { - callback( sessionId ); - }, - - getLastSessionId: function( callback ) { - callback( lastSessionId ); + postal.configuration.getSessionIdAction.call( this, callback ); }, setSessionId: function( value, callback ) { - lastSessionId = sessionId; - sessionId = value; - if( callback ) { - callback(); - } + postal.utils.getSessionId( function( info ) { + // get the session info to move id to last id + info.lastId = info.id; + info.id = value; + // invoke the callback the user provided to handle storing session + postal.configuration.setSessionIdAction( info, function( session ) { + callback( session ); + // publish postal event msg about the change + postal.publish({ + channel: SYSTEM_CHANNEL, + topic: "sessionId.changed", + data: session + }); + } ); + }); }, getSubscribersFor: function() { @@ -464,26 +493,12 @@ var postal = { return result; }, - reset: function( callback ) { - // we check first in case a custom bus or resolver - // doesn't expose subscriptions or a resolver cache - if(postal.configuration.bus.subscriptions) { - _.each( postal.configuration.bus.subscriptions , function( channel ){ - _.each( channel, function( topic ){ - while( topic.length ) { - topic.pop().unsubscribe(); - } - }); - }); - postal.configuration.bus.subscriptions = {}; - } - if(postal.configuration.resolver.cache) { - postal.configuration.resolver.cache = {}; - } + reset: function() { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); } } }; - return postal; }); \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.min.js b/example/amd/js/libs/postal/postal.min.js index ef95cef..c01629f 100644 --- a/example/amd/js/libs/postal/postal.min.js +++ b/example/amd/js/libs/postal/postal.min.js @@ -1 +1 @@ -define(["underscore"],function(a,b){var c="/",d=50,e=0,f="postal",g=function(){},h=function(){var b;return function(c){var d=!1;return a.isString(c)?(d=c===b,b=c):(d=a.isEqual(c,b),b=a.clone(c)),!d}},i=function(a,b){this.channel=a||c,this._topic=b||""};i.prototype={subscribe:function(){var a=arguments.length;if(a===1)return new j(this.channel,this._topic,arguments[0]);if(a===2)return new j(this.channel,arguments[0],arguments[1])},publish:function(a){var b={channel:this.channel,topic:this._topic,data:a||{}};return a.topic&&a.data&&(b=a,b.channel=b.channel||this.channel),b.timeStamp=new Date,q.configuration.bus.publish(b),b},topic:function(a){return a===this._topic?this:new i(this.channel,a)}};var j=function(a,b,c){this.channel=a,this.topic=b,this.callback=c,this.priority=d,this.constraints=new Array(0),this.maxCalls=e,this.onHandled=g,this.context=null,q.configuration.bus.publish({channel:f,topic:"subscription.created",timeStamp:new Date,data:{event:"subscription.created",channel:a,topic:b}}),q.configuration.bus.subscribe(this)};j.prototype={unsubscribe:function(){q.configuration.bus.unsubscribe(this),q.configuration.bus.publish({channel:f,topic:"subscription.removed",timeStamp:new Date,data:{event:"subscription.removed",channel:this.channel,topic:this.topic}})},defer:function(){var a=this.callback;return this.callback=function(b){setTimeout(a,0,b)},this},disposeAfter:function(b){if(a.isNaN(b)||b<=0)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var c=this.onHandled,d=a.after(b,a.bind(function(){this.unsubscribe(this)},this));return this.onHandled=function(){c.apply(this.context,arguments),d()},this},ignoreDuplicates:function(){return this.withConstraint(new h),this},withConstraint:function(b){if(!a.isFunction(b))throw"Predicate constraint must be a function";return this.constraints.push(b),this},withConstraints:function(b){var c=this;return a.isArray(b)&&a.each(b,function(a){c.withConstraint(a)}),c},withContext:function(a){return this.context=a,this},withDebounce:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.debounce(c,b),this},withDelay:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=function(a){setTimeout(function(){c(a)},b)},this},withPriority:function(b){if(a.isNaN(b))throw"Priority must be a number";return this.priority=b,this},withThrottle:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.throttle(c,b),this},subscribe:function(a){return this.callback=a,this}};var k={cache:{},compare:function(a,b){if(this.cache[b]&&this.cache[b][a])return!0;var c=new RegExp("^"+a.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/#/g,"[A-Z,a-z,0-9]*")+"$"),d=c.test(b);return d&&(this.cache[b]||(this.cache[b]={}),this.cache[b][a]=!0),d}},l={subscriptions:{},wireTaps:new Array(0),publish:function(b){a.each(this.wireTaps,function(a){a(b.data,b)}),a.each(this.subscriptions[b.channel],function(c){a.each(c,function(c){q.configuration.resolver.compare(c.topic,b.topic)&&a.all(c.constraints,function(a){return a(b.data,b)})&&typeof c.callback=="function"&&(c.callback.apply(c.context,[b.data,b]),c.onHandled())})})},subscribe:function(a){var b,c,d,e=this.subscriptions[a.channel],f;e||(e=this.subscriptions[a.channel]={}),f=this.subscriptions[a.channel][a.topic],f||(f=this.subscriptions[a.channel][a.topic]=new Array(0)),b=f.length-1;for(;b>=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},subscriptions:{},wireTaps:new Array(0),unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c -
+
diff --git a/example/node/client/js/views/templates/menu.html b/example/node/client/js/views/templates/menu.html index b77a8a4..c5e2e17 100644 --- a/example/node/client/js/views/templates/menu.html +++ b/example/node/client/js/views/templates/menu.html @@ -1,7 +1,7 @@
diff --git a/example/node/client/js/views/templates/search-requests.html b/example/node/client/js/views/templates/search-requests.html new file mode 100644 index 0000000..00dd7b8 --- /dev/null +++ b/example/node/client/js/views/templates/search-requests.html @@ -0,0 +1,18 @@ +
+ <% if( requests.length > 0 ) { %> +
+

Search Requests <% if( sessionId === ownerId ) { %>(click one to give control to the requester)<% } %>

+
+ <% _.each( requests, function ( request, idx ) { %> +
(Client ID: <%= request.correlationId %>) - + <% if( sessionId === ownerId ) { %> + <%= request.searchTerm %> + <% } else { %> + <%= request.searchTerm %> + <% } %> +
+ <% }) %> + <% } else { %> +
No other searches have been requested at this time.
+ <% } %> +
\ No newline at end of file diff --git a/example/node/index.js b/example/node/index.js index 2c4635f..ac775e6 100644 --- a/example/node/index.js +++ b/example/node/index.js @@ -54,6 +54,8 @@ var TwitterSocketStats = function( port, refreshinterval ) { searchAgent: new BusAdapter(new TwitterSearch( refreshinterval), searchChannel, searchChannel ), + requestedSearches: [], + stats: collectors.load( searchChannel, statsChannel ), postal: postal, @@ -75,7 +77,8 @@ var TwitterSocketStats = function( port, refreshinterval ) { id: correlationId, searchTerm: searchTerm }; - this.searchAgent.search(searchTerm); + this.searchAgent.search( searchTerm ); + this.removeSearchRequest( correlationId, searchTerm ); this.appChannel.publish({ topic: "search.info", data: this.currentSearch @@ -90,6 +93,35 @@ var TwitterSocketStats = function( port, refreshinterval ) { }); }, + getSearchRequests: function ( env ) { + env || (env = {}); + this.appChannel.publish({ + topic: "search.requests", + correlationId: env.correlationId, + data: this.requestedSearches + }); + }, + + addSearchRequest: function( correlationId, searchTerm ) { + if( !_.any( this.searchRequests, function( item ) { + return item.correlationId === request.correlationId && + item.searchTerm === request.searchTerm; + })) { + this.requestedSearches.push( { correlationId: correlationId, searchTerm: searchTerm } ); + } + }, + + removeSearchRequest: function ( correlationId, searchTerm ) { + if(_.any( this.requestedSearches, function ( item ) { + return item.correlationId = correlationId && item.searchTerm === searchTerm; + })) { + this.requestedSearches = _.filter( this.requestedSearches, function ( item ){ + return item.correlationId !== correlationId && item.searchTerm !== searchTerm; + }); + this.getSearchRequests(); + } + }, + states: { uninitialized: { start: function() { @@ -113,14 +145,15 @@ var TwitterSocketStats = function( port, refreshinterval ) { }, searching: { "search.new.request" : function( data, envelope ) { - if(envelope.correlationId === this.currentSearch.id) { + if( envelope.correlationId === this.currentSearch.id ) { this.setSearch( envelope.correlationId, data.searchTerm ); } else { + this.addSearchRequest( envelope.correlationId, data.searchTerm ); this.appChannel.publish({ topic: "search.new.ask", data: { - correlationId: this.currentSearch.id, + correlationId: envelope.correlationId, searchTerm: data.searchTerm } }); @@ -134,6 +167,9 @@ var TwitterSocketStats = function( port, refreshinterval ) { "get.search.info": function( data, env ) { this.getSearchInfo( env ); }, + "get.search.requests": function( data, env ) { + this.getSearchRequests( env ); + }, "get.available" : function( data, envelope ) { this.getAvailableStats( envelope.correlationId ); }, diff --git a/example/node/messaging/postal.diagnostics.js b/example/node/messaging/postal.diagnostics.js index c9c7d49..f74dacf 100644 --- a/example/node/messaging/postal.diagnostics.js +++ b/example/node/messaging/postal.diagnostics.js @@ -1,25 +1,80 @@ -var _ = require('underscore'); - -module.exports = function(postal) { +module.exports = function( _, postal ) { + var filters = [], + applyFilter = function ( filter, env ) { + var match = 0, possible = 0; + _.each( filter, function ( item, key ) { + if ( env[key] ) { + possible++; + if ( _.isObject( env[key] ) && !_.isArray( env[key] ) ) { + if ( applyFilter( item, env[key] ) ) { + match++; + } + } + else { + if ( _.isEqual( env[key], item ) ) { + match++; + } + } + } + } ); + return match === possible; + }; - // this returns a callback that, if invoked, removes the wireTap - postal.diagnostics = postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { + // this returns a callback that, if invoked, removes the wireTap + var wireTap = postal.addWireTap( function ( data, envelope ) { + if ( !filters.length || _.any( filters, function ( filter ) { + return applyFilter( filter, envelope ); + } ) ) { + if ( !JSON ) { throw "This browser or environment does not provide JSON support"; } try { - console.log(JSON.stringify(all)); + console.log( JSON.stringify( envelope ) ); } - catch(exception) { + catch ( exception ) { try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); + var env = _.extend( {}, envelope ); + delete env.data; + console.log( JSON.stringify( env ) + "\n\t" + "JSON.stringify Error: " + exception.message ); } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); + catch ( ex ) { + console.log( "Unable to parse data to JSON: " + exception ); } } - }); + } + } ); + + postal.diagnostics = { + clearFilters : function () { + filters = []; + }, + removeFilter : function ( filter ) { + filters = _.filter( filters, function ( item ) { + return !_.isEqual( item, filter ); + } ); + }, + addFilter : function ( constraint ) { + if ( !_.isArray( constraint ) ) { + constraint = [ constraint ]; + } + _.each( constraint, function( item ){ + if ( filters.length === 0 || !_.any( filters, function ( filter ) { + return _.isEqual( filter, item ); + } ) ) { + filters.push( item ); + } + }); + + }, + getCurrentFilters : function () { + return filters; + }, + removeWireTap : function () { + if ( wireTap ) { + wireTap(); + } + } + }; + }; \ No newline at end of file diff --git a/example/node/messaging/postal.js b/example/node/messaging/postal.js index 7ae3167..c05f882 100644 --- a/example/node/messaging/postal.js +++ b/example/node/messaging/postal.js @@ -225,14 +225,25 @@ var bindingsResolver = { this.cache[topic][binding] = true; } return result; + }, + + reset: function() { + this.cache = {}; } }; var localBus = { - subscriptions: {}, - - wireTaps: new Array(0), + addWireTap: function(callback) { + var self = this; + self.wireTaps.push(callback); + return function() { + var idx = self.wireTaps.indexOf(callback); + if(idx !== -1) { + self.wireTaps.splice(idx,1); + } + }; + }, publish: function(envelope) { _.each(this.wireTaps,function(tap) { @@ -253,6 +264,19 @@ var localBus = { }); }, + reset: function() { + if( this.subscriptions ) { + _.each( this.subscriptions , function( channel ){ + _.each( channel, function( topic ){ + while( topic.length ) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + subscribe: function(subDef) { var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; @@ -278,6 +302,10 @@ var localBus = { return subDef; }, + subscriptions: {}, + + wireTaps: new Array(0), + unsubscribe: function(config) { if(this.subscriptions[config.channel][config.topic]) { var len = this.subscriptions[config.channel][config.topic].length, @@ -289,17 +317,6 @@ var localBus = { } } } - }, - - addWireTap: function(callback) { - var self = this; - self.wireTaps.push(callback); - return function() { - var idx = self.wireTaps.indexOf(callback); - if(idx !== -1) { - self.wireTaps.splice(idx,1); - } - }; } }; @@ -351,8 +368,7 @@ var publishPicker = { return new postal.channelTypes[ options.type || "local" ]( channel, topic ); } }, - sessionId = undefined, - lastSessionId = undefined; + sessionInfo = {}; // save some setup time, albeit tiny localBus.subscriptions[SYSTEM_CHANNEL] = {}; @@ -361,6 +377,13 @@ var postal = { configuration: { bus: localBus, resolver: bindingsResolver, + getSessionIdAction: function( callback ) { + callback( sessionInfo ); + }, + setSessionIdAction: function( info, callback ) { + sessionInfo = info; + callback( sessionInfo ); + }, DEFAULT_CHANNEL: DEFAULT_CHANNEL, DEFAULT_PRIORITY: DEFAULT_PRIORITY, DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER, @@ -428,19 +451,25 @@ var postal = { utils: { getSessionId: function( callback ) { - callback( sessionId ); - }, - - getLastSessionId: function( callback ) { - callback( lastSessionId ); + postal.configuration.getSessionIdAction.call( this, callback ); }, setSessionId: function( value, callback ) { - lastSessionId = sessionId; - sessionId = value; - if( callback ) { - callback(); - } + postal.utils.getSessionId( function( info ) { + // get the session info to move id to last id + info.lastId = info.id; + info.id = value; + // invoke the callback the user provided to handle storing session + postal.configuration.setSessionIdAction( info, function( session ) { + callback( session ); + // publish postal event msg about the change + postal.publish({ + channel: SYSTEM_CHANNEL, + topic: "sessionId.changed", + data: session + }); + } ); + }); }, getSubscribersFor: function() { @@ -464,25 +493,11 @@ var postal = { return result; }, - reset: function( callback ) { - // we check first in case a custom bus or resolver - // doesn't expose subscriptions or a resolver cache - if(postal.configuration.bus.subscriptions) { - _.each( postal.configuration.bus.subscriptions , function( channel ){ - _.each( channel, function( topic ){ - while( topic.length ) { - topic.pop().unsubscribe(); - } - }); - }); - postal.configuration.bus.subscriptions = {}; - } - if(postal.configuration.resolver.cache) { - postal.configuration.resolver.cache = {}; - } + reset: function() { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); } } }; - module.exports = postal; \ No newline at end of file diff --git a/example/node/messaging/postal.socket-host.js b/example/node/messaging/postal.socket-host.js index 67a59fe..d6eca0d 100644 --- a/example/node/messaging/postal.socket-host.js +++ b/example/node/messaging/postal.socket-host.js @@ -60,10 +60,10 @@ var RemoteClientProxy = function( postal, socketClient, bridge ) { "*" : function() { this.deferUntilTransition(); }, - clientId : function( data ) { - this.sessionId = data.sessionId; - if( bridge.enableMigration && data.lastSessionId && data.lastSessionId !== data.sessionId ) { - this.lastSessionId = data.lastSessionId; + clientId : function( session ) { + this.sessionId = session.id; + if( bridge.enableMigration && session.lastId && session.lastId !== session.id ) { + this.lastSessionId = session.lastId; this.transition( "migrating" ); } else { diff --git a/example/standard/js/postal.diagnostics.js b/example/standard/js/postal.diagnostics.js index 250d5bc..4cfdf0b 100644 --- a/example/standard/js/postal.diagnostics.js +++ b/example/standard/js/postal.diagnostics.js @@ -2,26 +2,83 @@ // If you need the amd-module style version, go to http://github.com/ifandelse/postal.js (function(postal, _, undefined) { - + var filters = [], + applyFilter = function ( filter, env ) { + var match = 0, possible = 0; + _.each( filter, function ( item, key ) { + if ( env[key] ) { + possible++; + if ( _.isObject( env[key] ) && !_.isArray( env[key] ) ) { + if ( applyFilter( item, env[key] ) ) { + match++; + } + } + else { + if ( _.isEqual( env[key], item ) ) { + match++; + } + } + } + } ); + return match === possible; + }; + // this returns a callback that, if invoked, removes the wireTap - postal.diagnostics = postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { - throw "This browser or environment does not provide JSON support"; - } - try { - console.log(JSON.stringify(all)); - } - catch(exception) { + var wireTap = postal.addWireTap( function ( data, envelope ) { + if ( !filters.length || _.any( filters, function ( filter ) { + return applyFilter( filter, envelope ); + } ) ) { + if ( !JSON ) { + throw "This browser or environment does not provide JSON support"; + } try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); + console.log( JSON.stringify( envelope ) ); } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); + catch ( exception ) { + try { + var env = _.extend( {}, envelope ); + delete env.data; + console.log( JSON.stringify( env ) + "\n\t" + "JSON.stringify Error: " + exception.message ); + } + catch ( ex ) { + console.log( "Unable to parse data to JSON: " + exception ); + } } } - }); - + } ); + + postal.diagnostics = { + clearFilters : function () { + filters = []; + }, + removeFilter : function ( filter ) { + filters = _.filter( filters, function ( item ) { + return !_.isEqual( item, filter ); + } ); + }, + addFilter : function ( constraint ) { + if ( !_.isArray( constraint ) ) { + constraint = [ constraint ]; + } + _.each( constraint, function( item ){ + if ( filters.length === 0 || !_.any( filters, function ( filter ) { + return _.isEqual( filter, item ); + } ) ) { + filters.push( item ); + } + }); + + }, + getCurrentFilters : function () { + return filters; + }, + removeWireTap : function () { + if ( wireTap ) { + wireTap(); + } + } + }; + + })( postal, _ ); \ No newline at end of file diff --git a/example/standard/js/postal.diagnostics.min.js b/example/standard/js/postal.diagnostics.min.js index dfd9e1b..139585c 100644 --- a/example/standard/js/postal.diagnostics.min.js +++ b/example/standard/js/postal.diagnostics.min.js @@ -1 +1 @@ -(function(a,b,c){a.diagnostics=a.addWireTap(function(a,c){var d=b.extend(c,{data:a});if(!JSON)throw"This browser or environment does not provide JSON support";try{console.log(JSON.stringify(d))}catch(e){try{d.data="ERROR: "+e.message,console.log(JSON.stringify(d))}catch(f){console.log("Unable to parse data to JSON: "+e)}}})})(postal,_) \ No newline at end of file +(function(a,b,c){var d=[],e=function(a,c){var d=0,f=0;return b.each(a,function(a,g){c[g]&&(f++,b.isObject(c[g])&&!b.isArray(c[g])?e(a,c[g])&&d++:b.isEqual(c[g],a)&&d++)}),d===f},f=a.addWireTap(function(a,c){if(!d.length||b.any(d,function(a){return e(a,c)})){if(!JSON)throw"This browser or environment does not provide JSON support";try{console.log(JSON.stringify(c))}catch(f){try{var g=b.extend({},c);delete g.data,console.log(JSON.stringify(g)+"\n "+"JSON.stringify Error: "+f.message)}catch(h){console.log("Unable to parse data to JSON: "+f)}}}});a.diagnostics={clearFilters:function(){d=[]},removeFilter:function(a){d=b.filter(d,function(c){return!b.isEqual(c,a)})},addFilter:function(a){b.isArray(a)||(a=[a]),b.each(a,function(a){(d.length===0||!b.any(d,function(c){return b.isEqual(c,a)}))&&d.push(a)})},getCurrentFilters:function(){return d},removeWireTap:function(){f&&f()}}})(postal,_) \ No newline at end of file diff --git a/example/standard/js/postal.js b/example/standard/js/postal.js index a81f1a4..80a240f 100644 --- a/example/standard/js/postal.js +++ b/example/standard/js/postal.js @@ -225,14 +225,25 @@ var bindingsResolver = { this.cache[topic][binding] = true; } return result; + }, + + reset: function() { + this.cache = {}; } }; var localBus = { - subscriptions: {}, - - wireTaps: new Array(0), + addWireTap: function(callback) { + var self = this; + self.wireTaps.push(callback); + return function() { + var idx = self.wireTaps.indexOf(callback); + if(idx !== -1) { + self.wireTaps.splice(idx,1); + } + }; + }, publish: function(envelope) { _.each(this.wireTaps,function(tap) { @@ -253,6 +264,19 @@ var localBus = { }); }, + reset: function() { + if( this.subscriptions ) { + _.each( this.subscriptions , function( channel ){ + _.each( channel, function( topic ){ + while( topic.length ) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + subscribe: function(subDef) { var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; @@ -278,6 +302,10 @@ var localBus = { return subDef; }, + subscriptions: {}, + + wireTaps: new Array(0), + unsubscribe: function(config) { if(this.subscriptions[config.channel][config.topic]) { var len = this.subscriptions[config.channel][config.topic].length, @@ -289,17 +317,6 @@ var localBus = { } } } - }, - - addWireTap: function(callback) { - var self = this; - self.wireTaps.push(callback); - return function() { - var idx = self.wireTaps.indexOf(callback); - if(idx !== -1) { - self.wireTaps.splice(idx,1); - } - }; } }; @@ -351,8 +368,7 @@ var publishPicker = { return new postal.channelTypes[ options.type || "local" ]( channel, topic ); } }, - sessionId = undefined, - lastSessionId = undefined; + sessionInfo = {}; // save some setup time, albeit tiny localBus.subscriptions[SYSTEM_CHANNEL] = {}; @@ -361,6 +377,13 @@ var postal = { configuration: { bus: localBus, resolver: bindingsResolver, + getSessionIdAction: function( callback ) { + callback( sessionInfo ); + }, + setSessionIdAction: function( info, callback ) { + sessionInfo = info; + callback( sessionInfo ); + }, DEFAULT_CHANNEL: DEFAULT_CHANNEL, DEFAULT_PRIORITY: DEFAULT_PRIORITY, DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER, @@ -428,19 +451,25 @@ var postal = { utils: { getSessionId: function( callback ) { - callback( sessionId ); - }, - - getLastSessionId: function( callback ) { - callback( lastSessionId ); + postal.configuration.getSessionIdAction.call( this, callback ); }, setSessionId: function( value, callback ) { - lastSessionId = sessionId; - sessionId = value; - if( callback ) { - callback(); - } + postal.utils.getSessionId( function( info ) { + // get the session info to move id to last id + info.lastId = info.id; + info.id = value; + // invoke the callback the user provided to handle storing session + postal.configuration.setSessionIdAction( info, function( session ) { + callback( session ); + // publish postal event msg about the change + postal.publish({ + channel: SYSTEM_CHANNEL, + topic: "sessionId.changed", + data: session + }); + } ); + }); }, getSubscribersFor: function() { @@ -464,27 +493,13 @@ var postal = { return result; }, - reset: function( callback ) { - // we check first in case a custom bus or resolver - // doesn't expose subscriptions or a resolver cache - if(postal.configuration.bus.subscriptions) { - _.each( postal.configuration.bus.subscriptions , function( channel ){ - _.each( channel, function( topic ){ - while( topic.length ) { - topic.pop().unsubscribe(); - } - }); - }); - postal.configuration.bus.subscriptions = {}; - } - if(postal.configuration.resolver.cache) { - postal.configuration.resolver.cache = {}; - } + reset: function() { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); } } }; - global.postal = postal; })(_, window); \ No newline at end of file diff --git a/example/standard/js/postal.min.js b/example/standard/js/postal.min.js index 01f72c8..833338c 100644 --- a/example/standard/js/postal.min.js +++ b/example/standard/js/postal.min.js @@ -1 +1 @@ -(function(a,b,c){var d="/",e=50,f=0,g="postal",h=function(){},i=function(){var b;return function(c){var d=!1;return a.isString(c)?(d=c===b,b=c):(d=a.isEqual(c,b),b=a.clone(c)),!d}},j=function(a,b){this.channel=a||d,this._topic=b||""};j.prototype={subscribe:function(){var a=arguments.length;if(a===1)return new k(this.channel,this._topic,arguments[0]);if(a===2)return new k(this.channel,arguments[0],arguments[1])},publish:function(a){var b={channel:this.channel,topic:this._topic,data:a||{}};return a.topic&&a.data&&(b=a,b.channel=b.channel||this.channel),b.timeStamp=new Date,r.configuration.bus.publish(b),b},topic:function(a){return a===this._topic?this:new j(this.channel,a)}};var k=function(a,b,c){this.channel=a,this.topic=b,this.callback=c,this.priority=e,this.constraints=new Array(0),this.maxCalls=f,this.onHandled=h,this.context=null,r.configuration.bus.publish({channel:g,topic:"subscription.created",timeStamp:new Date,data:{event:"subscription.created",channel:a,topic:b}}),r.configuration.bus.subscribe(this)};k.prototype={unsubscribe:function(){r.configuration.bus.unsubscribe(this),r.configuration.bus.publish({channel:g,topic:"subscription.removed",timeStamp:new Date,data:{event:"subscription.removed",channel:this.channel,topic:this.topic}})},defer:function(){var a=this.callback;return this.callback=function(b){setTimeout(a,0,b)},this},disposeAfter:function(b){if(a.isNaN(b)||b<=0)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var c=this.onHandled,d=a.after(b,a.bind(function(){this.unsubscribe(this)},this));return this.onHandled=function(){c.apply(this.context,arguments),d()},this},ignoreDuplicates:function(){return this.withConstraint(new i),this},withConstraint:function(b){if(!a.isFunction(b))throw"Predicate constraint must be a function";return this.constraints.push(b),this},withConstraints:function(b){var c=this;return a.isArray(b)&&a.each(b,function(a){c.withConstraint(a)}),c},withContext:function(a){return this.context=a,this},withDebounce:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.debounce(c,b),this},withDelay:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=function(a){setTimeout(function(){c(a)},b)},this},withPriority:function(b){if(a.isNaN(b))throw"Priority must be a number";return this.priority=b,this},withThrottle:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.throttle(c,b),this},subscribe:function(a){return this.callback=a,this}};var l={cache:{},compare:function(a,b){if(this.cache[b]&&this.cache[b][a])return!0;var c=new RegExp("^"+a.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/#/g,"[A-Z,a-z,0-9]*")+"$"),d=c.test(b);return d&&(this.cache[b]||(this.cache[b]={}),this.cache[b][a]=!0),d}},m={subscriptions:{},wireTaps:new Array(0),publish:function(b){a.each(this.wireTaps,function(a){a(b.data,b)}),a.each(this.subscriptions[b.channel],function(c){a.each(c,function(c){r.configuration.resolver.compare(c.topic,b.topic)&&a.all(c.constraints,function(a){return a(b.data,b)})&&typeof c.callback=="function"&&(c.callback.apply(c.context,[b.data,b]),c.onHandled())})})},subscribe:function(a){var b,c,d,e=this.subscriptions[a.channel],f;e||(e=this.subscriptions[a.channel]={}),f=this.subscriptions[a.channel][a.topic],f||(f=this.subscriptions[a.channel][a.topic]=new Array(0)),b=f.length-1;for(;b>=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},subscriptions:{},wireTaps:new Array(0),unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},subscriptions:{},wireTaps:new Array(0),unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},subscriptions:{},wireTaps:new Array(0),unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c