2 Développement-Plugins
Claude edited this page 2026-05-16 12:33:42 +02:00

Développement de Plugins

NoxIRC supporte un système de plugins backend permettant d'étendre les fonctionnalités via des scripts Python exécutés dans un sandbox sécurisé.

Structure d'un plugin

Un plugin est un fichier ZIP contenant au minimum :

mon-plugin.zip
├── plugin.json       # Manifest obligatoire
└── main.py           # Point d'entrée (configurable)

Manifest — plugin.json

{
  "id": "mon-plugin",
  "name": "Mon Plugin",
  "version": "1.0.0",
  "author": "Auteur",
  "description": "Description courte du plugin",
  "type": ["backend"],
  "hooks": ["on_message_received"],
  "permissions": [],
  "entry_point": "main.py",
  "min_noxirc_version": "1.0.0"
}

Champs du manifest

Champ Type Description
id string Identifiant unique (slug, ex: imgur-uploader)
name string Nom affiché dans l'interface
version string Version semver
hooks array Hooks que le plugin utilise
permissions array Permissions requises
entry_point string Fichier Python principal (défaut: main.py)

Point d'entrée — main.py

Le plugin doit exposer une fonction register(ctx, hooks) :

def register(ctx, hooks):
    hooks.subscribe("on_message_received", on_message)

def on_message(payload):
    target = payload.get("target")
    message = payload.get("message")
    nick = payload.get("by")
    # Traitement...

API disponible — ctx

Requêtes HTTP

Permission requise : network.outbound:<domaine>

# GET
response = ctx.http_get("https://api.example.com/data")
# {"status": 200, "body": "..."}

# POST
response = ctx.http_post("https://api.example.com/endpoint", {"key": "value"})

Stockage clé/valeur (Redis, isolé par plugin)

# Lire
api_key = ctx.store_get("api_key")

# Écrire
ctx.store_set("last_run", "2026-01-01")

Storage provider (hébergement de fichiers)

Permission requise : storage.register

def register(ctx, hooks):
    def upload(file_bytes, filename, content_type, user_id):
        # file_bytes   : bytes  — contenu brut du fichier
        # filename     : str    — nom original
        # content_type : str    — type MIME
        # Retourne     : {"url": str, "provider_path": str}
        import json
        response = ctx.http_post("https://api.monhost.com/upload", {
            "filename": filename,
        })
        body = json.loads(response["body"])
        return {"url": body["link"], "provider_path": body["id"]}

    def delete(provider_path):
        ctx.http_post("https://api.monhost.com/delete", {"id": provider_path})
        return True

    ctx.storage.register(
        name="monhost",
        label="Mon hébergeur",
        upload_fn=upload,
        delete_fn=delete,  # optionnel
    )

Hooks disponibles

Hook Payload Description
on_message_received {target, by, message, is_private, is_highlight, network_id, user_id} Message IRC reçu
on_highlight {target, by, message, is_private, network_id, user_id} Mention de l'utilisateur
on_file_upload {file_id, filename, content_type, size, user_id} Fichier uploadé
on_connect {network_id} Connexion à un réseau IRC
on_disconnect {network_id} Déconnexion

Permissions disponibles

Permission Accès accordé
network.outbound:<domaine> Requêtes HTTP vers le domaine spécifié
storage.register Enregistrement d'un provider de stockage
irc.send Émission d'événements IRC
"permissions": ["network.outbound:api.imgur.com", "storage.register"]

Imports Python autorisés dans le sandbox

json, re, math, datetime


Exemple complet — Plugin Imgur

plugin.json :

{
  "id": "imgur-uploader",
  "name": "Imgur Uploader",
  "version": "1.0.0",
  "author": "Vous",
  "description": "Upload les fichiers sur Imgur",
  "type": ["backend"],
  "hooks": [],
  "permissions": ["network.outbound:api.imgur.com", "storage.register"],
  "entry_point": "main.py"
}

main.py :

import json

def register(ctx, hooks):
    def upload(file_bytes, filename, content_type, user_id):
        client_id = ctx.store_get("imgur_client_id") or "VOTRE_CLIENT_ID"
        response = ctx.http_post("https://api.imgur.com/3/image", {
            "image": list(file_bytes),
            "type": "file",
        })
        body = json.loads(response["body"])
        if not body.get("success"):
            raise Exception("Imgur upload failed: " + str(body))
        return {
            "url": body["data"]["link"],
            "provider_path": body["data"]["id"],
        }

    def delete(provider_path):
        ctx.http_post("https://api.imgur.com/3/image/" + provider_path + "/delete", {})
        return True

    ctx.storage.register("imgur", "Imgur", upload_fn=upload, delete_fn=delete)

Installation

Via le panel d'administration : Administration → Plugins → Installer

Via l'API :

curl -X POST /api/plugins/install \
  -H "Authorization: Bearer <token>" \
  -d '{"plugin_id": "imgur-uploader", "version": "1.0.0", "source_url": "https://..."}'

Désactiver le stockage local (admin)

Pour forcer l'utilisation d'un provider plugin :

curl -X PUT /api/admin/settings \
  -H "Authorization: Bearer <token>" \
  -d '{"key": "local_storage_enabled", "value": "false"}'