Skip to content

joeschmo/joebot2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

joebot2

Fully Customizable Haskell IRC Bot

##Table of Contents

#Introduction joebot2 is an upgrade from the original joe_bot that runs on irc.freenode.net #roboclub. joebot2 was designed to be an easy to customize and upgrade haskell irc bot.

#Installation To install joe_bot, you need the latest haskell platform. Afterwards, just run cabal install in the directory containing joebot.cabal.

To run after installing, just run joe_bot.

#The Basics The bare minimum for Main.hs is:

import Config
main = joebot defaultConfig

This will run joebot2 with the default configurations specified in Config.hs.

Changing the configuration is relatively simple (note the underscore before each field name):

{-# LANGUAGE OverloadedStrings #-}
import Config
main = joebot $ defaultConfig
    { _nick = "test_bot"
    , _chan = "#haskell"
    , _pass = Just "fake_password"
    }

More advanced users will note that joebot2 uses the Control.Lens library extensively. The above code snippet can be then rewritten to use lenses (you must import Core to access the lenses):

{-# LANGUAGE OverloadedStrings #-}
import Config
import Control.Lens
import Core
main = joebot $ defaultConfig 
    & nick .~ "test_bot"
    & chan .~ "#haskell"
    & pass .~ Just "fake_password"

Whether doing so is overkill is an exercise left to the reader.

The Config type has the following fields:

data Config = Config        -- Field Explanation      Default Value
    { nick   :: Text        -- nickname of bot        "default-bot"
    , rname  :: Text        -- real name of bot       "ircbot" 
    , server :: Text        -- irc server hostname    "irc.freenode.net"
    , port   :: Int         -- port                   6667
    , chan   :: Text        -- irc channel            "#joebot-test"
    , pass   :: Maybe Text  -- password for NickServ  Nothing
    }

There are 3 more fields, but these are the fields that should be changed to run joe_bot as something other than "default-bot".

#Rolling Your Own Plugins joebot2 was designed to make it easy to add plugins. Custom plugins are separated into two concepts: custom commands and plugin processes.

Note: it is recommended that you add the following line

{-# LANGUAGE OverloadedStrings #-}

to the top of every .hs file. Furthermore, it is recommended that you import Data.Text like so:

import qualified Data.Text as T

This is due to the fact that many of the functions provided for plugin support rely heavily on Data.Text for performance and compatibility purposes.

##Custom Commands A Command is roughly the type

data Command = Command
    { cmdName :: Text
    , arity   :: Int
    , runCmd  :: Text -> Maybe Text -> [Text] -> Net ()
    , help    :: Text
    }

Here is a brief description of each of the fields:

  • cmdName is the name of the command (e.g. "!quit").
  • arity is the number of arguments you expect the command to take.
  • runCmd takes in a nick, a channel, and arguments and executes the command.
  • help is shown when the command is used incorrectly.

###Example A simple example of a custom command is found in the Dice Plugin:

roll = Command "!roll" 1 rollDie "!roll <num_dice>d<num_sides>"

Here, we see that Command is the constructor, and it takes in the following arguments:

  • "!roll" is the name of the command.
  • 1 roll expects 1 argument, namely an argument of the form "#d#".
  • rollDie is the function that is invoked when the command is run.
  • "!roll <num_dice>d<num_sides>" is shown when an inappropriate number of arguments is given to roll.

###Helper Functions Note that runCmd returns a Net (). In order to not expose the underlying implementation of Net, three functions have been provided in the Core module:

write   :: Text -> Text -> Net ()
privmsg :: Text -> Maybe Text -> Text -> Net ()
action  :: Text -> Net ()

The functions do the following:

  • write s t writes to the server with the format "s t \r\n". This function is very general, so usage is not recommended. However, this function is useful for writing messages that are not PRIVMSG (e.g. PART, QUIT).
  • privmsg nick chan text writes a private message to the server. If chan is not specified (i.e. Nothing), the message is sent as a private message to the user with the nickname nick. Otherwise the message is written to the channel specified by chan.
  • action text will make the bot perform an action on the channel specified by the initial configuration.

##Plugin Processes Sometimes it is desirable for a plugin to have persistent state that joebot2 can access. Going in to Core.Types and changing Net () is not recommended as it breaks the plugin abstraction. So how do we add new state to joebot2?

The solution is Plugin Processes. Simply put, a Plugin Process is an IO thread that reads the command argument data from a channel (or channels) a la the Actor Model. Due to the multithreaded nature of plugin processes, please note that you are responsible for your own race conditions.

###Plugins.Utils Types Plugins/Utils.hs provides some helper functions and types for writing your own plugin process.

The two types exported are:

type Hook = Text -> Text -> Net ()
type Proc = Chan Msg -> IO ()

A Hook is a command that is run when a user joins, parts, or quits a channel. Currently there are two types of hooks in Config - jhooks and phooks. The former hook is run when a user joins and the latter when a user parts/quits.

A Proc is the type of a plugin process. Note that this is only a suggestion. Using Proc allows you to interface with the functions exported by PluginUtils.

###Plugins.Utils Functions The two functions exported are:

spawnProc    :: Config 
             -> Proc 
             -> [Chan Msg -> Command] 
             -> [Chan Msg -> Hook] 
             -> [Chan Msg -> Hook] 
             -> Bool
             -> IO Config

updateConfig :: Config 
             -> Chan Msg
             -> [Chan Msg -> Command] 
             -> [Chan Msg -> Hook] 
             -> [Chan Msg -> Hook] 
             -> Bool
             -> Config

Both functions take in lists of commands, jhooks, and phooks.

  • spawnProc takes a Proc, creates a channel, and then runs the process. It then takes the newly created channel, applies all the commands and hooks with it and updates the configuration. The final boolean argument is to tell joe_bot whether or not to send a Quit message to the process upon shutdown.
  • updateConfig takes a channel and applies all the commands and hooks with it and then updates the configuration.

#Examples There are few example plugins packaged in with joebot2:

  • Dice is a custom command that allows joebot to roll any number of any kind of dice. The annotated source gives a detailed example of how this plugin was written and may be helpful to those who want to write plugins of their own.
  • Mail is a mail server that allows people to send messages to others even when they're offline. This shows an example of how a plugin process works, along with an example of a join hook.

About

Haskell IRC Bot

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors