Skip to content

Commit 481f6bb

Browse files
committed
refactor a bit
1 parent c38285a commit 481f6bb

3 files changed

Lines changed: 76 additions & 50 deletions

File tree

misc/helper_definitions.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,19 @@ def generate_cmd_dict_msg(description, commands: dict) -> str:
4343
return f"```{table}```"
4444

4545

46-
def generate_proc_dict_msg(description, processes: list) -> List[str]:
46+
def generate_machine_stats_msg(description, cpu_usage, memory_info, disk_usage) -> str:
47+
header = f"{description}\n| Resource | Usage |\n"
48+
separator = "|------------|---------------------------|\n"
49+
50+
table = header + separator
51+
table += f"| {'CPU':<10} | {f'{cpu_usage}%':<25} |\n"
52+
table += f"| {'Memory':<10} | {f'{memory_info.percent}% ({memory_info.used / (1024 ** 3):.1f}/{memory_info.total / (1024 ** 3):.1f} GB)':<25} |\n"
53+
table += f"| {'Disk':<10} | {f'{disk_usage.percent}% ({disk_usage.used / (1024 ** 3):.1f}/{disk_usage.total / (1024 ** 3):.1f} GB)':<25} |\n"
54+
55+
return f"```{table}```"
56+
57+
58+
def generate_proc_stats_msg(description, processes: list) -> List[str]:
4759
table_header = f"{description}\n| PID | Name | CPU (%) | Mem (%) |\n"
4860
separator = "|-------|----------------------|---------|----------|\n"
4961
table = table_header + separator
@@ -75,5 +87,3 @@ def load_config(conf_path: Path) -> Dict[str, Any]:
7587
except json.JSONDecodeError as e:
7688
print_error(f"Error decoding config -> {conf_path}.")
7789
raise e
78-
79-

misc/output_manager.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,10 @@ def print_cmd(text):
5959
TG_BANNER = """
6060
█▀ █▄█ █▀ ▀█▀ ▄▀█ █▀▄▀█ █▀▀ █▀█
6161
▄█ ░█░ ▄█ ░█░ █▀█ █░▀░█ ██▄ █▀▄
62+
"""
63+
64+
START_INTRO = """
65+
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
66+
by [@flashnuke](https://github.com/flashnuke/SysTamer)
67+
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n
6268
"""

systamer.py

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
# Ⓒ by https://github.com/flashnuke Ⓒ................................................................................
3737
# --------------------------------------------------------------------------------------------------------------------
3838

39-
def require_authentication(func, *args, **kwargs):
39+
# ============= WRAPPERS =============
40+
41+
def require_authentication(func, *_args, **_kwargs):
4042
async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
4143
if context.user_data.get("authenticated", False) or not SysTamer.should_authenticate():
4244
# User is authenticated, proceed with the function
@@ -48,7 +50,7 @@ async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args,
4850
return _impl
4951

5052

51-
def log_action(func, *args, **kwargs):
53+
def log_action(func, *_args, **_kwargs):
5254
async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
5355
message_text = update.message.text # This will contain the full command, e.g., "/start arg1 arg2"
5456
parts = message_text.split()
@@ -61,6 +63,18 @@ async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args,
6163
return _impl
6264

6365

66+
def check_for_permission(func, *_args, **_kwargs):
67+
async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
68+
try:
69+
return await func(self, update, context, *args, **kwargs)
70+
except PermissionError:
71+
if update.effective_message:
72+
await update.effective_message.reply_text("No permissions for this action, try running as superuser.")
73+
if update.callback_query:
74+
await SysTamer.delete_message(update, context)
75+
return _impl
76+
77+
6478
class SysTamer:
6579
_BROWSE_IGNORE_PATH = ".browseignore"
6680
_PASSWORD = str()
@@ -86,6 +100,17 @@ def __init__(self, json_conf: dict):
86100
self._browse_path_dict = dict()
87101
self._ignored_paths = SysTamer.load_ignore_paths()
88102

