Giter Site home page Giter Site logo

debot.js's Introduction

DeBot.js

Node.JS IRC Bot version of the DeBot PHP IRC Bot.

Getting Started

First, install dependencies by going into /src/ and doing npm install

Rename or copy config.example.json to config.json. Make your changes to the config as per the comments. MAKE SURE TO REMOVE THE COMMENTS as JSON syntax doesn't allow comments.

Once done, you can launch the bot.

To do this, do node --harmony_proxies index.js The bot will then start. The --harmony flag is requred because DeBot.js uses a few features of ECMA6 (mainly the Proxy object). Once node.js/V8 have native Proxy object included, the flag should no longer be nessecary.

Writing Modules

Should you want to add a feature or special behavior to DeBot.js, the preferred way would be to use Modules. The Module structure is very straight forward.

var DeBot = require('../core/Module');

module.exports = new (DeBot.module(function (bot, group) {
	// Code Here
}))();

The module will need to go into /src/modules/. Modules will work for both a BotGroup and Bot. If the module is loaded via a BotGroup, the bot object will always be null/undefined. See the structure of DeBot.js for information on how to handle BotGroup events.

Note that when you are adding commands via a module, you need to pass the persist setting as false. Otherwise the command will be stored and loaded on restarts. Depending on the callback given, it may crash the bot. Example of setting persist to false is provided below.

