Source: provider/convention/eventListenerProviderByDirectory.js

  1. /**
  2. * @author Sloan Seaman
  3. * @copyright 2016 and on
  4. *
  5. * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  6. */
  7. /** @private */
  8. var AbstractProviderByAsyncDirectory = require('../abstractProviderByAsyncDirectory.js');
  9. var svUtil = require('../../util.js');
  10. var providerUtil = require('../providerUtil.js');
  11. var fs = require('fs');
  12. var path = require('path');
  13. var events = require('events');
  14. var log = require('winston-simple').getLogger('EventListenerProviderByDirectory');
  15. /**
  16. * Considering moving IntentHandlers to be based on events
  17. *
  18. * @param {String} directory The directory to read
  19. * @param {Map} [options] The options to use
  20. */
  21. function EventListenerProviderByDirectory(directory, options) {
  22. if (!directory) throw Error('directory required');
  23. AbstractProviderByAsyncDirectory.apply(this, [
  24. directory,
  25. options]);
  26. }
  27. EventListenerProviderByDirectory.prototype = Object.create(AbstractProviderByAsyncDirectory.prototype);
  28. EventListenerProviderByDirectory.prototype.constructor = EventListenerProviderByDirectory;
  29. /**
  30. *
  31. * @param {Map} items Map of the items being processed
  32. * @param {String} itemId The Id of the item to process
  33. * @param {String} fileName The name of the file being processed
  34. * @param {Object} options Any options that are being passed to the ItemProcessor (can be null)
  35. */
  36. EventListenerProviderByDirectory.prototype.processItem = function(items, itemId, fileName, options) {
  37. /*eslint no-unused-vars: ["error", { "args": "none" }]*/
  38. // This gets called if there is a request for a intentHandler before they are all loaded
  39. // Since intents can declare what they do inside of them, I can't load by the filename and
  40. // assume that it represents what it can handle. I need to scan everything.
  41. var files = fs.readdirSync(this._directory);
  42. for (var i=0;i<files.length;i++) {
  43. this.processItems(items, path.resolve(this._directory, files[i]), options);
  44. if (items[itemId]) break; // found the one we want, stop loading
  45. }
  46. };
  47. /**
  48. * Uses node require to load the file. If the intent is not found this method
  49. * will favor performance and never look for the file again.
  50. *
  51. * @function
  52. * @param {Map} items Map of the items being processed
  53. * @param {String} fileName The name of the file being processed
  54. * @param {Object} options Any options that are being passed to the ItemProcessor (can be null)
  55. */
  56. EventListenerProviderByDirectory.prototype.processItems = function(items, fileName, options) {
  57. /*eslint no-unused-vars: ["error", { "args": "none" }]*/
  58. try {
  59. var loaded = svUtil.instantiate(path.resolve(process.cwd(), fileName));
  60. providerUtil.addFunctions(loaded, { 'name' : path.parse(fileName).name });
  61. var eventEmitter = new events.EventEmitter();
  62. if (svUtil.isFunction(loaded.registerListener)) {
  63. loaded.registerListener(eventEmitter);
  64. var itemNames = eventEmitter.eventNames();
  65. for (var i=0;i<itemNames.length;i++) {
  66. //FIXME: won't handle more than one eventlistener per event
  67. items[itemNames[i]] = loaded;
  68. log.info('Loaded event listener '+loaded.getName()+ ' for event '+itemNames[i]);
  69. }
  70. }
  71. else { // it didn't specify an intent list, so make it what the name of the file is
  72. log.info('Loaded event listener '+loaded.getName()+ ' for event '+path.parse(fileName).name);
  73. }
  74. // also store it under the filename just for reference and to ensure Async doesn't attempt to load it again
  75. items[path.parse(fileName).name] = loaded;
  76. }
  77. catch (err) {
  78. log.error("Error event listener "+path.parse(fileName).base+". Error:"+err.stack);
  79. }
  80. };
  81. module.exports = EventListenerProviderByDirectory;