3.0.0

New version incoming
Added by David Demelier 5 months ago

Irccd 3.0.0 is coming soon!

The next major irccd version will be released in the next few months. While it's a major version step ahead 2.0.0, it has less more changes than the step between 1.y and 2.y. There are still exciting features that I'll show you now.

Native plugins

Native plugins are finally here!

You can now write a plugin in C++ in case of need. Even though I really encourage to write a Javascript plugin, one may need to use C++ for various reasons (e.g. networking).

A plugin needs to derive from plugin class and export a unique symbol name, that's it.

Example of very basic plugin:

#include <iostream>

#include <irccd/daemon/plugin.hpp>

class my_plugin : public plugin {
public:
    my_plugin()
        : plugin("translate-me", "")
    {
    }

    void on_load(irccd&) override
    {
        std::cout << "native plugin loaded!" << std::endl;
    }
};

// Note, one may need BOOST_SYMBOL_EXPORT on Windows though.
extern "C" my_plugin irccd_plugin_translate_me;

// And define it.
my_plugin irccd_plugin_translate_me;

Note: the symbol name is tied to the file name by default. For example, if you want to load a native plugin with id “translate-me”, a file translate-me.so|dylib|dll will be searched and the symbol irccd_plugin_translate_me must be exported (hyphens are translated to underscores).

Warning: remember that irccd has currently no safe way to protect itself for broken plugins, if your plugin crashes, irccd will too.

The exported IrccdDefinePlugin will help developers to build and install plugins along with their documentation easily.

Live rule editing

The irccdctl tool gained a set of rule editing functions. The following commands have been added:

  • irccdctl rule-add, add a new rule into irccd,
  • irccdctl rule-info, get information about a rule,
  • irccdctl rule-list, list all current rules,
  • irccdctl rule-edit, update an existing rule,
  • irccdctl rule-move, swap rule positions.

Example, listing rules

Listing rules with rule-list:

$ irccdctl rule-list 
rule:        0
servers:     
channels:    
plugins:     hangman 
events:      
action:      drop

rule:        1
servers:     localhost 
channels:    #games 
plugins:     hangman 
events:      
action:      accept

Editing an existing rule

With the same set as before, edit one and see:

$ ./bin/irccdctl -c irccdctl.conf rule-edit --add-channel "#staff" 1
$ ./bin/irccdctl -c irccdctl.conf rule-info 1
rule:        1
servers:     localhost 
channels:    #games #staff 
plugins:     hangman 
events:      
action:      accept

Tests, tests and tests

This version adds a very large number of unit tests. I wanted to make this version the most well tested as possible.

I have added unit tests for irccdctl commands, now I will guarantee that irccdctl output stays compatible between minor versions. This also ensure compatibility in irccdctl options and arguments. Error strings are tested as well to be sure that scripts can rely on irccdctl in a safe and compatible way. The network protocol API errors are tested as well, unit tests have been added to ensure compatibility if commands are not completely valid.

Tests your plugins

If you have used irccd in the 1.y era, you may remember the irccd-test command, it was removed in 2.0.0 for some reasons but is now available again. In bonus, it contains a basic completion support for event names (requires libedit library).

$ ./bin/irccd-test ../plugins/ask/ask.js
> onCommand localhost jean #staff Will I be rich?
localhost: connect
localhost: message #staff jean, Yes!!
> onCommand localhost jean #staff Are you sure?
localhost: message #staff jean, Definitely not!
> 

In this example, if you start typing onCom and complete with tab key, you will be completed through onCommand. For the moment, there is no completion on servers names but I'll try to add this later.

Note: as you can see, there is an onConnect event before the response, this happens because each time you invoke an event with a different server, a fake one is created if it does not exist.

Internal code change

Most of the development have been done to switch to Boost. I'm sorry if you feel disappointed of having boost dependency in irccd, but I was not able to provide perfect system compatibility by writing my own code in many places.

On the other hand, irccd does not use boost for everything, the following modules are used:

  • Asio,
  • Filesystem,
  • Process (unit tests only),
  • Timer (Javascript API only),
  • Format.

New tictactoe plugin

