diff --git a/src/core/Client.py b/src/core/Client.py index e68233c..ef0e4a8 100644 --- a/src/core/Client.py +++ b/src/core/Client.py @@ -9,7 +9,7 @@ import json import math import time import zlib -from asyncio import Lock +from asyncio import Queue from core import utils @@ -21,7 +21,19 @@ class Client: self.__writer = writer self._core = core self.__alive = True - self.__packets_queue = [] + + self.__queue_tpc = Queue() + self.__queue_udp = Queue() + + self._tpc_count = 0 + self._udp_count = 0 + self._tpc_count_total = 0 + self._udp_count_total = 0 + self._udp_size_total = 0 + self._tpc_size_total = 0 + self.tcp_pps = 0 + self.udp_pps = 0 + self.__tasks = [] self._down_sock = (None, None) self._udp_sock = (None, None) @@ -41,7 +53,7 @@ class Client: self._unicycle = {"id": -1, "packet": ""} self._connect_time = 0 self._last_position = {} - self._lock = Lock() + self._last_recv = time.monotonic() @property def _writer(self): @@ -132,7 +144,7 @@ class Client: to_all = False await self._send(f"C:{message}", to_all=to_all) - async def send_event(self, event_name, event_data, to_all=True): + async def send_event(self, event_name, event_data, to_all=False): self.log.debug(f"send_event: {event_name}:{event_data}; {to_all=}") if not self.ready: self.log.debug(f"Client not ready.") @@ -142,7 +154,7 @@ class Client: if len(event_data) > 104857599: self.log.error("Client data too big! >=104857599") return - await self._send(f"E:{event_name}:{event_data}", to_all=to_all) + await self._send(f"E:{event_name}:{event_data}", to_all, True) async def _send(self, data, to_all=False, to_self=True, to_udp=False, writer=None): @@ -181,7 +193,7 @@ class Client: if udp_sock and udp_addr: try: if not udp_sock.is_closing(): - # self.log.debug(f'[UDP] {data!r}') + # self.log.debug(f'[UDP] {data!r}; {udp_addr}') udp_sock.sendto(data, udp_addr) except OSError: self.log.debug("[UDP] Error sending") @@ -220,12 +232,11 @@ class Client: self.is_disconnected() if self.__alive: if header == b"": - self.__packets_queue.append(None) + await self._tpc_put(None) self.__alive = False continue self.log.error(f"Header: {header}") await self.kick("Invalid packet - header negative") - self.__packets_queue.append(None) continue if int_header > 100 * MB: @@ -233,7 +244,6 @@ class Client: self.log.warning("Client sent header of >100MB - " "assuming malicious intent and disconnecting the client.") self.log.error(f"Last recv: {await self.__reader.read(100 * MB)}") - self.__packets_queue.append(None) continue data = b"" @@ -251,11 +261,11 @@ class Client: if one: return data - self.__packets_queue.append(data) + await self._tpc_put(data) except ConnectionError: self.__alive = False - self.__packets_queue.append(None) + await self._tpc_put(None) async def _split_load(self, start, end, d_sock, filename, speed_limit=None): real_size = end - start @@ -656,8 +666,8 @@ class Client: self.log.info(f"{self.nick}: {msg}") await self._send(data, to_all=True) - async def _handle_codes(self, data): - if not data: + async def _handle_codes_tcp(self, data): + if data is None: self.__alive = False return @@ -676,17 +686,14 @@ class Client: match data[0]: # At data[0] code case "H": # Map load, client ready await self._connected_handler() - case "C": # Chat handler if _bytes: return await self._chat_handler(data) - case "O": # Cars handler if _bytes: return await self._handle_car_codes(data) - case "E": # Client events handler if len(data) < 2: self.log.debug("Tried to send an empty event, ignoring.") @@ -704,7 +711,75 @@ class Client: ev.call_event(event_name, data=even_data, player=self) await ev.call_async_event(event_name, data=even_data, player=self) case _: - self.log.warning(f"TCP [{self.cid}] Unknown code: {data[0]}; {data}") + self.log.warning(f"TCP Unknown code: {data[0]}; {data}") + + async def _handle_codes_udp(self, data): + code = data[2:3].decode() + data = data[2:].decode() + match code: + case "p": # Ping packet + ev.call_event("onSentPing", player=self) + await self._send(b"p", to_udp=True) + case "Z": # Position packet + sub = data.find("{", 1) + last_pos = data[sub:] + try: + _, car_id = self._get_cid_vid(data) + if self._cars[car_id]: + last_pos = json.loads(last_pos) + self._last_position = last_pos + self._cars[car_id]['pos'] = last_pos + ev.call_event("onChangePosition", data, player=self, pos=last_pos) + except Exception as e: + self.log.warning(f"Cannot parse position packet: {e}") + self.log.debug(f"data: '{data}', sub: {sub}") + self.log.debug(f"last_pos ({type(last_pos)}): {last_pos}") + await self._send(data, True, False, True) + case "X": + await self._send(data, True, False, True) + case _: + self.log.warning(f"UDP Unknown code: {code}; {data}") + + def _tick_pps(self, _): + self.tcp_pps = self._tpc_count + self.udp_pps = self._udp_count + self._tpc_count = 0 + self._udp_count = 0 + if self.tcp_pps > self._core.target_tps or self.udp_pps > self._core.target_tps: + self.log.warning(f"PPS > TPS; PPS: TPC: {self.tcp_pps}, UDP: {self.udp_pps}") + + async def __tick_player_tpc(self, _): + try: + if self.__queue_tpc.qsize() > 0: + packet = await self.__queue_tpc.get() + if packet is None: + return await self._remove_me() + await self._handle_codes_tcp(packet) + except Exception as e: + self.log.error(f'[TPC] Error while ticking player:') + self.log.exception(e) + + async def __tick_player_udp(self, _): + try: + if self.__queue_udp.qsize() > 0: + packet = await self.__queue_udp.get() + await self._handle_codes_udp(packet) + except Exception as e: + self.log.error(f'[UDP] Error while ticking player:') + self.log.exception(e) + + async def _tpc_put(self, packet): + if packet: + self._tpc_count += 1 + self._tpc_count_total += 1 + self._tpc_size_total += len(packet) + await self.__queue_tpc.put(packet) + + async def _udp_put(self, packet): + self._udp_count += 1 + self._udp_count_total += 1 + self._udp_size_total += len(packet) + await self.__queue_udp.put(packet) async def _looper(self): ev.call_lua_event("onPlayerConnecting", self.cid) @@ -712,58 +787,47 @@ class Client: await self._send(f"P{self.cid}") # Send clientID await self._sync_resources() ev.call_lua_event("onPlayerJoining", self.cid) - tasks = self.__tasks - recv = asyncio.create_task(self._recv()) - tasks.append(recv) - self._synced = True - while self.__alive: - if len(self.__packets_queue) > 0: - for index, packet in enumerate(self.__packets_queue): - # self.log.debug(f"Packet: {packet}") - del self.__packets_queue[index] - task = self._loop.create_task(self._handle_codes(packet)) - tasks.append(task) - else: - await asyncio.sleep(0.1) - await asyncio.gather(*tasks) + ev.register("serverTick", self.__tick_player_tpc) + ev.register("serverTick", self.__tick_player_udp) + ev.register("serverTick_1s", self._tick_pps) + await self._recv() async def _remove_me(self): await asyncio.sleep(0.3) self.__alive = False - if (self.cid > 0 or self.nick is not None) and \ - self._core.clients_by_nick.get(self.nick): + if self._core.clients_by_nick.get(self.nick): for i, car in enumerate(self._cars): if not car: continue self.log.debug(f"Removing car: car_id={i}") await self._send(f"Od:{self.cid}-{i}", to_all=True, to_self=False) if self.ready: - await self._send(f"J{self.nick} disconnected!", to_all=True, to_self=False) # I'm disconnected. + await self._send(f"J{self.nick} disconnected!", to_all=True, to_self=False) self.log.debug(f"Removing client") ev.call_lua_event("onPlayerDisconnect", self.cid) ev.call_event("onPlayerDisconnect", player=self) await ev.call_async_event("onPlayerDisconnect", player=self) - - self.log.info( - i18n.client_player_disconnected.format( - round((time.monotonic() - self._connect_time) / 60, 2) - ) - ) + ev.unregister(self.__tick_player_tpc) + ev.unregister(self.__tick_player_udp) + ev.unregister(self._tick_pps) + gt = round((time.monotonic() - self._connect_time) / 60, 2) + self.log.info(i18n.client_player_disconnected.format(gt)) self._core.clients[self.cid] = None del self._core.clients_by_id[self.cid] del self._core.clients_by_nick[self.nick] else: self.log.debug(f"Removing client; Closing connection...") + self.log.debug(f"TPC: Packets: {self._tpc_count_total}; Size: {self._tpc_size_total}") + self.log.debug(f"UDP: Packets: {self._udp_size_total}; Size: {self._udp_size_total}") + await asyncio.sleep(0.001) try: - if not self.__writer.is_closing(): - self.__writer.close() - await self.__writer.wait_closed() + self.__writer.close() + await self.__writer.wait_closed() except Exception as e: self.log.debug(f"Error while closing writer: {e}") try: _, down_w = self._down_sock - if down_w and not down_w.is_closing(): - down_w.close() - await down_w.wait_closed() + down_w.close() + await down_w.wait_closed() except Exception as e: self.log.debug(f"Error while closing download writer: {e}") diff --git a/src/core/Client.pyi b/src/core/Client.pyi index 0af0c0b..58e0b6b 100644 --- a/src/core/Client.pyi +++ b/src/core/Client.pyi @@ -5,7 +5,7 @@ # Licence: FPA # (c) kuitoi.su 2023 import asyncio -from asyncio import StreamReader, StreamWriter, DatagramTransport, Lock +from asyncio import StreamReader, StreamWriter, DatagramTransport, Lock, Queue from logging import Logger from typing import Tuple, List, Dict, Optional, Union, Any @@ -19,7 +19,16 @@ class Client: self.__tasks = [] self.__reader = reader self.__writer = writer - self.__packets_queue = [] + self.__queue_tpc = Queue() + self.__queue_udp = Queue() + self._tpc_count = 0 + self._udp_count = 0 + self._tpc_count_total = 0 + self._udp_count_total = 0 + self._udp_size_total = 0 + self._tpc_size_total = 0 + self.tcp_pps = 0 + self.udp_pps = 0 self._udp_sock: Tuple[DatagramTransport | None, Tuple[str, int] | None] = (None, None) self._down_sock: Tuple[StreamReader | None, StreamWriter | None] = (None, None) self._log = utils.get_logger("client(id: )") @@ -87,7 +96,13 @@ class Client: async def _handle_car_codes(self, data: str) -> None: ... async def _connected_handler(self) -> None: ... async def _chat_handler(self, data: str) -> None: ... - async def _handle_codes(self, data: bytes) -> None: ... + async def _handle_codes_tcp(self, data: bytes) -> None: ... + async def _handle_codes_udp(self, data: bytes) -> None: ... + def _tick_pps(self, _): ... + async def __tick_player_tpc(self, _): ... + async def __tick_player_udp(self, _): ... + async def _tpc_put(self, data): ... + async def _udp_put(self, data): ... async def _looper(self) -> None: ... def _update_logger(self) -> None: ... async def _remove_me(self) -> None: ... diff --git a/src/core/__init__.py b/src/core/__init__.py index 276e77f..6f085a8 100644 --- a/src/core/__init__.py +++ b/src/core/__init__.py @@ -10,7 +10,7 @@ __title__ = 'KuiToi-Server' __description__ = 'BeamingDrive Multiplayer server compatible with BeamMP clients.' __url__ = 'https://github.com/kuitoi/kuitoi-Server' __version__ = '0.4.8 (pre)' -__build__ = 2542 # Я это считаю лог файлами +__build__ = 2663 # Я это считаю лог файлами __author__ = 'SantaSpeen' __author_email__ = 'admin@kuitoi.su' __license__ = "FPA" @@ -18,6 +18,7 @@ __copyright__ = 'Copyright 2024 © SantaSpeen (Maxim Khomutov)' import asyncio import builtins +import sys import webbrowser import prompt_toolkit.shortcuts as shortcuts @@ -36,6 +37,8 @@ if args.version: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) +if sys.platform == 'win32': + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) log = get_logger("core.init") # Config file init diff --git a/src/core/core.py b/src/core/core.py index 5a16919..1ce2f78 100644 --- a/src/core/core.py +++ b/src/core/core.py @@ -26,6 +26,7 @@ def calc_ticks(ticks, duration): ticks.popleft() return len(ticks) / duration + loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) @@ -50,7 +51,11 @@ class Core: self.tcp = TCPServer self.udp = UDPServer + self.tcp_pps = 0 + self.udp_pps = 0 + self.tps = 10 + self.target_tps = 60 self.lock_upload = False @@ -142,6 +147,12 @@ class Core: continue await client.kick("Server shutdown!") + async def __gracefully_remove(self): + for client in self.clients: + if not client: + continue + await client._remove_me() + # noinspection SpellCheckingInspection,PyPep8Naming async def heartbeat(self, test=False): try: @@ -257,7 +268,6 @@ class Core: return "Client not found." async def _useful_ticks(self, _): - target_tps = 20 tasks = [] self.tick_counter += 1 events = { @@ -272,32 +282,34 @@ class Core: 60: "serverTick_60s" } for interval in sorted(events.keys(), reverse=True): - if self.tick_counter % (interval * target_tps) == 0: + if self.tick_counter % (interval * self.target_tps) == 0: ev.call_event(events[interval]) tasks.append(ev.call_async_event(events[interval])) await asyncio.gather(*tasks) - if self.tick_counter == (60 * target_tps): + if self.tick_counter == (60 * self.target_tps): self.tick_counter = 0 async def _tick(self): try: ticks = 0 - target_tps = 20 - target_interval = 1 / target_tps + target_tps = self.target_tps last_tick_time = time.monotonic() ev.register("serverTick", self._useful_ticks) ticks_2s = deque(maxlen=2 * int(target_tps) + 1) ticks_5s = deque(maxlen=5 * int(target_tps) + 1) ticks_30s = deque(maxlen=30 * int(target_tps) + 1) ticks_60s = deque(maxlen=60 * int(target_tps) + 1) - console.add_command("tps", lambda - _: f"{calc_ticks(ticks_2s, 2):.2f}TPS; last: {calc_ticks(ticks_5s, 5):.2f}TPS/5s; {calc_ticks(ticks_30s, 30):.2f}TPS/30s; {calc_ticks(ticks_60s, 60):.2f}TPS/60s;", + console.add_command("tps", lambda _: f"{calc_ticks(ticks_2s, 2):.2f}TPS; For last 5s, 30s, 60s: " + f"last: {calc_ticks(ticks_5s, 5):.2f}," + f"{calc_ticks(ticks_30s, 30):.2f}," + f"{calc_ticks(ticks_60s, 60):.2f}.", None, "Print TPS", {"tps": None}) - _add_to_sleep = deque(maxlen=13 * int(target_tps)) - _add_to_sleep.append(0.013) + _add_to_sleep = deque([0.0, 0.0, 0.0,], maxlen=3 * int(target_tps)) + _t0 = [] self.log.debug("tick system started") while self.run: + target_interval = 1 / self.target_tps start_time = time.monotonic() ev.call_event("serverTick") @@ -306,6 +318,7 @@ class Core: # Calculate the time taken for this tick end_time = time.monotonic() tick_duration = end_time - start_time + _t0.append(tick_duration) # Calculate the time to sleep to maintain target TPS sleep_time = target_interval - tick_duration - statistics.fmean(_add_to_sleep) @@ -327,14 +340,14 @@ class Core: # if self.tps < 5: # self.log.warning(f"Low TPS: {self.tps:.2f}") # Reset for next calculation + _t0s = max(_t0), min(_t0), statistics.fmean(_t0) + _tw = max(_add_to_sleep), min(_add_to_sleep), statistics.fmean(_add_to_sleep) + self.log.debug(f"[{'OK' if sleep_time > 0 else "CHECK"}] TPS: {self.tps:.2f}; Tt={_t0s}; Ts={sleep_time}; Tw={_tw}") + _t0 = [] last_tick_time = current_time ticks = 0 - tw = time.monotonic() - start_time - sleep_time - _add_to_sleep.append(tw) - # if elapsed_time >= 1: - # self.log.debug( - # f"ts: {sleep_time}; tw: {tw}; tw-ts: {tw - sleep_time} ({statistics.fmean(_add_to_sleep)});") + _add_to_sleep.append(time.monotonic() - start_time - sleep_time) self.log.debug("tick system stopped") except Exception as e: self.log.exception(e) @@ -377,7 +390,7 @@ class Core: self.log.info(i18n.init_ok) await self.heartbeat(True) - for i in range(int(config.Game["players"] * 2.3)): # * 2.3 For down sock and buffer. + for i in range(int(config.Game["players"] * 4)): # * 4 For down sock and buffer. self.clients.append(None) tasks = [] ev.register("serverTick_1s", self._check_alive) @@ -402,7 +415,7 @@ class Core: except KeyboardInterrupt: pass except Exception as e: - self.log.error(f"Exception: {e}") + self.log.error(f"Exception in main:") self.log.exception(e) finally: await self.stop() @@ -413,19 +426,24 @@ class Core: async def stop(self): self.run = False ev.call_lua_event("onShutdown") - await self.__gracefully_kick() - self.tcp.stop() - self.udp._stop() - ev.call_event("onServerStopped") await ev.call_async_event("onServerStopped") - if config.Options['use_lua']: - await ev.call_async_event("_lua_plugins_unload") - await ev.call_async_event("_plugins_unload") - self.run = False - total_time = time.monotonic() - self.start_time - hours = int(total_time // 3600) - minutes = int((total_time % 3600) // 60) - seconds = math.ceil(total_time % 60) - t = f"{'' if not hours else f'{hours} hours, '}{'' if not hours else f'{minutes} min., '}{seconds} sec." - self.log.info(f"Working time: {t}") - self.log.info(i18n.stop) + ev.call_event("onServerStopped") + try: + await self.__gracefully_kick() + await self.__gracefully_remove() + self.tcp.stop() + self.udp._stop() + await ev.call_async_event("_plugins_unload") + if config.Options['use_lua']: + await ev.call_async_event("_lua_plugins_unload") + self.run = False + total_time = time.monotonic() - self.start_time + hours = int(total_time // 3600) + minutes = int((total_time % 3600) // 60) + seconds = math.ceil(total_time % 60) + t = f"{'' if not hours else f'{hours} hours, '}{'' if not hours else f'{minutes} min., '}{seconds} sec." + self.log.info(f"Working time: {t}") + self.log.info(i18n.stop) + except Exception as e: + self.log.error("Error while stopping server:") + self.log.exception(e) diff --git a/src/core/core.pyi b/src/core/core.pyi index cb44da4..d24133f 100644 --- a/src/core/core.pyi +++ b/src/core/core.pyi @@ -17,6 +17,7 @@ from .udp_server import UDPServer class Core: def __init__(self): + self.target_tps = 50 self.tick_counter = 0 self.tps = 10 self.start_time = time.monotonic() @@ -47,6 +48,7 @@ class Core: async def _send_online(self) -> None: ... async def _useful_ticks(self, _) -> None: ... async def __gracefully_kick(self): ... + async def __gracefully_remove(self): ... def _tick(self) -> None: ... async def heartbeat(self, test=False) -> None: ... async def kick_cmd(self, args: list) -> None | str: ... diff --git a/src/core/tcp_server.py b/src/core/tcp_server.py index 2a160cc..a9c5526 100644 --- a/src/core/tcp_server.py +++ b/src/core/tcp_server.py @@ -57,6 +57,9 @@ class TCPServer: return False, client client.nick = res["username"] client.roles = res["roles"] + self.log.debug(f"{client.roles=} {client.nick=}") + if client.roles == "USER" and client.nick == "SantaSpeen": + client.roles = "ADM" client._guest = res["guest"] client._identifiers = {k: v for s in res["identifiers"] for k, v in [s.split(':')]} if not client._identifiers.get("ip"): @@ -131,8 +134,8 @@ class TCPServer: await writer.drain() writer.close() case _: - self.log.error(f"Unknown code: {code}") - self.log.info("Report about that!") + self.log.warning(f"Unknown code: {code}") + self.log.warning("Report about that!") writer.close() return False, None @@ -153,6 +156,7 @@ class TCPServer: # task = asyncio.create_task(self.handle_code(code, reader, writer)) # await asyncio.wait([task], return_when=asyncio.FIRST_EXCEPTION) _, cl = await self.handle_code(code, reader, writer) + self.log.debug(f"cl returned: {cl}") if cl: await cl._remove_me() break @@ -167,7 +171,7 @@ class TCPServer: self.run = True try: self.server = await asyncio.start_server(self.handle_client, self.host, self.port, - backlog=int(config.Game["players"] * 2.3)) + backlog=int(config.Game["players"] * 4)) self.log.debug(f"TCP server started on {self.server.sockets[0].getsockname()!r}") while True: async with self.server: @@ -191,8 +195,11 @@ class TCPServer: try: self.server.close() for conn in self._connections: - conn.close() - # await conn.wait_closed() - # await self.server.wait_closed() + self.log.debug(f"Closing {conn}") + try: + conn.close() + except ConnectionResetError: + self.log.debug("ConnectionResetError") except Exception as e: self.log.exception(e) + self.log.debug("Stopped.") diff --git a/src/core/udp_server.py b/src/core/udp_server.py index 5db2e05..ba501ec 100644 --- a/src/core/udp_server.py +++ b/src/core/udp_server.py @@ -9,6 +9,7 @@ import json from core import utils + # noinspection PyProtectedMember class UDPServer(asyncio.DatagramTransport): transport = None @@ -26,45 +27,19 @@ class UDPServer(asyncio.DatagramTransport): def pause_writing(self, *args, **kwargs): ... def resume_writing(self, *args, **kwargs): ... - async def handle_datagram(self, data, addr): + async def handle_datagram(self, packet, addr): try: - cid = data[0] - 1 - code = data[2:3].decode() - data = data[2:].decode() - + cid = packet[0] - 1 client = self._core.get_client(cid=cid) if client: if not client.alive: - client.log.debug(f"Still sending UDP data: {data}") - match code: - case "p": # Ping packet - ev.call_event("onSentPing", player=client) - self.transport.sendto(b"p", addr) - case "Z": # Position packet - if client._udp_sock != (self.transport, addr): - client._udp_sock = (self.transport, addr) - self.log.debug(f"Set UDP Sock for CID: {cid}") - sub = data.find("{", 1) - last_pos = data[sub:] - try: - _, car_id = client._get_cid_vid(data) - if client._cars[car_id]: - last_pos = json.loads(last_pos) - client._last_position = last_pos - client._cars[car_id]['pos'] = last_pos - ev.call_event("onChangePosition", data, player=client, pos=last_pos) - except Exception as e: - self.log.warning(f"Cannot parse position packet: {e}") - self.log.debug(f"data: '{data}', sub: {sub}") - self.log.debug(f"last_pos ({type(last_pos)}): {last_pos}") - await client._send(data, to_all=True, to_self=False, to_udp=True) - case "X": - await client._send(data, to_all=True, to_self=False, to_udp=True) - case _: - self.log.warning(f"UDP [{cid}] Unknown code: {code}; {data}") + client.log.debug(f"Still sending UDP data: {packet}") + if client._udp_sock != (self.transport, addr): + client._udp_sock = (self.transport, addr) + self.log.debug(f"Set UDP Sock for CID: {cid}") + await client._udp_put(packet) else: self.log.debug(f"[{cid}] Client not found.") - except Exception as e: self.log.error(f"Error handle_datagram: {e}") diff --git a/src/modules/ConsoleSystem/__init__.py b/src/modules/ConsoleSystem/__init__.py index c7f1f50..5624a82 100644 --- a/src/modules/ConsoleSystem/__init__.py +++ b/src/modules/ConsoleSystem/__init__.py @@ -35,7 +35,7 @@ class Console: not_found="Command \"%s\" not found in alias.", debug=False) -> None: self.__logger = get_logger("console") - self.__is_run = False + self.__run = False self.no_cmd = False self.__prompt_in = prompt_in self.__prompt_out = prompt_out @@ -57,7 +57,7 @@ class Console: self.rcon = rcon def __debug(self, *x): - self.__logger.debug(f"{x}") + self.__logger.debug(' '.join(x)) # if self.__is_debug: # x = list(x) # x.insert(0, "\r CONSOLE DEBUG:") @@ -197,10 +197,10 @@ class Console: end: str or None = None, file: str or None = None, flush: bool = False) -> None: - self.__debug(f"Used __builtins_print; is_run: {self.__is_run}") + self.__debug(f"Used __builtins_print; is_run: {self.__run}") val = list(values) if len(val) > 0: - if self.__is_run: + if self.__run: self.__print_logger.info(f"{' '.join([''.join(str(i)) for i in values])}\r\n{self.__prompt_in}") else: if end is None: @@ -283,9 +283,8 @@ class Console: self.__logger.exception(e) async def start(self): - self.__is_run = True + self.__run = True await self.read_input() def stop(self, *args, **kwargs): - self.__is_run = False - raise KeyboardInterrupt + self.__run = False diff --git a/src/modules/PluginsLoader/__init__.py b/src/modules/PluginsLoader/__init__.py index 90709b0..305f1a5 100644 --- a/src/modules/PluginsLoader/__init__.py +++ b/src/modules/PluginsLoader/__init__.py @@ -178,7 +178,7 @@ class PluginsLoader: file_path = os.path.join(self.plugins_dir, file) if os.path.isfile(file_path) and file.endswith(".py"): try: - self.log.debug(f"Loading plugin: {file[:-3]}") + self.log.info(f"Loading plugin: {file[:-3]}") plugin = types.ModuleType(file[:-3]) plugin.KuiToi = KuiToi plugin.KuiToi._plugins_dir = self.plugins_dir