"""Kirim notifikasi status distribusi + klaim via Telegram Bot API (best-effort). Dua kanal (V30/V36): KOMUNITAS (`TELEGRAM_COMMUNITY_CHAT_IDS`) hanya brief mulai/selesai distribusi; INTERNAL (`TELEGRAM_INTERNAL_CHAT_IDS`) detail distribusi + semua kegagalan + klaim reward (⊥ komunitas). Token tunggal `TELEGRAM_BOT_TOKEN`. Tanpa token/daftar → kanal itu no-op senyap (⊥ ganggu run). Gagal kirim hanya dicatat — ⊥ pernah crash distribusi/klaim. """ import requests from config import (TELEGRAM_BOT_TOKEN, TELEGRAM_COMMUNITY_CHAT_IDS, TELEGRAM_INTERNAL_CHAT_IDS) def send_text(text, chat_ids=None): """Kirim `text` ke daftar chat id. `chat_ids=None` → kanal komunitas. Best-effort: tanpa token/daftar → no-op; gagal → log saja. """ if chat_ids is None: chat_ids = TELEGRAM_COMMUNITY_CHAT_IDS if not TELEGRAM_BOT_TOKEN or not chat_ids: return url = f'https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage' for chat_id in chat_ids: try: resp = requests.post(url, json={'chat_id': chat_id, 'text': text}, timeout=10) resp.raise_for_status() except requests.RequestException as exc: print(f'[Peringatan] Gagal kirim Telegram ke {chat_id}: {exc}', flush=True) def send_internal(text): """Kirim ke kanal internal (detail + kegagalan + klaim).""" send_text(text, TELEGRAM_INTERNAL_CHAT_IDS) def notify_start(run_date, n_voters, total_share, balance): """Run nyata dimulai: komunitas brief + internal detail.""" send_text(f'DISTRIBUSI MULAI\nTanggal: {run_date}') send_internal( f'DISTRIBUSI MULAI\n' f'Tanggal: {run_date}\n' f'Pemilih: {n_voters}\n' f'Total share: {total_share} VEX\n' f'Saldo: {balance} VEX' ) def notify_finish(status, sent, total, total_share, failed, run_date): """Run selesai: komunitas brief + internal detail (ok | partial).""" send_text( f'DISTRIBUSI SELESAI\n' f'Tanggal: {run_date}\n' f'Status: {status}' ) send_internal( f'DISTRIBUSI SELESAI\n' f'Tanggal: {run_date}\n' f'Status: {status}\n' f'Terkirim: {sent}/{total} pemilih\n' f'Total share: {total_share} VEX\n' f'Gagal: {len(failed)}' ) def notify_failure(exc): """Run gagal total — kanal internal saja (ops detail).""" send_internal( f'DISTRIBUSI GAGAL\n' f'Error: {exc}' ) def notify_claim(reward, fee, wallet): """Klaim reward BP sukses — kanal internal saja, ⊥ komunitas (V36).""" send_internal( f'KLAIM REWARD SUKSES\n' f'Reward: {reward} VEX\n' f'Fee BP: {fee} VEX → {wallet}' ) def notify_claim_unmeasured(txid_label): """Klaim mendarat tapi reward tak terukur (V45) — internal, ⊥ "sukses 0".""" send_internal( f'KLAIM MENDARAT · REWARD TAK TERUKUR\n' f'Periksa reward & fee BP manual (txid {txid_label})' ) def notify_claim_failure(exc): """Kegagalan siklus klaim — kanal internal saja (V36).""" send_internal( f'KLAIM GAGAL\n' f'Error: {exc}' )