secubox-openwrt/docs-fr/luci-development-reference.md
CyberMind-FR ccfb58124c docs: Add trilingual documentation (French and Chinese translations)
Add complete French (fr) and Chinese (zh) translations for all documentation:

- Root files: README, CHANGELOG, SECURITY, BETA-RELEASE
- docs/: All 16 core documentation files
- DOCS/: All 19 deep-dive documents including embedded/ and archive/
- package/secubox/: All 123+ package READMEs
- Misc: secubox-tools/, scripts/, EXAMPLES/, config-backups/, streamlit-apps/

Total: 346 translation files created

Each file includes language switcher links for easy navigation between
English, French, and Chinese versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-20 10:00:18 +01:00

32 KiB

Guide de Reference pour le Developpement LuCI

Langues: English | Francais | 中文

Version: 1.0.0 Derniere mise a jour: 2025-12-28 Statut: Actif Base sur: implementations luci-app-secubox et luci-app-system-hub Public cible: Claude.ai et developpeurs travaillant sur des applications LuCI OpenWrt


Voir aussi

Ce document capture les patterns critiques, bonnes pratiques et pieges courants decouverts lors du developpement des applications LuCI SecuBox. Utilisez-le comme reference de validation pour tout developpement futur d'applications LuCI.


Table des matieres

  1. Fondamentaux ubus et RPC
  2. Patterns Backend RPCD
  3. Patterns Module API LuCI
  4. Patterns d'Import de Vues LuCI
  5. Structure des Permissions ACL
  6. Conventions de Structure de Donnees
  7. Erreurs Courantes et Solutions
  8. Checklist de Validation
  9. Tests et Deploiement

Fondamentaux ubus et RPC

Qu'est-ce que ubus ?

ubus (architecture micro bus OpenWrt) est le systeme de communication inter-processus (IPC) d'OpenWrt. Il permet :

  • RPC (Remote Procedure Call) entre processus
  • Communication entre l'interface web (LuCI) et les services backend
  • Interaction en ligne de commande via ubus call

Convention de Nommage des Objets ubus

REGLE CRITIQUE : Tous les objets ubus des applications LuCI DOIVENT utiliser le prefixe luci..

// ✅ CORRECT
object: 'luci.system-hub'
object: 'luci.cdn-cache'
object: 'luci.wireguard-dashboard'

// ❌ INCORRECT
object: 'system-hub'
object: 'systemhub'
object: 'cdn-cache'

Pourquoi ? LuCI attend les objets sous l'espace de noms luci.* pour les applications web. Sans ce prefixe :

  • Les permissions ACL ne correspondent pas
  • RPCD ne route pas correctement les appels
  • La console du navigateur affiche : RPC call to system-hub/status failed with error -32000: Object not found

Le Nom du Script RPCD DOIT Correspondre a l'Objet ubus

Le nom du fichier script RPCD DOIT correspondre exactement au nom de l'objet ubus :

# Si JavaScript declare :
# object: 'luci.system-hub'

# Alors le script RPCD DOIT etre nomme :
/usr/libexec/rpcd/luci.system-hub

# PAS :
/usr/libexec/rpcd/system-hub
/usr/libexec/rpcd/luci-system-hub

Commande de Validation :

# Verifier les fichiers JavaScript pour les noms d'objets ubus
grep -r "object:" luci-app-*/htdocs --include="*.js"

# Verifier que le script RPCD existe avec le nom correspondant
ls luci-app-*/root/usr/libexec/rpcd/

Types d'Appels ubus

Operations de Lecture (type GET) :

  • status - Obtenir l'etat actuel
  • get_* - Recuperer des donnees (ex: get_health, get_settings)
  • list_* - Enumerer des elements (ex: list_services)

Operations d'Ecriture (type POST) :

  • save_* - Persister la configuration (ex: save_settings)
  • *_action - Effectuer des actions (ex: service_action)
  • backup, restore, reboot - Modifications systeme

Mapping ACL :

  • Operations de lecture → section "read" dans ACL
  • Operations d'ecriture → section "write" dans ACL

Patterns Backend RPCD

Structure des Scripts Shell

