scales-monitor 0.0.1.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE +22 -0
  4. data/Rakefile +8 -0
  5. data/bin/scales-monitor +8 -0
  6. data/lib/scales-monitor.rb +11 -0
  7. data/lib/scales-monitor/app/Gemfile +3 -0
  8. data/lib/scales-monitor/app/Rakefile +0 -0
  9. data/lib/scales-monitor/app/app/assets/images/.gitignore +0 -0
  10. data/lib/scales-monitor/app/app/assets/images/glyphicons-halflings-white.png +0 -0
  11. data/lib/scales-monitor/app/app/assets/images/glyphicons-halflings.png +0 -0
  12. data/lib/scales-monitor/app/app/assets/javascripts/app/config/config.js.coffee +8 -0
  13. data/lib/scales-monitor/app/app/assets/javascripts/app/config/routes.js.coffee +15 -0
  14. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/.gitignore +0 -0
  15. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/log.jst.coffee +58 -0
  16. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/machines.js.coffee +60 -0
  17. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/queues.js.coffee +55 -0
  18. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/resources.js.coffee +128 -0
  19. data/lib/scales-monitor/app/app/assets/javascripts/app/index.js.coffee +8 -0
  20. data/lib/scales-monitor/app/app/assets/javascripts/app/models/.gitignore +0 -0
  21. data/lib/scales-monitor/app/app/assets/javascripts/app/models/socket.js.coffee +9 -0
  22. data/lib/scales-monitor/app/app/assets/javascripts/app/views/.gitignore +0 -0
  23. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_format_bar.jst.eco +10 -0
  24. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_machine.jst.eco +11 -0
  25. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_queue_item.jst.eco +10 -0
  26. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_resource.jst.eco +5 -0
  27. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_top.jst.eco +1 -0
  28. data/lib/scales-monitor/app/app/assets/javascripts/app/views/log.jst.eco +11 -0
  29. data/lib/scales-monitor/app/app/assets/javascripts/app/views/machines.jst.eco +33 -0
  30. data/lib/scales-monitor/app/app/assets/javascripts/app/views/queues.jst.eco +33 -0
  31. data/lib/scales-monitor/app/app/assets/javascripts/app/views/resources.jst.eco +31 -0
  32. data/lib/scales-monitor/app/app/assets/javascripts/application.js.coffee +16 -0
  33. data/lib/scales-monitor/app/app/assets/javascripts/lib/bootstrap.js +1825 -0
  34. data/lib/scales-monitor/app/app/assets/javascripts/lib/jquery.js +4 -0
  35. data/lib/scales-monitor/app/app/assets/javascripts/lib/jquery.timeago.js +152 -0
  36. data/lib/scales-monitor/app/app/assets/javascripts/lib/json2.js +485 -0
  37. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/ajax.coffee +208 -0
  38. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/list.coffee +43 -0
  39. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/local.coffee +16 -0
  40. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/manager.coffee +83 -0
  41. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/relation.coffee +144 -0
  42. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/route.coffee +145 -0
  43. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/spine.coffee +537 -0
  44. data/lib/scales-monitor/app/app/assets/stylesheets/application.css.scss +58 -0
  45. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap-docs.css +845 -0
  46. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap-responsive.css +815 -0
  47. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap.css +4983 -0
  48. data/lib/scales-monitor/app/app/views/index.html.erb +45 -0
  49. data/lib/scales-monitor/app/config.ru +3 -0
  50. data/lib/scales-monitor/app/config/config.rb +17 -0
  51. data/lib/scales-monitor/app/config/routes.rb +13 -0
  52. data/lib/scales-monitor/app/public/assets/.gitignore +0 -0
  53. data/lib/scales-monitor/app/public/assets/application.css +6709 -0
  54. data/lib/scales-monitor/app/public/assets/application.js +5563 -0
  55. data/lib/scales-monitor/app/public/assets/glyphicons-halflings-white.png +0 -0
  56. data/lib/scales-monitor/app/public/assets/glyphicons-halflings.png +0 -0
  57. data/lib/scales-monitor/app/public/index.html +45 -0
  58. data/lib/scales-monitor/base.rb +17 -0
  59. data/lib/scales-monitor/boot/autoload.rb +5 -0
  60. data/lib/scales-monitor/boot/initializers/goliath.rb +3 -0
  61. data/lib/scales-monitor/monitor.rb +33 -0
  62. data/lib/scales-monitor/version.rb +5 -0
  63. data/lib/scales-monitor/web_socket.rb +180 -0
  64. data/scales-monitor.gemspec +24 -0
  65. data/spec/gem_spec.rb +7 -0
  66. data/spec/helper.rb +50 -0
  67. data/spec/monitor_spec.rb +50 -0
  68. data/spec/web_socket_spec.rb +103 -0
  69. metadata +174 -0