A brand new tictactoe plugin has been added. It allows two players playing tictactoe game on IRC. The plugin takes care of checking if users are in the channel and stay the lifetime of the game.

< markand> !tictactoe linkdd 
< irccd>   a b c
< irccd> 1 . . .
< irccd> 2 . . .
< irccd> 3 . . .
< irccd> markand, it's your turn
< markand> a 1
< irccd>   a b c
< irccd> 1 x . .
< irccd> 2 . . .
< irccd> 3 . . .
< irccd> linkdd, it's your turn
< linkdd> a 3
< irccd>   a b c
< irccd> 1 x . .
< irccd> 2 . . .
< irccd> 3 o . .
< irccd> markand, it's your turn

New joke plugin

A very simple joke plugin has been added.

The purpose of this plugin is to randomly choose a joke in a set of user defined jokes. It shuffles the list of jokes and pick one of the current list, therefore, you will not see the same joke until the full pile has been shown.

< markand> !joke
< irccd> keep calm and drop database
< markand> !joke
< irccd> francis: make me a sandwish
< irccd> lisa: do it yourself
< irccd> francis: sudo make me a sandwich
< irccd> lisa: ok

And since the plugin uses the templating system in irccd, it is possible to specify a set of jokes for a different server/channel.

Please note that there is no fallback in that method, if you start using templates in the configuration, you will need to symlink/create jokes for every channels you want to use.

Decomissionning libircclient

Unfortunately, the major part of irccd has left. I have decided to remove libircclient from our code and use a house code itself. Since IRC protocol is very easy, it was pretty quick.

The biggest problem of libircclient is the dependency on the `select(2)` system call. This was pretty hard to mix with the irccd main loop which uses Boost.Asio context object. Instead of creating a thread and complex code for retrieving data, I've created a simple class that does most of the IRC protocol.

It is not that big though:

$ cloc irccd/daemon/irc.*
       2 text files.
       2 unique files.                              
       0 files ignored.

github.com/AlDanial/cloc v 1.72  T=0.01 s (320.0 files/s, 137922.1 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C/C++ Header                     1             60            240            287
C++                              1             58             21            196
-------------------------------------------------------------------------------
SUM:                             2            118            261            483
-------------------------------------------------------------------------------

New path system

One of the biggest issue I had in the last two versions was the management of directories. Irccd had used a dynamic directory lookup when loading plugins, this confuse users and is hard to understand. For example, when the plugin ask was loaded, irccd searched different configuration and data directories and if it does not find one, it uses the system wide. You may think it's not a problem, but it is! What if a plugin needs to write some data? This is the reason you see in old documentation that you were needed to create a directory before using a plugin.

In irccd 3.0.0, there is no more “dynamic directories”. Instead, if irccd is started without any directories set, it uses the default system ones, period. There is no more an autodetection of user, system directories. Thus, if you want to use different directories, you may set the [paths] section.

There are two sections, the global [paths] and per-plugin [paths.name]. The first one is the defaults for everything and the second can be added to adjust settings for a specific plugin.

Example:

[paths]
cache = "/var/cache/irccd" 
config = "/etc/irccd/" 
data = "/var/irccd" 

If the plugin ask is started with this configuration, it will have the following directories set:

  • cache: /var/cache/irccd/plugin/ask
  • config: /etc/irccd/plugin/ask
  • data: /var/irccd/plugin/ask

And then, if you want, you can override any directory without the need to set all.

[paths]
cache = "/var/cache/irccd" 
config = "/etc/irccd" 
data = "/var/irccd" 

[paths.ask]
data = "/etc/irccd/jokes" 

Then, ask will have the following paths instead:

  • cache: /var/cache/irccd/plugin/ask (default from `[paths]`),
  • config: /etc/irccd/plugin/ask (default from `[paths]`),
  • data: /etc/irccd/jokes (overriden from `[paths.ask]`).

Miscellaneous

Another minor changes:

  • If irccd is built from a Mercurial repository, the irccd --version command shows the last revision,
  • If no identity is set into a [server] section, it tries to uses the system username by default,
  • The systemd service file is now first class citizen.

Comments