Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions .github/skills/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Skill : Authentification des utilisateurs

## Description

Ce skill contrôle l'accès à toutes les commandes du bot. Seuls les utilisateurs présents dans la liste blanche définie dans `topology.json` peuvent utiliser les fonctionnalités du bot. L'authentification est implémentée via des décorateurs Python appliqués aux handlers.

---

## Sous-skills

### 1. Décorateur `@auth_required` (handlers de commandes)

Fichier : `src/handlers/common.py`

```python
@auth_required
async def node(update: Update, context: CallbackContext) -> None:
...
```

**Fonctionnement :**
1. Extrait `user_id = str(update.effective_user.id)`
2. Lit la liste blanche depuis `context.bot_data['allowed_user_ids']` (un `set` de strings)
3. Si l'utilisateur **n'est pas** dans la liste :
- Envoie "You are not authorized to use this bot."
- Retourne `None` sans exécuter la fonction décorée
4. Si l'utilisateur **est** dans la liste : appelle la fonction handler normalement

**Commandes concernées :** `/node`, `/btc`, `/mas`, `/hi`, `/temperature`, `/perf`

---

### 2. Décorateur `@cb_auth_required` (handlers de callback query)

Fichier : `src/handlers/common.py`

```python
@cb_auth_required
async def flush_confirm_yes(update: Update, context: CallbackContext) -> int:
...
```

**Spécificité :** Utilisé pour les callbacks des boutons inline (réponses aux claviers interactifs). Contrairement à `@auth_required`, il :
1. Extrait le `user_id` depuis `query.from_user.id` (et non `update.effective_user.id`)
2. En cas de refus : appelle `query.answer("Access denied.", show_alert=True)` (alerte popup)
3. Retourne `ConversationHandler.END` pour terminer proprement la conversation

**Callbacks concernées :** `flush_confirm_yes/no`, `hist_confirm_yes/no`, `docker_start/stop`, `docker_*_confirm`, `massa_*`

---

### 3. Vérification manuelle dans les ConversationHandlers

Les points d'entrée des `ConversationHandler` ne peuvent pas utiliser `@auth_required` car ils doivent retourner un entier (état de la conversation) et non `None`.

```python
async def flush(update: Update, context: CallbackContext) -> int:
user_id = str(update.effective_user.id)
allowed_user_ids = context.bot_data.get('allowed_user_ids', set())
if user_id not in allowed_user_ids:
await update.message.reply_text("Access denied. You are not authorized.")
return ConversationHandler.END
...
```

**Commandes concernées :** `/flush`, `/hist`, `/docker`

---

### 4. Chargement de la liste blanche

Fichier : `src/main.py`

Au démarrage, la liste blanche est construite depuis `topology.json` :

```python
admin_id = config.get('user_white_list', {}).get('admin')
allowed_user_ids = {str(admin_id)}
```

- La valeur est un `set` de strings (IDs Telegram sous forme de chaîne)
- Le set est stocké dans `application.bot_data['allowed_user_ids']`
- Tous les handlers y accèdent via `context.bot_data.get('allowed_user_ids', set())`
- Actuellement, seul le rôle `admin` est supporté (un seul utilisateur autorisé)

---

### 5. Gestion des erreurs API (`handle_api_error`)

Fichier : `src/handlers/common.py`

Bien que non directement lié à l'authentification, cette fonction sécurise les réponses des APIs externes :

```python
async def handle_api_error(update: Update, error_data: dict) -> bool
```

