File size: 8,787 Bytes
26069e1
 
71634bf
 
163eb6d
9f2ee93
37574c6
 
993ae60
 
 
faeb9b4
2b7cf34
163eb6d
20a9f83
 
 
 
 
 
 
 
 
 
71634bf
2b7cf34
993ae60
3faff69
2b7cf34
37574c6
2b7cf34
71634bf
2b7cf34
37574c6
2b7cf34
3faff69
 
2b7cf34
3faff69
2b7cf34
3faff69
71634bf
993ae60
2b7cf34
993ae60
 
 
 
 
 
 
 
 
2b7cf34
993ae60
 
2b7cf34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c102777
2b7cf34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c102777
2b7cf34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163eb6d
2b7cf34
71634bf
 
2b7cf34
3faff69
2b7cf34
 
37574c6
993ae60
2b7cf34
9f2ee93
37574c6
 
 
993ae60
37574c6
2b7cf34
993ae60
 
37574c6
993ae60
2b7cf34
 
 
 
 
 
 
 
 
 
 
 
 
faeb9b4
2b7cf34
 
993ae60
 
faeb9b4
37574c6
2b7cf34
 
993ae60
2b7cf34
 
 
 
 
 
9fc3878
2b7cf34
 
 
 
993ae60
2b7cf34
993ae60
 
 
2b7cf34
993ae60
2b7cf34
 
163eb6d
2b7cf34
71634bf
2b7cf34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# Discord Bot for our community : https://github.com/TSOWatch/HF-Discord-Bot/
# based on discord boilerplate : https://github.com/VolkanSah/HF-Discord-Bot
from flask import Flask, request, jsonify
import os
import logging
from waitress import serve
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError
import threading
import requests
import time
from commands import ping_command, settings_command
from bank import BankSystem, BankAccount, TransactionError

# Logging konfigurieren: Nur in die Konsole ausgeben
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)


# Umgebungsvariablen und Konfiguration
PUBLIC_KEY = os.getenv('Public_Key', '').strip()
APPLICATION_ID = os.getenv('Application_ID', '').strip()
PORT = int(os.getenv('PORT', 7860))  # Hugging Face Standard-Port

# Flask App und Bank-System initialisieren
app = Flask(__name__)
bank_system = BankSystem()

# Discord Verifizierungsschlüssel initialisieren
try:
    verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY)) if PUBLIC_KEY else None
    logger.info("Discord Verifizierungsschlüssel erfolgreich initialisiert")
except Exception as e:
    logger.error(f"Fehler beim Initialisieren des Verifizierungsschlüssels: {str(e)}")
    verify_key = None

def verify_discord_request():
    """Überprüft die Authentizität der Discord-Anfrage"""
    try:
        signature = request.headers.get('X-Signature-Ed25519')
        timestamp = request.headers.get('X-Signature-Timestamp')
        if not signature or not timestamp:
            return False
        body = request.data.decode('utf-8')
        verify_key.verify(f"{timestamp}{body}".encode(), bytes.fromhex(signature))
        return True
    except Exception as e:
        logger.error(f"Verifikationsfehler: {str(e)}")
        return False

# Bank-bezogene Command-Handler
def handle_balance_command(data):
    """Verarbeitet den Balance-Check Befehl"""
    user_id = data.get("member", {}).get("user", {}).get("id")
    try:
        account = bank_system.get_account(user_id)
        if not account:
            account = bank_system.create_account(user_id)
        return jsonify({
            "type": 4,
            "data": {
                "content": f"💰 Dein Kontostand: {account.format_balance()}"
            }
        })
    except Exception as e:
        logger.error(f"Fehler beim Balance-Check: {str(e)}")
        return jsonify({
            "type": 4,
            "data": {
                "content": "❌ Fehler beim Abrufen des Kontostands."
            }
        })

def handle_transfer_command(data):
    """Verarbeitet Überweisungsbefehle"""
    options = data.get("data", {}).get("options", [{}])[0].get("options", [])
    user_id = data.get("member", {}).get("user", {}).get("id")
    
    # Parameter aus den Optionen extrahieren
    target_id = next((opt.get("value") for opt in options if opt.get("name") == "user"), None)
    amount = next((float(opt.get("value")) for opt in options if opt.get("name") == "amount"), None)
    
    try:
        bank_system.transfer_between_accounts(user_id, target_id, amount)  # Richtige Einrückung
        return jsonify({
            "type": 4,
            "data": {
                "content": f"✅ Erfolgreich {amount:,.2f} Credits an <@{target_id}> überwiesen!"
            }
        })
    except TransactionError as e:
        return jsonify({
            "type": 4,
            "data": {
                "content": f"❌ Überweisungsfehler: {str(e)}"
            }
        })
    except Exception as e:
        logger.error(f"Unerwarteter Fehler bei Überweisung: {str(e)}")
        return jsonify({
            "type": 4,
            "data": {
                "content": "❌ Ein unerwarteter Fehler ist aufgetreten."
            }
        })


