-
Notifications
You must be signed in to change notification settings - Fork 29
Plugins
Plugins are classes that listen to specific events from the Telegram API.
See the architecture diagram in this folder for an overview of how plugins communicate with the other components.
const Plugin = require("../Plugin");
module.exports = class MyPlugin extends Plugin {
// Information about your plugin.
static get plugin() {
return {
name: "MyPlugin",
description: "It does things.",
help: "Try saying 'Hello!', or using the /hello command."
}
}
// Optional: initialize the plugin. Gets passed the event listener, the bot object, the bot configuration, and the auth API object.
// You shouldn't need direct access to the event listener or the bot object.
constructor(listener, bot, config, auth) {
super(listener, bot, config, auth);
/* ... */
}
// Optional: stop the plugin.
stop() {
foo.stop();
}
// An object, mapping commands to their handlers.
// Handlers can return a string, representing a text reply.
get commands() { return {
hello: ({args, message}) => {
// Args is an array of arguments passed by the user (eg. `/foo bar` would have args = ["bar"])
// Message is the message that triggered the handler
return "Heyo!";
}; }
// Alternatively, you can use the more verbose onCommand listener.
onCommand({message, command, args}) {
if (command === "hello") {
this.sendMessage(message.chat.id, "Heyo!");
}
}
// Called when a message is received.
onText({message}) {
if (message === "Hello!") {
this.sendMessage(message.chat.id, "Hi!");
}
}
onPhoto({message}) {
/* ... */
}
/* ... */
}
Common pitfall! To reply to messages, you use
this.sendMessage(...)
. However, note that insidefunction() {...}
blocks,this
does not refer to the plugin. So, you must use arrow functions in callbacks. For instance:
onCommand({message, command, args}) {
if (command !== "reddit") return;
// Do NOT use function(err, request) { ... }!
request("https://reddit.com/...", (err, request) => {
this.sendMessage(message.chat.id, ...)
});
Every plugin must provide some data about itself, using the plugin
getter. It returns an object with the following properties:
-
name
, mandatory -
description
, a short description of what the plugin does (recommended) -
help
, the help text to be shown when the user runs/help myPlugin
(recommended) -
visibility
, eitherPlugin.Visiblity.VISIBLE
(the default) orPlugin.Visibility.HIDDEN
. You probably won't need this. -
type
, a bitmask ofPlugin.Type.NORMAL
,.INLINE
(whether the plugin can be used in inline mode),.PROXY
(whether the plugin acts as a proxy, see below), and.SPECIAL
(for internal usage). The default is.NORMAL
.
It is optional to add a constructor
(which must always call start
!) or a stop
method,
If the plugin is in an invalid state (for instance, a token is invalid), or an issue occurs while initialising the plugin, constructor
must throw an error. This will cause the plugin not to be loaded.
These (optional) functions are called when a message of their type is received. The full list is: onText
, onAudio
, onDocument
, onPhoto
, onSticker
, onVideo
, onVoice
, onContact
, onLocation
, onNewChatParticipant
, onLeftChatParticipant
. They are passed two parameters, message
and reply
. The former is the object returned by the Telegram API; the latter is a function, to be called like this: reply({type: "text", text: "Hello!"})
.
Plugins are not required to implement any of these methods. Proxies, for instance, usually don't.
If a plugin is registered as a proxy (get plugin()
contains isProxy: true
), the proxy
method is called on every incoming message. It returns an ES6 Promise.
- If the Proxy approves the message, it must return Promise.resolve().
- If the Proxy rejects the message, it returns a Promise.reject(). It will cause the message not to be passed along the plugin chain.
Example:
class Antiflood extends Plugin {
static get plugin() {
return {
name: "Antiflood",
description: "Automatically ignore spamming users",
help: "...",
isProxy: true
};
}
proxy(eventName, message) {
if (this.isFlood(message))
return Promise.reject("flood");
return Promise.resolve();
}
isFlood(message) {
/* ... */
}
}