Move/create rocketchat callbacks (#13034)
* Move rocketchat settings to specific package * WIP: Move models from rocketchat-lib to a specific package (server) * Move function from rocketchat:lib to rocketchat:utils to use it in rocketchat:models * Move client models from rocketchat:lib to rocketchat:models * Fix lint * Move rocketchat.info from lib to utils * Remove directly dependency between lib and migrations * Move statistics Model to rocketchat:models * Create rocketchat:metrics to be able to depacking rocketchat callbacks * Move callbacks to specific package * Remove unused dependency * Merge branch 'develop' into globals/move-rocketchat-callbackspull/13119/head
parent
39bb16182f
commit
ff39241b85
@ -0,0 +1,5 @@ |
||||
import { callbacks } from '../lib/callbacks'; |
||||
|
||||
export { |
||||
callbacks, |
||||
}; |
@ -0,0 +1,152 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Random } from 'meteor/random'; |
||||
import { metrics, StatsTracker } from 'meteor/rocketchat:metrics'; |
||||
import _ from 'underscore'; |
||||
|
||||
/* |
||||
* Callback hooks provide an easy way to add extra steps to common operations. |
||||
* @namespace RocketChat.callbacks |
||||
*/ |
||||
|
||||
export const callbacks = {}; |
||||
|
||||
if (Meteor.isServer) { |
||||
callbacks.showTime = true; |
||||
callbacks.showTotalTime = true; |
||||
} else { |
||||
callbacks.showTime = false; |
||||
callbacks.showTotalTime = false; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Callback priorities |
||||
*/ |
||||
|
||||
callbacks.priority = { |
||||
HIGH: -1000, |
||||
MEDIUM: 0, |
||||
LOW: 1000, |
||||
}; |
||||
|
||||
const getHooks = (hookName) => callbacks[hookName] || []; |
||||
|
||||
/* |
||||
* Add a callback function to a hook |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Function} callback - The callback function |
||||
*/ |
||||
|
||||
callbacks.add = function(hook, callback, priority, id = Random.id()) { |
||||
if (!_.isNumber(priority)) { |
||||
priority = callbacks.priority.MEDIUM; |
||||
} |
||||
callback.priority = priority; |
||||
callback.id = id; |
||||
callbacks[hook] = getHooks(hook); |
||||
|
||||
if (callbacks.showTime === true) { |
||||
const err = new Error; |
||||
callback.stack = err.stack; |
||||
} |
||||
|
||||
if (callbacks[hook].find((cb) => cb.id === callback.id)) { |
||||
return; |
||||
} |
||||
callbacks[hook].push(callback); |
||||
callbacks[hook] = _.sortBy(callbacks[hook], function(callback) { |
||||
return callback.priority || callbacks.priority.MEDIUM; |
||||
}); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Remove a callback from a hook |
||||
* @param {string} hook - The name of the hook |
||||
* @param {string} id - The callback's id |
||||
*/ |
||||
|
||||
callbacks.remove = function(hook, id) { |
||||
callbacks[hook] = getHooks(hook).filter((callback) => callback.id !== id); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Successively run all of a hook's callbacks on an item |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks |
||||
* @param {Object} [constant] - An optional constant that will be passed along to each callback |
||||
* @returns {Object} Returns the item after it's been through all the callbacks for this hook |
||||
*/ |
||||
|
||||
callbacks.run = function(hook, item, constant) { |
||||
const callbackItems = callbacks[hook]; |
||||
if (!callbackItems || !callbackItems.length) { |
||||
return item; |
||||
} |
||||
|
||||
let rocketchatHooksEnd; |
||||
if (Meteor.isServer) { |
||||
rocketchatHooksEnd = metrics.rocketchatHooks.startTimer({ hook, callbacks_length: callbacks.length }); |
||||
} |
||||
|
||||
let totalTime = 0; |
||||
const result = callbackItems.reduce(function(result, callback) { |
||||
let rocketchatCallbacksEnd; |
||||
if (Meteor.isServer) { |
||||
rocketchatCallbacksEnd = metrics.rocketchatCallbacks.startTimer({ hook, callback: callback.id }); |
||||
} |
||||
const time = callbacks.showTime === true || callbacks.showTotalTime === true ? Date.now() : 0; |
||||
|
||||
const callbackResult = callback(result, constant); |
||||
|
||||
if (callbacks.showTime === true || callbacks.showTotalTime === true) { |
||||
const currentTime = Date.now() - time; |
||||
totalTime += currentTime; |
||||
if (callbacks.showTime === true) { |
||||
if (Meteor.isServer) { |
||||
rocketchatCallbacksEnd(); |
||||
StatsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]); |
||||
} else { |
||||
let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n'); |
||||
stack = stack && stack[2] && (stack[2].match(/\(.+\)/) || [])[0]; |
||||
console.log(String(currentTime), hook, callback.id, stack); |
||||
} |
||||
} |
||||
} |
||||
return (typeof callbackResult === 'undefined') ? result : callbackResult; |
||||
}, item); |
||||
|
||||
if (Meteor.isServer) { |
||||
rocketchatHooksEnd(); |
||||
} |
||||
|
||||
if (callbacks.showTotalTime === true) { |
||||
if (Meteor.isServer) { |
||||
StatsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]); |
||||
} else { |
||||
console.log(`${ hook }:`, totalTime); |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
|
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Successively run all of a hook's callbacks on an item, in async mode (only works on server) |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks |
||||
* @param {Object} [constant] - An optional constant that will be passed along to each callback |
||||
*/ |
||||
|
||||
callbacks.runAsync = function(hook, item, constant) { |
||||
const callbackItems = callbacks[hook]; |
||||
if (Meteor.isServer && callbackItems && callbackItems.length) { |
||||
Meteor.defer(function() { |
||||
callbackItems.forEach((callback) => callback(item, constant)); |
||||
}); |
||||
} |
||||
return item; |
||||
}; |
@ -0,0 +1,15 @@ |
||||
Package.describe({ |
||||
name: 'rocketchat:callbacks', |
||||
summary: 'Rocketchat Callbacks', |
||||
version: '0.0.1', |
||||
git: '', |
||||
}); |
||||
|
||||
Package.onUse(function(api) { |
||||
api.use([ |
||||
'ecmascript', |
||||
'rocketchat:metrics', |
||||
]); |
||||
api.mainModule('client/index.js', 'client'); |
||||
api.mainModule('server/index.js', 'server'); |
||||
}); |
@ -0,0 +1,5 @@ |
||||
import { callbacks } from '../lib/callbacks'; |
||||
|
||||
export { |
||||
callbacks, |
||||
}; |
@ -1,151 +1,8 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Random } from 'meteor/random'; |
||||
import _ from 'underscore'; |
||||
import { callbacks } from 'meteor/rocketchat:callbacks'; |
||||
|
||||
/* |
||||
* Callback hooks provide an easy way to add extra steps to common operations. |
||||
* @namespace RocketChat.callbacks |
||||
*/ |
||||
|
||||
RocketChat.callbacks = {}; |
||||
|
||||
if (Meteor.isServer) { |
||||
RocketChat.callbacks.showTime = true; |
||||
RocketChat.callbacks.showTotalTime = true; |
||||
} else { |
||||
RocketChat.callbacks.showTime = false; |
||||
RocketChat.callbacks.showTotalTime = false; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Callback priorities |
||||
*/ |
||||
|
||||
RocketChat.callbacks.priority = { |
||||
HIGH: -1000, |
||||
MEDIUM: 0, |
||||
LOW: 1000, |
||||
}; |
||||
|
||||
const getHooks = (hookName) => RocketChat.callbacks[hookName] || []; |
||||
|
||||
/* |
||||
* Add a callback function to a hook |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Function} callback - The callback function |
||||
*/ |
||||
|
||||
RocketChat.callbacks.add = function(hook, callback, priority, id = Random.id()) { |
||||
if (!_.isNumber(priority)) { |
||||
priority = RocketChat.callbacks.priority.MEDIUM; |
||||
} |
||||
callback.priority = priority; |
||||
callback.id = id; |
||||
RocketChat.callbacks[hook] = getHooks(hook); |
||||
|
||||
if (RocketChat.callbacks.showTime === true) { |
||||
const err = new Error; |
||||
callback.stack = err.stack; |
||||
} |
||||
|
||||
if (RocketChat.callbacks[hook].find((cb) => cb.id === callback.id)) { |
||||
return; |
||||
} |
||||
RocketChat.callbacks[hook].push(callback); |
||||
RocketChat.callbacks[hook] = _.sortBy(RocketChat.callbacks[hook], function(callback) { |
||||
return callback.priority || RocketChat.callbacks.priority.MEDIUM; |
||||
}); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Remove a callback from a hook |
||||
* @param {string} hook - The name of the hook |
||||
* @param {string} id - The callback's id |
||||
*/ |
||||
|
||||
RocketChat.callbacks.remove = function(hook, id) { |
||||
RocketChat.callbacks[hook] = getHooks(hook).filter((callback) => callback.id !== id); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Successively run all of a hook's callbacks on an item |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks |
||||
* @param {Object} [constant] - An optional constant that will be passed along to each callback |
||||
* @returns {Object} Returns the item after it's been through all the callbacks for this hook |
||||
*/ |
||||
|
||||
RocketChat.callbacks.run = function(hook, item, constant) { |
||||
const callbacks = RocketChat.callbacks[hook]; |
||||
if (!callbacks || !callbacks.length) { |
||||
return item; |
||||
} |
||||
|
||||
let rocketchatHooksEnd; |
||||
if (Meteor.isServer) { |
||||
rocketchatHooksEnd = RocketChat.metrics.rocketchatHooks.startTimer({ hook, callbacks_length: callbacks.length }); |
||||
} |
||||
|
||||
let totalTime = 0; |
||||
const result = callbacks.reduce(function(result, callback) { |
||||
let rocketchatCallbacksEnd; |
||||
if (Meteor.isServer) { |
||||
rocketchatCallbacksEnd = RocketChat.metrics.rocketchatCallbacks.startTimer({ hook, callback: callback.id }); |
||||
} |
||||
const time = RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true ? Date.now() : 0; |
||||
|
||||
const callbackResult = callback(result, constant); |
||||
|
||||
if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { |
||||
const currentTime = Date.now() - time; |
||||
totalTime += currentTime; |
||||
if (RocketChat.callbacks.showTime === true) { |
||||
if (Meteor.isServer) { |
||||
rocketchatCallbacksEnd(); |
||||
RocketChat.statsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]); |
||||
} else { |
||||
let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n'); |
||||
stack = stack && stack[2] && (stack[2].match(/\(.+\)/) || [])[0]; |
||||
console.log(String(currentTime), hook, callback.id, stack); |
||||
} |
||||
} |
||||
} |
||||
return (typeof callbackResult === 'undefined') ? result : callbackResult; |
||||
}, item); |
||||
|
||||
if (Meteor.isServer) { |
||||
rocketchatHooksEnd(); |
||||
} |
||||
|
||||
if (RocketChat.callbacks.showTotalTime === true) { |
||||
if (Meteor.isServer) { |
||||
RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]); |
||||
} else { |
||||
console.log(`${ hook }:`, totalTime); |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
|
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Successively run all of a hook's callbacks on an item, in async mode (only works on server) |
||||
* @param {String} hook - The name of the hook |
||||
* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks |
||||
* @param {Object} [constant] - An optional constant that will be passed along to each callback |
||||
*/ |
||||
|
||||
RocketChat.callbacks.runAsync = function(hook, item, constant) { |
||||
const callbacks = RocketChat.callbacks[hook]; |
||||
if (Meteor.isServer && callbacks && callbacks.length) { |
||||
Meteor.defer(function() { |
||||
callbacks.forEach((callback) => callback(item, constant)); |
||||
}); |
||||
} |
||||
return item; |
||||
}; |
||||
RocketChat.callbacks = callbacks; |
||||
|
Loading…
Reference in new issue