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>
1194 lines
32 KiB
Markdown
1194 lines
32 KiB
Markdown
# Guide de Reference pour le Developpement LuCI
|
|
|
|
> **Langues:** [English](../docs/luci-development-reference.md) | Francais | [中文](../docs-zh/luci-development-reference.md)
|
|
|
|
**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
|
|
|
|
- **Design et Standards:** [DEVELOPMENT-GUIDELINES.md](development-guidelines.md)
|
|
- **Commandes Rapides:** [QUICK-START.md](quick-start.md)
|
|
- **Briefing Automatisation:** [CODEX.md](codex.md)
|
|
- **Modeles de Code:** [CODE-TEMPLATES.md](code-templates.md)
|
|
|
|
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](#fondamentaux-ubus-et-rpc)
|
|
2. [Patterns Backend RPCD](#patterns-backend-rpcd)
|
|
3. [Patterns Module API LuCI](#patterns-module-api-luci)
|
|
4. [Patterns d'Import de Vues LuCI](#patterns-dimport-de-vues-luci)
|
|
5. [Structure des Permissions ACL](#structure-des-permissions-acl)
|
|
6. [Conventions de Structure de Donnees](#conventions-de-structure-de-donnees)
|
|
7. [Erreurs Courantes et Solutions](#erreurs-courantes-et-solutions)
|
|
8. [Checklist de Validation](#checklist-de-validation)
|
|
9. [Tests et Deploiement](#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.`.
|
|
|
|
```javascript
|
|
// ✅ 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 :
|
|
|
|
```bash
|
|
# 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** :
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
#!/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 :
|
|
|
|
```bash
|
|
# 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 :
|
|
|
|
```bash
|
|
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) :
|
|
|
|
```bash
|
|
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** :
|
|
```bash
|
|
# Bien
|
|
uptime=$(cat /proc/uptime | cut -d' ' -f1)
|
|
|
|
# Mieux
|
|
read uptime _ < /proc/uptime
|
|
uptime=${uptime%.*}
|
|
```
|
|
3. **Eviter les commandes externes quand possible** :
|
|
```bash
|
|
# 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()`.
|
|
|
|
```javascript
|
|
'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()
|
|
|
|
```javascript
|
|
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** :
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// 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 :
|
|
|
|
```javascript
|
|
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.
|
|
|
|
```javascript
|
|
// ✅ 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
|
|
|
|
```javascript
|
|
'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
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```json
|
|
{
|
|
"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** :
|
|
```bash
|
|
# 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 :
|
|
|
|
```json
|
|
{
|
|
"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 :
|
|
```bash
|
|
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 :
|
|
```bash
|
|
json_add_boolean "wan_up" 1 # true
|
|
json_add_boolean "wan_up" 0 # false
|
|
```
|
|
|
|
En JavaScript :
|
|
```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** :
|
|
```json
|
|
// 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 :
|
|
```bash
|
|
grep -r "object:" luci-app-system-hub/htdocs --include="*.js"
|
|
```
|
|
Sortie : `object: 'luci.system-hub'`
|
|
|
|
2. Renommer le script RPCD pour correspondre exactement :
|
|
```bash
|
|
mv root/usr/libexec/rpcd/system-hub root/usr/libexec/rpcd/luci.system-hub
|
|
```
|
|
|
|
3. S'assurer que le script est executable :
|
|
```bash
|
|
chmod +x root/usr/libexec/rpcd/luci.system-hub
|
|
```
|
|
|
|
4. Redemarrer RPCD :
|
|
```bash
|
|
/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 :
|
|
```javascript
|
|
var api = L.require('system-hub.api'); // ❌ Incorrect
|
|
```
|
|
|
|
A :
|
|
```javascript
|
|
'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 :
|
|
```json
|
|
"read": {
|
|
"ubus": {
|
|
"luci.system-hub": [
|
|
"get_settings"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
3. Deployer et redemarrer RPCD :
|
|
```bash
|
|
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 :
|
|
```bash
|
|
ubus call luci.system-hub get_health
|
|
```
|
|
|
|
2. Mettre a jour le frontend pour correspondre a la structure :
|
|
```javascript
|
|
// ❌ 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 :
|
|
```javascript
|
|
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 :
|
|
```bash
|
|
cat root/usr/share/luci/menu.d/luci-app-netifyd-dashboard.json
|
|
```
|
|
Chercher : `"path": "netifyd/overview"`
|
|
|
|
2. Verifier l'emplacement reel du fichier :
|
|
```bash
|
|
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 :
|
|
```json
|
|
// 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()` :
|
|
```javascript
|
|
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 :
|
|
```bash
|
|
ssh router "ls -la /usr/libexec/rpcd/"
|
|
```
|
|
|
|
2. Verifier que le script est executable :
|
|
```bash
|
|
ssh router "chmod +x /usr/libexec/rpcd/luci.system-hub"
|
|
```
|
|
|
|
3. Redemarrer RPCD :
|
|
```bash
|
|
ssh router "/etc/init.d/rpcd restart"
|
|
```
|
|
|
|
4. Vider le cache du navigateur (Ctrl+Shift+R)
|
|
|
|
5. Verifier les logs RPCD :
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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 :
|
|
|
|
```bash
|
|
# 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 :
|
|
|
|
```bash
|
|
#!/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 :
|
|
|
|
```bash
|
|
# 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** :
|
|
```bash
|
|
# 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** :
|
|
```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** :
|
|
```bash
|
|
# 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
|
|
|
|
- **Documentation OpenWrt** : https://openwrt.org/docs/guide-developer/start
|
|
- **Documentation LuCI** : https://github.com/openwrt/luci/wiki
|
|
- **Documentation ubus** : https://openwrt.org/docs/techref/ubus
|
|
- **Documentation UCI** : https://openwrt.org/docs/guide-user/base-system/uci
|
|
- **Bibliotheque jshn.sh** : `/usr/share/libubox/jshn.sh` sur OpenWrt
|
|
|
|
---
|
|
|
|
## Contact
|
|
|
|
Pour des questions ou contributions a ce guide de reference :
|
|
- **Auteur** : CyberMind <contact@cybermind.fr>
|
|
- **Projet** : SecuBox OpenWrt
|
|
- **Depot** : https://github.com/cybermind-fr/secubox-openwrt
|
|
|
|
---
|
|
|
|
**FIN DU GUIDE DE REFERENCE**
|