Les backends RPCD sont des scripts shell executables qui :

  1. Analysent $1 pour l'action (list ou call)
  2. Analysent $2 pour le nom de la methode (si call)
  3. Lisent l'entree JSON depuis stdin (pour les methodes avec parametres)
  4. Produisent du JSON sur stdout
  5. Se terminent avec le statut 0 en cas de succes, non-zero en cas d'erreur

Modele Standard

#!/bin/sh
# Backend RPCD : luci.system-hub
# Version : 0.1.0

# Charger l'assistant JSON shell
. /usr/share/libubox/jshn.sh

case "$1" in
    list)
        # Lister toutes les methodes disponibles et leurs parametres
        echo '{
            "status": {},
            "get_health": {},
            "service_action": { "service": "string", "action": "string" },
            "save_settings": {
                "auto_refresh": 0,
                "health_check": 0,
                "refresh_interval": 0
            }
        }'
        ;;
    call)
        case "$2" in
            status)
                status
                ;;
            get_health)
                get_health
                ;;
            service_action)
                # Lire l'entree JSON depuis stdin
                read -r input
                json_load "$input"
                json_get_var service service
                json_get_var action action
                service_action "$service" "$action"
                ;;
            save_settings)
                read -r input
                json_load "$input"
                json_get_var auto_refresh auto_refresh
                json_get_var health_check health_check
                json_get_var refresh_interval refresh_interval
                save_settings "$auto_refresh" "$health_check" "$refresh_interval"
                ;;
            *)
                echo '{"error": "Method not found"}'
                exit 1
                ;;
        esac
        ;;
esac

Sortie JSON avec jshn.sh

jshn.sh fournit des fonctions shell pour la manipulation JSON :

# Initialiser l'objet JSON
json_init

# Ajouter des valeurs simples
json_add_string "hostname" "openwrt"
json_add_int "uptime" 86400
json_add_boolean "running" 1

# Ajouter un objet imbrique
json_add_object "cpu"
json_add_int "usage" 25
json_add_string "status" "ok"
json_close_object

# Ajouter un tableau
json_add_array "services"
json_add_string "" "network"
json_add_string "" "firewall"
json_close_array

# Produire le JSON sur stdout
json_dump

Fonctions Courantes :

  • json_init - Demarrer un nouvel objet JSON
  • json_add_string "key" "value" - Ajouter une chaine
  • json_add_int "key" 123 - Ajouter un entier
  • json_add_boolean "key" 1 - Ajouter un booleen (0 ou 1)
  • json_add_object "key" - Demarrer un objet imbrique
  • json_close_object - Terminer l'objet imbrique
  • json_add_array "key" - Demarrer un tableau
  • json_close_array - Terminer le tableau
  • json_dump - Produire le JSON sur stdout

Gestion des Erreurs

Toujours valider les entrees et retourner des erreurs significatives :

service_action() {
    local service="$1"
    local action="$2"

    # Valider le nom du service
    if [ -z "$service" ]; then
        json_init
        json_add_boolean "success" 0
        json_add_string "error" "Service name is required"
        json_dump
        return 1
    fi

    # Valider l'action
    case "$action" in
        start|stop|restart|enable|disable)
            ;;
        *)
            json_init
            json_add_boolean "success" 0
            json_add_string "error" "Invalid action: $action"
            json_dump
            return 1
            ;;
    esac

    # Executer l'action
    /etc/init.d/"$service" "$action" >/dev/null 2>&1

    if [ $? -eq 0 ]; then
        json_init
        json_add_boolean "success" 1
        json_add_string "message" "Service $service $action successful"
        json_dump
    else
        json_init
        json_add_boolean "success" 0
        json_add_string "error" "Service $service $action failed"
        json_dump
        return 1
    fi
}

Integration UCI

Pour la configuration persistante, utiliser UCI (Unified Configuration Interface) :

save_settings() {
    local auto_refresh="$1"
    local health_check="$2"
    local refresh_interval="$3"

    # Creer/mettre a jour la config UCI
    uci set system-hub.general=general
    uci set system-hub.general.auto_refresh="$auto_refresh"
    uci set system-hub.general.health_check="$health_check"
    uci set system-hub.general.refresh_interval="$refresh_interval"
    uci commit system-hub

    json_init
    json_add_boolean "success" 1
    json_add_string "message" "Settings saved successfully"
    json_dump
}