group.addCommand(
	command_prefix + "getcmd", 
	{"level":3, "timer":0, "persist":false}, // Requires level 3 to use, can be used over and over with no delay, and do not store for later use.
	function(server, channel, msg, bot, group) { // bot and group are optional and will be injected on saving/reloading
	......

Structure of DeBot.js

Going from the bottom up. The heierarchy looks like so:

index -> Core -> BotGroups -> Bots -> Networks.

Each bot has a map of socket connections to networks. Each BotGroup has bots that are all connected to the same networks. This gives your BotGroup the ability to be distributed across the network during netsplits.

Each BotGroup and Bots can have commands. Bots emit the Command callback on the botgroup, meaning if you have multiple bots in a channel, a botgroup command can be called more than once

When a group callback is fired due to an IRC event, it will be executed for each bot in the bot group that received that event. If you have 2 bots that are in a channel, and a privmsg event is fired, the BotGroup will fire the OnPrivmsg event twice.

Due to this, you will want to check if the bot is the executor, before performing any code. If you only want one bot to execute this command or event, you can use the following snippet:

if (!group.botIsExecutor(server.alias, bot.alias, channel)) {
	return;
}
.... // Code to execute as this bot

To get the bot in a module, you can access the group.passer property. The passer is the IRC bot that initiated this event.

If you want to just add simple commands to the bot, it's best to use the !addcmd function inside IRC. The check for the bot executor is inserted automatically.

A Bot can have modules of its own, and can have its own Commands. It can have its own channels (its own unique channels), but cannot have its own networks.

For example, you can have the following: IRC Server Channel1: Bot 1 Bot 2 Channel2: Bot 2 Channel3: Bot 1 IRC Server 2 Bot 2 (no channels) Channel1: Bot 1

All bots must be on the same networks, but can have any assortment of channels. Any bot can have any of their own modules, and their own commands.

Anatomy of a callback

The callback for a command will provide various variables you can use as short hand.

  • server: The server that executed this command. You can grab stats from it.
    • The server.Attributes has the network settings (Max # chans, etc).
    • The server.Channels contains a list of all your channels in the BotGroup. This means, if you have 2 bots in different channels, they can refer to each others' channels. The Channels object can be accessed by the channel name. Channels["#channel"] object has various properties stored about it.
      • A Channel object has a .Topic, .Modes, and .Users (as may be expected).
        • .Users allows you to get the users in the channel. You can access the Users list as both an array and a map. If you want the highest ranked user in the channel, you can use .Users[0]. The .Nick returns the nickname and .Ident. The .Host will return if the server supports UHNAMES (UnrealIRCD).
        • .Topic.Display shows the topic. There are other attributes such as .SetBy and .DateSet which should be self explanatory.
        • .Modes is an array of modes applied to the channel. This does NOT include bans and Invites (I don't think. Can't remember now).
  • channel: This represents the location this command was executed at. The name channel is a bit misleading since this can also be executed inside a Private Message.
    • The channel.Display property shows where this command was sent to, if a channel. If it was a PM, it is the nick that sent the message.
    • The channel.isChannel property lets you know if this was a PM or a #channel.
  • msg: This stores various representations of the data received by the bot. They all inherit a Message object which has at least the .From, .Parts, .RawLine and .MessageLine.
    • msg.Parts is the line split by a space. So will usually look like [ "nick!ident@host", "COMMAND", "etc"].
    • msg.RawLine is the line received straight from the server without the ending \r\n. No modifications will be performed to this string.
    • msg.MessageLine is the text after the 2nd : character. This is useful if you want to handle the text said in a PrivateMessage.
    • msg.Command is the command that this msg represents. This is default to [1] of msg.Parts or [0] if ERROR/PING.
    • A message may have other attributes to make handling that event easier. This will be documented later, or you can check in the dabbit.Base.js/Events/ items.
  • (Command Only) bot: This is the bot that received this message. It is the same as doing server.Me. The bot inherits the User object so has items like .Nick, .Ident, .Host, and .Modes.
  • (Command Only) group: The group this command belongs to. Allows you to access the .bots, and .networks should you need to access another bot or network.

There is also the globally available Core object. This provides access to every botgroup, every bot, and settings.

debot.js's People

Contributors

dabbers avatar

Stargazers

Andrew Bates avatar

Watchers

 avatar James Cloos avatar

debot.js's Issues

Commands module feature complete

Make the Commands module feature complete. Including viewing and resetting properties, binding, antispam, and access privileges.

Abstract Storage Logic for Modules

The storage logic used in the command handler should be abstracted out and made available in Core so we can use the simple storage logic anywhere. Something like:

getStorage(botOrGroup, name) and wrap the object returned by a proxy so every time a get is processed, we set the is Dirty flag. Then we hook into the core tick event to save to disk, creating if necessary.

Multiple Bots causes race condition with commands

Not sure the repro, but when executing commands, some users can't use the commands because the bots are both attempting to attempt. I suspect the functionCanExecute is being called even if the isBotExecutor is not for the passing bot.

Group.botIsExecutor use privilage to determine candidate.

The botIsExecutor method in BotGRoup should use the bot with the highest privilege to determine the executor. This let's us take advantage of having a bot with higher privilege executing our commands at all time. This is useful if a command is supposed to be done to voice users, but that bot left and left only a non privilege bot to do things. Actually.. I can't imagine the idea of a bot not having a required privilege being helpful, but this is a good idea...

Make config easier to access and update

Currently, we need to rewrite code to access a bot's/botgroup's settings and update then save the update.

There should be some friendly accessors to the settings to allow us to access, update, and save with ease.

Make a central area for HTTP Server

Make a central web server part of the core bot, then when modules add an http server, make sure they just add a route to the existing server. This way, modules aren't binding to ports then not closing down the servers when they are unloaded.

Bot doesn't auto reconnect on timeouts and errors

There's a module in the repo to auto reconnect but isn't finished.

When a connection is lost between the bot and the server, the bot just sits there doing nothing. There may need to be a callback added to the bot for ERROR messages, or Socket disconnect events (or both).

Refactoring Placeholder 2

Will need another refactoring at some point. Placeholding refactor for the milestone progress tracking.

Add IP Binding

Allow a bot or bot group to connect to a variety of IPs. This could be on a per botgroup basis, or for a more granular approach, a bot basis.

Can have an array of IPs listed in the config, then on connection, evenly distribute bots on that IP for that network.

Optionally, you can let a bot bind to a single IP. Since a bot doesn't know anything about its networks, you can't have a bot bind a certain IP to a certain network unless that behavior is changed somehow.

Nick changes cause problem with bot.lastChannel

Repro:
Change bot nick to something.
Change bot nick back

                    bot.lastChannel = (msg.To.Type == "Client" ? msg.From.Parts[0] : msg.To.Par
                                    ^

TypeError: Cannot set property 'lastChannel' of undefined
at BotGroup. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Commandable.js:133:20)
at BotGroup.emit (events.js:98:17)
at Bot. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\BotGroup.js:146:10)
at Bot.emit (events.js:117:20)
at Object.parse (C:\Users\me_000\Documents\Projects\DeBot.js\src\node_modules\dabbit.base\Parser.js:156:25)
at Network.rawMessageReceived (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Network.js:179:16)
at DeBotConnection.RawMessageReceived (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Network.js:164:18)
at Connection.onRead (C:\Users\me_000\Documents\Projects\DeBot.js\src\node_modules\dabbit.base\Connection.js:133:14)
at CleartextStream.NodeSocket.onData (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\NodeSocket.js:67:13)
at CleartextStream.emit (events.js:95:17)
at CleartextStream. (_stream_readable.js:764:14)

Group unloading module

Attempted to unload then reload a group.module

PROXYBOT cleanupMethods
PROXYBOT cleanupMethods

C:\Users\me_000\Documents\Projects\DeBot.js\src\core\FakeGroup.js:30
callbacksToRemove.forEach(function(cb) { realBot.removeListener(cb.event,
^
ReferenceError: realBot is not defined
at C:\Users\me_000\Documents\Projects\DeBot.js\src\core\FakeGroup.js:30:47
at Array.forEach (native)
at BotGroup. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\FakeGroup.js:30:24)
at self.uninit (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Module.js:36:15)
at BotGroup.ModuleHandler.obj.unloadModule (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\ModuleHandler.js:33:25)
at Object.eval (eval at (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\BotGroup.js:228:32), <anonymous
at Object.callback (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\BotGroup.js:228:3)
at BotGroup. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Commandable.js:136:23)
at BotGroup.emit (events.js:98:17)
at Bot. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\BotGroup.js:146:10)

Auth verification

There needs to be a way to verify an authed user hasn't left and a new user is falsifying identity.

There is a doc writeup on how this will be done.

See /docs/User Online Checking.txt

Long output is truncated due to 512 character limit

Need a way to split up multiple messages when sending a private message. Could do it at the .say layer, or at the raw layer, but only if privmsg is the first word. .say probably makes the most sense for this.

Should bot(group) modules be NPM modules?

As it stands, there's 2 folders that indicate modules. There's the DeBot.js modules folder, then there's the node.js npm node_modules folder.

it adds extra folders structure and makes module management a bit tougher. The benefits of making debot.js modules npm modules, is that we get download support, and dependencies support. To make modules easily searchable, we can add the DeBot Module to the keywords.

The downside to this, is your node_modules folder might get messy and it would be difficult to manage unused modules.

The other option is to let users manage it themselves. This isn't pretty, but is how it works now, and would be cleaner in terms of module management.

Thoughts?

Some kind of string triggered an unknown command

Sample chat that killed the bot:
[15:02:49] <+afschuld> This is the guilty code
[15:02:49] <+afschuld> if (eDataType == eSDT_REST_XML)
[15:02:50] <+afschuld> {
[15:02:50] <+afschuld> CRestRequest RequestREST(session, vecStrURL_REST[0]);
[15:02:50] <+afschuld> }
[15:02:50] <+afschuld> else if (eDataType == eSDT_REST_BOND)
[15:02:51] <+afschuld> {
[15:02:53] <+afschuld> CRestRequest RequestREST(session, vecStrURL_BOND[0]);
[15:02:55] <+afschuld> }
[15:04:07] <+afschuld> I guess the easiest solution is just to set a string variable to either vecStrURL_REST[0] or vecStrURL_BOND[0] but I know there is another way to do this
[15:04:08] <+dab> different constructor like a different declaration?
[15:04:26] <+afschuld> constructor with different arguements actually
[15:04:27] * DaBot ([email protected]) Quit (Connection reset by peer)

Error message from window:

|=> 'PONG :navi.gamergalaxy.net'
fce 1

C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Commandable.js:65
for(var i = 0; i < command.options.exceptions.channels.length; i++) {
^
TypeError: Cannot read property 'exceptions' of undefined
at Bot.Commandable.functionCanExecute (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Commandable.js:65:37)
at Bot. (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Commandable.js:118:35)
at Bot.emit (events.js:117:20)
at Object.parse (C:\Users\me_000\Documents\Projects\DeBot.js\src\node_modules\dabbit.base\Parser.js:156:25)
at Network.rawMessageReceived (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Network.js:176:16)
at DeBotConnection.RawMessageReceived (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\Network.js:161:18)
at Connection.onRead (C:\Users\me_000\Documents\Projects\DeBot.js\src\node_modules\dabbit.base\Connection.js:142:14)
at CleartextStream.NodeSocket.onData (C:\Users\me_000\Documents\Projects\DeBot.js\src\core\NodeSocket.js:66:13)
at CleartextStream.emit (events.js:95:17)
at CleartextStream. (_stream_readable.js:764:14)
at CleartextStream.emit (events.js:92:17)

Config for bot:
"BotGroups": {
"dbot": {
"Networks": [
{
"Network": "ggxy",
"Channels": [
"#dab.beta",
"#dab2"
]
}
],
"Bots": {
"DaBot": {
"Nick": "DaBot",
"Ident": "thebotidentity",
"Channels": {
"ggxy": [
"#marblecake"
]
},
"Modules": [
"iHate"
]
},
"DiBot": {
"Ident": "dbt",
"Channels": {
"ggxy": []
},
"Modules": [],
"Nick": "DiBot"
}
},
"Modules": [
"Commands"
],
"CommandPrefix": "#",
"RawCommandPrefix": ">>"
}
},

Commands json:
Empty?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.