def handle_daily_command(data):
    """Verarbeitet den täglichen Bonus-Befehl"""
    user_id = data.get("member", {}).get("user", {}).get("id")
    try:
        result = bank_system.daily_reward(user_id)
        return jsonify({
            "type": 4,
            "data": {
                "content": f"🎁 {result}"
            }
        })
    except Exception as e:
        logger.error(f"Fehler beim Daily Reward: {str(e)}")
        return jsonify({
            "type": 4,
            "data": {
                "content": "❌ Fehler beim Abholen der täglichen Belohnung."
            }
        })

# Haupt-Route für Discord-Interaktionen
@app.route("/interactions", methods=["POST"])
def interactions():
    """Hauptendpunkt für alle Discord-Interaktionen"""
    if not verify_key:
        logger.error("Verifizierungsschlüssel nicht initialisiert")
        return "Konfigurationsfehler", 500

    if not verify_discord_request():
        return "Ungültige Anfrage-Signatur", 401

    try:
        data = request.json
        
        # Discord Ping Verification
        if data.get("type") == 1:
            return jsonify({"type": 1})
        
        # Slash Commands
        if data.get("type") == 2:
            command = data.get("data", {}).get("name")
            
            # Bank-bezogene Befehle
            if command == "bank":
                subcommand = data.get("data", {}).get("options", [{}])[0].get("name")
                if subcommand == "balance":
                    return handle_balance_command(data)
                elif subcommand == "transfer":
                    return handle_transfer_command(data)
                elif subcommand == "daily":
                    return handle_daily_command(data)
            
            # Andere Befehle
            elif command == "settings":
                return settings_command(data)
            elif command == "ping":
                return ping_command(data)
        
        return jsonify({"type": 1})

    except Exception as e:
        logger.error(f"Fehler bei der Verarbeitung der Anfrage: {str(e)}")
        return "Interner Serverfehler", 500

# Health Check Endpoint
@app.route("/", methods=["GET"])
def health_check():
    """Endpoint für Hugging Face Health Checks"""
    return jsonify({
        "status": "running",
        "message": "The BOT runs!",
        "public_key_present": bool(PUBLIC_KEY),
        "verify_key_initialized": verify_key is not None,
        "bank_system_status": "active"
    })
def health_check_worker():
    """Background Worker für regelmäßige Health Checks"""
    while True:
        try:
            response = requests.get(f"http://localhost:{PORT}/")
            logger.info(f"Health Check Status: {response.status_code}")
        except Exception as e:
            logger.error(f"Health Check fehlgeschlagen: {str(e)}")
        time.sleep(30)  # 30 Sekunden Pause zwischen den Checks

# Hauptausführung
if __name__ == "__main__":
    try:
        logger.info(f"Starte Discord Bot auf Port {PORT}...")
        logger.info("Initialisiere Bank-System...")
        
        # Starte Health-Check Worker in separatem Thread
        health_thread = threading.Thread(target=health_check_worker, daemon=True)
        health_thread.start()
        
        # Registriere Slash-Commands (einmalig bei Bot-Start)
        BANK_COMMANDS = {
            "name": "bank",
            "description": "Bank-bezogene Befehle",
            "options": [
                {
                    "name": "balance",
                    "description": "Zeigt deinen aktuellen Kontostand",
                    "type": 1
                },
                {
                    "name": "transfer",
                    "description": "Überweise Credits an einen anderen Benutzer",
                    "type": 1,
                    "options": [
                        {
                            "name": "user",
                            "description": "Der Empfänger der Überweisung",
                            "type": 6,
                            "required": True
                        },
                        {
                            "name": "amount",
                            "description": "Die Menge an Credits",
                            "type": 10,
                            "required": True
                        }
                    ]
                },
                {
                    "name": "daily",
                    "description": "Hole dir deine tägliche Belohnung ab",
                    "type": 1
                }
            ]
        }
        
        # Starte Server
        logger.info("Server wird gestartet...")
        serve(app, host="0.0.0.0", port=PORT)
        
    except Exception as e:
        logger.critical(f"Kritischer Fehler beim Starten des Bots: {str(e)}")
        raise