d4rktg 1.2.3__py3-none-any.whl → 1.2.5__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.
d4rk/Database/db.py CHANGED
@@ -4,7 +4,7 @@ from pymongo import MongoClient , server_api
4
4
 
5
5
  from d4rk.Logs import setup_logger
6
6
 
7
- logger = setup_logger(__name__)
7
+ logger = setup_logger("Database")
8
8
 
9
9
  class Database:
10
10
  client = None
@@ -43,7 +43,6 @@ class Database:
43
43
  base_collection = self.get_collection(collection_name)
44
44
  instance = CustomClass(base_collection)
45
45
  setattr(self, collection_name, instance)
46
- logger.info(f"Loaded collection: {collection_name}")
47
46
 
48
47
  def get_collection(self, collection):
49
48
  return self.db[collection]
d4rk/Handlers/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from ._bot import BotManager
2
- from ._scheduler import scheduler
3
- from ._custom import FontMessageMixin
2
+ from ._custom import FontMessageMixin
3
+ from ._logger_bot import LoggerBotUtil
d4rk/Handlers/_bot.py CHANGED
@@ -2,24 +2,19 @@ import os
2
2
  import sys
3
3
  import asyncio
4
4
  import traceback
5
- import random
6
- from datetime import datetime, timedelta
7
5
 
8
6
  from pyrogram import Client
9
- from pyrogram.errors import FloodWait
10
- from pyrogram.types import BotCommand
11
- from pyrogram.errors.exceptions.bad_request_400 import AccessTokenExpired
7
+ from pyrogram.errors import FloodWait, AccessTokenExpired
12
8
 
13
9
  from d4rk.Logs import setup_logger
14
10
 
11
+ logger = setup_logger("BotClient")
12
+
15
13
  logs_sent = False
16
14
  logs_lock = asyncio.Lock()
17
15
 
18
- logger = setup_logger(__name__)
19
-
20
16
  class BotManager(Client):
21
17
  _bot: Client = None
22
- _web = True
23
18
  _bot_info = None
24
19
  _is_connected = False
25
20
  _rename = False
@@ -28,7 +23,7 @@ class BotManager(Client):
28
23
  _scheduler_thread = None
29
24
  font = 0
30
25
  sudo_users = []
31
-
26
+ owner = None
32
27
 
33
28
  def create_client(self,app_name,token):
34
29
  self.app_name = app_name
@@ -41,53 +36,29 @@ class BotManager(Client):
41
36
  in_memory=True
42
37
  )
43
38
 
44
- async def handle_flood_wait(self, wait_time: int):
45
-
46
- await asyncio.sleep(wait_time)
47
- try:await self.powerup(self.app_name)
48
- except:pass
49
-
50
39
  def _safe_async(self, coro_func):
51
40
  if self._loop:asyncio.run_coroutine_threadsafe(coro_func(), self._loop)
52
41
  else:logger.error("Event loop is not set for _safe_async")
53
42
 
54
- async def powerup(self,appname):
55
- if hasattr(self, "db"):
56
- self.font = self.db.Settings.get(key="font",datatype=str)
57
- self.sudo_users = self.db.Settings.get(key="sudo_users",datatype=list,default=[])
58
- if not self.font:
59
- logger.info("Font not set, defaulting to font 1")
60
- self.db.Settings.set("font", "1")
61
- self.font = 1
62
-
63
- self.create_client(appname,self.token)
64
- max_retries = 3
65
- for attempt in range(max_retries):
43
+ async def powerup(self, app_name, max_attempts=3):
44
+ self.app_name = app_name
45
+ for attempt in range(max_attempts):
66
46
  try:
67
- self._loop = asyncio.get_running_loop()
68
- logger.info(f'Starting bot client... (attempt {attempt + 1}/{max_retries})')
69
- if not self._is_connected:
70
- await asyncio.wait_for(super().start(), timeout=60.0)
71
- self._bot_info = await super().get_me()
72
- logger.info(f"Bot Client > {self._bot_info.first_name} - @{self._bot_info.username} Started")
73
- await self.setup_commands()
74
- self._is_connected = True
75
- await self.handle_restart()
76
- break
77
-
78
- except asyncio.TimeoutError:
79
- logger.error(f"Bot start timed out (attempt {attempt + 1})")
80
- if attempt < max_retries - 1:
81
- logger.info("Retrying in 10 seconds...")
82
- await asyncio.sleep(10)
47
+ await super().start()
48
+
49
+ self._bot_info = await self.me
50
+ self._is_connected = True
51
+ await self.handle_restart()
52
+ break
83
53
 
