mc5-api-client 1.0.16__py3-none-any.whl → 1.0.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mc5_api_client/__init__.py +297 -8
- mc5_api_client/account.py +352 -0
- mc5_api_client/account_quick.py +246 -0
- mc5_api_client/alerts.py +336 -0
- mc5_api_client/alerts_quick.py +210 -0
- mc5_api_client/client.py +898 -34
- mc5_api_client/debug.py +259 -0
- mc5_api_client/easy_mc5.py +682 -0
- mc5_api_client/federation.py +257 -0
- mc5_api_client/federation_quick.py +198 -0
- mc5_api_client/pc_storage_client.py +229 -0
- mc5_api_client/pc_storage_quick.py +234 -0
- mc5_api_client/platform.py +108 -0
- mc5_api_client/simple_client.py +563 -19
- mc5_api_client/squad_battle.py +439 -0
- mc5_api_client/squad_battle_quick.py +223 -0
- mc5_api_client/storage_admin.py +285 -0
- mc5_api_client/telemetry.py +344 -0
- mc5_api_client/transfer.py +348 -0
- mc5_api_client/transfer_quick.py +280 -0
- {mc5_api_client-1.0.16.dist-info → mc5_api_client-1.0.18.dist-info}/METADATA +730 -11
- mc5_api_client-1.0.18.dist-info/RECORD +32 -0
- mc5_api_client-1.0.16.dist-info/RECORD +0 -15
- {mc5_api_client-1.0.16.dist-info → mc5_api_client-1.0.18.dist-info}/WHEEL +0 -0
- {mc5_api_client-1.0.16.dist-info → mc5_api_client-1.0.18.dist-info}/entry_points.txt +0 -0
- {mc5_api_client-1.0.16.dist-info → mc5_api_client-1.0.18.dist-info}/licenses/LICENSE +0 -0
- {mc5_api_client-1.0.16.dist-info → mc5_api_client-1.0.18.dist-info}/top_level.txt +0 -0
mc5_api_client/alerts.py
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# ────────────[ CHIZOBA ]────────────────────────────
|
|
3
|
+
# | Email : chizoba2026@hotmail.com
|
|
4
|
+
# | File : alerts.py
|
|
5
|
+
# | License | MIT License © 2026 Chizoba
|
|
6
|
+
# | Brief | Real-time alerts and streaming functionality
|
|
7
|
+
# ────────────────★─────────────────────────────────
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
import threading
|
|
12
|
+
from typing import Optional, Dict, Any, List, Callable
|
|
13
|
+
from .telemetry import report_error, report_usage
|
|
14
|
+
from .debug import debug_function, debug_print
|
|
15
|
+
|
|
16
|
+
class AlertsMixin:
|
|
17
|
+
"""Mixin class for real-time alerts and streaming functionality."""
|
|
18
|
+
|
|
19
|
+
@debug_function
|
|
20
|
+
def start_alert_stream(self,
|
|
21
|
+
webhook_url: Optional[str] = None,
|
|
22
|
+
alert_types: List[str] = None,
|
|
23
|
+
callback: Optional[Callable] = None) -> Dict[str, Any]:
|
|
24
|
+
"""
|
|
25
|
+
Start real-time alert streaming for live notifications.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
webhook_url: Optional webhook URL for alert forwarding
|
|
29
|
+
alert_types: List of alert types to subscribe to
|
|
30
|
+
callback: Optional callback function for handling alerts
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Stream session information
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
if alert_types is None:
|
|
37
|
+
alert_types = ["connection", "message", "connection_request", "connection_request_accepted"]
|
|
38
|
+
|
|
39
|
+
# Get a fedex server endpoint (these appear to be load balanced)
|
|
40
|
+
fedex_servers = [
|
|
41
|
+
"eur-fedex-fsg006.gameloft.com:45040",
|
|
42
|
+
"eur-fedex-fsg002.gameloft.com:41245",
|
|
43
|
+
"eur-fedex-fsg001.gameloft.com:45040"
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Use first available server
|
|
47
|
+
server = fedex_servers[0]
|
|
48
|
+
url = f"https://{server}/alerts/me"
|
|
49
|
+
|
|
50
|
+
params = {
|
|
51
|
+
"access_token": self._token_data["access_token"],
|
|
52
|
+
"content_type": "event-stream",
|
|
53
|
+
"push_method": "streaming",
|
|
54
|
+
"alert_types": ",".join(alert_types)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
debug_print(f"🌊 Starting alert stream from {server}", "info")
|
|
58
|
+
debug_print(f"📋 Alert types: {', '.join(alert_types)}", "info")
|
|
59
|
+
|
|
60
|
+
# Create stream session info
|
|
61
|
+
session_info = {
|
|
62
|
+
"server": server,
|
|
63
|
+
"url": url,
|
|
64
|
+
"params": params,
|
|
65
|
+
"alert_types": alert_types,
|
|
66
|
+
"webhook_url": webhook_url,
|
|
67
|
+
"callback": callback,
|
|
68
|
+
"started_at": time.time(),
|
|
69
|
+
"status": "starting"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Start streaming in background thread
|
|
73
|
+
if callback:
|
|
74
|
+
stream_thread = threading.Thread(
|
|
75
|
+
target=self._stream_alerts,
|
|
76
|
+
args=(session_info,),
|
|
77
|
+
daemon=True
|
|
78
|
+
)
|
|
79
|
+
stream_thread.start()
|
|
80
|
+
session_info["thread"] = stream_thread
|
|
81
|
+
session_info["status"] = "streaming"
|
|
82
|
+
|
|
83
|
+
report_usage("start_alert_stream", True, 0, {
|
|
84
|
+
"server": server,
|
|
85
|
+
"alert_types_count": len(alert_types),
|
|
86
|
+
"has_webhook": webhook_url is not None,
|
|
87
|
+
"has_callback": callback is not None
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
return session_info
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
debug_print(f"❌ Failed to start alert stream: {e}", "error")
|
|
94
|
+
report_error(e, "start_alert_stream", {
|
|
95
|
+
"alert_types": alert_types,
|
|
96
|
+
"has_webhook": webhook_url is not None
|
|
97
|
+
})
|
|
98
|
+
raise
|
|
99
|
+
|
|
100
|
+
def _stream_alerts(self, session_info: Dict[str, Any]):
|
|
101
|
+
"""
|
|
102
|
+
Internal method to handle alert streaming.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
session_info: Stream session information
|
|
106
|
+
"""
|
|
107
|
+
try:
|
|
108
|
+
import requests
|
|
109
|
+
|
|
110
|
+
url = session_info["url"]
|
|
111
|
+
params = session_info["params"]
|
|
112
|
+
callback = session_info.get("callback")
|
|
113
|
+
webhook_url = session_info.get("webhook_url")
|
|
114
|
+
|
|
115
|
+
debug_print("🌊 Connecting to alert stream...", "info")
|
|
116
|
+
|
|
117
|
+
# Make streaming request
|
|
118
|
+
response = requests.get(url, params=params, stream=True, timeout=30)
|
|
119
|
+
|
|
120
|
+
if response.status_code == 200:
|
|
121
|
+
debug_print("✅ Alert stream connected", "success")
|
|
122
|
+
|
|
123
|
+
# Process stream events
|
|
124
|
+
for line in response.iter_lines(decode_unicode=True):
|
|
125
|
+
if line and line.strip():
|
|
126
|
+
try:
|
|
127
|
+
# Parse alert data
|
|
128
|
+
if line.startswith("data: "):
|
|
129
|
+
alert_data = line[6:] # Remove "data: " prefix
|
|
130
|
+
alert_json = json.loads(alert_data)
|
|
131
|
+
|
|
132
|
+
# Process alert
|
|
133
|
+
self._process_alert(alert_json, callback, webhook_url)
|
|
134
|
+
|
|
135
|
+
except json.JSONDecodeError:
|
|
136
|
+
debug_print(f"⚠️ Invalid alert data: {line[:50]}...", "warning")
|
|
137
|
+
except Exception as e:
|
|
138
|
+
debug_print(f"⚠️ Error processing alert: {e}", "warning")
|
|
139
|
+
else:
|
|
140
|
+
debug_print(f"❌ Alert stream failed: {response.status_code}", "error")
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
debug_print(f"❌ Alert stream error: {e}", "error")
|
|
144
|
+
report_error(e, "_stream_alerts", session_info)
|
|
145
|
+
|
|
146
|
+
def _process_alert(self,
|
|
147
|
+
alert_data: Dict[str, Any],
|
|
148
|
+
callback: Optional[Callable] = None,
|
|
149
|
+
webhook_url: Optional[str] = None):
|
|
150
|
+
"""
|
|
151
|
+
Process incoming alert data.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
alert_data: Alert data from stream
|
|
155
|
+
callback: Optional callback function
|
|
156
|
+
webhook_url: Optional webhook URL for forwarding
|
|
157
|
+
"""
|
|
158
|
+
try:
|
|
159
|
+
alert_type = alert_data.get("type", "unknown")
|
|
160
|
+
timestamp = alert_data.get("timestamp", time.time())
|
|
161
|
+
|
|
162
|
+
debug_print(f"🔔 Received alert: {alert_type}", "info")
|
|
163
|
+
|
|
164
|
+
# Format alert for processing
|
|
165
|
+
formatted_alert = {
|
|
166
|
+
"type": alert_type,
|
|
167
|
+
"timestamp": timestamp,
|
|
168
|
+
"data": alert_data,
|
|
169
|
+
"received_at": time.time()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# Call callback if provided
|
|
173
|
+
if callback:
|
|
174
|
+
try:
|
|
175
|
+
callback(formatted_alert)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
debug_print(f"⚠️ Callback error: {e}", "warning")
|
|
178
|
+
|
|
179
|
+
# Forward to webhook if provided
|
|
180
|
+
if webhook_url:
|
|
181
|
+
try:
|
|
182
|
+
self._forward_alert_to_webhook(formatted_alert, webhook_url)
|
|
183
|
+
except Exception as e:
|
|
184
|
+
debug_print(f"⚠️ Webhook forwarding error: {e}", "warning")
|
|
185
|
+
|
|
186
|
+
except Exception as e:
|
|
187
|
+
debug_print(f"❌ Error processing alert: {e}", "error")
|
|
188
|
+
|
|
189
|
+
def _forward_alert_to_webhook(self, alert: Dict[str, Any], webhook_url: str):
|
|
190
|
+
"""
|
|
191
|
+
Forward alert to Discord webhook.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
alert: Formatted alert data
|
|
195
|
+
webhook_url: Discord webhook URL
|
|
196
|
+
"""
|
|
197
|
+
try:
|
|
198
|
+
import requests
|
|
199
|
+
|
|
200
|
+
# Create Discord embed
|
|
201
|
+
alert_type = alert.get("type", "unknown")
|
|
202
|
+
timestamp = alert.get("timestamp", time.time())
|
|
203
|
+
|
|
204
|
+
embed = {
|
|
205
|
+
"title": f"🔔 MC5 Alert: {alert_type.upper()}",
|
|
206
|
+
"description": f"Real-time alert received from MC5 servers",
|
|
207
|
+
"color": 5814783, # Blue color
|
|
208
|
+
"fields": [
|
|
209
|
+
{
|
|
210
|
+
"name": "Alert Type",
|
|
211
|
+
"value": alert_type,
|
|
212
|
+
"inline": True
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"name": "Timestamp",
|
|
216
|
+
"value": f"<t:{int(timestamp)}:R>",
|
|
217
|
+
"inline": True
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "Server",
|
|
221
|
+
"value": "eur-fedex servers",
|
|
222
|
+
"inline": True
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
"footer": {
|
|
226
|
+
"text": "MC5 API Client - Real-time Alerts"
|
|
227
|
+
},
|
|
228
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# Add alert data if available
|
|
232
|
+
alert_data = alert.get("data", {})
|
|
233
|
+
if alert_data:
|
|
234
|
+
# Add relevant data fields
|
|
235
|
+
for key, value in list(alert_data.items())[:5]: # Limit to 5 fields
|
|
236
|
+
if isinstance(value, (str, int, float, bool)):
|
|
237
|
+
embed["fields"].append({
|
|
238
|
+
"name": key.replace("_", " ").title(),
|
|
239
|
+
"value": str(value),
|
|
240
|
+
"inline": True
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
payload = {
|
|
244
|
+
"embeds": [embed],
|
|
245
|
+
"username": "MC5 Alerts"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Send to webhook
|
|
249
|
+
response = requests.post(webhook_url, json=payload, timeout=10)
|
|
250
|
+
|
|
251
|
+
if response.status_code == 204:
|
|
252
|
+
debug_print(f"✅ Alert forwarded to webhook: {alert_type}", "success")
|
|
253
|
+
else:
|
|
254
|
+
debug_print(f"⚠️ Webhook response: {response.status_code}", "warning")
|
|
255
|
+
|
|
256
|
+
except Exception as e:
|
|
257
|
+
debug_print(f"❌ Webhook forwarding failed: {e}", "error")
|
|
258
|
+
raise
|
|
259
|
+
|
|
260
|
+
@debug_function
|
|
261
|
+
def test_alert_connection(self) -> Dict[str, Any]:
|
|
262
|
+
"""
|
|
263
|
+
Test connection to alert servers.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Connection test results
|
|
267
|
+
"""
|
|
268
|
+
try:
|
|
269
|
+
import requests
|
|
270
|
+
|
|
271
|
+
fedex_servers = [
|
|
272
|
+
"eur-fedex-fsg006.gameloft.com:45040",
|
|
273
|
+
"eur-fedex-fsg002.gameloft.com:41245",
|
|
274
|
+
"eur-fedex-fsg001.gameloft.com:45040"
|
|
275
|
+
]
|
|
276
|
+
|
|
277
|
+
results = []
|
|
278
|
+
|
|
279
|
+
for server in fedex_servers:
|
|
280
|
+
try:
|
|
281
|
+
url = f"https://{server}/alerts/me"
|
|
282
|
+
params = {
|
|
283
|
+
"access_token": self._token_data["access_token"],
|
|
284
|
+
"content_type": "event-stream",
|
|
285
|
+
"push_method": "streaming"
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# Test connection (short timeout)
|
|
289
|
+
response = requests.get(url, params=params, timeout=5, stream=True)
|
|
290
|
+
|
|
291
|
+
server_result = {
|
|
292
|
+
"server": server,
|
|
293
|
+
"status_code": response.status_code,
|
|
294
|
+
"connected": response.status_code == 200,
|
|
295
|
+
"response_time": response.elapsed.total_seconds() if hasattr(response, 'elapsed') else 0
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if response.status_code == 200:
|
|
299
|
+
debug_print(f"✅ {server}: Connected", "success")
|
|
300
|
+
else:
|
|
301
|
+
debug_print(f"❌ {server}: {response.status_code}", "error")
|
|
302
|
+
|
|
303
|
+
results.append(server_result)
|
|
304
|
+
|
|
305
|
+
# Close connection
|
|
306
|
+
response.close()
|
|
307
|
+
|
|
308
|
+
except Exception as e:
|
|
309
|
+
debug_print(f"❌ {server}: {e}", "error")
|
|
310
|
+
results.append({
|
|
311
|
+
"server": server,
|
|
312
|
+
"status_code": 0,
|
|
313
|
+
"connected": False,
|
|
314
|
+
"error": str(e)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
# Find best server
|
|
318
|
+
connected_servers = [r for r in results if r.get("connected")]
|
|
319
|
+
best_server = None
|
|
320
|
+
|
|
321
|
+
if connected_servers:
|
|
322
|
+
best_server = min(connected_servers, key=lambda x: x.get("response_time", float('inf')))
|
|
323
|
+
|
|
324
|
+
debug_print(f"🎯 Best server: {best_server.get('server') if best_server else 'None'}", "info")
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
"results": results,
|
|
328
|
+
"connected_count": len(connected_servers),
|
|
329
|
+
"best_server": best_server,
|
|
330
|
+
"total_tested": len(results)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
except Exception as e:
|
|
334
|
+
debug_print(f"❌ Alert connection test failed: {e}", "error")
|
|
335
|
+
report_error(e, "test_alert_connection", {})
|
|
336
|
+
raise
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# ────────────[ CHIZOBA ]────────────────────────────
|
|
3
|
+
# | Email : chizoba2026@hotmail.com
|
|
4
|
+
# | File : alerts_quick.py
|
|
5
|
+
# | License | MIT License © 2026 Chizoba
|
|
6
|
+
# | Brief | Quick functions for real-time alerts
|
|
7
|
+
# ────────────────★─────────────────────────────────
|
|
8
|
+
|
|
9
|
+
from typing import Optional, Dict, Any, List, Callable
|
|
10
|
+
from .simple_client import SimpleMC5Client
|
|
11
|
+
from .telemetry import report_usage
|
|
12
|
+
from .debug import debug_function, debug_print
|
|
13
|
+
|
|
14
|
+
@debug_function
|
|
15
|
+
def quick_start_alert_stream(username: str, password: str,
|
|
16
|
+
webhook_url: Optional[str] = None,
|
|
17
|
+
alert_types: Optional[List[str]] = None,
|
|
18
|
+
callback: Optional[Callable] = None) -> Optional[Dict[str, Any]]:
|
|
19
|
+
"""
|
|
20
|
+
Quick function to start real-time alert streaming.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
username: MC5 username
|
|
24
|
+
password: MC5 password
|
|
25
|
+
webhook_url: Optional Discord webhook URL for alert forwarding
|
|
26
|
+
alert_types: List of alert types to subscribe to
|
|
27
|
+
callback: Optional callback function for handling alerts
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Stream session information or None if failed
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
with SimpleMC5Client(username, password) as client:
|
|
34
|
+
if client.connect():
|
|
35
|
+
session = client.client.start_alert_stream(
|
|
36
|
+
webhook_url=webhook_url,
|
|
37
|
+
alert_types=alert_types,
|
|
38
|
+
callback=callback
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
debug_print(f"✅ Alert stream started on {session.get('server')}", "success")
|
|
42
|
+
return session
|
|
43
|
+
return None
|
|
44
|
+
except Exception as e:
|
|
45
|
+
debug_print(f"❌ Failed to start alert stream: {e}", "error")
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
@debug_function
|
|
49
|
+
def quick_test_alert_connection(username: str, password: str) -> Optional[Dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Quick function to test alert server connections.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
username: MC5 username
|
|
55
|
+
password: MC5 password
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Connection test results or None if failed
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
with SimpleMC5Client(username, password) as client:
|
|
62
|
+
if client.connect():
|
|
63
|
+
results = client.client.test_alert_connection()
|
|
64
|
+
|
|
65
|
+
connected_count = results.get('connected_count', 0)
|
|
66
|
+
total_tested = results.get('total_tested', 0)
|
|
67
|
+
|
|
68
|
+
debug_print(f"✅ Alert connection test: {connected_count}/{total_tested} servers connected", "success")
|
|
69
|
+
|
|
70
|
+
best_server = results.get('best_server')
|
|
71
|
+
if best_server and best_server.get('connected'):
|
|
72
|
+
debug_print(f"🎯 Best server: {best_server.get('server')} ({best_server.get('response_time', 0):.2f}s)", "info")
|
|
73
|
+
|
|
74
|
+
return results
|
|
75
|
+
return None
|
|
76
|
+
except Exception as e:
|
|
77
|
+
debug_print(f"❌ Failed to test alert connection: {e}", "error")
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
@debug_function
|
|
81
|
+
def quick_start_alerts_with_discord(username: str, password: str,
|
|
82
|
+
discord_webhook: str,
|
|
83
|
+
alert_types: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
|
|
84
|
+
"""
|
|
85
|
+
Quick function to start alerts with Discord webhook forwarding.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
username: MC5 username
|
|
89
|
+
password: MC5 password
|
|
90
|
+
discord_webhook: Discord webhook URL for alert forwarding
|
|
91
|
+
alert_types: List of alert types to subscribe to
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Stream session information or None if failed
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
# Default alert types if not provided
|
|
98
|
+
if alert_types is None:
|
|
99
|
+
alert_types = ["connection", "message", "connection_request", "connection_request_accepted"]
|
|
100
|
+
|
|
101
|
+
debug_print(f"🔔 Starting alerts with Discord forwarding", "info")
|
|
102
|
+
debug_print(f"📋 Alert types: {', '.join(alert_types)}", "info")
|
|
103
|
+
debug_print(f"🔗 Webhook: {discord_webhook[:50]}...", "info")
|
|
104
|
+
|
|
105
|
+
return quick_start_alert_stream(
|
|
106
|
+
username=username,
|
|
107
|
+
password=password,
|
|
108
|
+
webhook_url=discord_webhook,
|
|
109
|
+
alert_types=alert_types
|
|
110
|
+
)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
debug_print(f"❌ Failed to start alerts with Discord: {e}", "error")
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def create_alert_callback(print_alerts: bool = True, save_to_file: Optional[str] = None) -> Callable:
|
|
116
|
+
"""
|
|
117
|
+
Create a callback function for handling alerts.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
print_alerts: Whether to print alerts to console
|
|
121
|
+
save_to_file: Optional file path to save alerts
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Callback function
|
|
125
|
+
"""
|
|
126
|
+
def alert_callback(alert_data: Dict[str, Any]):
|
|
127
|
+
"""Handle incoming alert data."""
|
|
128
|
+
try:
|
|
129
|
+
alert_type = alert_data.get('type', 'unknown')
|
|
130
|
+
timestamp = alert_data.get('timestamp', 0)
|
|
131
|
+
|
|
132
|
+
# Format timestamp
|
|
133
|
+
import time
|
|
134
|
+
formatted_time = time.strftime("%H:%M:%S", time.localtime(timestamp))
|
|
135
|
+
|
|
136
|
+
# Print alert if requested
|
|
137
|
+
if print_alerts:
|
|
138
|
+
debug_print(f"🔔 [{formatted_time}] {alert_type.upper()}", "info")
|
|
139
|
+
|
|
140
|
+
# Print additional data if available
|
|
141
|
+
alert_info = alert_data.get('data', {})
|
|
142
|
+
if alert_info:
|
|
143
|
+
for key, value in list(alert_info.items())[:3]: # Show first 3 items
|
|
144
|
+
debug_print(f" {key}: {value}", "info")
|
|
145
|
+
|
|
146
|
+
# Save to file if requested
|
|
147
|
+
if save_to_file:
|
|
148
|
+
import json
|
|
149
|
+
with open(save_to_file, 'a', encoding='utf-8') as f:
|
|
150
|
+
f.write(json.dumps({
|
|
151
|
+
'timestamp': timestamp,
|
|
152
|
+
'type': alert_type,
|
|
153
|
+
'data': alert_data
|
|
154
|
+
}) + '\n')
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
debug_print(f"❌ Error in alert callback: {e}", "error")
|
|
158
|
+
|
|
159
|
+
return alert_callback
|
|
160
|
+
|
|
161
|
+
@debug_function
|
|
162
|
+
def quick_monitor_alerts(username: str, password: str,
|
|
163
|
+
duration: int = 60,
|
|
164
|
+
discord_webhook: Optional[str] = None,
|
|
165
|
+
save_file: Optional[str] = None) -> int:
|
|
166
|
+
"""
|
|
167
|
+
Quick function to monitor alerts for a specific duration.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
username: MC5 username
|
|
171
|
+
password: MC5 password
|
|
172
|
+
duration: Duration in seconds to monitor
|
|
173
|
+
discord_webhook: Optional Discord webhook URL
|
|
174
|
+
save_file: Optional file to save alerts
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Number of alerts received
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
import time
|
|
181
|
+
|
|
182
|
+
# Create callback
|
|
183
|
+
callback = create_alert_callback(print_alerts=True, save_to_file=save_file)
|
|
184
|
+
|
|
185
|
+
# Start alert stream
|
|
186
|
+
session = quick_start_alert_stream(
|
|
187
|
+
username=username,
|
|
188
|
+
password=password,
|
|
189
|
+
webhook_url=discord_webhook,
|
|
190
|
+
alert_types=["connection", "message", "connection_request", "connection_request_accepted"],
|
|
191
|
+
callback=callback
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
if not session:
|
|
195
|
+
return 0
|
|
196
|
+
|
|
197
|
+
debug_print(f"⏰ Monitoring alerts for {duration} seconds...", "info")
|
|
198
|
+
|
|
199
|
+
# Monitor for specified duration
|
|
200
|
+
time.sleep(duration)
|
|
201
|
+
|
|
202
|
+
debug_print(f"⏹️ Alert monitoring completed", "info")
|
|
203
|
+
|
|
204
|
+
# Note: In a real implementation, you'd want to track alert count
|
|
205
|
+
# For now, return a placeholder
|
|
206
|
+
return 0
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
debug_print(f"❌ Failed to monitor alerts: {e}", "error")
|
|
210
|
+
return 0
|