get_settings() {
    # Charger la config UCI
    if [ -f "/etc/config/system-hub" ]; then
        . /lib/functions.sh
        config_load system-hub
    fi

    json_init
    json_add_object "general"

    # Obtenir la valeur ou utiliser la valeur par defaut
    config_get auto_refresh general auto_refresh "1"
    json_add_boolean "auto_refresh" "${auto_refresh:-1}"

    config_get refresh_interval general refresh_interval "30"
    json_add_int "refresh_interval" "${refresh_interval:-30}"

    json_close_object
    json_dump
}

Conseils de Performance

  1. Mettre en cache les operations couteuses : Ne pas relire les fichiers /proc plusieurs fois
  2. Utiliser efficacement la substitution de commande :
    # Bien
    uptime=$(cat /proc/uptime | cut -d' ' -f1)
    
    # Mieux
    read uptime _ < /proc/uptime
    uptime=${uptime%.*}
    
  3. Eviter les commandes externes quand possible :
    # Lent
    count=$(ls /etc/init.d | wc -l)
    
    # Rapide
    count=0
    for file in /etc/init.d/*; do
        [ -f "$file" ] && count=$((count + 1))
    done
    

Patterns Module API LuCI

CRITIQUE : Utiliser baseclass.extend()

REGLE : Les modules API LuCI DOIVENT utiliser le pattern baseclass.extend().

'use strict';
'require baseclass';
'require rpc';

// Declarer les methodes RPC
var callStatus = rpc.declare({
    object: 'luci.system-hub',
    method: 'status',
    expect: {}
});

var callGetHealth = rpc.declare({
    object: 'luci.system-hub',
    method: 'get_health',
    expect: {}
});

var callSaveSettings = rpc.declare({
    object: 'luci.system-hub',
    method: 'save_settings',
    params: ['auto_refresh', 'health_check', 'refresh_interval'],
    expect: {}
});

// ✅ CORRECT : Utiliser baseclass.extend()
return baseclass.extend({
    getStatus: callStatus,
    getHealth: callGetHealth,
    saveSettings: callSaveSettings
});

// ❌ INCORRECT : Ne PAS utiliser ces patterns
return baseclass.singleton({...});  // Casse tout !
return {...};  // L'objet simple ne fonctionne pas

Pourquoi baseclass.extend() ?

  • Le systeme de modules LuCI attend des modules bases sur des classes
  • Les vues importent avec 'require module/api as API' qui auto-instancie
  • baseclass.extend() cree un constructeur de classe approprié
  • baseclass.singleton() casse le mecanisme d'instanciation
  • Les objets simples ne supportent pas le cycle de vie des modules LuCI

Parametres rpc.declare()

var callMethodName = rpc.declare({
    object: 'luci.module-name',     // nom objet ubus (DOIT commencer par luci.)
    method: 'method_name',          // nom methode RPCD
    params: ['param1', 'param2'],   // Optionnel : noms des parametres (l'ordre compte !)
    expect: {}                      // Structure de retour attendue (ou { key: [] } pour les tableaux)
});

L'Ordre des Parametres est Important :

// RPCD attend les parametres dans cet ordre exact
var callSaveSettings = rpc.declare({
    object: 'luci.system-hub',
    method: 'save_settings',
    params: ['auto_refresh', 'health_check', 'debug_mode', 'refresh_interval'],
    expect: {}
});

// L'appel JavaScript DOIT passer les parametres dans le meme ordre
API.saveSettings(1, 1, 0, 30);  // auto_refresh=1, health_check=1, debug_mode=0, refresh_interval=30

Patterns du Parametre expect

// La methode retourne un objet unique
expect: {}

// La methode retourne un tableau au niveau superieur
expect: { services: [] }

// La methode retourne une structure specifique
expect: {
    services: [],
    count: 0
}

Gestion des Erreurs dans le Module API

Les methodes API retournent des Promises. Gerer les erreurs dans les vues :

return API.getHealth().then(function(data) {
    if (!data || typeof data !== 'object') {
        console.error('Invalid health data:', data);
        return null;
    }
    return data;
}).catch(function(err) {
    console.error('Failed to load health data:', err);
    ui.addNotification(null, E('p', {}, 'Failed to load health data'), 'error');
    return null;
});

Patterns d'Import de Vues LuCI

CRITIQUE : Utiliser 'require ... as VAR' pour les APIs

REGLE : Lors de l'import de modules API, utiliser le pattern 'require ... as VAR' en haut du fichier.

// ✅ CORRECT : Auto-instancie la classe
'require system-hub/api as API';

return L.view.extend({
    load: function() {
        return API.getHealth();  // API est deja instancie
    }
});

// ❌ INCORRECT : Retourne le constructeur de classe, pas l'instance
var api = L.require('system-hub.api');
api.getHealth();  // ERREUR : api.getHealth is not a function

Pourquoi ?

  • 'require module/path as VAR' (avec des slashes) auto-instancie les classes
  • L.require('module.path') (avec des points) retourne le constructeur de classe brut
  • Les modules API etendent baseclass, qui necessite une instanciation
  • Le chargeur de modules LuCI gere l'instanciation avec le pattern as VAR

Structure de Vue Standard

'use strict';
'require view';
'require form';
'require ui';
'require system-hub/api as API';

return L.view.extend({
    load: function() {
        // Charger les donnees necessaires au rendu
        return Promise.all([
            API.getHealth(),
            API.getStatus()
        ]);
    },

    render: function(data) {
        var health = data[0];
        var status = data[1];

        // Creer les elements UI
        var container = E('div', { 'class': 'cbi-map' }, [
            E('h2', {}, 'Dashboard'),
            // ... plus d'elements
        ]);

        return container;
    },

    handleSave: null,  // Desactiver le bouton sauvegarder
    handleSaveApply: null,  // Desactiver le bouton sauvegarder et appliquer
    handleReset: null  // Desactiver le bouton reinitialiser
});

Resume des Patterns d'Import

// Modules core LuCI (toujours avec des guillemets)
'require view';
'require form';
'require ui';
'require rpc';
'require baseclass';

// Modules API personnalises (utiliser 'as VAR' pour l'auto-instanciation)
'require system-hub/api as API';
'require cdn-cache/api as CdnAPI';

// Acceder a l'objet global L (pas de require)
L.resolveDefault(...)
L.Poll.add(...)
L.ui.addNotification(...)

Structure des Permissions ACL

Emplacement du Fichier

Les fichiers ACL sont situes dans :

/usr/share/rpcd/acl.d/luci-app-<nom-module>.json

Dans l'arborescence source :

luci-app-<nom-module>/root/usr/share/rpcd/acl.d/luci-app-<nom-module>.json

Modele ACL Standard

{
    "luci-app-module-name": {
        "description": "Module Name - Description",
        "read": {
            "ubus": {
                "luci.module-name": [
                    "status",
                    "get_system_info",
                    "get_health",
                    "list_services",
                    "get_logs",
                    "get_storage",
                    "get_settings"
                ]
            }
        },
        "write": {
            "ubus": {
                "luci.module-name": [
                    "service_action",
                    "backup_config",
                    "restore_config",
                    "reboot",
                    "save_settings"
                ]
            }
        }
    }
}

Classification Lecture vs Ecriture

Operations de Lecture (pas de modification systeme) :

  • status - Obtenir l'etat actuel
  • get_* - Recuperer des donnees (info systeme, sante, parametres, logs, stockage)
  • list_* - Enumerer des elements (services, interfaces, etc.)

Operations d'Ecriture (modifier l'etat systeme) :

  • *_action - Effectuer des actions (demarrer/arreter services, etc.)
  • save_* - Persister les changements de configuration
  • backup, restore - Sauvegarde/restauration systeme
  • reboot, shutdown - Controle systeme

Erreurs ACL Courantes

Erreur : Access denied ou erreur RPC -32002

Cause : Methode non listee dans l'ACL, ou listee dans la mauvaise section (lecture vs ecriture)

Solution :

  1. Identifier si la methode est une operation de lecture ou d'ecriture
  2. Ajouter le nom de la methode a la section appropriee dans l'ACL
  3. Redemarrer RPCD : /etc/init.d/rpcd restart

Validation :

# Verifier que le fichier ACL est du JSON valide
jsonlint /usr/share/rpcd/acl.d/luci-app-system-hub.json

# Lister tous les objets et methodes ubus
ubus list luci.system-hub

# Tester une methode avec ubus call
ubus call luci.system-hub get_health

Conventions de Structure de Donnees

Structure des Metriques de Sante (system-hub v0.1.0)

Basee sur des iterations extensives, cette structure fournit clarte et coherence :

{
    "cpu": {
        "usage": 25,
        "status": "ok",
        "load_1m": "0.25",
        "load_5m": "0.30",
        "load_15m": "0.28",
        "cores": 4
    },
    "memory": {
        "total_kb": 4096000,
        "free_kb": 2048000,
        "available_kb": 3072000,
        "used_kb": 1024000,
        "buffers_kb": 512000,
        "cached_kb": 1536000,
        "usage": 25,
        "status": "ok"
    },
    "disk": {
        "total_kb": 30408704,
        "used_kb": 5447680,
        "free_kb": 24961024,
        "usage": 19,
        "status": "ok"
    },
    "temperature": {
        "value": 45,
        "status": "ok"
    },
    "network": {
        "wan_up": true,
        "status": "ok"
    },
    "services": {
        "running": 35,
        "failed": 2
    },
    "score": 92,
    "timestamp": "2025-12-26 10:30:00",
    "recommendations": [
        "2 service(s) enabled but not running. Check service status."
    ]
}

Principes Cles :

  1. Objets imbriques pour les metriques liees (cpu, memory, disk, etc.)
  2. Structure coherente : Chaque metrique a usage (pourcentage) et status (ok/warning/critical)
  3. Valeurs brutes + calculees : Fournir les deux (ex: used_kb ET usage en pourcentage)
  4. Seuils de statut : ok (< warning), warning (warning-critical), critical (>= critical)
  5. Score global : Score de sante unique 0-100 pour le tableau de bord
  6. Recommandations dynamiques : Tableau d'alertes actionnables basees sur les seuils

Valeurs de Statut

Utiliser des chaines de statut coherentes pour toutes les metriques :

  • "ok" - Fonctionnement normal (vert)
  • "warning" - Approche du seuil (orange)
  • "critical" - Seuil depasse (rouge)
  • "error" - Impossible de recuperer la metrique
  • "unknown" - Metrique non disponible

Format d'Horodatage

Utiliser ISO 8601 ou un format local coherent :

timestamp="$(date '+%Y-%m-%d %H:%M:%S')"  # 2025-12-26 10:30:00

Valeurs Booleennes en JSON

Dans les scripts shell utilisant jshn.sh :

json_add_boolean "wan_up" 1  # true
json_add_boolean "wan_up" 0  # false

En JavaScript :

if (health.network.wan_up) {
    // WAN est actif
}

Tableau vs Valeur Unique

Utiliser des tableaux pour :

  • Elements multiples du meme type (services, interfaces, points de montage)
  • Donnees de longueur variable

Utiliser des valeurs uniques pour :

  • Metriques systeme globales (CPU, memoire, disque)
  • Valeurs primaires/agregees (temperature globale, uptime total)

Exemple - Stockage :

// Points de montage multiples - utiliser un tableau
"storage": [
    {
        "mount": "/",
        "total_kb": 30408704,
        "used_kb": 5447680,
        "usage": 19
    },
    {
        "mount": "/mnt/usb",
        "total_kb": 128000000,
        "used_kb": 64000000,
        "usage": 50
    }
]

// Systeme de fichiers racine seulement - utiliser un objet
"disk": {
    "total_kb": 30408704,
    "used_kb": 5447680,
    "usage": 19,
    "status": "ok"
}

Erreurs Courantes et Solutions

1. Erreur RPC : "Object not found" (-32000)

Message d'Erreur :

RPC call to system-hub/status failed with error -32000: Object not found

Cause : Le nom du script RPCD ne correspond pas au nom de l'objet ubus en JavaScript

Solution :

  1. Verifier le nom de l'objet dans JavaScript :

    grep -r "object:" luci-app-system-hub/htdocs --include="*.js"
    

    Sortie : object: 'luci.system-hub'

  2. Renommer le script RPCD pour correspondre exactement :

    mv root/usr/libexec/rpcd/system-hub root/usr/libexec/rpcd/luci.system-hub
    
  3. S'assurer que le script est executable :

    chmod +x root/usr/libexec/rpcd/luci.system-hub
    
  4. Redemarrer RPCD :

    /etc/init.d/rpcd restart
    

2. Erreur JavaScript : "api.methodName is not a function"

Message d'Erreur :

Uncaught TypeError: api.getHealth is not a function
    at view.load (health.js:12)

Cause : Mauvais pattern d'import - import du constructeur de classe au lieu de l'instance

Solution : Changer de :

var api = L.require('system-hub.api');  // ❌ Incorrect

A :

'require system-hub/api as API';  // ✅ Correct

Pourquoi : L.require('module.path') retourne la classe brute, 'require module/path as VAR' auto-instancie.

3. Erreur RPC : "Access denied" (-32002)

Message d'Erreur :

RPC call to luci.system-hub/get_settings failed with error -32002: Access denied

Cause : Methode non listee dans le fichier ACL, ou dans la mauvaise section (lecture vs ecriture)

Solution :

  1. Ouvrir le fichier ACL : root/usr/share/rpcd/acl.d/luci-app-system-hub.json

  2. Ajouter la methode a la section appropriee :

    "read": {
        "ubus": {
            "luci.system-hub": [
                "get_settings"
            ]
        }
    }
    
  3. Deployer et redemarrer RPCD :

    scp luci-app-system-hub/root/usr/share/rpcd/acl.d/*.json router:/usr/share/rpcd/acl.d/
    ssh router "/etc/init.d/rpcd restart"
    

4. Erreur d'Affichage : "NaN%" ou Valeurs Indefinies

Erreur : Le tableau de bord affiche "NaN%", "undefined", ou des valeurs vides

Cause : Le frontend utilise des cles de structure de donnees incorrectes (obsoletes apres des changements backend)

Solution :

  1. Verifier la sortie backend :

    ubus call luci.system-hub get_health
    
  2. Mettre a jour le frontend pour correspondre a la structure :

    // ❌ Ancienne structure
    var cpuPercent = health.load / health.cores * 100;
    var memPercent = health.memory.percent;
    
    // ✅ Nouvelle structure
    var cpuPercent = health.cpu ? health.cpu.usage : 0;
    var memPercent = health.memory ? health.memory.usage : 0;
    
  3. Ajouter des verifications null/undefined :

    var temp = health.temperature?.value || 0;
    var loadAvg = health.cpu?.load_1m || '0.00';
    

5. HTTP 404 : Fichier Vue Non Trouve

Message d'Erreur :

HTTP error 404 while loading class file '/luci-static/resources/view/netifyd/overview.js'

Cause : Le chemin du menu ne correspond pas a l'emplacement reel du fichier vue

Solution :

  1. Verifier le JSON du menu :

    cat root/usr/share/luci/menu.d/luci-app-netifyd-dashboard.json
    

    Chercher : "path": "netifyd/overview"

  2. Verifier l'emplacement reel du fichier :

    ls htdocs/luci-static/resources/view/
    

    Le fichier est a : view/netifyd-dashboard/overview.js

  3. Corriger soit le chemin du menu SOIT l'emplacement du fichier :

    // Option 1 : Mettre a jour le chemin du menu pour correspondre au fichier
    "path": "netifyd-dashboard/overview"
    
    // Option 2 : Deplacer le fichier pour correspondre au menu
    mv view/netifyd-dashboard/ view/netifyd/
    

6. Erreur de Build : "factory yields invalid constructor"

Message d'Erreur :

/luci-static/resources/system-hub/api.js: factory yields invalid constructor

Cause : Mauvais pattern utilise dans le module API (singleton, objet simple, etc.)

Solution : Toujours utiliser baseclass.extend() :

return baseclass.extend({
    getStatus: callStatus,
    getHealth: callGetHealth,
    // ... plus de methodes
});

Ne PAS utiliser :

  • baseclass.singleton({...})
  • Objet simple : return {...}
  • baseclass.prototype

7. RPCD Ne Repond Plus Apres des Changements

Symptome : Les changements au script RPCD ne prennent pas effet

Solution :

  1. Verifier que le script est deploye :

    ssh router "ls -la /usr/libexec/rpcd/"
    
  2. Verifier que le script est executable :

    ssh router "chmod +x /usr/libexec/rpcd/luci.system-hub"
    
  3. Redemarrer RPCD :

    ssh router "/etc/init.d/rpcd restart"
    
  4. Vider le cache du navigateur (Ctrl+Shift+R)

  5. Verifier les logs RPCD :

    ssh router "logread | grep rpcd"
    

Checklist de Validation

Utiliser cette checklist avant le deploiement :

Structure des Fichiers

  • Le script RPCD existe : /usr/libexec/rpcd/luci.<nom-module>
  • Le script RPCD est executable : chmod +x
  • Le JSON du menu existe : /usr/share/luci/menu.d/luci-app-<module>.json
  • Le JSON ACL existe : /usr/share/rpcd/acl.d/luci-app-<module>.json
  • Le module API existe : htdocs/luci-static/resources/<module>/api.js
  • Les vues existent : htdocs/luci-static/resources/view/<module>/*.js

Conventions de Nommage

  • Le nom du script RPCD correspond a l'objet ubus en JavaScript (incluant le prefixe luci.)
  • Les chemins du menu correspondent a la structure de repertoire des fichiers vue
  • Tous les objets ubus commencent par luci.
  • La cle ACL correspond au nom du package : "luci-app-<module>"

Validation du Code

  • Le module API utilise le pattern baseclass.extend()
  • Les vues importent l'API avec le pattern 'require <module>/api as API'
  • Tous les appels rpc.declare() incluent object, method, params, expect corrects
  • Le script RPCD produit du JSON valide (tester avec ubus call)
  • Le JSON du menu est valide (tester avec jsonlint)
  • Le JSON ACL est valide (tester avec jsonlint)

Permissions

  • Toutes les methodes de lecture dans la section ACL "read"
  • Toutes les methodes d'ecriture dans la section ACL "write"
  • Les methodes dans l'ACL correspondent exactement aux noms des methodes du script RPCD

Tests

  • Executer le script de validation : ./secubox-tools/validate-modules.sh
  • Tester chaque methode via ubus : ubus call luci.<module> <method>
  • Tester le frontend dans le navigateur (verifier la console pour les erreurs)
  • Vider le cache du navigateur apres le deploiement
  • Verifier le redemarrage RPCD : /etc/init.d/rpcd restart

Commande de Validation Automatisee

# Executer la validation complete
./secubox-tools/validate-modules.sh

# Valider un module specifique
./secubox-tools/validate-module-generation.sh luci-app-system-hub

# Verifier la syntaxe JSON
find luci-app-system-hub -name "*.json" -exec jsonlint {} \;

# Verifier les scripts shell
shellcheck luci-app-system-hub/root/usr/libexec/rpcd/*

Tests et Deploiement

Tests Locaux avec ubus

Avant de deployer sur le routeur, tester le script RPCD localement :

# Copier le script RPCD vers /tmp local
cp luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub /tmp/

# Rendre executable
chmod +x /tmp/luci.system-hub

# Tester l'action 'list'
/tmp/luci.system-hub list

# Tester l'action 'call' avec une methode
/tmp/luci.system-hub call status

# Tester une methode avec parametres
echo '{"service":"network","action":"restart"}' | /tmp/luci.system-hub call service_action

Script de Deploiement

Utiliser un script de deploiement pour une iteration rapide :

#!/bin/bash
# deploy-system-hub.sh

ROUTER="root@192.168.8.191"

echo "Deploiement de system-hub vers $ROUTER"

# Deployer le module API
scp luci-app-system-hub/htdocs/luci-static/resources/system-hub/api.js \
    "$ROUTER:/www/luci-static/resources/system-hub/"

# Deployer les vues
scp luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/*.js \
    "$ROUTER:/www/luci-static/resources/view/system-hub/"

# Deployer le backend RPCD
scp luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub \
    "$ROUTER:/usr/libexec/rpcd/"

# Deployer l'ACL
scp luci-app-system-hub/root/usr/share/rpcd/acl.d/luci-app-system-hub.json \
    "$ROUTER:/usr/share/rpcd/acl.d/"

# Definir les permissions et redemarrer
ssh "$ROUTER" "chmod +x /usr/libexec/rpcd/luci.system-hub && /etc/init.d/rpcd restart"

echo "Deploiement termine ! Videz le cache du navigateur (Ctrl+Shift+R)"

Tests Navigateur

  1. Ouvrir la console du navigateur (F12)
  2. Naviguer vers la page du module
  3. Verifier les erreurs :
    • Erreurs RPC (object not found, method not found, access denied)
    • Erreurs JavaScript (api.method is not a function)
    • Erreurs 404 (fichiers vue non trouves)
  4. Tester les fonctionnalites :
    • Le chargement des donnees s'affiche correctement
    • Les actions fonctionnent (demarrer/arreter services, sauvegarder parametres)
    • Pas de "NaN", "undefined", ou valeurs vides

Tests ubus a Distance

Tester les methodes RPCD sur le routeur :

# Lister toutes les methodes
ssh router "ubus list luci.system-hub"

# Appeler une methode sans parametres
ssh router "ubus call luci.system-hub status"

# Appeler une methode avec parametres
ssh router "ubus call luci.system-hub service_action '{\"service\":\"network\",\"action\":\"restart\"}'"

# Formater la sortie JSON
ssh router "ubus call luci.system-hub get_health | jsonlint"

Conseils de Debogage

Activer la journalisation de debogage RPCD :

# Editer /etc/init.d/rpcd
# Ajouter le flag -v a la commande procd_set_param
procd_set_param command "$PROG" -v

# Redemarrer RPCD
/etc/init.d/rpcd restart

# Surveiller les logs
logread -f | grep rpcd

Activer la journalisation console JavaScript :

// Ajouter a api.js
console.log('API v0.1.0 chargee a', new Date().toISOString());

// Ajouter aux vues
console.log('Chargement des donnees de sante...');
API.getHealth().then(function(data) {
    console.log('Donnees de sante:', data);
});

Tester la sortie JSON :

# Sur le routeur
/usr/libexec/rpcd/luci.system-hub call get_health | jsonlint

# Verifier les erreurs courantes
# - Virgules manquantes
# - Virgules en fin de liste
# - Cles non quotees
# - Sequences d'echappement invalides

Resume des Bonnes Pratiques

A FAIRE :

  • Utiliser le prefixe luci. pour tous les objets ubus
  • Nommer les scripts RPCD pour correspondre exactement a l'objet ubus
  • Utiliser baseclass.extend() pour les modules API
  • Importer les APIs avec le pattern 'require module/api as API'
  • Ajouter des verifications null/undefined dans le frontend : health.cpu?.usage || 0
  • Valider le JSON avec jsonlint avant de deployer
  • Tester avec ubus call avant les tests navigateur
  • Redemarrer RPCD apres les changements backend
  • Vider le cache du navigateur apres les changements frontend
  • Executer ./secubox-tools/validate-modules.sh avant de commiter

A NE PAS FAIRE :

  • Utiliser des noms d'objets ubus sans le prefixe luci.
  • Utiliser baseclass.singleton() ou des objets simples pour les modules API
  • Importer les APIs avec L.require('module.path') (retourne la classe, pas l'instance)
  • Oublier d'ajouter les methodes au fichier ACL
  • Melanger les methodes lecture/ecriture dans les sections ACL
  • Produire du non-JSON depuis les scripts RPCD
  • Utiliser des structures de donnees incoherentes entre backend et frontend
  • Deployer sans tester localement d'abord
  • Supposer que les donnees existent - toujours verifier null/undefined
  • Oublier de rendre les scripts RPCD executables (chmod +x)

Historique des Versions

v1.0 (2025-12-26)

  • Guide de reference initial
  • Base sur luci-app-secubox v1.0.0 et luci-app-system-hub v0.1.0
  • Documentation de tous les patterns critiques et erreurs courantes
  • Valide contre les defis d'implementation reels

References


Contact

Pour des questions ou contributions a ce guide de reference :


FIN DU GUIDE DE REFERENCE