banter 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +8 -0
  4. data/Gemfile +2 -0
  5. data/Rakefile +29 -0
  6. data/lib/banter/subscriber.rb +18 -0
  7. data/lib/banter/version.rb +1 -1
  8. data/lib/banter/web.rb +6 -0
  9. data/lib/banter/web/application.rb +62 -13
  10. data/lib/banter/web/helpers.rb +6 -2
  11. data/lib/banter/web/models/banter_message.rb +45 -5
  12. data/lib/banter/web/models/banter_worker.rb +5 -0
  13. data/lib/banter/web/serializers/banter_message_serializer.rb +34 -0
  14. data/lib/banter/web/serializers/banter_worker_serializer.rb +30 -0
  15. data/lib/banter/web/serializers/subscriber_serializer.rb +26 -0
  16. data/spec/banter/subscriber_spec.rb +82 -1
  17. data/spec/banter/web/application_spec.rb +173 -2
  18. data/spec/factories/banter_messages.rb +28 -0
  19. data/spec/spec_helper.rb +0 -1
  20. data/web/assets/javascripts/banter.js +449 -0
  21. data/web/assets/javascripts/dashboard_app/app.coffee +4 -0
  22. data/web/assets/javascripts/dashboard_app/controllers/message_controller.coffee +27 -0
  23. data/web/assets/javascripts/dashboard_app/controllers/messages_controller.coffee +57 -0
  24. data/web/assets/javascripts/dashboard_app/controllers/subscribers_controller.coffee +25 -0
  25. data/web/assets/javascripts/dashboard_app/controllers/worker_controller.coffee +30 -0
  26. data/web/assets/javascripts/dashboard_app/controllers/workers_list_controller.coffee +28 -0
  27. data/web/assets/javascripts/dashboard_app/routes.coffee +82 -0
  28. data/web/assets/javascripts/dashboard_app/services/common_methods_service.coffee +6 -0
  29. data/web/assets/javascripts/dashboard_app/services/message_methods_service.coffee +18 -0
  30. data/web/assets/javascripts/dashboard_app/services/messages_service.coffee +17 -0
  31. data/web/assets/javascripts/dashboard_app/services/subscribers_service.coffee +8 -0
  32. data/web/assets/javascripts/dashboard_app/services/worker_methods_service.coffee +11 -0
  33. data/web/assets/javascripts/dashboard_app/services/worker_service.coffee +15 -0
  34. data/web/assets/javascripts/ng-prettyjson.js +15 -0
  35. data/web/assets/stylesheets/banter.css +13 -1
  36. data/web/views/_message.haml +59 -0
  37. data/web/views/_messages.haml +77 -0
  38. data/web/views/_subscribers.haml +22 -0
  39. data/web/views/_worker.haml +52 -0
  40. data/web/views/_workers_list.haml +35 -0
  41. data/web/views/index.haml +16 -29
  42. data/web/views/layout.haml +16 -10
  43. metadata +28 -7
  44. data/web/views/message.haml +0 -52
  45. data/web/views/messages.haml +0 -20
  46. data/web/views/subscribers.haml +0 -17
  47. data/web/views/worker.haml +0 -51
