En route pour irccd 4.0.0

Posted by David Demelier on Tue 09 February 2021

En cette nouvelle année, je prévois une nouvelle version majeure d'irccd. À savoir la version 4.0.0.

Dans un précédent billet de blog j'ai annoncé qu'irccd n'aurait pas de changement majeur à l'avenir mais en faisant face à quelques déceptions j'ai décidé de lui donner un grand coup de rabot.

C'est une traduction et un article plus libre et moins formel que la note officielle.

Presque totale réécriture

Tout d'abord, j'avais annoncé qu'il était peu probable que je réécrive en C mais contre toute attente j'ai tout de même décidé de le faire et pour plusieurs raisons :

Le code C++ et l'API sont beaucoup trop compliqués

Depuis mon utilisation de Boost le code s'est naturellement complexifié due à l'utilisation intensive des templates et de la surconception de Boost.

Par exemple, le code des transport est sur-templatisé parce que Boost.Asio en fait aussi une utilisation intensive.

Voir stream.hpp

Trop de fonctionnalités

N'étant qu'un simple bot IRC, je pense qu'il y a pas mal de fonctionnalités que je considère comme inutiles. Par conséquent, j'en ai profité pour simplifier le code et réduire ce qui est moins important.

Boost

Mon plus grand regret était l'inclusion de Boost. C'est une bibliothèque trop monumentale que beaucoup de développeurs et/ou utilisateurs n'aiment pas avoir à gérer. Il faut avouer que la taille de l'exécutable et de l'espace disque requis est conséquent lorsque vous liez un exécutable à une des bibliothèques.

Et non, contrairement aux idées reçues Boost n'est pas une bibliothèque “headers-only”. En réalité une grande partie des modules ont besoin de Boost.System pour fonctionner et vous devez donc avoir ces bibliothèques au runtime.

Alors sans grande surprise, j'annonce qu'irccd est totalement réécrit en pur C, mais à cela s'ajoute quelques changements drastiques.

Pur POSIX

Développer en pur C n'est pas possible dès lors qu'on a besoin d'avoir une API de réseau. Il en va de même pour les accès aux répertoires et d'autres fonctionnalités. Il ne faut pas oublier que C se veut le plus simple à implémenter possible.

