ravisremotet 2.0__tar.gz → 2.2__tar.gz
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.
- {ravisremotet-2.0/ravisremotet.egg-info → ravisremotet-2.2}/PKG-INFO +1 -1
- {ravisremotet-2.0 → ravisremotet-2.2}/handlers/core_handler.py +1 -86
- ravisremotet-2.2/moudels/core/status_panel.py +202 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/pyproject.toml +1 -1
- {ravisremotet-2.0 → ravisremotet-2.2/ravisremotet.egg-info}/PKG-INFO +1 -1
- {ravisremotet-2.0 → ravisremotet-2.2}/setup.py +1 -1
- ravisremotet-2.0/moudels/core/status_panel.py +0 -82
- {ravisremotet-2.0 → ravisremotet-2.2}/LICENSE +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/MANIFEST.in +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/README.md +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/handlers/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/account_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/account_viewer.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/cleaner.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/client_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/flood_guard.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/online_client.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/status_report.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/client/test.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/device/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/device/device_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/profile/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/profile/profile_info.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/profile/profile_media.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/profile/profile_privacy.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/account/profile/username_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/admin/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/admin/admin_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/analytics/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/analytics/analytics_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/batch/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/batch/batch_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/batch/batch_scheduler.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/batch/message_shift.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/batch/shift_scheduler.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/config.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/getcode_controller.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/help_menu.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/human_behavior.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/menu_state.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/precise_engine.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/response_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/restart_module.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/core/typing_indicator.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/db/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/db/db_monitor.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/db/sqlite_utils.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/forward/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/forward/forward_commands.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/forward/forwarder.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/forward/speed_for_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/forward/stop_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/group/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/group/join_controller.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/group/joiner.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/group/leave_controller.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/group/lefter.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/actions.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/backup_legacy_inline/button_actions.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/backup_legacy_inline/keyboards.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/callback_router.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/keyboards.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/output_view.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/proxy_message.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/register.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/schema.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/state_catchers.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/menu/state_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/text/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/text/caption_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/text/finaly_text.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/text/mention_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/text/text_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/utils/__init__.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/utils/block_manager.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/utils/file_sender.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/utils/health.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/moudels/utils/humanize.py +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/ravisremotet.egg-info/SOURCES.txt +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/ravisremotet.egg-info/dependency_links.txt +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/ravisremotet.egg-info/requires.txt +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/ravisremotet.egg-info/top_level.txt +0 -0
- {ravisremotet-2.0 → ravisremotet-2.2}/setup.cfg +0 -0
|
@@ -9,8 +9,7 @@ from moudels.analytics import (analytics_manager)
|
|
|
9
9
|
from moudels.batch import (batch_manager)
|
|
10
10
|
from moudels.core import (config,restart_module,getcode_controller,help_menu,status_panel)
|
|
11
11
|
from moudels.db import (db_monitor)
|
|
12
|
-
from moudels.group import (join_controller,leave_controller)
|
|
13
|
-
from moudels.text import (caption_manager,mention_manager,text_manager)
|
|
12
|
+
from moudels.group import (join_controller,leave_controller)
|
|
14
13
|
from moudels.utils import (block_manager,file_sender)
|
|
15
14
|
from moudels.menu.register import register_menu
|
|
16
15
|
from moudels.forward import (speed_for_manager,forward_commands)
|
|
@@ -90,90 +89,6 @@ def register_commands(app):
|
|
|
90
89
|
@app.on_message(filters.command("delalldevices", "") & admin_filter)
|
|
91
90
|
async def kill_other_sessions(client, message):
|
|
92
91
|
await device_manager.terminate_all_other_sessions_cmd(message)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
#TEXT
|
|
97
|
-
@app.on_message(filters.command('text', prefixes=["/", ""]) & admin_filter)
|
|
98
|
-
async def save_text(client, message):
|
|
99
|
-
await text_manager.save_text_cmd(message)
|
|
100
|
-
|
|
101
|
-
@app.on_message(filters.command('ctext', prefixes=["/", ""]) & admin_filter)
|
|
102
|
-
async def clear_texts(client, message):
|
|
103
|
-
await text_manager.clear_texts_cmd(message)
|
|
104
|
-
|
|
105
|
-
@app.on_message(filters.command('shtext', prefixes=["/", ""]) & admin_filter)
|
|
106
|
-
async def show_text(client, message):
|
|
107
|
-
await text_manager.show_texts_cmd(message)
|
|
108
|
-
|
|
109
|
-
@app.on_message(filters.command('shcap', prefixes=["/", ""]) & admin_filter)
|
|
110
|
-
async def show_caption(client, message):
|
|
111
|
-
await caption_manager.show_caption_cmd(message, config.spam_config)
|
|
112
|
-
|
|
113
|
-
@app.on_message(filters.command('cap', prefixes=["/", ""]) & admin_filter)
|
|
114
|
-
async def add_caption(client, message):
|
|
115
|
-
await caption_manager.add_caption_cmd(message, config.spam_config)
|
|
116
|
-
|
|
117
|
-
@app.on_message(filters.command('ccap', prefixes=["/", ""]) & admin_filter)
|
|
118
|
-
async def clear_caption(client, message):
|
|
119
|
-
await caption_manager.clear_caption_cmd(message, config.spam_config)
|
|
120
|
-
|
|
121
|
-
@app.on_message(admin_filter & filters.command("textmention", prefixes=["/", ""]))
|
|
122
|
-
async def _setmention(client, m: Message):
|
|
123
|
-
txt = m.text.split(None, 1)[1] if (m.text and len(m.command) > 1) else ""
|
|
124
|
-
await m.reply(await mention_manager.set_mention_text(txt))
|
|
125
|
-
|
|
126
|
-
@app.on_message(admin_filter & filters.command("mention_user", prefixes=["/", ""]))
|
|
127
|
-
async def _mention_user(client, m: Message):
|
|
128
|
-
user = m.command[1]
|
|
129
|
-
await m.reply(await mention_manager.set_mention_user(user))
|
|
130
|
-
|
|
131
|
-
@app.on_message(admin_filter & filters.command("mention_toggle", prefixes=["/", ""]))
|
|
132
|
-
async def _mention_toggle(client, m: Message):
|
|
133
|
-
if len(m.command) < 2:
|
|
134
|
-
return await m.reply("Usage: /mention_toggle <on|off>")
|
|
135
|
-
enable = (m.command[1].lower() == "on")
|
|
136
|
-
await m.reply(await mention_manager.toggle_mention(enable))
|
|
137
|
-
|
|
138
|
-
@app.on_message(admin_filter & filters.command("mention_group_toggle", prefixes=["/", ""]))
|
|
139
|
-
async def _mention_group_toggle(client, m: Message):
|
|
140
|
-
if len(m.command) < 2:
|
|
141
|
-
return await m.reply("Usage: /mention_group_toggle <on|off>")
|
|
142
|
-
enable = (m.command[1].lower() == "on")
|
|
143
|
-
await m.reply(await mention_manager.toggle_group_mention(enable))
|
|
144
|
-
|
|
145
|
-
@app.on_message(admin_filter & filters.command("mention_gps", prefixes=["/", ""]))
|
|
146
|
-
async def _mention_gps(client, m: Message):
|
|
147
|
-
if not (m.text and len(m.command) > 1):
|
|
148
|
-
return await m.reply("Usage: /mention_gps <id1> <id2> ...")
|
|
149
|
-
tokens = m.command[1:]
|
|
150
|
-
ids = await mention_manager._resolve_many_tokens_to_ids(client, tokens)
|
|
151
|
-
if not ids:
|
|
152
|
-
return await m.reply("❌ هیچ شناسهٔ معتبری تشخیص داده نشد.")
|
|
153
|
-
msg = await mention_manager.add_groups_by_ids(*ids)
|
|
154
|
-
await m.reply(msg)
|
|
155
|
-
|
|
156
|
-
await m.reply(msg)
|
|
157
|
-
|
|
158
|
-
@app.on_message(admin_filter & filters.command("mention_del", prefixes=["/", ""]))
|
|
159
|
-
async def _mention_del(client, m: Message):
|
|
160
|
-
if not (m.text and len(m.command) > 1):
|
|
161
|
-
return await m.reply("Usage: /mention_del <id1> <id2> ...")
|
|
162
|
-
tokens = m.command[1:]
|
|
163
|
-
ids = await mention_manager._resolve_many_tokens_to_ids(client, tokens)
|
|
164
|
-
if not ids:
|
|
165
|
-
return await m.reply("❌ هیچ شناسهٔ معتبری برای حذف تشخیص داده نشد.")
|
|
166
|
-
msg = await mention_manager.remove_groups_by_ids(*ids)
|
|
167
|
-
await m.reply(msg)
|
|
168
|
-
|
|
169
|
-
@app.on_message(admin_filter & filters.command("mention_clear", prefixes=["/", ""]))
|
|
170
|
-
async def _mention_clear(client, m: Message):
|
|
171
|
-
await m.reply(await mention_manager.clear_groups())
|
|
172
|
-
|
|
173
|
-
@app.on_message(admin_filter & filters.command("mention_status", prefixes=["/", ""]))
|
|
174
|
-
async def _mention_status(client, m: Message):
|
|
175
|
-
await m.reply(await mention_manager.mention_status())
|
|
176
|
-
|
|
177
92
|
|
|
178
93
|
#MORE
|
|
179
94
|
@app.on_message(filters.command('gcode', '') & admin_filter)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# remote/moudels/core/status_panel.py
|
|
2
|
+
"""
|
|
3
|
+
📊 پنل وضعیت بات — نمایش دقیق آپتایم، پینگ، مصرف رم (فعلی و سقف مصرف)، CPU و وضعیت اکانتها.
|
|
4
|
+
سازگار با لینوکس (هاست cPanel) و ویندوز بدون نیاز اجباری به پکیجهای خارجی.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Tuple
|
|
12
|
+
|
|
13
|
+
from ..account.client.client_manager import accounts, client_pool
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
START_TIME = time.time()
|
|
18
|
+
_LAST_CPU_CHECK_WALL = time.perf_counter()
|
|
19
|
+
_LAST_CPU_CHECK_PROC = time.process_time()
|
|
20
|
+
_PEAK_RAM_MB = 0.0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _format_uptime(seconds: float) -> str:
|
|
24
|
+
m, s = divmod(int(seconds), 60)
|
|
25
|
+
h, m = divmod(m, 60)
|
|
26
|
+
d, h = divmod(h, 24)
|
|
27
|
+
if d:
|
|
28
|
+
return f"{d}d {h}h {m}m"
|
|
29
|
+
if h:
|
|
30
|
+
return f"{h}h {m}m"
|
|
31
|
+
return f"{m}m {s}s"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _get_memory_usage_mb() -> Tuple[float, float]:
|
|
35
|
+
"""
|
|
36
|
+
برمیگرداند: (رم فعلی به مگابایت, بیشترین رم ثبتشده به مگابایت)
|
|
37
|
+
ابتدا از هسته لینوکس (/proc/self/status) یا psutil و در ویندوز از ctypes میخواند.
|
|
38
|
+
"""
|
|
39
|
+
global _PEAK_RAM_MB
|
|
40
|
+
current_mb = 0.0
|
|
41
|
+
peak_mb = 0.0
|
|
42
|
+
|
|
43
|
+
# ۱) خواندن مستقیم و فوقسبک از کرنل لینوکس (cPanel)
|
|
44
|
+
if os.path.exists("/proc/self/status"):
|
|
45
|
+
try:
|
|
46
|
+
with open("/proc/self/status", "r", encoding="utf-8") as f:
|
|
47
|
+
for line in f:
|
|
48
|
+
if line.startswith("VmRSS:"):
|
|
49
|
+
current_mb = int(line.split()[1]) / 1024.0
|
|
50
|
+
elif line.startswith("VmHWM:"):
|
|
51
|
+
peak_mb = int(line.split()[1]) / 1024.0
|
|
52
|
+
except Exception:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# ۲) استفاده از psutil در صورت موجود بودن و عدم استخراج در مرحله قبل
|
|
56
|
+
if current_mb <= 0.0:
|
|
57
|
+
try:
|
|
58
|
+
import psutil
|
|
59
|
+
proc = psutil.Process(os.getpid())
|
|
60
|
+
mem = proc.memory_info()
|
|
61
|
+
current_mb = mem.rss / (1024.0 * 1024.0)
|
|
62
|
+
peak_mb = getattr(mem, "peak_wset", 0) / (1024.0 * 1024.0)
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
# ۳) پشتیبانی بومی از ویندوز (بدون نیاز به psutil)
|
|
67
|
+
if current_mb <= 0.0 and os.name == "nt":
|
|
68
|
+
try:
|
|
69
|
+
import ctypes
|
|
70
|
+
from ctypes import wintypes
|
|
71
|
+
|
|
72
|
+
class PROCESS_MEMORY_COUNTERS(ctypes.Structure):
|
|
73
|
+
_fields_ = [
|
|
74
|
+
("cb", wintypes.DWORD),
|
|
75
|
+
("PageFaultCount", wintypes.DWORD),
|
|
76
|
+
("PeakWorkingSetSize", ctypes.c_size_t),
|
|
77
|
+
("WorkingSetSize", ctypes.c_size_t),
|
|
78
|
+
("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
|
|
79
|
+
("QuotaPagedPoolUsage", ctypes.c_size_t),
|
|
80
|
+
("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
|
|
81
|
+
("QuotaNonPagedPoolUsage", ctypes.c_size_t),
|
|
82
|
+
("PagefileUsage", ctypes.c_size_t),
|
|
83
|
+
("PeakPagefileUsage", ctypes.c_size_t),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
pmc = PROCESS_MEMORY_COUNTERS()
|
|
87
|
+
pmc.cb = ctypes.sizeof(PROCESS_MEMORY_COUNTERS)
|
|
88
|
+
handle = ctypes.windll.kernel32.GetCurrentProcess()
|
|
89
|
+
if ctypes.windll.psapi.GetProcessMemoryInfo(handle, ctypes.byref(pmc), pmc.cb):
|
|
90
|
+
current_mb = pmc.WorkingSetSize / (1024.0 * 1024.0)
|
|
91
|
+
peak_mb = pmc.PeakWorkingSetSize / (1024.0 * 1024.0)
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
if current_mb > _PEAK_RAM_MB:
|
|
96
|
+
_PEAK_RAM_MB = current_mb
|
|
97
|
+
if peak_mb > _PEAK_RAM_MB:
|
|
98
|
+
_PEAK_RAM_MB = peak_mb
|
|
99
|
+
|
|
100
|
+
return round(current_mb, 2), round(_PEAK_RAM_MB, 2)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
async def _measure_ping_and_cpu(app) -> Tuple[int, float, float]:
|
|
104
|
+
"""
|
|
105
|
+
همزمان با گرفتن پینگ تلگرام، درصد مصرف لحظهای و میانگین CPU پروسه را محاسبه میکند.
|
|
106
|
+
برمیگرداند: (پینگ به میلیثانیه, مصرف لحظهای CPU, میانگین مصرف CPU)
|
|
107
|
+
"""
|
|
108
|
+
global _LAST_CPU_CHECK_WALL, _LAST_CPU_CHECK_PROC
|
|
109
|
+
|
|
110
|
+
w_start = time.perf_counter()
|
|
111
|
+
p_start = time.process_time()
|
|
112
|
+
|
|
113
|
+
ping_ms = -1
|
|
114
|
+
t0 = time.perf_counter()
|
|
115
|
+
try:
|
|
116
|
+
await app.get_me()
|
|
117
|
+
ping_ms = int((time.perf_counter() - t0) * 1000)
|
|
118
|
+
except Exception:
|
|
119
|
+
ping_ms = -1
|
|
120
|
+
|
|
121
|
+
# اگر پینگ خیلی سریع بود، یک مکث کوتاه میکنیم تا نمونه CPU دقیق باشد
|
|
122
|
+
elapsed_wall = time.perf_counter() - w_start
|
|
123
|
+
if elapsed_wall < 0.12:
|
|
124
|
+
await asyncio.sleep(0.12 - elapsed_wall)
|
|
125
|
+
|
|
126
|
+
w_now = time.perf_counter()
|
|
127
|
+
p_now = time.process_time()
|
|
128
|
+
|
|
129
|
+
# مصرف لحظهای در بازه نمونهگیری
|
|
130
|
+
inst_wall = max(0.001, w_now - w_start)
|
|
131
|
+
inst_cpu = ((p_now - p_start) / inst_wall) * 100.0
|
|
132
|
+
|
|
133
|
+
# میانگین مصرف از آخرین بازدید پنل وضعیت
|
|
134
|
+
delta_wall = w_now - _LAST_CPU_CHECK_WALL
|
|
135
|
+
if delta_wall >= 1.0:
|
|
136
|
+
avg_recent_cpu = ((p_now - _LAST_CPU_CHECK_PROC) / delta_wall) * 100.0
|
|
137
|
+
else:
|
|
138
|
+
avg_recent_cpu = inst_cpu
|
|
139
|
+
|
|
140
|
+
_LAST_CPU_CHECK_WALL = w_now
|
|
141
|
+
_LAST_CPU_CHECK_PROC = p_now
|
|
142
|
+
|
|
143
|
+
return ping_ms, round(min(100.0, max(0.0, inst_cpu)), 1), round(min(100.0, max(0.0, avg_recent_cpu)), 1)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _active_coroutines() -> int:
|
|
147
|
+
try:
|
|
148
|
+
return len(asyncio.all_tasks())
|
|
149
|
+
except Exception:
|
|
150
|
+
return -1
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _connected_clients_count() -> int:
|
|
154
|
+
try:
|
|
155
|
+
return sum(1 for cli in client_pool.values() if cli and getattr(cli, "is_connected", False))
|
|
156
|
+
except Exception:
|
|
157
|
+
return 0
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _account_status_text() -> str:
|
|
161
|
+
try:
|
|
162
|
+
from ..account.client import flood_guard
|
|
163
|
+
values = flood_guard.statuses()
|
|
164
|
+
if not values:
|
|
165
|
+
return "وضعیت اکانتها: فعال"
|
|
166
|
+
counts = {}
|
|
167
|
+
for value in values.values():
|
|
168
|
+
counts[value] = counts.get(value, 0) + 1
|
|
169
|
+
return "وضعیت اکانتها: " + " | ".join(f"{k}: {v}" for k, v in sorted(counts.items()))
|
|
170
|
+
except Exception:
|
|
171
|
+
return "وضعیت اکانتها: نامشخص"
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
async def show_status(app, message) -> None:
|
|
175
|
+
"""نمایش کامل وضعیت ربات شامل رم، CPU، پینگ و سشنها."""
|
|
176
|
+
try:
|
|
177
|
+
uptime = _format_uptime(time.time() - START_TIME)
|
|
178
|
+
ping, cpu_now, cpu_avg = await _measure_ping_and_cpu(app)
|
|
179
|
+
ram_now, ram_peak = _get_memory_usage_mb()
|
|
180
|
+
|
|
181
|
+
ping_txt = f"{ping} ms" if ping != -1 else "Failed"
|
|
182
|
+
acc_count = len(accounts())
|
|
183
|
+
connected_count = _connected_clients_count()
|
|
184
|
+
coro_count = _active_coroutines()
|
|
185
|
+
|
|
186
|
+
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
|
187
|
+
await message.reply(
|
|
188
|
+
" <b>وضعیت بات و منابع سرور</b>\n"
|
|
189
|
+
"┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈\n"
|
|
190
|
+
f" آپتایم: <code>{uptime}</code>\n"
|
|
191
|
+
f" رم فعلی: <code>{ram_now:.2f} MB</code> (سقف: <code>{ram_peak:.2f} MB</code>)\n"
|
|
192
|
+
f" مصرف CPU: <code>{cpu_now:.1f}%</code> (میانگین: <code>{cpu_avg:.1f}%</code>)\n"
|
|
193
|
+
f" اکانتها: <code>{acc_count}</code> (متصل در رم: <code>{connected_count}</code>)\n"
|
|
194
|
+
f" تسکهای فعال (Coroutines): <code>{coro_count}</code>\n"
|
|
195
|
+
f" پینگ تلگرام: <code>{ping_txt}</code>\n"
|
|
196
|
+
f" {_account_status_text()}",
|
|
197
|
+
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔄 رفرش", callback_data="act:sysstatus")]]),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
logger.exception(f"show_status error: {e}")
|
|
202
|
+
await message.reply(f"💥 خطا در نمایش وضعیت بات: {e}")
|
|
@@ -5,7 +5,7 @@ with open("README.md", encoding="utf-8") as f:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="ravisremotet",
|
|
8
|
-
version="2.
|
|
8
|
+
version="2.2",
|
|
9
9
|
author="MrAhmadiRad",
|
|
10
10
|
author_email="mohammadahmadirad69@gmail.com",
|
|
11
11
|
description="A precise, async-safe, Telegram automation core (Python 3.8+)",
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# remote/moudels/core/status_panel.py
|
|
2
|
-
"""
|
|
3
|
-
📊 پنل وضعیت بات — نسخهی سادهی متنی (بدون matplotlib/نمودار/CPU/RAM طبق درخواست).
|
|
4
|
-
|
|
5
|
-
فقط: آپتایم + پینگ تلگرام + تعداد اکانتها + تعداد coroutine های فعال.
|
|
6
|
-
یک پیام متنی ساده با دکمهی 🔄 رفرش.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import time
|
|
10
|
-
import asyncio
|
|
11
|
-
import logging
|
|
12
|
-
|
|
13
|
-
from ..account.client.client_manager import accounts
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
START_TIME = time.time()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _format_uptime(seconds: float) -> str:
|
|
21
|
-
m, s = divmod(int(seconds), 60)
|
|
22
|
-
h, m = divmod(m, 60)
|
|
23
|
-
d, h = divmod(h, 24)
|
|
24
|
-
if d:
|
|
25
|
-
return f"{d}d {h}h {m}m"
|
|
26
|
-
if h:
|
|
27
|
-
return f"{h}h {m}m"
|
|
28
|
-
return f"{m}m {s}s"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _active_coroutines() -> int:
|
|
32
|
-
try:
|
|
33
|
-
return len(asyncio.all_tasks())
|
|
34
|
-
except Exception:
|
|
35
|
-
return -1
|
|
36
|
-
|
|
37
|
-
def _account_status_text() -> str:
|
|
38
|
-
try:
|
|
39
|
-
from ..account.client import flood_guard
|
|
40
|
-
values = flood_guard.statuses()
|
|
41
|
-
if not values:
|
|
42
|
-
return "وضعیت اکانتها: فعال"
|
|
43
|
-
counts = {}
|
|
44
|
-
for value in values.values(): counts[value] = counts.get(value, 0) + 1
|
|
45
|
-
return "وضعیت اکانتها: " + " | ".join(f"{k}: {v}" for k, v in sorted(counts.items()))
|
|
46
|
-
except Exception:
|
|
47
|
-
return "وضعیت اکانتها: نامشخص"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
async def _telegram_ping(app) -> int:
|
|
51
|
-
start = time.time()
|
|
52
|
-
try:
|
|
53
|
-
await app.get_me()
|
|
54
|
-
return int((time.time() - start) * 1000)
|
|
55
|
-
except Exception:
|
|
56
|
-
return -1
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
async def show_status(app, message) -> None:
|
|
60
|
-
"""اجرای اصلی: یک پیام متنی با آمار وضعیت بات میفرسته."""
|
|
61
|
-
try:
|
|
62
|
-
uptime = _format_uptime(time.time() - START_TIME)
|
|
63
|
-
ping = await _telegram_ping(app)
|
|
64
|
-
ping_txt = f"{ping} ms" if ping != -1 else "Failed"
|
|
65
|
-
acc_count = len(accounts())
|
|
66
|
-
coro_count = _active_coroutines()
|
|
67
|
-
|
|
68
|
-
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
|
69
|
-
await message.reply(
|
|
70
|
-
"📊 <b>وضعیت بات</b>\n"
|
|
71
|
-
"┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈\n"
|
|
72
|
-
f"⏱ آپتایم: <code>{uptime}</code>\n"
|
|
73
|
-
f"👥 اکانتها: <code>{acc_count}</code>\n"
|
|
74
|
-
f"🧵 Coroutine های فعال: <code>{coro_count}</code>\n"
|
|
75
|
-
f"📡 پینگ تلگرام: <code>{ping_txt}</code>\n"
|
|
76
|
-
f"🛡 {_account_status_text()}",
|
|
77
|
-
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("رفرش", callback_data="act:sysstatus")]]),
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
except Exception as e:
|
|
81
|
-
logger.exception(f"show_status error: {e}")
|
|
82
|
-
await message.reply(f"💥 خطا در نمایش وضعیت بات: {e}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|