PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/server/combine.js

https://bitbucket.org/mattijs/sourceboard
JavaScript | 162 lines | 87 code | 26 blank | 49 comment | 10 complexity | bdf885d1a0f3a2db794f076983ac6bfd MD5 | raw file
Possible License(s): MIT
  1. var util = require('util'),
  2. events = require('events'),
  3. fs = require('fs'),
  4. path = require('path'),
  5. _ = require('underscore'),
  6. Backbone = require('backbone'),
  7. logger = require('./logging').logger;
  8. // Location of reapers
  9. var REAPER_DIR = path.join(__dirname, 'reapers');
  10. /**
  11. * Combine for collecting reaper data
  12. */
  13. function Combine(config) {
  14. events.EventEmitter.call(this);
  15. // List of Reapers
  16. this.reapers = [];
  17. // Collected actions from reapers
  18. this.actions = new ActionsCollection();
  19. this.actions.on('add', function(action, collection, index) {
  20. this.emit('action', action);
  21. }.bind(this));
  22. // Try to load configured reapers
  23. if (config.reapers) {
  24. config.reapers.forEach(function(spec) {
  25. var reaper = createReaper(spec);
  26. this.addReaper(reaper);
  27. }, this);
  28. }
  29. }
  30. util.inherits(Combine, events.EventEmitter);
  31. /**
  32. * Harvest Actions from a data set, provided by a reaper
  33. */
  34. Combine.prototype.harvest = function(data, reaper) {
  35. // Add a custom ID for recognizing the action and
  36. // prevent ID collisions from other systems.
  37. data.pid = data.id + '@' + reaper.source;
  38. // Add a prefixed type to the action
  39. data.ptype = reaper.source + '#' + data.type;
  40. // Add timestamp of the action date for convenience
  41. if ('string' === typeof(data.date)) {
  42. data.date = moment(data.date).toDate();
  43. }
  44. data.timestamp = data.date.getTime();
  45. // Add the action model
  46. this.actions.add(new ActionModel(data));
  47. };
  48. /**
  49. * Add a reaper. This will keep watch for `data` events on the
  50. * reaper and pass this information to the `harvest` method.
  51. */
  52. Combine.prototype.addReaper = function(reaper) {
  53. // Watch for reaper data
  54. reaper.on('data', this.harvest.bind(this));
  55. // Keep a reference to the reaper
  56. this.reapers.push(reaper);
  57. return this;
  58. };
  59. /**
  60. * Start harvesting
  61. */
  62. Combine.prototype.start = function() {
  63. this.reapers.forEach(function(reaper) {
  64. reaper.start();
  65. });
  66. };
  67. // # getActionCount
  68. // ================
  69. // @TODO Add filter method to count subsets
  70. Combine.prototype.getActionCount = function(filter) {
  71. return this.actions.length;
  72. };
  73. // # getActionSet
  74. // ============
  75. // Get a subset of the Combine actions.
  76. Combine.prototype.getActionSet = function(number, startAt) {
  77. startAt = startAt - 1 || 0;
  78. if (0 > startAt) {
  79. startAt = 0;
  80. }
  81. // Get the actions
  82. var actions = this.actions.toArray();
  83. // If a number is specified return a subset
  84. if (_.isNumber(number)) {
  85. actions = actions.slice(startAt, number);
  86. }
  87. return actions;
  88. };
  89. /**
  90. * Create a reaper instance based on a small specification
  91. */
  92. function createReaper(spec) {
  93. // @TODO Check if reaper file exists
  94. // @TODO Crash gracefully
  95. // Load the reaper from disk
  96. var Reaper = require(path.join(REAPER_DIR, spec.module));
  97. // Return a new instance
  98. return new Reaper(spec.config);
  99. }
  100. // # ActionModel
  101. // =============
  102. // Model for data received from a reaper
  103. var ActionModel = Backbone.Model.extend();
  104. // # ActionsCollection
  105. // ===================
  106. // Collection for storing Action Models
  107. var ActionsCollection = Backbone.Collection.extend({
  108. model: ActionModel,
  109. comparator: function(a, b) {
  110. var aTime = a.get('date'),
  111. bTime = b.get('date');
  112. if (aTime > bTime) { return -1; }
  113. else if (aTime < bTime) { return 1; }
  114. else { return 0; }
  115. },
  116. // Override the default add method to add duplicate id check
  117. add: function(models, options) {
  118. if (!_.isArray(models)) {
  119. models = [models];
  120. }
  121. // Filter duplicate models
  122. models = models.filter(function(model) {
  123. return (0 === this.where({ id: model.get('id') }).length);
  124. }.bind(this));
  125. // Pass through to the prototype add method
  126. Backbone.Collection.prototype.add.call(this, models, options);
  127. }
  128. });
  129. // our awesome export products
  130. exports = module.exports = {
  131. "Combine": Combine,
  132. "reaper": {},
  133. "create": function(options) {
  134. return new Combine(options);
  135. }
  136. };