Contenu

Ecrire un bot pour Slack en Rust 🤖

Introduction

Slack est un outil utilisĂ© dans de nombreuses entreprises pour faciliter la communication au sein des Ă©quipes. Et il est possible d’augmenter les fonctionnalitĂ©s de Slack via des commandes personnalisĂ©es. Parmi les plus utilisĂ©es, on retrouve la commande /polly pour crĂ©er des sondages, ainsi que la commande /giphy pour aller chercher des gifs et participer de façon constructive Ă  une conversation. Dans cet article, nous allons prĂ©senter une façon d’ajouter ses propres commandes via la crĂ©ation d’un bot Slack fait en Rust. (Aucune connaissance de Rust n’est requise pour lire cet article).

Fonctionnement global

Le bot est un service-web REST déployé sur le produit Cloud Run de GCP (Google Cloud Platform) et qui expose le endpoint /commands (POST).

Slack va envoyer la ligne de commande entière au webservice, avec une url de callback et un token d’authentification, ainsi que des informations sur l’utilisateur et le channel.

Le bot s’occupera d’interprĂ©ter la commande et de renvoyer une rĂ©ponse au format d’un message Slack classique.

Paramétrage côté Slack

Pour attaquer notre bot, il nous faut d’abord configurer notre Slack pour lui ajouter une application, pour cela, direction le site api.slack.com/apps

Il existe ensuite diffĂ©rents types de features qu’on peut ajouter, ici celle qui nous intĂ©resse est le fait d’ajouter un slash command

/rust-slack-bot/max-bot-slash.jpg

Ici on peut dĂ©finir de nouvelle commande Slack, comme par exemple /maxbot pour utiliser notre bot, ainsi que l’url Ă  utiliser.

Il est aussi possible d’avoir un hook sur diffĂ©rents types d’Ă©vènements, par exemple Ă  chaque fois qu’une personne rejoint un channel, pour lancer automatiquement un message de bienvenue.

Côté webservice

Afin de communiquer avec l’api Slack, on utilise une librairie qui dĂ©finit dĂ©jĂ  toutes les structures utilisĂ©es par l’api, il s’agit de slack_api

1
2
[dependencies]
slack_api = "0.23.0"

Infrastructure

Notre webservice est déployé dans un conteneur docker sur GCP, et Slack envoie chaque commande /maxbot au webservice avec une url de callback( même chose pour les évènements)

/rust-slack-bot/diag.png

Implémentation du bot en Rust

Exposition

Pour la partie webservice et exposition du endpoint, on utilise la librairie Rocket.

Création des endpoints :

1
2
3
4
5
pub fn create_routes(sender: Sender<ExchangeInChannel>) -> rocket::Rocket {
    Rocket::ignite()
        .manage(sender)
        .mount("/commands", rocket::routes![process_all_commands])
        .mount(...)
1
2
#[post("/", data = "<command_input>")]
pub fn process_all_commands( ... ) 

Interprétation de la commande

Pour savoir quel traitement doit être effectué, il faut parser la ligne de commande. Exemple de commande à parser :

/maxbot météo , /maxbot help , /maxbot csgo stats.

Dans la structure que l’on reçoit, le nom de la commande et le texte qui suit sont deux champs sĂ©parĂ©s.

1
2
3
4
5
6
7
8
9
pub fn process_maxbot_command(input_cmd: CommandInput, sender: State<Sender<ExchangeInChannel>>) -> EventResponse {
    let cmd = &input_cmd.text.url_decode().unwrap();
    let cmd_params: Vec<&str> = cmd.trim().split(' ').collect::<Vec<&str>>();
    match cmd_params[0] {
        "météo" | "meteo" => process_meteo_command(...),
        "csgo" => process_command_csgo(...),
        "random" => process_random_command(...),
        "" | "help" => process_help_command(...),
        // et autres commandes

Ensuite le traitement Ă  faire est Ă  adapter selon les besoins, pour l’une des commandes les plus utilisĂ©es sur notre bot, il s’agit de la commande /maxbot csgo stat qui s’occupe d’aller se connecter via ssh sur un VPS oĂą tourne un serveur privĂ© CSGO, et d’effectuer une requĂŞte sql pour la rĂ©cupĂ©ration des statistiques de tous nos participants.

Ici on prĂ©sentera plutĂ´t ensuite la rĂ©ponse de la commande random qui permet d’effectuer un jet de pièce ou de dĂ©s, afin d’Ă©viter le stat shaming auprès de nos collègues.

RĂ©pondre Ă  Slack.

Une fois le traitement effectué, il nous reste à renvoyer la réponse à Slack.

Pour cela on utilise tout ce qui nous a Ă©tĂ© transmis en mĂŞme temps que la requĂŞte, Ă  savoir une url de callback et un token d’authentification :

1
2
3
4
5
6
/**
* Appel de l'url sur https://hooks.slack.com/commands/XXX/ZZZZZZZZZZZZZZZ fourni dans l'url passée en paramètre
*/
fn post_hooks(client: &Reqwest_client, token: &str, url: String, text: String, response_type: String) {
    client.post(url.as_str()).bearer_auth(token).json(&Hook { text, response_type }).send().unwrap();
}

Exemple de réponse pour la commande /maxbot random coin :

/rust-slack-bot/result-random.png

Conclusion

Dans cet article, on a prĂ©sentĂ© une façon de personnaliser Slack et son utilisation via une application simple. Ce projet Ă©tait aussi l’occasion d’avoir un terrain de jeu pour monter en compĂ©tence sur Rust, mais ce sera pour un prochain article.