@@ -0,0 +1,4 @@
1
+ window.Banter ||= {}
2
+
3
+ angular.module('dashboardApp', [ 'angularMoment', 'ngRoute', 'ngPrettyJson' ])
4
+ angular.module('dashboardApp').constant('rootPath', Banter.rootPath)
@@ -0,0 +1,27 @@
1
+ angular.module('dashboardApp').controller 'messageController', ($scope, $rootScope, $http, $routeParams, $timeout, message, messagesService, commonMethodsService, messageMethodsService) ->
2
+ commonMethodsService.setup($scope)
3
+ messageMethodsService.setup($scope)
4
+ $scope.message = message
5
+
6
+ $rootScope.$on 'start-messageController', ->
7
+ $scope.resumeUpdating() if autoUpdate
8
+ $rootScope.$on 'stop-messageController', ->
9
+ $scope.pauseUpdating()
10
+
11
+ $scope.updateMessage = ->
12
+ if autoUpdate
13
+ messagesService.getMessage($scope.message.id).success (response) ->
14
+ $scope.message = response.message
15
+ $scope.resumeUpdating()
16
+
17
+ $scope.pauseUpdating = ->
18
+ autoUpdate = false
19
+
20
+ $scope.resumeUpdating = ->
21
+ autoUpdate = true
22
+ $timeout($scope.updateMessage, 5000)
23
+
24
+ autoUpdate = $scope.isMessageExecuting()
25
+ $scope.resumeUpdating() if $scope.isMessageExecuting()
26
+
27
+ return
@@ -0,0 +1,57 @@
1
+ angular.module('dashboardApp').controller 'messagesController', ($scope, $rootScope, $http, $routeParams, $timeout, messages, messagesService, commonMethodsService, messageMethodsService, workerMethodsService) ->
2
+ commonMethodsService.setup($scope)
3
+ messageMethodsService.setup($scope)
4
+ workerMethodsService.setup($scope)
5
+
6
+ $scope.messages = messages
7
+ $scope.page = 1
8
+ $scope.worker = null
9
+
10
+ workerId = $routeParams.worker_id
11
+ $scope.subscriber = $routeParams.subscriber
12
+ autoUpdate = true
13
+
14
+ if workerId
15
+ workersService.getWorker(workerId).success (response) ->
16
+ $scope.worker = response.worker
17
+
18
+ fetchMessages = ->
19
+ messagesService.getMessages($scope.page, workerId, $scope.subscriber).success (response) ->
20
+ $scope.messages = response.messages
21
+ $scope.worker = response.worker
22
+
23
+ $rootScope.$on 'start-messagesController', ->
24
+ $scope.resumeUpdating()
25
+ $rootScope.$on 'stop-messagesController', ->
26
+ $scope.pauseUpdating()
27
+
28
+ $scope.updateMessages = (resumeUpdate = true) ->
29
+ if autoUpdate
30
+ fetchMessages()
31
+ $scope.resumeUpdating()
32
+
33
+ $scope.pauseUpdating = ->
34
+ autoUpdate = false
35
+
36
+ $scope.resumeUpdating = ->
37
+ autoUpdate = true
38
+ $timeout($scope.updateMessages, 5000)
39
+
40
+ $scope.resumeUpdating() if autoUpdate
41
+ $scope.isAutoUpdating = ->
42
+ autoUpdate
43
+
44
+ $scope.getNextPage = ->
45
+ $scope.page += 1
46
+ fetchMessages()
47
+
48
+ $scope.getPreviousPage = ->
49
+ $scope.page -= 1
50
+ $scope.page = 1 if $scope.page < 1
51
+ fetchMessages()
52
+
53
+ $scope.getFirstPage = ->
54
+ $scope.page = 1
55
+ fetchMessages()
56
+
57
+ return
@@ -0,0 +1,25 @@
1
+ angular.module('dashboardApp').controller 'subscribersController', ($scope, $rootScope, subscribers, $timeout, subscribersService) ->
2
+ $scope.subscribers = subscribers
3
+
4
+ $rootScope.$on 'start-subscribersController', ->
5
+ $scope.resumeUpdating() if autoUpdate
6
+ $rootScope.$on 'stop-subscribersController', ->
7
+ $scope.pauseUpdating()
8
+
9
+ $scope.updateSubscribers = ->
10
+ if autoUpdate
11
+ subscribersService.getIndex().success (response) ->
12
+ $scope.subscribers = response.subscribers
13
+ $scope.resumeUpdating()
14
+
15
+ $scope.pauseUpdating = ->
16
+ autoUpdate = false
17
+
18
+ $scope.resumeUpdating = ->
19
+ autoUpdate = true
20
+ $timeout($scope.updateSubscribers, 10000)
21
+
22
+ autoUpdate = true
23
+ $scope.resumeUpdating()
24
+
25
+ return
@@ -0,0 +1,30 @@
1
+ angular.module('dashboardApp').controller 'workerController', ($scope, $rootScope, $http, $routeParams, $timeout, worker, workersService, commonMethodsService, workerMethodsService) ->
2
+ commonMethodsService.setup($scope)
3
+ workerMethodsService.setup($scope)
4
+
5
+ $scope.worker = worker
6
+ autoUpdate = false
7
+
8
+ $rootScope.$on 'start-workerController', ->
9
+ $scope.resumeUpdating() if autoUpdate
10
+ $rootScope.$on 'stop-workerController', ->
11
+ $scope.pauseUpdating()
12
+
13
+
14
+ $scope.updateWorker = ->
15
+ if autoUpdate
16
+ workersService.getWorker(worker.id).success (response) ->
17
+ $scope.worker = response.worker
18
+ $scope.resumeUpdating()
19
+
20
+ $scope.pauseUpdating = ->
21
+ autoUpdate = false
22
+
23
+ $scope.resumeUpdating = ->
24
+ autoUpdate = true
25
+ $timeout($scope.updateWorker, 5000)
26
+
27
+ autoUpdate = $scope.isWorkerAlive($scope.worker)
28
+ $scope.resumeUpdating() if $scope.isWorkerAlive($scope.worker)
29
+
30
+ return
@@ -0,0 +1,28 @@
1
+ angular.module('dashboardApp').controller 'workersListController', ($scope, $rootScope, $timeout, $http, workers, rootPath, workersService, commonMethodsService) ->
2
+ commonMethodsService.setup($scope)
3
+
4
+ $scope.workers = workers
5
+ autoUpdate = true
6
+
7
+ $rootScope.$on 'start-workersListController', ->
8
+ $scope.resumeUpdating()
9
+ $rootScope.$on 'stop-workersListController', ->
10
+ $scope.pauseUpdating()
11
+
12
+ $scope.updateWorkers = ->
13
+ if autoUpdate
14
+ workersService.getCurrentList().success (response) ->
15
+ $scope.workers = response.workers
16
+ $scope.resumeUpdating()
17
+
18
+ $scope.pauseUpdating = ->
19
+ autoUpdate = false
20
+
21
+ $scope.resumeUpdating = ->
22
+ autoUpdate = true
23
+ $timeout($scope.updateWorkers, 5000)
24
+
25
+ $scope.resumeUpdating()
26
+ return
27
+
28
+
@@ -0,0 +1,82 @@
1
+ angular.module('dashboardApp').config([ '$routeProvider', '$locationProvider', ($routeProvider, $locationProvider, workersService, messagesService) ->
2
+ messagesResolver = ($q, messagesService, $route) ->
3
+ deferred = $q.defer()
4
+ workerId = $route.current.params.worker_id
5
+ subscriber = $route.current.params.subscriber
6
+ messagesService.getMessages(1, workerId, subscriber).success (response) ->
7
+ deferred.resolve(response.messages)
8
+ deferred.promise
9
+
10
+ messageResolver = ($q, messagesService, $route) ->
11
+ deferred = $q.defer()
12
+ messagesService.getMessage($route.current.params.message_id).success (response) ->
13
+ deferred.resolve(response.message)
14
+ deferred.promise
15
+
16
+ workerResolver = ($q, $route, workersService) ->
17
+ deferred = $q.defer()
18
+ workersService.getWorker($route.current.params.worker_id).success (response) ->
19
+ deferred.resolve(response.worker)
20
+ deferred.promise
21
+
22
+ workersResolver = ($q, workersService) ->
23
+ deferred = $q.defer()
24
+ workersService.getCurrentList().success (response) ->
25
+ deferred.resolve(response.workers)
26
+ deferred.promise
27
+
28
+ subscribersResolver = ($q, subscribersService) ->
29
+ deferred = $q.defer()
30
+ subscribersService.getIndex().success (response) ->
31
+ deferred.resolve(response.subscribers)
32
+ deferred.promise
33
+
34
+ $routeProvider.when("/",
35
+ templateUrl: 'banter/workers-list.html'
36
+ controller: 'workersListController'
37
+ resolve:
38
+ workers: workersResolver
39
+
40
+ ).when("/workers/:worker_id",
41
+ templateUrl: 'banter/worker.html'
42
+ controller: 'workerController'
43
+ resolve:
44
+ worker: workerResolver
45
+ ).when("/workers/:worker_id/messages",
46
+ templateUrl: 'banter/messages.html'
47
+ controller: 'messagesController'
48
+ resolve:
49
+ messages: messagesResolver
50
+ ).when("/subscribers/:subscriber/messages",
51
+ templateUrl: 'banter/messages.html'
52
+ controller: 'messagesController'
53
+ resolve:
54
+ messages: messagesResolver
55
+ ).when("/messages/:message_id",
56
+ templateUrl: 'banter/message.html'
57
+ controller: 'messageController'
58
+ resolve:
59
+ message: messageResolver
60
+ ).when("/messages",
61
+ templateUrl: 'banter/messages.html'
62
+ controller: 'messagesController'
63
+ resolve:
64
+ messages: messagesResolver
65
+ ).when("/subscribers",
66
+ templateUrl: 'banter/subscribers.html'
67
+ controller: 'subscribersController'
68
+ resolve:
69
+ subscribers: subscribersResolver
70
+ ).otherwise(
71
+ redirectTo: "/"
72
+ )
73
+ $locationProvider.html5Mode(true)
74
+ ])
75
+
76
+ angular.module('dashboardApp').run(['$rootScope', '$route', '$location', ($rootScope, $route, $location) ->
77
+ $rootScope.$on '$routeChangeStart', (event, next, current) ->
78
+ if next.$$route?.controller
79
+ $rootScope.$broadcast("start-" + next.$$route.controller)
80
+ if current?.$$route?.controller
81
+ $rootScope.$broadcast("stop-" + current.$$route.controller)
82
+ ])
@@ -0,0 +1,6 @@
1
+ angular.module('dashboardApp').service 'commonMethodsService', [ () ->
2
+ @setup = (scope) ->
3
+ scope.asTime = (time) ->
4
+ new Date(time)
5
+ return
6
+ ]
@@ -0,0 +1,18 @@
1
+ angular.module('dashboardApp').service 'messageMethodsService', [ () ->
2
+ @setup = (scope) ->
3
+ scope.isMessageFailed = (message) ->
4
+ message.status is 'failed' || message.status is 'validation_failed'
5
+
6
+ scope.timeElapsed = (message) ->
7
+ return 0 unless message.done_at
8
+ scope.asTime(message.done_at) - scope.asTime(message.started_at)
9
+
10
+ scope.isMessageExecuting = (message) ->
11
+ scope.message.status is 'started'
12
+
13
+ scope.isMessageSuccessful = (message) ->
14
+ scope.message.status is 'success'
15
+
16
+ return
17
+
18
+ ]
@@ -0,0 +1,17 @@
1
+ angular.module('dashboardApp').service 'messagesService', [ '$http', ($http) ->
2
+ @getMessages = (page, workerId, subscriber) ->
3
+ $http(
4
+ method: 'get'
5
+ url: Banter.rootPath + "messages.json"
6
+ params:
7
+ page: page
8
+ worker_id: workerId
9
+ subscriber: subscriber
10
+ )
11
+ @getMessage = (messageId) ->
12
+ $http(
13
+ method: 'get'
14
+ url: Banter.rootPath + "messages/#{messageId}.json",
15
+ )
16
+ return
17
+ ]
@@ -0,0 +1,8 @@
1
+ angular.module('dashboardApp').service 'subscribersService', [ '$http', ($http) ->
2
+ @getIndex = () ->
3
+ $http(
4
+ method: 'get'
5
+ url: Banter.rootPath + "subscribers.json"
6
+ )
7
+ return
8
+ ]
@@ -0,0 +1,11 @@
1
+ angular.module('dashboardApp').service 'workerMethodsService', [ () ->
2
+ @setup = (scope) ->
3
+ scope.isWorkerExecuting = (worker)->
4
+ worker?.current_message
5
+
6
+ scope.isWorkerAlive = (worker) ->
7
+ !worker?.stopped_at
8
+
9
+ return
10
+ ]
11
+
@@ -0,0 +1,15 @@
1
+ angular.module('dashboardApp').service 'workersService', [ '$http', ($http) ->
2
+ @getCurrentList = () ->
3
+ $http(
4
+ method: 'get'
5
+ url: Banter.rootPath + "workers.json",
6
+ )
7
+
8
+ @getWorker = (workerId) ->
9
+ $http(
10
+ method: 'get'
11
+ url: "#{Banter.rootPath}workers/#{workerId}.json",
12
+ )
13
+
14
+ return
15
+ ]
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @license ng-prettyjson - v0.1.2
3
+ * (c) 2013 Julien VALERY https://github.com/darul75/ng-prettyjson
4
+ * License: MIT
5
+ **/
6
+ angular.module("ngPrettyJson",[]).directive("prettyJson",["ngPrettyJsonFunctions",function(a){"use strict";var b=angular.isDefined;return{restrict:"AE",scope:{json:"=",prettyJson:"="},replace:!0,template:'<div><button ng-click="edit()" ng-show="edition && !editActivated">Edit</button><button ng-click="edit()" ng-show="edition && editActivated">Cancel</button><button ng-click="update()" ng-show="editActivated && parsable">Update</button><pre id="prettyjson"></pre></div>',link:function(c,d,e){var f={},g="prettyjson",h=null;c.editActivated=!1,c.edition=e.edition;// prefer the "json" attribute over the "prettyJson" one.
7
+ // the value on the scope might not be defined yet, so look at the markup.
8
+ var i,j=b(e.json)?"json":"prettyJson",k=function(c){return b(c)?d.find("pre").html(a.syntaxHighlight(c)):d.empty()};i=c.$watch(j,function(a){// BACKWARDS COMPATIBILITY:
9
+ // if newValue is an object, and we find a `json` property,
10
+ // then stop watching on `exp`.
11
+ angular.isObject(a)&&b(a.json)?(i(),c.$watch(j+".json",function(a){k(a),f=a},!0)):(k(a),f=a)},!0);var l=function(){try{c.currentValue=JSON.parse(h.getValue()),c.parsable=!0}catch(a){c.parsable=!1}// trigger update
12
+ c.$apply(function(){})};c.edit=function(){c.editActivated?(h&&(document.getElementById(g).env=null),k(f)):(h=ace.edit(g),h.on("change",l),h.getSession().setMode("ace/mode/json")),c.editActivated=!c.editActivated},c.update=function(){c.$emit("json-updated",c.newValue)}}}}]).factory("ngPrettyJsonFunctions",function(){// cache some regular expressions
13
+ var a={entities:/((&)|(<)|(>))/g,json:/"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|(null))\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g},b=["&amp;","&lt;","&gt;"],c=["number","string","key","boolean","null"],d=function(){var a=arguments.length-2;do a--;while(!arguments[a]);return a},e=function(a){var b;// the final two arguments are the length, and the entire string itself;
14
+ // we don't care about those.
15
+ if(arguments.length<7)throw new Error("markup() must be called from String.prototype.replace()");return b=d.apply(null,arguments),'<span class="'+c[b]+'">'+a+"</span>"},f=function(){var a;if(arguments.length<5)throw new Error("makeEntities() must be called from String.prototype.replace()");return a=d.apply(null,arguments),b[a-2]},g=function(b){return angular.isString(b)||(b=JSON.stringify(b,null,2)),angular.isDefined(b)?b.replace(a.entities,f).replace(a.json,e):void 0};return{syntaxHighlight:g,makeEntities:f,markup:e,rx:a}});
@@ -22,6 +22,10 @@ body {
22
22
  border-radius: 4px;
23
23
  }