103+
# ============= static method helpers =============
104+
105+
@staticmethod
106+
def build_navigate_keyboard(all_buttons: List[InlineKeyboardButton]) -> List[List[InlineKeyboardButton]]:
107+
# separate navigation buttons from path buttons...
108+
navigation_buttons = all_buttons[-1] if isinstance(all_buttons[-1], list) else [all_buttons[-1]]
109+
regular_buttons = all_buttons[:-1] if isinstance(all_buttons[-1], list) else all_buttons
110+
keyboard = [regular_buttons[i:i + 2] for i in range(0, len(regular_buttons), 2)]
111+
keyboard.append(navigation_buttons)
112+
return keyboard
113+
89114
@staticmethod
90115
async def delete_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
91116
try:
@@ -96,17 +121,6 @@ async def delete_message(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
96121
except telegram.error.BadRequest as e:
97122
print_error(f"Error deleting message: {e}")
98123

99-
def check_for_permission(func, *args, **kwargs):
100-
async def _impl(self, update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
101-
try:
102-
return await func(self, update, context, *args, **kwargs)
103-
except PermissionError:
104-
if update.effective_message:
105-
await update.effective_message.reply_text("No permissions for this action, try running as superuser.")
106-
if update.callback_query:
107-
await SysTamer.delete_message(update, context)
108-
return _impl
109-
110124
@staticmethod
111125
def get_update_username(update: Update) -> str:
112126
return update.effective_user.username if update.effective_user.username else update.effective_user.id
@@ -171,7 +185,7 @@ def deauthenticate(context: ContextTypes.DEFAULT_TYPE):
171185

172186
@log_action
173187
@require_authentication
174-
async def send_screenshot(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
188+
async def send_screenshot(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
175189
with mss.mss() as sct:
176190
screenshot = sct.grab(sct.monitors[0]) # Capture the full screen
177191

@@ -191,13 +205,13 @@ async def reply_with_timeout(self, update: Update, async_reply_ptr: Callable[...
191205
try:
192206
await async_reply_ptr(*args, write_timeout=self._timeout_duration,
193207
connect_timeout=self._timeout_duration, read_timeout=self._timeout_duration, **kwargs)
194-
except telegram.error.TimedOut as exc:
208+
except telegram.error.TimedOut as _exc:
195209
await update.message.reply_text(f"Request timed out after {self._timeout_duration} seconds.")
196210
except telegram.error.NetworkError as exc:
197211
await update.message.reply_text(f"Network error occurred: {exc}. Please try again later.")
198212

199213
@require_authentication
200-
async def handle_file_upload(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
214+
async def handle_file_upload(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
201215
if not os.path.exists(self._uploads_dir):
202216
os.makedirs(self._uploads_dir)
203217
file_path = str()
@@ -255,7 +269,7 @@ async def handle_file_upload(self, update: Update, context: ContextTypes.DEFAULT
255269

256270
@log_action
257271
@require_authentication
258-
async def list_uploads(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
272+
async def list_uploads(self, update: Update, _context: ContextTypes.DEFAULT_TYPE) -> None:
259273
try:
260274
if not os.path.exists(self._uploads_dir):
261275
await update.message.reply_text("Upload directory does not exist.")
@@ -287,18 +301,13 @@ async def list_uploads(self, update: Update, context: ContextTypes.DEFAULT_TYPE)
287301

288302
@log_action
289303
@require_authentication
290-
async def system_resource_monitoring(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
304+
async def system_resource_monitoring(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
291305
cpu_usage = psutil.cpu_percent(interval=1)
292306
memory_info = psutil.virtual_memory()
293307
disk_usage = psutil.disk_usage('/')
294308

295-
response = (
296-
f"CPU Usage: {cpu_usage}%\n"
297-
f"Memory Usage: {memory_info.percent}% ({memory_info.used / (1024 ** 3):.2f} GB used of {memory_info.total / (1024 ** 3):.2f} GB)\n"
298-
f"Disk Usage: {disk_usage.percent}% ({disk_usage.used / (1024 ** 3):.2f} GB used of {disk_usage.total / (1024 ** 3):.2f} GB)"
299-
)
300-
301-
await update.message.reply_text(response)
309+
await update.message.reply_text(generate_machine_stats_msg("MachineStats", cpu_usage, memory_info, disk_usage),
310+
parse_mode="MarkdownV2")
302311

303312
@log_action
304313
@require_authentication
@@ -319,7 +328,8 @@ async def list_processes(self, update: Update, context: ContextTypes.DEFAULT_TYP
319328
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
320329
continue
321330

322-
table_chunks = generate_proc_dict_msg(f"Processes:{len(processes)},Filters:{context.args if context.args else None}", processes)
331+
table_chunks = generate_proc_stats_msg(f"Processes:{len(processes)},"
332+
f"Filters:{context.args if context.args else None}", processes)
323333
for chunk in table_chunks:
324334
await update.message.reply_text(f"```{chunk}```", parse_mode="MarkdownV2")
325335

@@ -339,16 +349,13 @@ async def kill_process(self, update: Update, context: ContextTypes.DEFAULT_TYPE)
339349
await update.message.reply_text("Invalid process ID or process does not exist.")
340350

341351
@log_action
342-
async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
343-
welcome_message = TG_BANNER + "\n\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n" \
344-
"by [@flashnuke](https://github.com/flashnuke/SysTamer)" \
345-
"\n\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\n"\
346-
+ generate_cmd_dict_msg("Commands", COMMANDS_DICT)
352+
async def start(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
353+
welcome_message = TG_BANNER + START_INTRO + generate_cmd_dict_msg("Commands", COMMANDS_DICT)
347354
await update.message.reply_text(welcome_message, parse_mode='MarkdownV2', disable_web_page_preview=True)
348355

349356
@log_action
350357
@require_authentication
351-
async def upload_info(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
358+
async def upload_info(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
352359
upload_message = (
353360
f"Simply send a file, and it will be saved to -> {self._uploads_dir}"
354361
)
@@ -367,29 +374,29 @@ def list_files_and_directories(self, path: str):
367374
entry_hashed = hashlib.md5(full_path.encode()).hexdigest()
368375
self._browse_path_dict[entry_hashed] = full_path
369376

370-
# Ensure that it's a directory or file and not something like NTUSER.DAT
371377
if os.path.isdir(full_path):
372378
buttons.append(InlineKeyboardButton(entry + '/', callback_data=f"cd {entry_hashed}"))
373379
else:
374380
buttons.append(InlineKeyboardButton(entry, callback_data=f"file {entry_hashed}"))
375381

376-
# Add "Back" button to navigate to the parent directory if not at the root
377-
# if path != str(Path.home()): # If we are not in the home directory
378-
parent_directory = os.path.dirname(path) # Get parent directory
379-
if os.path.isdir(parent_directory): # Ensure the parent directory is valid
382+
parent_directory = os.path.dirname(path)
383+
if os.path.isdir(parent_directory):
380384
parent_hashed = hashlib.md5(parent_directory.encode()).hexdigest()
381385
self._browse_path_dict[parent_hashed] = parent_directory
382-
buttons.append(InlineKeyboardButton("⬅️ Back", callback_data=f"cd {parent_hashed}"))
383-
buttons.append(InlineKeyboardButton("❌️ Close", callback_data=f"action close"))
386+
buttons.append([InlineKeyboardButton("⬅️ Back", callback_data=f"cd {parent_hashed}"),
387+
InlineKeyboardButton("❌️ Close", callback_data=f"action close")])
388+
else:
389+
buttons.append([InlineKeyboardButton("❌️ Close", callback_data=f"action close")])
384390
return buttons
385391

386392
@log_action
387393
@check_for_permission
388394
@require_authentication
389-
async def browse(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
390-
path = str(Path.home()) # Start from the home directory
391-
buttons = self.list_files_and_directories(path)
392-
keyboard = [buttons[i:i + 2] for i in range(0, len(buttons), 2)] # Group buttons in rows
395+
async def browse(self, update: Update, _context: ContextTypes.DEFAULT_TYPE):
396+
path = str(Path.home())
397+
all_buttons = self.list_files_and_directories(path)
398+
keyboard = self.build_navigate_keyboard(all_buttons)
399+
393400
reply_markup = InlineKeyboardMarkup(keyboard)
394401
await update.message.reply_text('Choose a directory or file:', reply_markup=reply_markup)
395402

@@ -399,15 +406,18 @@ async def handle_navigation(self, update: Update, context: ContextTypes.DEFAULT_
399406
query = update.callback_query
400407
data = query.data.split(' ', 1)
401408
command = data[0] # The command is the first part (e.g., "cd", "file", "action")
402-
print_cmd(f"user {SysTamer.get_update_username(update)}\t|\thandle_navigation received cmd -> {' '.join(data)}" + ('\t|\t(' + self._browse_path_dict.get(data[1]) + ')' if len(data) >= 1 and data[1] in self._browse_path_dict else ''))
409+
print_cmd(f"user {SysTamer.get_update_username(update)}\t|\t"
410+
f"handle_navigation received cmd -> {' '.join(data)}" +
411+
('\t|\t(' + self._browse_path_dict.get(data[1]) + ')'
412+
if len(data) >= 1 and data[1] in self._browse_path_dict else ''))
403413

404414
if command == "cd": # Handle directory navigation
405415
hashed_path = data[1]
406416
path = self._browse_path_dict.get(hashed_path)
407417

408418
if path and os.path.isdir(path): # Ensure the path is a valid directory
409-
buttons = self.list_files_and_directories(path)
410-
keyboard = [buttons[i:i + 2] for i in range(0, len(buttons), 2)]
419+
all_buttons = self.list_files_and_directories(path)
420+
keyboard = self.build_navigate_keyboard(all_buttons)
411421
reply_markup = InlineKeyboardMarkup(keyboard)
412422
await query.edit_message_text(text=f'Navigating to: {path}', reply_markup=reply_markup)
413423
else:
@@ -496,7 +506,7 @@ def _build_app(self) -> telegram.ext.Application:
496506

497507
return application
498508

499-
def _error_handler(self, update: object, context: telegram.ext.CallbackContext):
509+
def _error_handler(self, _update: object, context: telegram.ext.CallbackContext):
500510
try:
501511
raise context.error
502512
except Exception as exc:

0 commit comments

Comments
 (0)