init: workspace opencode sync

This commit is contained in:
2026-08-15 00:28:08 +07:00
commit 2451170708
122 changed files with 10549 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
# Telegram Reset Button untuk Notifikasi Expired (MSR Hotspot)
> Ringkasan perubahan arsitektur notifikasi expired hotspot & tombol "🔄 Reset" via Telegram.
> Tanggal: 1 Agu 2026 · RouterOS v6.49.6 · Mikhmon (Docker)
---
## 1. Masalah Awal
1. Notifikasi "User X expired" sebelumnya dikirim oleh `notify-expire.php` di server Mikhmon, yang menampilkan inline keyboard **🔄 Reset** dengan `callback_data=reset_<user>`.
2. Router (MikroTik) tidak bisa menjangkau path lama (`192.168.100.6`, sudah mati). Scheduler di router mengirim notifikasi ke URL Telegram lama yang tidak lagi berfungsi.
3. Akibatnya pesan expired terkirim **tanpa tombol Reset**, dan callback reset tidak berfungsi.
## 2. Solusi Baru (Arsitektur)
```
[RouterOS Scheduler] --/tool/fetch sendMessage--> [Telegram Bot] --Kirim ke Grup (thread "Notif Expire")
^
[User klik 🔄 Reset] --> callback_query --> [Bot] --> poller getUpdates
|
v
[Host rl] cron tiap menit --> msr-poller.sh --> docker start mikhmon
|
v
telegram-cb.php (di container) --> RouterOS API reset user
|
v
Telegram: "✅ {user} has been reset"
```
### Komponen
| Komponen | Lokasi | Peran |
|---|---|---|
| Scheduler RouterOS | Router 192.168.100.2 | Kirim pesan expired + `reply_markup` tombol Reset langsung ke Telegram |
| Telegram Bot | `5115036608:AAGey...` | Terima/teruskan pesan & callback |
| Cron host | `/usr/local/bin/msr-poller.sh` di `rl` | Setiap menit: `docker start mikhmon` + curl `telegram-cb.php` |
| `telegram-cb.php` | `/var/www/html/` di container `mikhmon` | getUpdates → reset user di RouterOS → jawab callback + kirim konfirmasi |
| `lib/routeros_api.class.php` | `/var/www/html/lib/` | Koneksi RouterOS API dari PHP |
## 3. Perubahan yang Dilakukan
### 3.1 Scheduler RouterOS (Family, Bulanan2, Bulanan4)
`on-event` scheduler sekarang melakukan `/tool/fetch` ke Telegram `sendMessage` dengan:
- `chat_id=-1002554941429`, `message_thread_id=42` (thread "Notif Expire")
- `text=" . $name . "+expired`
- `reply_markup` = JSON inline keyboard **URL-encoded**:
```
%7B%22inline_keyboard%22%3A%5B%5B%7B%22text%22%3A%22%F0%9F%94%84%20Reset%22%2C%22callback_data%22%3A%22reset_" . $name . "%22%7D%5D%5D%7D
```
yang setara dengan:
```json
{"inline_keyboard":[[{"text":"🔴 Reset","callback_data":"reset_<name>"}]]}
```
Contoh cuplikan on-event Family:
```
tool fetch url=("https://api.telegram.org/bot5115036608:AAGey.../sendMessage?chat_id=-1002554941429&message_thread_id=42&text=" . $name . "+expired&reply_markup=" . "%7B%22inline_keyboard%22%3A...%22reset_" . $name . "%22%7D%5D%5D%7D") mode=https http-method=get keep-result=no
```
**Penting:** deduplikasi (`:if ($curlim = "")`) tetap dipertahankan agar setiap user hanya dikirim sekali.
### 3.2 Container Mikhmon — Install php81-curl
Container PHP 8.1 (Alpine) awalnya tanpa ekstensi cURL → `telegram-cb.php` error HTTP 500.
```sh
docker exec -u root mikhmon apk add --no-cache php81-curl
```
### 3.3 Perbaikan include path `telegram-cb.php`
Dari `dirname(__DIR__) . '/lib/routeros_api.class.php'` → `__DIR__ . '/lib/routeros_api.class.php'` (2 tempat), karena file berada langsung di `/var/www/html/`.
### 3.4 Poller Host (atasi sablier)
Container `mikhmon` dikelola **sablier** (traefik plugin) yang mematikannya setelah **5 menit idle** — cron di dalam container tidak bisa diandalkan. Solusi: cron di **host** yang men-starter container lalu memanggil callback.
`/usr/local/bin/msr-poller.sh`:
```bash
#!/bin/bash
CB_KEY="msr-2026-reset"
URL="http://172.18.0.15/telegram-cb.php?key=${CB_KEY}"
docker start mikhmon >/dev/null 2>&1
sleep 1
curl -s -m 30 "$URL" >/dev/null 2>&1
```
Crontab host (`crontab -l`):
```
* * * * * /usr/local/bin/msr-poller.sh >/dev/null 2>&1
```
Catatan:
- `docker start` idempotent (kalau sudah jalan, no-op) → otomatis menjaga container hidup.
- Polling maksimal latency ~1 menit setelah klik tombol.
### 3.5 Callback Handler `telegram-cb.php`
- Auth via `?key=msr-2026-reset` (403 kalau salah).
- `getUpdates` (hanya `callback_query`).
- Untuk `data` berawalan `reset_`:
1. Cari user di `/ip/hotspot/user/print?name=<user>`
2. `set limit-uptime=0, comment=''` + `reset-counters`
3. Hapus scheduler bernama `<user>` (jika ada)
4. `answerCallbackQuery` (`✅ {user} reset!`)
5. `sendMessage` ke chat/thread: `✅ *{user}* has been reset\nReady to use again`
- User tidak ditemukan → `answerCallbackQuery` alert `User {user} not found` (tanpa pesan).
- Meng-konfirmasi offset via `getUpdates?offset=<last_id+1>` setelah diproses.
## 4. Verifikasi
| Item | Hasil |
|---|---|
| Pesan expired + tombol Reset muncul di grup | ✅ Bubble punya `reply-markup-button` "Reset" |
| Klik tombol → callback `reset_<user>` sampai ke bot | ✅ `data: "reset_TMR-1"` via getUpdates |
| Poller cron memproses callback | ✅ `processed: 1` |
| User di-reset di router | ✅ `limit-uptime` 10s → None (unlimited), counters reset |
| Scheduler user dihapus | ✅ |
| Konfirmasi bot di grup | ✅ `msr_net: TMR-1 has been reset` (09:11) |
Test user `TMR-1` dibuat khusus lalu dihapus setelah verifikasi.
## 5. Operasional & Troubleshooting
### Cek status
- Poller: `ssh rl "cat /usr/local/bin/msr-poller.sh; crontab -l | grep poller"`
- Container: `ssh rl "docker ps --filter name=mikhmon --format '{{.Status}}'"`
- Callback pending: `curl 'http://172.18.0.15/telegram-cb.php?key=msr-2026-reset'` → harus `processed: 0` / `no updates`
- Webhook tidak terpasang (poller getUpdates aman): `getWebhookInfo` → `url: ""`, `allowed_updates:["callback_query"]`
### Gejala umum
- **HTTP 500 dari telegram-cb.php** → cek cURL: `docker exec mikhmon php -r 'var_dump(function_exists("curl_init"));'`
- **Container mati** → sablier mematikannya setelah 5m idle; poller harusnya men-starter. Cek log poller/cron.
- **Callback tidak terproses** → JANGAN baca `getUpdates` manual (maju offset & poller kehilangan callback). Biarkan poller cron yang memproses.
- **Tombol tidak muncul** → `reply_markup` tidak ter-encode dengan benar; cek `verify-markup.py` & on-event scheduler.
## 6. Kredensial & Referensi
- Router: `192.168.100.2`, API `remote.vpnmurahjogja.my.id:33206`, login `mi4`/`m14`
- Bot: `5115036608:AAGeyXVq5eNvdAkaCQHU9NfH16uAAiSKiuk`
- Chat/Grup: `-1002554941429`, thread `42` ("Notif Expire")
- Container: `mikhmon` (animegasan/mikhmon:v3-latest) di host `rl` (`root@100.100.31.46`, ssh alias `rl`, key `~/.ssh/pl`)
- Callback secret: `msr-2026-reset`
- Container IP: `172.18.0.15`
## 7. Skrip Bantu (folder `C:\Users\Admin\dev\mikhmon-fix\`)
| Skrip | Fungsi |
|---|---|
| `patch-notif2.py` | Patch on-event scheduler → tambah `reply_markup` Reset button |
| `verify-markup.py` | Verifikasi on-event berisi `reply_markup` & `reset_` |
| `verify-notif.py` | Verifikasi isi scheduler (api.telegram.org, tidak ada URL lama) |
| `dump-sched.py` | Dump penuh on-event scheduler |
| `telegram-cb.php` | Callback handler (sumber; di-deploy ke container) |
| `poller.sh` | Poller host (sumber; di-deploy ke `/usr/local/bin/msr-poller.sh`) |
| `mk-user.py` / `rm-user.py` | Buat / hapus user test |
| `send-expired-tmr.py` | Kirim pesan expired + tombol untuk user tertentu |
| `check-reset.py` | Cek limit-uptime & scheduler user setelah reset |
## 8. Catatan
- Bot menampilkan tombol sebagai "Reset" — teks `🔄` (U+1F504, `%F0%9F%94%84`) di-render Telegram sebagai ikon 🔄.
- `keep-result=no` di scheduler fetch (tidak menyimpan file respons di router). Saat debug bisa ubah `keep-result=yes` untuk lihat file `sendMessage?...`.
- Jika tombol ditekan dua kali, user kedua dikirim ulang notif "expired" (karena sudah reset, limit-uptime unlimited → tidak ada scheduler baru sampai limit diubah lagi).