Baphomet is the dedicated bot for nulloctet matrix
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.5 KiB

  1. /**
  2. * Base module that all modules extend
  3. */
  4. let { logger } = require('../logging');
  5. let message = require('../message');
  6. let { isFunction, getObjectKeysToPrototype } = require('../utility');
  7. class AbstractModule {
  8. /*
  9. Name of the module used in help documentation and logging.
  10. */
  11. name = "AbstractModule";
  12. /*
  13. Short description of the module functionality.
  14. */
  15. description = "Base Module That All Other Modules Extend";
  16. /*
  17. A helpful multiline string that defines the module usage
  18. */
  19. helpAndUsage = `Example: !abstract_module <command>
  20. !abstract_module <boo> : scares people`
  21. /*
  22. The exported command used to invoke the module directly.
  23. */
  24. command = "abstract_module";
  25. /*
  26. The default method to call when a command word is not recognized.
  27. */
  28. defaultCommand = null;
  29. /*
  30. The module should be hidden from help and command dialogs.
  31. */
  32. hidden = false;
  33. /*
  34. This module should receive all messages, regardless of whether
  35. the module was directly referenced with a command.
  36. */
  37. canHandleIndirectMessages = false;
  38. constructor(name, description, command) {
  39. this.name = name;
  40. this.description = description;
  41. this.command = command;
  42. this._recognizedCommands = [];
  43. this._recognizedCommandMap = new Map();
  44. }
  45. addRecognizedCommand(command, methodName) {
  46. this._recognizedCommands.push(command);
  47. this._recognizedCommandMap.set(command, methodName);
  48. }
  49. getRecognizedCommands() {
  50. return this._recognizedCommandMap.keys();
  51. }
  52. /**
  53. * Default functionality for receiving and processing a message.
  54. *
  55. * Override this if the module needs to do more complicated message processing.
  56. */
  57. handleMessage(event, room, callback) {
  58. logger.debug("[%s] [%s] [%s]", this.name, room.name, event.event.content.body);
  59. let messageBody = event.event.content.body;
  60. let bodyParts = messageBody.split(' ');
  61. let trigger = bodyParts[0];
  62. let command = bodyParts[1];
  63. var args = [];
  64. if (bodyParts.length > 2) {
  65. args = bodyParts.slice(2);
  66. }
  67. logger.debug("Attempting to call %s with %s", command, args);
  68. let responseMessage = this.processMessage(command, ...args);
  69. callback(
  70. room,
  71. responseMessage
  72. );
  73. }
  74. /*
  75. Call the command method with the args
  76. */
  77. processMessage(command, ...args) {
  78. if (this._recognizedCommands.includes(command)) {
  79. logger.debug("Calling %s with %s", this._recognizedCommandMap.get(command), args);
  80. return this[this._recognizedCommandMap.get(command)](...args);
  81. } else {
  82. if (this.defaultCommand != null) {
  83. logger.debug("Attempting to use default command %s", this.defaultCommand);
  84. try {
  85. let newArgs = [command].concat(...args);
  86. logger.debug("Calling %s with %s", this._recognizedCommandMap.get(this.defaultCommand), newArgs);
  87. return this[this._recognizedCommandMap.get(this.defaultCommand)](...newArgs);
  88. } catch (e) {
  89. logger.error("Error while calling default command %s %s", this.defaultCommand, e);
  90. return this.cmd_help();
  91. }
  92. } else {
  93. logger.debug("Unrecognized command %s", command);
  94. return this.cmd_help();
  95. }
  96. }
  97. }
  98. /* Basic cmd methods */
  99. /*
  100. return basic help information,.
  101. */
  102. cmd_help(...args) {
  103. return message.createBasic(this.helpAndUsage);
  104. }
  105. }
  106. let abstractModulePrototype = Object.getPrototypeOf(new AbstractModule('', '', ''));
  107. /*
  108. Initialization of a module.
  109. */
  110. function init(mod) {
  111. logger.debug("Initializing module %s", mod.name)
  112. let commandMethods = getObjectKeysToPrototype(mod, abstractModulePrototype, (key) => {
  113. return key.startsWith('cmd_') && isFunction(mod[key]);
  114. })
  115. // let commandMethods = objectKeys.filter();
  116. logger.debug("Identified command methods: %s", commandMethods);
  117. commandMethods.forEach((commandMethodName) => {
  118. let command = commandMethodName.substring(4);
  119. mod.addRecognizedCommand(command, commandMethodName);
  120. })
  121. logger.debug("Bound command methods for %s as %s", mod.name, mod.getRecognizedCommands());
  122. }
  123. exports.AbstractModule = AbstractModule
  124. exports.initModule = init;