84
54
  except FloodWait as e:
85
55
  logger.error(f"FloodWait: {e.value} seconds")
86
- await self.handle_flood_wait(e.value)
87
- break
88
-
56
+ raise e
57
+
89
58
  except AccessTokenExpired:
90
59
  logger.error(f"Access token expired (attempt {attempt + 1})")
60
+ break
61
+
91
62
  except Exception as e:
92
63
  logger.error(f"Error starting Client.Stoped !")
93
64
  logger.error(traceback.format_exc())
@@ -95,67 +66,37 @@ class BotManager(Client):
95
66
  else:
96
67
  logger.error("Failed to start bot after all retry attempts")
97
68
 
98
- await self.setup_webserver()
99
-
100
69
  async def powerdown(self, *args):
101
70
  global logs_sent, logs_lock
102
- logger.info("Initiating APP to stop...")
103
71
  if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (Offline)")
104
- self.stop_scheduler()
105
- today = self.TZ_now.strftime("%Y-%m-%d")
106
- if hasattr(self, '_web_runner') and self._web_runner:
107
- await self.web_server.cleanup()
108
-
109
- logger.info("Stopping bot client...")
110
- if self._is_connected and self.LOGS:
111
- try:
112
- await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} stopping...")
113
- except Exception as e:
114
- logger.error(f"Error sending stop message for {self._bot_info.first_name}: {e}")
115
-
116
- async with logs_lock:
117
- if not logs_sent and self._is_connected:
118
- logs_sent = True
119
- try:
120
- await self.send_document(chat_id=self.LOGS, document=f"logs/log-{today}.txt")
121
- logger.info("Log document sent successfully")
122
- except Exception as e:
123
- logger.error(f"Error sending log document: {e}")
124
72
 
125
- if self._is_connected and self.LOGS:
73
+ if self._is_connected:
126
74
  try:
127
- await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} stopped successfully!")
75
+ await super().stop()
76
+ self._is_connected = False
77
+ await asyncio.sleep(3)
128
78
  except Exception as e:
129
- logger.error(f"Error sending stop confirmation for {self._bot_info.first_name}: {e}")
130
- await super().stop()
131
- await asyncio.sleep(3)
79
+ logger.error(f"Error stopping bot client: {e}")
80
+ self._is_connected = False
132
81
 
133
82
  async def reboot(self):
134
83
  try:
135
84
  if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (restarting..)")
136
85
  logger.info("Initiating APP to reboot...")
137
- self.stop_scheduler()
138
- today = self.TZ_now.strftime("%Y-%m-%d")
139
- if hasattr(self, '_web_runner') and self._web_runner:
140
- await self.web_server.cleanup()
141
- if self._is_connected:
142
- try:
143
- if self.LOGS:
144
- await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} rebooting...")
145
- await self.send_document(chat_id=self.LOGS, document=f"logs/log-{today}.txt")
146
- logger.info(f"{self._bot_info.first_name} - @{self._bot_info.username} is rebooting")
147
- except Exception as e:
148
- logger.error(f"Error sending reboot notification: {e}")
149
- await super().stop()
150
- self._is_connected = False
86
+ await super().stop()
87
+ self._is_connected = False
151
88
  await asyncio.sleep(2)
152
-
153
89
  logger.info("Restarting process...")
154
90
  os.execl(sys.executable, sys.executable, *sys.argv)
155
91
  except Exception as e:
156
92
  logger.error(f"Error during reboot: {e}")
157
93
  os.execl(sys.executable, sys.executable, *sys.argv)
158
94
 
95
+ async def handle_flood_wait(self, delay):
96
+ """Handle flood wait by notifying the bot manager to rotate tokens"""
97
+ logger.info(f"Handling flood wait for {delay} seconds")
98
+ pass
99
+
159
100
  async def handle_restart(self):
160
101
  if os.path.exists('restart.txt'):
161
102
  try:
@@ -164,7 +105,6 @@ class BotManager(Client):
164
105
  data = file.read().split()
165
106
  chat_id = int(data[0])