@@ -0,0 +1,208 @@
1
+ Spine = @Spine or require('spine')
2
+ $ = Spine.$
3
+ Model = Spine.Model
4
+
5
+ Ajax =
6
+ getURL: (object) ->
7
+ object and object.url?() or object.url
8
+
9
+ enabled: true
10
+ pending: false
11
+ requests: []
12
+
13
+ disable: (callback) ->
14
+ if @enabled
15
+ @enabled = false
16
+ try
17
+ do callback
18
+ catch e
19
+ throw e
20
+ finally
21
+ @enabled = true
22
+ else
23
+ do callback
24
+
25
+ requestNext: ->
26
+ next = @requests.shift()
27
+ if next
28
+ @request(next)
29
+ else
30
+ @pending = false
31
+
32
+ request: (callback) ->
33
+ (do callback).complete(=> do @requestNext)
34
+
35
+ queue: (callback) ->
36
+ return unless @enabled
37
+ if @pending
38
+ @requests.push(callback)
39
+ else
40
+ @pending = true
41
+ @request(callback)
42
+ callback
43
+
44
+ class Base
45
+ defaults:
46
+ contentType: 'application/json'
47
+ dataType: 'json'
48
+ processData: false
49
+ headers: {'X-Requested-With': 'XMLHttpRequest'}
50
+
51
+ ajax: (params, defaults) ->
52
+ $.ajax($.extend({}, @defaults, defaults, params))
53
+
54
+ queue: (callback) ->
55
+ Ajax.queue(callback)
56
+
57
+ class Collection extends Base
58
+ constructor: (@model) ->
59
+
60
+ find: (id, params) ->
61
+ record = new @model(id: id)
62
+ @ajax(
63
+ params,
64
+ type: 'GET',
65
+ url: Ajax.getURL(record)
66
+ ).success(@recordsResponse)
67
+ .error(@errorResponse)
68
+
69
+ all: (params) ->
70
+ @ajax(
71
+ params,
72
+ type: 'GET',
73
+ url: Ajax.getURL(@model)
74
+ ).success(@recordsResponse)
75
+ .error(@errorResponse)
76
+
77
+ fetch: (params = {}, options = {}) ->
78
+ if id = params.id
79
+ delete params.id
80
+ @find(id, params).success (record) =>
81
+ @model.refresh(record, options)
82
+ else
83
+ @all(params).success (records) =>
84
+ @model.refresh(records, options)
85
+
86
+ # Private
87
+
88
+ recordsResponse: (data, status, xhr) =>
89
+ @model.trigger('ajaxSuccess', null, status, xhr)
90
+
91
+ errorResponse: (xhr, statusText, error) =>
92
+ @model.trigger('ajaxError', null, xhr, statusText, error)
93
+
94
+ class Singleton extends Base
95
+ constructor: (@record) ->
96
+ @model = @record.constructor
97
+
98
+ reload: (params, options) ->
99
+ @queue =>
100
+ @ajax(
101
+ params,
102
+ type: 'GET'
103
+ url: Ajax.getURL(@record)
104
+ ).success(@recordResponse(options))
105
+ .error(@errorResponse(options))
106
+
107
+ create: (params, options) ->
108
+ @queue =>
109
+ @ajax(
110
+ params,
111
+ type: 'POST'
112
+ data: JSON.stringify(@record)
113
+ url: Ajax.getURL(@model)
114
+ ).success(@recordResponse(options))
115
+ .error(@errorResponse(options))
116
+
117
+ update: (params, options) ->
118
+ @queue =>
119
+ @ajax(
120
+ params,
121
+ type: 'PUT'
122
+ data: JSON.stringify(@record)
123
+ url: Ajax.getURL(@record)
124
+ ).success(@recordResponse(options))
125
+ .error(@errorResponse(options))
126
+
127
+ destroy: (params, options) ->
128
+ @queue =>
129
+ @ajax(
130
+ params,
131
+ type: 'DELETE'
132
+ url: Ajax.getURL(@record)
133
+ ).success(@recordResponse(options))
134
+ .error(@errorResponse(options))
135
+
136
+ # Private
137
+
138
+ recordResponse: (options = {}) =>
139
+ (data, status, xhr) =>
140
+ if Spine.isBlank(data)
141
+ data = false
142
+ else
143
+ data = @model.fromJSON(data)
144
+
145
+ Ajax.disable =>
146
+ if data
147
+ # ID change, need to do some shifting
148
+ if data.id and @record.id isnt data.id
149
+ @record.changeID(data.id)
150
+
151
+ # Update with latest data
152
+ @record.updateAttributes(data.attributes())
153
+
154
+ @record.trigger('ajaxSuccess', data, status, xhr)
155
+ options.success?.apply(@record)
156
+
157
+ errorResponse: (options = {}) =>
158
+ (xhr, statusText, error) =>
159
+ @record.trigger('ajaxError', xhr, statusText, error)
160
+ options.error?.apply(@record)
161
+
162
+ # Ajax endpoint
163
+ Model.host = ''
164
+
165
+ Include =
166
+ ajax: -> new Singleton(this)
167
+
168
+ url: (args...) ->
169
+ url = Ajax.getURL(@constructor)
170
+ url += '/' unless url.charAt(url.length - 1) is '/'
171
+ url += encodeURIComponent(@id)
172
+ args.unshift(url)
173
+ args.join('/')
174
+
175
+ Extend =
176
+ ajax: -> new Collection(this)
177
+
178
+ url: (args...) ->
179
+ args.unshift(@className.toLowerCase() + 's')
180
+ args.unshift(Model.host)
181
+ args.join('/')
182
+
183
+ Model.Ajax =
184
+ extended: ->
185
+ @fetch @ajaxFetch
186
+ @change @ajaxChange
187
+
188
+ @extend Extend
189
+ @include Include
190
+
191
+ # Private
192
+
193
+ ajaxFetch: ->
194
+ @ajax().fetch(arguments...)
195
+
196
+ ajaxChange: (record, type, options = {}) ->
197
+ return if options.ajax is false
198
+ record.ajax()[type](options.ajax, options)
199
+
200
+ Model.Ajax.Methods =
201
+ extended: ->
202
+ @extend Extend
203
+ @include Include
204
+
205
+ # Globals
206
+ Ajax.defaults = Base::defaults
207
+ Spine.Ajax = Ajax
208
+ module?.exports = Ajax
@@ -0,0 +1,43 @@
1
+ Spine = @Spine or require('spine')
2
+ $ = Spine.$
3
+
4
+ class Spine.List extends Spine.Controller
5
+ events:
6
+ 'click .item': 'click'
7
+
8
+ selectFirst: false
9
+
10
+ constructor: ->
11
+ super
12
+ @bind 'change', @change
13
+
14
+ template: ->
15
+ throw 'Override template'
16
+
17
+ change: (item) =>
18
+ @current = item
19
+
20
+ unless @current
21
+ @children().removeClass('active')
22
+ return
23
+
24
+ @children().removeClass('active')
25
+ $(@children().get(@items.indexOf(@current))).addClass('active')
26
+
27
+ render: (items) ->
28
+ @items = items if items
29
+ @html @template(@items)
30
+ @change @current
31
+ if @selectFirst
32
+ unless @children('.active').length
33
+ @children(':first').click()
34
+
35
+ children: (sel) ->
36
+ @el.children(sel)
37
+
38
+ click: (e) ->
39
+ item = @items[$(e.currentTarget).index()]
40
+ @trigger('change', item)
41
+ true
42
+
43
+ module?.exports = Spine.List
@@ -0,0 +1,16 @@
1
+ Spine = @Spine or require('spine')
2
+
3
+ Spine.Model.Local =
4
+ extended: ->
5
+ @change @saveLocal
6
+ @fetch @loadLocal
7
+
8
+ saveLocal: ->
9
+ result = JSON.stringify(@)
10
+ localStorage[@className] = result
11
+
12
+ loadLocal: ->
13
+ result = localStorage[@className]
14
+ @refresh(result or [], clear: true)
15
+
16
+ module?.exports = Spine.Model.Local
@@ -0,0 +1,83 @@
1
+ Spine = @Spine or require('spine')
2
+ $ = Spine.$
3
+
4
+ class Spine.Manager extends Spine.Module
5
+ @include Spine.Events
6
+
7
+ constructor: ->
8
+ @controllers = []
9
+ @bind 'change', @change
10
+ @add(arguments...)
11
+
12
+ add: (controllers...) ->
13
+ @addOne(cont) for cont in controllers
14
+
15
+ addOne: (controller) ->
16
+ controller.bind 'active', (args...) =>
17
+ @trigger('change', controller, args...)
18
+ controller.bind 'release', =>
19
+ @controllers.splice(@controllers.indexOf(controller), 1)
20
+
21
+ @controllers.push(controller)
22
+
23
+ deactivate: ->
24
+ @trigger('change', false, arguments...)
25
+
26
+ # Private
27
+
28
+ change: (current, args...) ->
29
+ for cont in @controllers
30
+ if cont is current
31
+ cont.activate(args...)
32
+ else
33
+ cont.deactivate(args...)
34
+
35
+ Spine.Controller.include
36
+ active: (args...) ->
37
+ if typeof args[0] is 'function'
38
+ @bind('active', args[0])
39
+ else
40
+ args.unshift('active')
41
+ @trigger(args...)
42
+ @
43
+
44
+ isActive: ->
45
+ @el.hasClass('active')
46
+
47
+ activate: ->
48
+ @el.addClass('active')
49
+ @
50
+
51
+ deactivate: ->
52
+ @el.removeClass('active')
53
+ @
54
+
55
+ class Spine.Stack extends Spine.Controller
56
+ controllers: {}
57
+ routes: {}
58
+
59
+ className: 'spine stack'
60
+
61
+ constructor: ->
62
+ super
63
+
64
+ @manager = new Spine.Manager
65
+
66
+ for key, value of @controllers
67
+ @[key] = new value(stack: @)
68
+ @add(@[key])
69
+
70
+ for key, value of @routes
71
+ do (key, value) =>
72
+ callback = value if typeof value is 'function'
73
+ callback or= => @[value].active(arguments...)
74
+ @route(key, callback)
75
+
76
+ @[@default].active() if @default
77
+
78
+ add: (controller) ->
79
+ @manager.add(controller)
80
+ @append(controller)
81
+
82
+ module?.exports = Spine.Manager
83
+ module?.exports.Stack = Spine.Stack
@@ -0,0 +1,144 @@
1
+ Spine = @Spine or require('spine')
2
+ isArray = Spine.isArray
3
+ require = @require or ((value) -> eval(value))
4
+
5
+ class Collection extends Spine.Module
6
+ constructor: (options = {}) ->
7
+ for key, value of options
8
+ @[key] = value
9
+
10
+ all: ->
11
+ @model.select (rec) => @associated(rec)
12
+
13
+ first: ->
14
+ @all()[0]
15
+
16
+ last: ->
17
+ values = @all()
18
+ values[values.length - 1]
19
+
20
+ find: (id) ->
21
+ records = @select (rec) =>
22
+ rec.id + '' is id + ''
23
+ throw('Unknown record') unless records[0]
24
+ records[0]
25
+
26
+ findAllByAttribute: (name, value) ->
27
+ @model.select (rec) =>
28
+ @associated(rec) and rec[name] is value
29
+
30
+ findByAttribute: (name, value) ->
31
+ @findAllByAttribute(name, value)[0]
32
+
33
+ select: (cb) ->
34
+ @model.select (rec) =>
35
+ @associated(rec) and cb(rec)
36
+
37
+ refresh: (values) ->
38
+ delete @model.records[record.id] for record in @all()
39
+ records = @model.fromJSON(values)
40
+
41
+ records = [records] unless isArray(records)
42
+
43
+ for record in records
44
+ record.newRecord = false
45
+ record[@fkey] = @record.id
46
+ @model.records[record.id] = record
47
+
48
+ @model.trigger('refresh', @model.cloneArray(records))
49
+
50
+ create: (record) ->
51
+ record[@fkey] = @record.id
52
+ @model.create(record)
53
+
54
+ # Private
55
+
56
+ associated: (record) ->
57
+ record[@fkey] is @record.id
58
+
59
+ class Instance extends Spine.Module
60
+ constructor: (options = {}) ->
61
+ for key, value of options
62
+ @[key] = value
63
+
64
+ exists: ->
65
+ @record[@fkey] and @model.exists(@record[@fkey])
66
+
67
+ update: (value) ->
68
+ unless value instanceof @model
69
+ value = new @model(value)
70
+ value.save() if value.isNew()
71
+ @record[@fkey] = value and value.id
72
+
73
+ class Singleton extends Spine.Module
74
+ constructor: (options = {}) ->
75
+ for key, value of options
76
+ @[key] = value
77
+
78
+ find: ->
79
+ @record.id and @model.findByAttribute(@fkey, @record.id)
80
+
81
+ update: (value) ->
82
+ unless value instanceof @model
83
+ value = @model.fromJSON(value)
84
+
85
+ value[@fkey] = @record.id
86
+ value.save()
87
+
88
+ singularize = (str) ->
89
+ str.replace(/s$/, '')
90
+
91
+ underscore = (str) ->
92
+ str.replace(/::/g, '/')
93
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
94
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2')
95
+ .replace(/-/g, '_')
96
+ .toLowerCase()
97
+
98
+ Spine.Model.extend
99
+ hasMany: (name, model, fkey) ->
100
+ fkey ?= "#{underscore(this.className)}_id"
101
+
102
+ association = (record) ->
103
+ model = require(model) if typeof model is 'string'
104
+
105
+ new Collection(
106
+ name: name, model: model,
107
+ record: record, fkey: fkey
108
+ )
109
+
110
+ @::[name] = (value) ->
111
+ association(@).refresh(value) if value?
112
+ association(@)
113
+
114
+ belongsTo: (name, model, fkey) ->
115
+ fkey ?= "#{singularize(name)}_id"
116
+
117
+ association = (record) ->
118
+ model = require(model) if typeof model is 'string'
119
+
120
+ new Instance(
121
+ name: name, model: model,
122
+ record: record, fkey: fkey
123
+ )
124
+
125
+ @::[name] = (value) ->
126
+ association(@).update(value) if value?
127
+ association(@).exists()
128
+
129
+ @attributes.push(fkey)
130
+
131
+ hasOne: (name, model, fkey) ->
132
+ fkey ?= "#{underscore(@className)}_id"
133
+
134
+ association = (record) ->
135
+ model = require(model) if typeof model is 'string'
136
+
137
+ new Singleton(
138
+ name: name, model: model,
139
+ record: record, fkey: fkey
140
+ )
141
+
142
+ @::[name] = (value) ->
143
+ association(@).update(value) if value?
144
+ association(@).find()