- Reçoit le dict retourné par une fonction API
- Si `"error"` est présent dans le dict :
- Timeout → envoie l'image `TIMEOUT_NAME`
- Autre erreur → envoie l'image `TIMEOUT_FIRE_NAME`
- Retourne `True` (erreur gérée, le handler doit s'arrêter)
- Si pas d'erreur → retourne `False` (le handler peut continuer)

---

## Fichiers concernés

| Fichier | Rôle |
|---------|------|
| `src/handlers/common.py` | Décorateurs `auth_required`, `cb_auth_required`, `handle_api_error` |
| `src/main.py` | Chargement de `allowed_user_ids` depuis `topology.json` |

## Configuration requise

| Clé `topology.json` | Description |
|---------------------|-------------|
| `user_white_list.admin` | ID Telegram de l'administrateur autorisé |

## Exemple `topology.json`

```json
{
"user_white_list": {
"admin": "123456789"
}
}
```

## Sécurité

- L'ID utilisateur est toujours converti en `str` avant comparaison (évite les erreurs de type int/str)
- La liste blanche est initialisée à `set()` par défaut (aucune autorisation si non configuré)
- La vérification s'effectue à chaque appel de handler (pas de cache de session)
93 changes: 93 additions & 0 deletions .github/skills/balance-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Skill : Historique du solde

## Description

Ce skill gère la persistance, la visualisation et l'effacement de l'historique des soldes Massa. Il comprend deux commandes interactives : `/hist` pour consulter l'historique sous forme de graphiques et de texte, et `/flush` pour effacer les logs et/ou l'historique.

## Commandes

```
/hist
/flush
```

---

## Sous-skills

### 1. Persistance JSON de l'historique (`services/history.py`)

- L'historique est stocké dans `config/balance_history.json` (volume Docker monté)
- **`save_balance_history(balance_history)`** — sérialise et écrit le dict en JSON
- **`make_time_key(dt=None)`** — génère une clé temporelle au format `YYYY/MM/DD-HH:MM`
- **`build_balance_entry(balance, system_stats)`** — construit une entrée dict contenant :
- `balance` — solde MAS (float)
- `temperature` — température CPU moyenne (float ou `null`)
- `ram_percent` — pourcentage d'utilisation RAM (float ou `null`)
- Toutes les écritures dans `balance_history` sont protégées par un `threading.Lock` (`balance_lock` dans `bot_data`)

### 2. Filtrage de l'historique

- **`filter_last_24h(balance_history)`** — retourne les entrées des dernières 24 heures (fenêtre glissante)
- **`filter_since_midnight(balance_history)`** — retourne les entrées depuis minuit du jour courant
- **`get_entry_balance(entry)`** — extrait le solde d'une entrée (compatible formats ancien et nouveau)
- **`get_entry_temperature(entry)`** — extrait la température d'une entrée (retourne `None` si absente)
- **`format_history_entry(timestamp, entry)`** — formate une ligne d'historique : `HH:MM | balance MAS | temp°C | ram%`

### 3. Commande `/hist` — Graphique et résumé

#### Étape 1 : Menu de confirmation
- Affiche un message avec un clavier inline :
- **Graph only** → génère uniquement les graphiques
- **Graph + Text** → génère les graphiques et envoie également un résumé textuel
- **Cancel** → annule et termine la conversation

#### Étape 2 : Génération des graphiques
- **`create_balance_history_plot(balance_history)`** — graphique matplotlib du solde dans le temps (`balance_history.png`)
- **`create_resources_plot(balance_history)`** — graphique matplotlib de la température CPU et RAM (`resources_plot.png`)
- Les deux images sont envoyées en réponse puis supprimées avec `safe_delete_file()`

#### Étape 3 (optionnel) : Résumé textuel
- Liste toutes les entrées de l'historique formatées par `format_history_entry()`
- Gère la limite de 4096 caractères des messages Telegram (découpe en plusieurs messages si nécessaire)

### 4. Commande `/flush` — Effacement des logs

#### Étape 1 : Menu de confirmation
- Affiche un clavier inline :
- **Logs only** → supprime uniquement `bot_activity.log`
- **Logs + History** → supprime le log ET vide `balance_history.json`
- **Cancel** → annule sans rien supprimer

#### Étape 2 : Exécution de l'effacement
- Efface le fichier `bot_activity.log` (chemin : `config/LOG_FILE_NAME`)
- Si « Logs + History » sélectionné : vide `balance_history` en mémoire et sur disque, puis recrée un fichier JSON vide

### 5. Formats de clés temporelles (rétrocompatibilité)

- Format actuel : `YYYY/MM/DD-HH:MM` (ex. `2024/03/15-14:30`)
- Format legacy : `DD/MM-HH:MM` (ex. `15/03-14:30`) — encore lisible par les filtres pour les anciennes données

## Fichiers concernés

| Fichier | Rôle |
|---------|------|
| `src/handlers/node.py` | Handlers `/hist` et `/flush` (ConversationHandler) |
| `src/services/history.py` | Persistance, filtrage et formatage de l'historique |
| `src/services/plotting.py` | Génération des graphiques solde et ressources |
| `src/handlers/common.py` | `safe_delete_file()`, `cb_auth_required` |

## Fichiers générés

| Fichier | Description | Cycle de vie |
|---------|-------------|--------------|
| `config/balance_history.json` | Snapshots horodatés du solde | Persistant (volume Docker) |
| `balance_history.png` | Graphique du solde | Temporaire, supprimé après envoi |
| `resources_plot.png` | Graphique CPU / RAM | Temporaire, supprimé après envoi |
| `bot_activity.log` | Journal d'activité du bot | Persistant, effaçable via `/flush` |

## Gestion des erreurs

- Historique vide → message informatif sans graphique
- Échec de génération de graphique → message d'erreur
- Fichier log absent → ignore l'erreur silencieusement
110 changes: 110 additions & 0 deletions .github/skills/crypto-prices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Skill : Prix des cryptomonnaies

## Description

Ce skill récupère et affiche les prix en temps réel de Bitcoin (BTC) et de Massa (MAS) via des API externes. Il expose deux commandes : `/btc` pour le prix du Bitcoin et `/mas` pour le prix Massa/USDT.

## Commandes

```
/btc
/mas
```

---

## Sous-skills

### 1. Prix Bitcoin — `/btc`

#### Source de données
- **API** : [API-Ninjas](https://www.api-ninjas.com/) — endpoint `/v1/cryptoprice?symbol=BTCUSDT`
- **Authentification** : Header `X-Api-Key: <ninja_api_key>`
- **Clé de configuration** : `ninja_api_key` dans `topology.json`

#### Fonction d'appel (`services/price_api.py`)
```python
get_bitcoin_price(logger, ninja_key) -> dict
```
- Effectue une requête GET avec retry (via `http_client.py`)
- Retourne les champs : `price`, `24h_price_change`, `24h_price_change_percent`, `24h_high`, `24h_low`, `24h_volume`
- En cas d'erreur réseau ou HTTP → retourne `{"error": "..."}`

#### Format de la réponse bot
```
Price: 65432.10 $
24h Price Change: +1234.56
24h Price Change Percent: +1.92%
24h High: 66000.00
24h Low: 64000.00
24h Volume: 12345678.90
```

#### Gestion d'erreur
- En cas d'erreur API → message "Nooooo" + image `BTC_CRY_NAME` (définie dans `config.py`)

---

### 2. Prix Massa — `/mas`

#### Sources de données
- **API instantanée** : MEXC — `GET /api/v3/avgPrice?symbol=MASUSDT`
- **API 24h** : MEXC — `GET /api/v3/ticker/24hr?symbol=MASUSDT`
- Pas d'authentification requise pour les endpoints publics MEXC

#### Fonctions d'appel (`services/price_api.py`)
```python
get_mas_instant(logger) -> dict # Prix moyen actuel
get_mas_daily(logger) -> dict # Statistiques 24h
```
- Les deux appels sont lancés **en parallèle** via `asyncio.gather()` pour minimiser la latence
- Retournent `{"error": "..."}` en cas d'échec réseau ou HTTP

#### Format de la réponse bot
```
MASUSDT
-----------
Price: 0.00734 USDT
24h Volume: 1234567.890000
-----------
Price Change %: +0.123456%
Price Change: +0.000009
24h High: 0.007500
24h Low: 0.007100
```

#### Gestion d'erreur
- Vérifie les deux réponses API séquentiellement (bail on first error)
- En cas d'erreur → message "Nooooo" + image `MAS_CRY_NAME` (définie dans `config.py`)

---

### 3. Client HTTP sécurisé (`services/http_client.py`)

- Enveloppe commune utilisée par toutes les fonctions d'appel API
- Implémente une logique de retry avec backoff exponentiel
- Gère les timeouts de connexion et de lecture
- Retourne un dict avec le corps de la réponse ou `{"error": "..."}` en cas d'échec

---

## Fichiers concernés

| Fichier | Rôle |
|---------|------|
| `src/handlers/price.py` | Handlers `/btc` et `/mas` |
| `src/services/price_api.py` | Appels API-Ninjas et MEXC |
| `src/services/http_client.py` | Client HTTP avec retry |
| `src/config.py` | Constantes `BTC_CRY_NAME`, `MAS_CRY_NAME` |

## Configuration requise

| Clé `topology.json` | Description |
|---------------------|-------------|
| `ninja_api_key` | Clé API pour API-Ninjas (Bitcoin) |

## Liens externes

- [API-Ninjas — Crypto Price](https://www.api-ninjas.com/api/cryptoprice)
- [MEXC API — avgPrice](https://mexcdevelop.github.io/apidocs/spot_v3_en/#current-average-price)
- [MEXC API — 24hr Ticker](https://mexcdevelop.github.io/apidocs/spot_v3_en/#24hr-ticker-price-change-statistics)
Loading
Loading