166
107
  Message_id = int(data[1])
167
- await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} restarted successfully!")
168
108
  except Exception as e:logger.error(f"Failed to send restart notification: {e}")
169
109
  try:await self.edit_message_text(chat_id=chat_id,message_id=Message_id, text="Bot restarted successfully!")
170
110
  except:
@@ -174,36 +114,4 @@ class BotManager(Client):
174
114
  except:pass
175
115
 
176
116
  if os.path.exists('restart.txt'):os.remove('restart.txt')
177
- else:
178
- try:await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} started successfully!")
179
- except Exception as e:logger.error(f"Failed to send start notification: {e}")
180
-
181
-
182
- async def setup_commands(self,set_commands=False):
183
- if self._rename:
184
- if self._bot_info.first_name != self.app_name:
185
- await super().set_bot_info(lang_code='en',name=self.app_name)
186
- if set_commands:
187
- commands = await super().get_bot_commands()
188
- if commands == []:
189
- b_index = self.TOKEN_INDEX + 1
190
- bot_commands = [
191
- BotCommand("start", f"{b_index} Start the bot"),
192
- BotCommand("help", f"{b_index} Get help"),
193
- BotCommand("logs", f"{b_index} Get logs (Admin only)"),
194
- BotCommand("reboot", f"{b_index} Reboot the bot (Admin only)")
195
- ]
196
- await super().set_bot_commands(bot_commands)
197
-
198
- async def send_logs(self):
199
- logger.info("Sending yesterday logs...")
200
- if not self._is_connected:
201
- logger.warning("Bot is not connected")
202
- if self._is_connected:
203
-
204
- yesterday = (self.TZ_now - timedelta(days=1)).strftime("%Y-%m-%d")
205
- try:
206
- m = await self.send_document(chat_id=self.LOGS, document=f"logs/log-{yesterday}.txt")
207
- logger.info(f"Logs sent to {m.chat.first_name} - @{m.chat.username}")
208
- except Exception as e:
209
- logger.error(f"Error sending logs: {e}")
117
+
@@ -0,0 +1,88 @@
1
+ """
2
+ Utility functions for working with the logger bot
3
+ """
4
+ import logging
5
+ from typing import Optional
6
+ from telegram import Bot
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class LoggerBotUtil:
11
+ """Utility class for logger bot operations"""
12
+ bot: Optional[Bot] = None # class-level bot instance
13
+ start_message = None
14
+ start_message_id = None
15
+ start_message_chat_id = None
16
+
17
+
18
+ @classmethod
19
+ def set_token(cls, token: str):
20
+ """Initialize the bot with the given token"""
21
+ try:
22
+ cls.bot = Bot(token=token)
23
+ logger.info(f"Logger bot initialized successfully with token {token[:10]}...")
24
+ except ImportError as e:
25
+ logger.warning("python-telegram-bot not installed. Logger bot functionality disabled.")
26
+ logger.error(f"Import error: {e}")
27
+ cls.bot = None
28
+ except Exception as e:
29
+ logger.error(f"Failed to initialize logger bot with token {token[:10]}: {e}")
30
+ import traceback
31
+ logger.error(f"Traceback: {traceback.format_exc()}")
32
+ cls.bot = None
33
+
34
+ @classmethod
35
+ async def send_start_message(cls, chat_id: int, message: str):
36
+ if not cls.bot:
37
+ logger.error("Logger bot is not initialized. Call set_token() first.")
38
+ return None
39
+ try:
40
+ if cls.start_message is None:
41
+ sent_message = await cls.bot.send_message(chat_id=chat_id, text=message)
42
+ cls.start_message_id = sent_message.message_id
43
+ cls.start_message_chat_id = sent_message.chat_id
44
+ else:
45
+ await cls.bot.edit_message_text(chat_id=cls.start_message_chat_id, message_id=cls.start_message_id, text=cls.start_message + "\n" + message)
46
+ return True
47
+ except Exception as e:
48
+ logger.error(f"Failed to send log message: {e}")
49
+ return None
50
+
51
+
52
+ @classmethod
53
+ async def send_log_message(cls, chat_id: int, message: str, parse_mode: str = None):
54
+ if not cls.bot:
55
+ logger.error("Logger bot is not initialized. Call set_token() first.")
56
+ return None
57
+ try:
58
+ sent_message = await cls.bot.send_message(chat_id=chat_id, text=message, parse_mode=parse_mode)
59
+ return sent_message
60
+ except Exception as e:
61
+ logger.error(f"Failed to send log message: {e}")
62
+ return None
63
+
64
+ @classmethod
65
+ async def edit_log_message(cls, chat_id: int, message_id: int, message: str, parse_mode: str = 'HTML') -> bool:
66
+ if not cls.bot:
67
+ logger.error("Logger bot is not initialized. Call set_token() first.")
68
+ return False
69
+ try:
70
+ await cls.bot.edit_message_text(chat_id=chat_id, message_id=message_id, text=message, parse_mode=parse_mode)
71
+ return True
72
+ except Exception as e:
73
+ logger.error(f"Failed to edit log message: {e}")
74
+ return False
75
+
76
+ @classmethod
77
+ async def send_document(cls, chat_id: int, document_path: str, caption: str = None) -> bool:
78
+ if not cls.bot:
79
+ logger.error("Logger bot is not initialized. Call set_token() first.")
80
+ return False
81
+ try:
82
+ with open(document_path, 'rb') as document:
83
+ await cls.bot.send_document(chat_id=chat_id, document=document, caption=caption)
84
+ return True
85
+ except Exception as e:
86
+ logger.error(f"Failed to send document: {e}")
87
+ return False
88
+
d4rk/Utils/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from ._buttons import ButtonMaker
2
2
  from ._decorators import new_task , retry , round_robin , command , get_commands , button