De ce fait, irccd a maintenant besoin d'un système compatible POSIX comprenant :

  • pthreads (uniquement pour l'API Javascript),
  • fmemopen et open_memstream,
  • Les outils lex/yacc (flex et bison via CMake).
  • API sockets,
  • API dirent (un polyfill Windows est disponible),
  • API dlfcn.

Par conséquent, votre système d'exploitation à la fenêtre est pour le moment fermé car ce système n'est pas compatible POSIX. Du code est rajouté au fur et à mesure pour corriger les manquements mais Windows n'est plus du tout prioritaire. N'hésitez pas à mettre la pression à Microsoft pour implémenter la totalité de l'API POSIX.

Peu de dépendances

Il n'y a plus beaucoup de dépendances obligatoires.

  • CMake : toujours utilisé pour compiler le projet. J'ai essayé d'utiliser GNU Make mais je n'étais pas convaincu du résultat. Irccd est découpé en trop nombreux petits projets.
  • Lex & Yacc : pour les nouvelles configurations.
  • OpenSSL : (Optionnel) pour se connecter à des serveurs IRC sécurisés.
  • CURL et liburiparser : (Optionnel) seulement pour le plugin natif links (qui n'utilise plus Boost.Beast).

Changements majeurs

La version 4.0.0 étant une nouvelle version majeure, il y a quelques changements non compatible avec les précédentes versions à prévoir.

Je ne détaillerai pas tous les changements car le guide de migration est déjà présent pour ça.

Nouvelles configurations

Cela faisait un moment que je réfléchissais à remplacer le vieillissant parseur d'options en .ini. Il pose beaucoup de problèmes parce que certaines options sont structurées pour aller dans un ensemble.

Voici ce qui est nécessaire d'écrire pour configurer les templates, chemins et options d'un plugin en irccd 3.y.z :

[plugins]
hangman =

[plugin.hangman]
collaborative = false

[paths.hangman]
data = "/var/data/hangman"

[templates.hangman]
win = "Bravo, le mot était #{word}"

Ce n'est pas élégant ni intuitif. Alors voici comment on configure un plugin avec irccd 4.0.0 :

plugin hangman {
    location "/var/srv/plugins/hangman.js"; # Optionnel

    options {
        collaborative = false;
    }
    templates {
        win "Bravo, le mot était #{word}";
    }
    paths {
        data "/var/data/hangman";
    }
}

On est d'accord, c'est plus logique ?

La syntaxe s'inspire de nginx et aussi du vénérable pf.conf. Les parties plus simples ne sont pas faites en bloc mais en simple lignes.

Par exemple, les logs et transports se configure plus aisément :

logs verbose to syslog
transport to "/tmp/irccd.sock"

L'API réseau est de nouveau du pur texte

Dans les premières versions d'irccd, les commandes d'irccdctl étaient envoyées en pur texte. Mais avec l'arrivée de commandes plus complexes j'ai souhaité passer à JSON.

Depuis irccd 4.0.0 il s'agit de nouveau d'un protocol simple utilisable directement depuis nc -U avec quelques lignes.

Exemple :

SERVER-MESSAGE malikania #test Ceci est un test
SERVER-JOIN malikania #test

Le protocol utilise '\n' pour délimiter les messages, ceux qui ont besoin d'envoyer plusieurs lignes variables l'indique en général dans leur réponse.

Par conséquent, en l'absence de JSON la commande irccdctl watch ne fait plus que du texte brut en sortie. Néanmoins étant normé et consolidé par la garantie de version, il est tout à fait utilisable en scripts.

L'API Javascript

L'API Javascript est celle que je souhaite modifier le moins possible. Il s'agit de la pierre angulaire d'irccd : créer des plugins afin de l'étendre. Le gestionnaire de fenêtre awesome est connu pour avoir généré beaucoup de frustration lorsque les développeurs cassaient les APIs entre chaque version.

Par conséquent, bien qu'étant une version majeure l'API Javascript est presque totalement rétro compatible.

Quelques fonctions ont été supprimées car ne sont pas utiles et n'étaient pas toujours fonctionnelles :

  • Irccd.Chrono : seule la méthode reset() est maintenue. La méthode elapsed() est maintenant une propriété du même nom ;
  • Irccd.Util : la méthode ticks() a été supprimée. La méthode cut() lève plus d'exceptions en cas d'erreur d'utilisation que précédemment ;
  • Irccd.Server : La propriété channels renvoyé via info() est maintenant un objet contenant tous les nicknames présents sur un canal.

Un autre point particulièrement intéressant a été rajouté, c'est le suivi des nicknames sur chaque canal où irccd est présent. Cela signifie qu'il n'est plus nécessaire de faire un appel à Server.names et d'attendre un évènement pour déterminer si quelqu'un est bien présent ou non.

L'API C

Étant totalement réécrit en C, l'API C++ n'est évidemment plus disponible. Par ailleurs, l'API native en C qui est exposée est bien plus minimaliste que précédemment. En effet, si vous écrivez un plugin natif vous n'aurez accès qu'à :

  • La gestion du bot (plugins, serveurs, règles) ;
  • Quelques utilitaires de bases ;
  • Le système de substitution de texte.

Cela pour la stabiliser au maximum l'API C et pouvoir changer du code sans avoir à impacter cette dernière.

Pour quand ?

La version 4.0.0 est pratiquement terminée en terme de fonctionnalités. Il reste essentiellement beaucoup de tests à écrire pour garantir la qualité du projet. Le dépôt officiel ne contient pas encore le code de cette version car la documentation n'est pas forcément à jour (surtout concernant les fichiers de configuration). J'écrirai un nouvel article lorsque irccd 4.0.0 sera disponible pour du test massif.

Je vais essayer de sortir une version stable d'ici l'automne 2021 et compte tenu de la stabilité d'irccd 3 et les changements majeurs, cette version sera maintenue pendant deux ans à compter de la sortie de la version 4.


Comments !