Rocket.Chat has deprecated and removed Internal Hubot functionality, but in our company we have some script that can't be moved to external bot at this moment, so we wanted to maintain Internal Hubot functionality on our own (since we already have custom fork because of LDAP related changes).
I was able to make it work, almost. Internal Hubot was initialized, scripts were loaded. But calling some command returned Meteor code must always run within a Fiber (...) error.
After some debugging it seems like the core issue here is class inheritance for Hubot's robot and adapter does not work. There are custom classes that extends Hubot's package ones:
export class InternalHubotRobot extends Hubot.Robot {
constructor(name, alias) {
super(null, 'shell', false, name, alias);
this.hear = bind(this.hear);
this.respond = bind(this.respond);
this.enter = bind(this.enter);
this.leave = bind(this.leave);
this.topic = bind(this.topic);
this.error = bind(this.error);
this.catchAll = bind(this.catchAll);
this.user = Meteor.users.findOne({ username: this.name }, { fields: { username: 1 } });
this.adapter = new RocketChatAdapter(this);
new HubotScripts(this);
console.log(`InternalHubotRobot initialized as '${ this.name }'`);
}
loadAdapter() { return false; }
hear(regex, callback) { return super.hear(regex, Meteor.bindEnvironment(callback)); }
respond(regex, callback) { return super.respond(regex, Meteor.bindEnvironment(callback)); }
enter(callback) { return super.enter(Meteor.bindEnvironment(callback)); }
leave(callback) { return super.leave(Meteor.bindEnvironment(callback)); }
topic(callback) { return super.topic(Meteor.bindEnvironment(callback)); }
error(callback) { return super.error(Meteor.bindEnvironment(callback)); }
catchAll(callback) { return super.catchAll(Meteor.bindEnvironment(callback)); }
}
and
export class RocketChatAdapter extends Hubot.Adapter {
constructor(robot) {
super(robot);
console.log('RocketChatAdapter initialized');
}
send(envelope, ...strings) {
this.robot.logger.info('[ROBOT → adapter → send()]');
// ...
}
// Many more overrides
}
The internal Hubot is initialized with InternalHubot = new InternalHubotRobot(RocketChat.settings.get('InternalHubot_Username'), 'Custom Alias'); and I see in the logs:
I20190318-11:28:59.866(1)? RocketChatAdapter initialized
I20190318-11:29:00.209(1)? [Mon Mar 18 2019 11:29:00 GMT+0100 (CET)] WARNING A script has tried registering a HTTP route while the HTTP server is disabled with --disabled-httpd.
I20190318-11:29:00.211(1)? Loaded help.coffee
I20190318-11:29:00.211(1)? InternalHubotRobot initialized as 'Custom Alias'
So both constructors are invoked properly. But all methods calls to robot's and adapter's methods are invoked on base classes from Hubot package, not from InternalHubotRobot / RocketChatAdapter.
And here's the problem: since those methods are not overriden / invoked as they should be, there is Fiber error and responses are not sent since default Hubot adapter's send() method does not do anything.
What I did:
- I was able to get rid of Fiber error by wrapping like
robot.respond /(help)+(?:\s+(.*))?$/i, Meteor.bindEnvironment((incomingMessage)(it's basically whatInternalHubotRobot's constructor should do by wrapping methods withbind() - I was able to send response by overriding
sendthrough prototype:Hubot.Robot.prototype.send = function(envelope, ...args) { return sendHelper(this, envelope, args, (string) => RocketChat.sendMessage(InternalHubot.user, { msg: string }, { _id: envelope.room }) ); };
However: it's dirty and I would like to rely on inheritance and method overriding in child class.
I'm not a JavaScript / Meteor / Rocket.Chat expert so maybe I'm missing something, a little detail. How can I achieve working inheritance?
Info about versions:
- Rocket.Chat 0.73.1 / 0.74.3 (both with customized Internal Hubot, restored in our custom fork). On production we have 0.72.3 and there Internal Hubot is working properly
- Hubot 3.3.1
- Meteor 1.8.0.2