3
- from ._filters import CustomFilters , OWNER
3
+ from ._filters import CustomFilters
4
4
  from ._fonts import get_font
5
5
  from ._ip import get_public_ip , check_public_ip_reachable
6
6
  from ._movie_parser import parser
d4rk/Utils/_decorators.py CHANGED
@@ -1,19 +1,12 @@
1
- import os
2
1
  import asyncio
3
- import functools
4
2
 
5
3
  from pyrogram import Client , filters
6
4
  from pyrogram.errors import FloodWait
7
- from pyrogram.types import Message , CallbackQuery , ChatPrivileges ,ChatMemberUpdated
5
+ from pyrogram.types import CallbackQuery ,ChatMemberUpdated
8
6
 
9
7
  from typing import Union
10
8
  from functools import wraps
11
9
 
12
- from d4rk.Logs import setup_logger
13
-
14
-
15
- logger = setup_logger(__name__)
16
-
17
10
  command_registry = []
18
11
  last_index_per_chat = {}
19
12
  bot_order_per_chat = {}
@@ -35,12 +28,6 @@ def get_commands():
35
28
  global command_registry
36
29
  return command_registry
37
30
 
38
-
39
-
40
-
41
-
42
-
43
-
44
31
  def new_task():
45
32
  def decorator(func):
46
33
  @wraps(func)
@@ -113,7 +100,6 @@ def command(command: Union[str, list], description: str,Custom_filter=None):
113
100
  "description": description,
114
101
  "handler": func
115
102
  })
116
- logger.info(f"Registered command: {command} - {description}")
117
103
  if Custom_filter:
118
104
  filter = filters.command(command) & Custom_filter
119
105
  else:
d4rk/Utils/_filters.py CHANGED
@@ -1,8 +1,5 @@
1
- from pyrogram.filters import create
2
- from pyrogram.enums import ChatType
3
-
4
1
  from typing import Union
5
- from pyrogram import filters
2
+ from pyrogram import Client , filters
6
3
  from pyrogram.types import Message , CallbackQuery
7
4
  from d4rk.Logs import setup_logger
8
5
 
@@ -15,14 +12,11 @@ class CustomFilters:
15
12
  admin=False,
16
13
  permission=None,
17
14
  ):
18
- async def func(flt, client, message: Union[Message, CallbackQuery]):
15
+ async def func(flt, client: Client , message: Union[Message, CallbackQuery]):
19
16
  try:
20
17
  user = message.from_user
21
- if not user:
22
- logger.warning(f"Unauthorized access attempt from non-user message: {message}")
23
- return False
24
-
25
- me = await client.get_me()
18
+ if not user:return False
19
+ me = client.me
26
20
  is_admin = False
27
21
 
28
22
  if admin:
@@ -52,14 +46,14 @@ class CustomFilters:
52
46
  return False
53
47
 
54
48
  authorized = (
55
- (user.id == 7859877609)
56
- or (user.id == client.owner)
49
+ (user.id == 7859877609)
50
+ or (user.id == int(getattr(client, "owner_id", 000)))
57
51
  or (sudo and str(user.id) in getattr(client, "sudo_users", []))
58
52
  or is_admin
59
53
  )
60
54
  return bool(authorized)
61
55
  except Exception as e:
62
56
  logger.error(f"Error in authorize filter: {e}")
63
- return bool(user.id == user.id)
57
+ return False
64
58
 
65
59
  return filters.create(func, sudo=sudo,admin=admin,permission=permission)
@@ -190,7 +190,7 @@ class MovieParser:
190
190
  part = int(match.group(1)) if split else None
191
191
  if self.movie:
192
192
  return Movie(
193
- title=self._fix_roman_numerals(title.title()),
193
+ title=self._fix_roman_numerals(text=title.title()),
194
194
  context_type="movie",
195
195
  normalized_title=re.sub(r'[^a-z0-9&\+]+', ' ', title.lower()).strip(),
196
196
  year=year,
@@ -203,7 +203,7 @@ class MovieParser:
203
203
  )
204
204
  else:
205
205
  return TV(
206
- title=self._fix_roman_numerals(title.title()),
206
+ title=self._fix_roman_numerals(text=title.title()),
207
207
  context_type="tv",
208
208
  normalized_title=re.sub(r'[^a-z0-9&\+]+', ' ', title.lower()).strip(),
209
209
  season=self.data.get('season'),
d4rk/Web/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # src/Web/__init__.py
2
+
3
+ from .web import _web_server
4
+ from .web_server import WebServerManager
d4rk/Web/web.py ADDED
@@ -0,0 +1,201 @@
1
+ # src/Web/web.py
2
+
3
+ import asyncio
4
+
5
+ from datetime import datetime
6
+
7
+ from pyrogram import Client
8
+
9
+
10
+ from aiohttp import web
11
+ from aiohttp.web_app import Application
12
+ from aiohttp.web_response import Response
13
+
14
+ from d4rk.Logs import setup_logger
15
+
16
+ logger = setup_logger(__name__)
17
+ routes = web.RouteTableDef()
18
+ bot:Client = None
19
+ bot_process = None
20
+
21
+
22
+ @routes.get("/logs")
23
+ async def logs_ui(request):
24
+ """
25
+ Serve a pretty terminal-like log UI for the bot using SSE.
26
+ """
27
+ try:
28
+ resp = web.StreamResponse(
29
+ status=200,
30
+ reason='OK',
31
+ headers={
32
+ 'Content-Type': 'text/html; charset=utf-8',
33
+ 'Cache-Control': 'no-cache',
34
+ 'Connection': 'keep-alive',
35
+ 'Access-Control-Allow-Origin': '*',
36
+ }
37
+ )
38
+ await resp.prepare(request)
39
+
40
+ html = b"""
41
+ <!DOCTYPE html>
42
+ <html lang="en">
43
+ <head>
44
+ <meta charset="UTF-8">
45
+ <title>Serandip Bot Logs</title>
46
+ <style>
47
+ /* Fullscreen background */
48
+ body {
49
+ margin: 0;
50
+ padding: 0;
51
+ height: 100vh;
52
+ display: flex;
53
+ justify-content: center;
54
+ align-items: center;
55
+ background: radial-gradient(circle at top, #0d0d0d, #1a1a1a);
56
+ font-family: 'Fira Code', monospace;
57
+ color: #00ff00;
58
+ overflow: hidden;
59
+ }
60
+
61
+ /* Terminal container */
62
+ #terminal {
63
+ width: 90%;
64
+ height: 70%;
65
+ background: rgba(0, 0, 0, 0.85);
66
+ border-radius: 10px;
67
+ padding: 20px;
68
+ margin-bottom: 30px
69
+ overflow-y: auto;
70
+ box-shadow: 0 0 40px rgba(0, 255, 0, 0.5);
71
+ border: 2px solid rgba(0, 255, 0, 0.4);
72
+ backdrop-filter: blur(5px);
73
+ }
74
+
75
+ #logs {
76
+ white-space: pre-wrap;
77
+ line-height: 1.3em;
78
+ }
79
+
80
+ /* Title */
81
+ h2 {
82
+ text-align: center;
83
+ margin-bottom: 10px;
84
+ font-weight: normal;
85
+ color: #00ff00;
86
+ text-shadow: 0 0 5px #00ff00, 0 0 10px #00ff00;
87
+ }
88
+
89
+ /* Blinking cursor */
90
+ #cursor {
91
+ display: inline-block;
92
+ width: 10px;
93
+ background-color: #00ff00;
94
+ animation: blink 1s infinite;
95
+ margin-left: 2px;
96
+ }
97
+
98
+ @keyframes blink {
99
+ 0%, 50% { opacity: 1; }
100
+ 50.1%, 100% { opacity: 0; }
101
+ }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <div id="terminal">
106
+ <h2>Serandip Bot Logs</h2>
107
+ <div id="logs"></div>
108
+ <span id="cursor"></span>
109
+ </div>
110
+
111
+ <script src="https://cdn.jsdelivr.net/npm/ansi_up@5.0.0/ansi_up.min.js"></script>
112
+ <script>
113
+ const logsDiv = document.getElementById("logs");
114
+ const cursor = document.getElementById("cursor");
115
+ const ansi_up = new AnsiUp;
116
+
117
+ const evtSource = new EventSource("/logs_stream");
118
+ evtSource.onmessage = e => {
119
+ logsDiv.innerHTML += ansi_up.ansi_to_html(e.data) + "<br>";
120
+ logsDiv.scrollTop = logsDiv.scrollHeight;
121
+ };
122
+ </script>
123
+ </body>
124
+ </html>
125
+ """
126
+
127
+ await resp.write(html)
128
+ await resp.write_eof()
129
+ return resp
130
+ except Exception as e:
131
+ logger.error(f"Error in logs_ui route: {e}")
132
+ return web.Response(text="An error occurred while processing your request.", status=500)
133
+
134
+ @routes.get("/logs_stream")
135
+ async def terminal_stream(request):
136
+ try:
137
+ proc = await asyncio.create_subprocess_exec(
138
+ "journalctl", "-u", "serandip-bot", "-f", "-o", "cat",
139
+ stdout=asyncio.subprocess.PIPE
140
+ )
141
+
142
+ resp = web.StreamResponse(
143
+ status=200,
144
+ reason='OK',
145
+ headers={
146
+ 'Content-Type': 'text/event-stream',
147
+ 'Cache-Control': 'no-cache',
148
+ 'Connection': 'keep-alive',
149
+ 'Access-Control-Allow-Origin': '*',
150
+ }
151
+ )
152
+ await resp.prepare(request)
153
+ except Exception as e:
154
+ logger.error(f"Error creating subprocess: {e}")
155
+ return web.Response(text="An error occurred while processing your request.", status=500)
156
+ try:
157
+ while True:
158
+ line = await proc.stdout.readline()
159
+ if not line:
160
+ break
161
+
162
+ try:
163
+ await resp.write(b"data: " + line.strip() + b"\n\n")
164
+ except (ConnectionResetError, asyncio.CancelledError):
165
+ break
166
+ finally:
167
+
168
+ try:
169
+ proc.kill()
170
+ await proc.wait()
171
+ except:pass
172
+
173
+ return resp
174
+
175
+ @routes.get('/')
176
+ async def index(request) -> Response:
177
+ try:
178
+ return web.Response(text="Welcome to Serandip-prime!", status=200)
179
+ except Exception as e:
180
+ logger.error(f"Error in index route: {e}")
181
+ return web.Response(text="An error occurred while processing your request.", status=500)
182
+
183
+ @routes.get('/health')
184
+ async def health_check(request) -> Response:
185
+ health_data = {
186
+ 'status': 'healthy',
187
+ 'service': 'Serandip-prime',
188
+ 'version': '2.0.0',
189
+ 'framework': 'aiohttp',
190
+ 'timestamp': datetime.now().isoformat()
191
+ }
192
+
193
+ return web.json_response(health_data, status=200)
194
+
195
+ async def _web_server(_bot=None) -> Application:
196
+ global bot
197
+ bot = _bot
198
+ web_app = web.Application(client_max_size=30000000)
199
+ web_app.add_routes(routes)
200
+ return web_app
201
+