24
24
 
25
+ .margin-top-md {
26
+ margin-top: 10px;
27
+ }
28
+
25
29
  .spin{
26
30
  -webkit-transform-origin: 50% 58%;
27
31
  transform-origin:50% 58%;
@@ -63,4 +67,12 @@ body {
63
67
  pre > kbd {
64
68
  background-color: transparent;
65
69
  box-shadow: none;
66
- }
70
+ }
71
+
72
+ /**
73
+ * @license ng-prettyjson - v0.1.2
74
+ * (c) 2013 Julien VALERY https://github.com/darul75/ng-prettyjson
75
+ * License: MIT
76
+ **/
77
+
78
+ pre{outline:1px solid #e9e9e9;padding:5px;margin:5px;width:100%;height:100%}.string{color:green}.number{color:#ff8c00}.boolean{color:#00f}.null{color:#ff00ff}.key{color:red}
@@ -0,0 +1,59 @@
1
+ .clearfix
2
+ %div.extra-bold.pull-right.padding-large.font-size-lg.rounded-corners-md{data: { 'ng-class' => "{'bg-danger' : isMessageFailed(message), 'bg-success': isMessageSuccessful(message), 'bg-info': isMessageExecuting(message)}"}}
3
+ %span{data: { 'ng-if' => 'isMessageExecuting(message)'}}
4
+ %span.glyphicon.glyphicon-refresh.spin
5
+ WORKING
6
+ %span{data: { 'ng-if' => 'isMessageSuccessful(message)'}}
7
+ %span.glyphicon.glyphicon-ok
8
+ SUCCESSFUL
9
+ %span{data: { 'ng-if' => "message.status == 'error' || message.status == 'failed'"}}
10
+ %span.glyphicon.glyphicon-remove
11
+ FAILED
12
+ %span{data: { 'ng-if' => "message.status == 'validation_failed'"}}
13
+ %span.glyphicon.glyphicon-remove
14
+ VALIDATION FAILED
15
+ %h2
16
+ Message
17
+
18
+ %ul.list-group.margin-top-md
19
+ %li.list-group-item.row
20
+ .col-sm-3.bold Subscriber
21
+ .col-sm-9 {{ message.subscriber_class }}
22
+
23
+ %li.list-group-item.row{data: {'ng-if' => 'message.worker'}}
24
+ .col-sm-3.bold Worker
25
+ .col-sm-9
26
+ %a{data: { 'ng-href' => dashboard_path("workers/{{message.worker.id}}")}} {{ message.worker.process_name }} (PID: {{ message.worker.pid }})
27
+ %li.list-group-item.row
28
+ .col-sm-3.bold Subscriber Key
29
+ .col-sm-9 {{ message.subscribed_key }}
30
+
31
+ %li.list-group-item.row
32
+ .col-sm-3.bold Payload Key
33
+ .col-sm-9 {{ message.payload_key }}
34
+
35
+ %li.list-group-item.row
36
+ .col-sm-3.bold Payload
37
+ .col-sm-9
38
+ %pre{data: { 'pretty-json' => 'message.payload'}}
39
+ %li.list-group-item.row{data: {'ng-show' => 'message.progress || message.progress_at || message.progress_total'}}
40
+ .col-sm-3.bold Progress
41
+ .col-sm-9
42
+ %div
43
+ %span{data: {'ng-show' => 'message.progress_at'}} Current: {{message.progress_at }}
44
+ %span{data: { 'ng-show' => 'message.progress_total'}} Total: {{ message.progress_total }}
45
+ %pre{data: { 'pretty-json' => 'message.progress'}}
46
+ %li.list-group-item.row
47
+ .col-sm-3.bold Context
48
+ .col-sm-9
49
+ %pre{data: { 'pretty-json' => 'message.context'}}
50
+ %li.list-group-item.row
51
+ .col-sm-3.bold Started Time
52
+ .col-sm-9 {{ asTime(message.started_at)| amDateFormat:'MM/DD/YYYY, h:mm:ss a' }}
53
+ %li.list-group-item.row{data: { "ng-if" => 'message.done_at'}}
54
+ .col-sm-3.bold Finished Time
55
+ .col-sm-9 {{ asTime(message.started_at)| amDateFormat:'MM/DD/YYYY, h:mm:ss a' }}. Took {{ timeElapsed(message) }}ms
56
+ %li.list-group-item.row
57
+ .col-sm-3.bold Queue
58
+ .col-sm-9 {{ message.queue_name }}
59
+ -#