PycordViews 1.1.4__py3-none-any.whl → 1.2.0__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.
- pycordViews/__init__.py +1 -1
- pycordViews/menu/menu.py +8 -8
- pycordViews/menu/selectMenu.py +15 -13
- pycordViews/multibot/__init__.py +1 -5
- pycordViews/multibot/bot.py +194 -0
- pycordViews/multibot/errors.py +25 -5
- pycordViews/multibot/multibot.py +206 -0
- pycordViews/multibot/process.py +217 -0
- pycordviews-1.2.0.dist-info/METADATA +241 -0
- pycordviews-1.2.0.dist-info/RECORD +21 -0
- {pycordviews-1.1.4.dist-info → pycordviews-1.2.0.dist-info}/WHEEL +1 -1
- pycordViews/multibot/process_for_bots.py +0 -112
- pycordViews/multibot/process_messages.py +0 -7
- pycordViews/multibot/runner.py +0 -14
- pycordViews/multibot/start_multibot.py +0 -80
- pycordviews-1.1.4.dist-info/METADATA +0 -80
- pycordviews-1.1.4.dist-info/RECORD +0 -22
- {pycordviews-1.1.4.dist-info → pycordviews-1.2.0.dist-info/licenses}/LICENSE +0 -0
- {pycordviews-1.1.4.dist-info → pycordviews-1.2.0.dist-info}/top_level.txt +0 -0
pycordViews/__init__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from .views.easy_modified_view import EasyModifiedViews
|
2
2
|
from .pagination.pagination_view import Pagination
|
3
|
-
from .multibot
|
3
|
+
from .multibot import Multibot
|
4
4
|
from .menu.selectMenu import SelectMenu
|
5
5
|
from .menu.menu import Menu, CustomSelect
|
pycordViews/menu/menu.py
CHANGED
@@ -27,13 +27,6 @@ class Menu:
|
|
27
27
|
self.__selectMenu.set_callable(self.__menu.custom_id, _callable=_callable)
|
28
28
|
return self
|
29
29
|
|
30
|
-
@property
|
31
|
-
def callable(self) -> Callable:
|
32
|
-
"""
|
33
|
-
Get the current callable menu
|
34
|
-
"""
|
35
|
-
return self.__selectMenu.get_callable(self.__menu.custom_id)
|
36
|
-
|
37
30
|
def add_option(self, label: str, value: str = MISSING, description: Union[str, None] = None, emoji: Union[str, Emoji, PartialEmoji, None] = None, default: bool = False) -> "Menu":
|
38
31
|
"""
|
39
32
|
Add an option to choice.
|
@@ -82,7 +75,7 @@ class Menu:
|
|
82
75
|
raise ComponentTypeError()
|
83
76
|
|
84
77
|
@property
|
85
|
-
def component(self) ->
|
78
|
+
def component(self) -> "CustomSelect":
|
86
79
|
"""
|
87
80
|
Get the component
|
88
81
|
"""
|
@@ -95,6 +88,13 @@ class Menu:
|
|
95
88
|
"""
|
96
89
|
return self.__selectMenu
|
97
90
|
|
91
|
+
@property
|
92
|
+
def callable(self) -> Callable:
|
93
|
+
"""
|
94
|
+
Get the current callable menu
|
95
|
+
"""
|
96
|
+
return self.__selectMenu.get_callable(self.__menu.custom_id)
|
97
|
+
|
98
98
|
class CustomSelect(Select):
|
99
99
|
"""
|
100
100
|
Subclass of Select discord Class to use some SelectMenu functions
|
pycordViews/menu/selectMenu.py
CHANGED
@@ -4,7 +4,8 @@ from .menu import Menu
|
|
4
4
|
|
5
5
|
from typing import Union, Callable, Any
|
6
6
|
from discord.components import ComponentType
|
7
|
-
from discord import ChannelType, Member,
|
7
|
+
from discord import ChannelType, Member, ApplicationContext
|
8
|
+
from discord.abc import GuildChannel
|
8
9
|
|
9
10
|
class SelectMenu:
|
10
11
|
"""
|
@@ -53,9 +54,9 @@ class SelectMenu:
|
|
53
54
|
"""
|
54
55
|
return self.__global_add_component(ComponentType.role_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row)
|
55
56
|
|
56
|
-
def
|
57
|
+
def add_mentionable_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None) -> Menu:
|
57
58
|
"""
|
58
|
-
Add a
|
59
|
+
Add a mentionable select menu in the ui
|
59
60
|
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
60
61
|
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
61
62
|
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
@@ -67,7 +68,7 @@ class SelectMenu:
|
|
67
68
|
|
68
69
|
def add_channel_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None, channel_types: list[ChannelType] = None):
|
69
70
|
"""
|
70
|
-
Add a
|
71
|
+
Add a channel select menu in the ui
|
71
72
|
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
72
73
|
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
73
74
|
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
@@ -100,8 +101,8 @@ class SelectMenu:
|
|
100
101
|
|
101
102
|
def set_callable(self, *custom_ids: str, _callable: Union[Callable, None]) -> "SelectMenu":
|
102
103
|
"""
|
103
|
-
Set a callable for
|
104
|
-
:param custom_ids: IDs
|
104
|
+
Set a callable for menus associated with custom_ids
|
105
|
+
:param custom_ids: IDs menus
|
105
106
|
:param _callable: The coroutine to set for all menus
|
106
107
|
"""
|
107
108
|
self.__select_menu.set_callable(*custom_ids, _callable=_callable)
|
@@ -113,7 +114,7 @@ class SelectMenu:
|
|
113
114
|
"""
|
114
115
|
return await self.__select_menu.respond(ctx=ctx, *args, view=self.__select_menu, **kwargs)
|
115
116
|
|
116
|
-
async def send(self, target: Union[Member,
|
117
|
+
async def send(self, target: Union[Member, GuildChannel], *args, **kwargs) -> Any:
|
117
118
|
"""
|
118
119
|
Send at the target
|
119
120
|
"""
|
@@ -128,6 +129,13 @@ class SelectMenu:
|
|
128
129
|
return
|
129
130
|
await self.__select_menu.update_items(*self.get_view.items)
|
130
131
|
|
132
|
+
def get_callable(self, custom_id: str) -> Union[Callable, None]:
|
133
|
+
"""
|
134
|
+
Get the callable UI
|
135
|
+
:param custom_id: UI ID
|
136
|
+
"""
|
137
|
+
return self.__select_menu.get_callable(custom_id)
|
138
|
+
|
131
139
|
@property
|
132
140
|
def get_view(self) -> EasyModifiedViews:
|
133
141
|
"""
|
@@ -135,9 +143,3 @@ class SelectMenu:
|
|
135
143
|
"""
|
136
144
|
return self.__select_menu
|
137
145
|
|
138
|
-
def get_callable(self, custom_id: str) -> Union[Callable, None]:
|
139
|
-
"""
|
140
|
-
Get the callable UI
|
141
|
-
:param custom_id: UI ID
|
142
|
-
"""
|
143
|
-
return self.__select_menu.get_callable(custom_id)
|
pycordViews/multibot/__init__.py
CHANGED
@@ -0,0 +1,194 @@
|
|
1
|
+
from threading import Thread
|
2
|
+
from discord import Intents, Bot, ApplicationCommand
|
3
|
+
from asyncio import run_coroutine_threadsafe, new_event_loop, set_event_loop, Future, AbstractEventLoop, sleep
|
4
|
+
from time import sleep as tsleep
|
5
|
+
from .errors import BotNotStartedError, SetupCommandFunctionNotFound, CommandFileNotFoundError
|
6
|
+
from typing import Optional
|
7
|
+
from importlib import reload
|
8
|
+
from importlib.util import spec_from_file_location, module_from_spec
|
9
|
+
from os import path
|
10
|
+
from sys import modules
|
11
|
+
|
12
|
+
|
13
|
+
class DiscordBot:
|
14
|
+
|
15
|
+
def __init__(self, token: str, intents: Intents, command_prefix: Optional[str] = None):
|
16
|
+
self.__token: str = token
|
17
|
+
self.__command_prefix: str = command_prefix
|
18
|
+
self.__running_bot: Future = None
|
19
|
+
self.__loop: AbstractEventLoop = new_event_loop()
|
20
|
+
self.__thread: Thread = Thread(target=self.run_loop, daemon=True) # Thread pour exécuter l'event loop
|
21
|
+
self.__thread.start()
|
22
|
+
self.__bot: Bot = Bot(loop=self.__loop, intents=intents, command_prefix=command_prefix, help_commad=None, auto_sync_commands=False)
|
23
|
+
self.__intents: Intents = intents
|
24
|
+
self.__imported_module: list[dict[str, ...]] = []
|
25
|
+
|
26
|
+
def run_loop(self):
|
27
|
+
"""Lance la boucle asyncio dans un thread séparé."""
|
28
|
+
set_event_loop(self.__loop)
|
29
|
+
self.__loop.run_forever()
|
30
|
+
|
31
|
+
def start(self) -> None:
|
32
|
+
"""Démarre le bot"""
|
33
|
+
|
34
|
+
self.__running_bot: Future = run_coroutine_threadsafe(self.__bot.start(token=self.__token, reconnect=True), self.__loop)
|
35
|
+
|
36
|
+
def stop(self) -> None:
|
37
|
+
"""
|
38
|
+
Stop le bot proprement depuis un autre thread
|
39
|
+
:raise: BotNotStartedError
|
40
|
+
"""
|
41
|
+
if self.is_running:
|
42
|
+
# Attendre que la fermeture du bot soit terminée
|
43
|
+
run_coroutine_threadsafe(self.__stop_bot_in_thread(), self.__loop).result(timeout=30)
|
44
|
+
self.__bot = Bot(token=self.__token, intents=self.__intents, command_prefix=self.__command_prefix, help_command=None)
|
45
|
+
self.__running_bot = None
|
46
|
+
else:
|
47
|
+
raise BotNotStartedError(self.__bot.user.name)
|
48
|
+
|
49
|
+
def add_pyFile_commands(self, file: str, setup_function: str, reload_command: bool):
|
50
|
+
"""
|
51
|
+
Ajoute et charge un fichier de commande bot et ses dépendances.
|
52
|
+
Les fichiers doivent avoir une fonction appelée « setup » ou un équivalent passé en paramètre.
|
53
|
+
|
54
|
+
def setup(bot: Bot) :
|
55
|
+
...
|
56
|
+
|
57
|
+
:param bot_name : Le nom du bot à ajouter au fichier de commandes
|
58
|
+
:param file: Chemin relatif ou absolue du fichier de commande
|
59
|
+
:param setup_function : Nom de la fonction appelée par le processus pour donner l'instance de Bot.
|
60
|
+
:param reload_command : Recharge toutes les commandes dans le fichier et les dépendances. Défaut : True
|
61
|
+
"""
|
62
|
+
module_name = path.splitext(path.basename(file))[0] # récupère le nom du fichier
|
63
|
+
spec = spec_from_file_location(module_name, file) # renvoie un "module spec" à partir du nom et du fichier
|
64
|
+
if spec and spec.loader:
|
65
|
+
module = module_from_spec(spec) # crée le package à partir du "module spec" s'il existe
|
66
|
+
spec.loader.exec_module(module) # charge tout le package
|
67
|
+
modules[module_name] = module # enregistre le modul dans les packages du système pour qu'il soit retrouvable lors du rechargement de celui-ci
|
68
|
+
self.__call_setup_function_in_command_file(file, module, setup_function, reload_command)
|
69
|
+
else:
|
70
|
+
raise CommandFileNotFoundError(file)
|
71
|
+
|
72
|
+
def modify_pyFile_commands(self, file: str, setup_function: str):
|
73
|
+
"""
|
74
|
+
Modifie un fichier de comandes et le recharge.
|
75
|
+
Ne recharge que le fichier et non les commandes du bot !
|
76
|
+
:param file: Le chemin d'accès relatif ou absolue du fichier
|
77
|
+
"""
|
78
|
+
print('ok')
|
79
|
+
module_name = path.splitext(path.basename(file))[0]
|
80
|
+
module_found = False
|
81
|
+
|
82
|
+
# Mise à jour du module et de son setup
|
83
|
+
print(self.__imported_module)
|
84
|
+
for imported in self.__imported_module:
|
85
|
+
print(imported['module'].__name__, module_name)
|
86
|
+
if imported['module'].__name__ == module_name:
|
87
|
+
print('reload module :', module_name)
|
88
|
+
reload(imported['module'])
|
89
|
+
imported['setup_function'] = setup_function
|
90
|
+
module_found = True
|
91
|
+
break
|
92
|
+
|
93
|
+
if not module_found:
|
94
|
+
raise CommandFileNotFoundError(file)
|
95
|
+
|
96
|
+
# Supprimer toutes les commandes du bot
|
97
|
+
for command in self.__bot.application_commands:
|
98
|
+
print('del commande', command.name)
|
99
|
+
self.__bot.remove_application_command(command)
|
100
|
+
|
101
|
+
# Réattacher toutes les commandes en réexécutant tous les setup
|
102
|
+
for imported in self.__imported_module:
|
103
|
+
self.__call_setup_function_in_command_file(
|
104
|
+
file,
|
105
|
+
imported['module'],
|
106
|
+
imported['setup_function'],
|
107
|
+
reload_command=False
|
108
|
+
)
|
109
|
+
|
110
|
+
|
111
|
+
def reload_commands(self, commands: Optional[list[ApplicationCommand]] = None):
|
112
|
+
"""
|
113
|
+
Charge toutes les commandes du bot sur Discord
|
114
|
+
"""
|
115
|
+
run_coroutine_threadsafe(self.__reload_commands(commands=commands), self.__loop).result(timeout=30)
|
116
|
+
|
117
|
+
|
118
|
+
@property
|
119
|
+
def is_running(self) -> bool:
|
120
|
+
"""Renvoie si la Websocket est connectée"""
|
121
|
+
return not self.__bot.is_closed()
|
122
|
+
|
123
|
+
@property
|
124
|
+
def is_ready(self) -> bool:
|
125
|
+
"""
|
126
|
+
Renvoie si le bot est ready
|
127
|
+
"""
|
128
|
+
return self.__bot.is_ready()
|
129
|
+
|
130
|
+
@property
|
131
|
+
def is_ws_ratelimited(self) -> bool:
|
132
|
+
"""
|
133
|
+
Renvoie si le bot est rate limit
|
134
|
+
"""
|
135
|
+
return self.__bot.is_ws_ratelimited()
|
136
|
+
|
137
|
+
|
138
|
+
async def __stop_bot_in_thread(self):
|
139
|
+
"""
|
140
|
+
Clear le cache du bot de manière asynchrone
|
141
|
+
"""
|
142
|
+
await self.__bot.close()
|
143
|
+
|
144
|
+
def close_ascyncio_loop(self):
|
145
|
+
"""
|
146
|
+
Ferme la boucle asyncio
|
147
|
+
"""
|
148
|
+
if self.__loop.is_running():
|
149
|
+
self.__loop.stop()
|
150
|
+
|
151
|
+
while self.__loop.is_running():
|
152
|
+
tsleep(0.3)
|
153
|
+
|
154
|
+
self.__loop.close()
|
155
|
+
|
156
|
+
async def __reload_commands(self, commands: Optional[list[ApplicationCommand]]):
|
157
|
+
"""
|
158
|
+
Recharge les commandes quand le bot est ready
|
159
|
+
"""
|
160
|
+
if self.__running_bot is not None:
|
161
|
+
while not self.is_ready:
|
162
|
+
await sleep(0.3)
|
163
|
+
await self.__bot.register_commands(commands=commands, method='individual', force=False)
|
164
|
+
else:
|
165
|
+
raise BotNotStartedError(self.__token)
|
166
|
+
|
167
|
+
def __call_setup_function_in_command_file(self, file: str, module, setup_function: str, reload_command: bool):
|
168
|
+
"""
|
169
|
+
Appel la fonction de setup du module pour charger toutes les commandes du bot
|
170
|
+
:param file: Le chemin d'accès du fichier de commandes
|
171
|
+
:param module: Le module préchargé
|
172
|
+
:param setup_function: Le nom de la fonction de setup
|
173
|
+
:param reload_command: Si les commandes doivent être recharger sur le bot (envoie une requête à Discord) automatiquement
|
174
|
+
"""
|
175
|
+
if hasattr(module, setup_function): # si la fonction setup (ou autre) est dans le package
|
176
|
+
getattr(module, setup_function)(self.__bot)
|
177
|
+
|
178
|
+
########## permet de modifier le dictionnaire des modules importés si celui-ci existe déjà, sinon il l'ajoute à la liste des dictionaires des modules importés. Utile car on reload tout si un des modules est modifié
|
179
|
+
find = False
|
180
|
+
for mod in self.__imported_module:
|
181
|
+
if mod['module'].__name__ == module.__name__:
|
182
|
+
mod['setup_function'] = setup_function
|
183
|
+
find = True
|
184
|
+
break
|
185
|
+
|
186
|
+
if not find:
|
187
|
+
self.__imported_module.append({'setup_function': setup_function, 'module': module})
|
188
|
+
##########
|
189
|
+
|
190
|
+
if reload_command:
|
191
|
+
self.reload_commands()
|
192
|
+
else:
|
193
|
+
raise SetupCommandFunctionNotFound(setup_function, file)
|
194
|
+
|
pycordViews/multibot/errors.py
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
class MultibotError(Exception):
|
2
2
|
pass
|
3
3
|
|
4
|
+
class BotAlreadyExistError(MultibotError):
|
5
|
+
def __init__(self, bot_name: str):
|
6
|
+
super().__init__(f"'{bot_name}' bot already exist !")
|
4
7
|
|
5
8
|
class BotNotFoundError(MultibotError):
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def __init__(self, bot_name: str):
|
10
|
+
super().__init__(f"'{bot_name}' bot doesn't exist !")
|
11
|
+
|
12
|
+
class BotNotStartedError(MultibotError):
|
13
|
+
def __init__(self, bot_name: str):
|
14
|
+
super().__init__(f"'{bot_name}' not started !")
|
15
|
+
|
16
|
+
class BotNotReadyedError(MultibotError):
|
17
|
+
def __init__(self, bot_name: str):
|
18
|
+
super().__init__(f"'{bot_name}' not ready !")
|
19
|
+
|
20
|
+
class BotAlreadyStartedError(MultibotError):
|
21
|
+
def __init__(self, bot_name: str):
|
22
|
+
super().__init__(f"'{bot_name}' already started !")
|
23
|
+
|
24
|
+
class SetupCommandFunctionNotFound(MultibotError):
|
25
|
+
def __init__(self, setup_command_name: str, file: str):
|
26
|
+
super().__init__(f"'{setup_command_name}' function not found in '{file}' file ! Init commands impossible.")
|
27
|
+
|
28
|
+
class CommandFileNotFoundError(MultibotError):
|
29
|
+
def __init__(self, file_name: str):
|
30
|
+
super().__init__(f"'{file_name}' file not found ! Init commands impossible.")
|
@@ -0,0 +1,206 @@
|
|
1
|
+
from multiprocessing import get_context
|
2
|
+
from multiprocessing.queues import Queue
|
3
|
+
from .process import ManageProcess
|
4
|
+
from discord import Intents
|
5
|
+
from sys import platform
|
6
|
+
from typing import Union
|
7
|
+
|
8
|
+
|
9
|
+
class Multibot:
|
10
|
+
|
11
|
+
def __init__(self, global_timeout: int = 30):
|
12
|
+
"""
|
13
|
+
Get instance to run few Discord bot
|
14
|
+
"""
|
15
|
+
if platform == 'win32':
|
16
|
+
ctx = get_context("spawn")
|
17
|
+
else:
|
18
|
+
ctx = get_context("forkserver")
|
19
|
+
self.__main_queue: Queue = ctx.Queue()
|
20
|
+
self.__process_queue: Queue = ctx.Queue()
|
21
|
+
# Création du processus gérant les bots
|
22
|
+
self.__DiscordProcess = ctx.Process(target=self._start_process)
|
23
|
+
self.__DiscordProcess.start()
|
24
|
+
|
25
|
+
self.global_timeout = global_timeout
|
26
|
+
|
27
|
+
def __get_data_queue(self) -> Union[list[dict], dict, None]:
|
28
|
+
"""
|
29
|
+
Récupère les données dans la queue processus
|
30
|
+
"""
|
31
|
+
#try:
|
32
|
+
result = self.__process_queue.get(timeout=self.global_timeout)
|
33
|
+
return result
|
34
|
+
#except:
|
35
|
+
#return None
|
36
|
+
|
37
|
+
def _start_process(self):
|
38
|
+
"""
|
39
|
+
Initialise et exécute le gestionnaire de processus.
|
40
|
+
"""
|
41
|
+
manager = ManageProcess(self.__main_queue, self.__process_queue)
|
42
|
+
manager.run()
|
43
|
+
|
44
|
+
def add_bot(self, bot_name: str, token: str, intents: Intents):
|
45
|
+
"""
|
46
|
+
Add a bot in the process
|
47
|
+
:param bot_name: Bot name
|
48
|
+
:param token: Token bot
|
49
|
+
:param intents: Intents bot to Intents discord class
|
50
|
+
"""
|
51
|
+
self.__main_queue.put({"type": "ADD", "bot_name": bot_name, "token": token, 'intents': intents})
|
52
|
+
response = self.__get_data_queue()
|
53
|
+
return response # Retourne le statut de l'ajout
|
54
|
+
|
55
|
+
def remove_bot(self, bot_name: str) -> dict[str, str]:
|
56
|
+
"""
|
57
|
+
Shutdown and remove à bot
|
58
|
+
:param bot_name: Bot name to remove
|
59
|
+
"""
|
60
|
+
self.__main_queue.put({"type": "REMOVE", "bot_name": bot_name})
|
61
|
+
response = self.__get_data_queue()
|
62
|
+
return response # Retourne le statut de la suppression
|
63
|
+
|
64
|
+
def start(self, *bot_names: str) -> list[dict[str, str]]:
|
65
|
+
"""
|
66
|
+
Start bots
|
67
|
+
:param bot_names: Bots name to start
|
68
|
+
:return: List of data bot status
|
69
|
+
"""
|
70
|
+
results = []
|
71
|
+
for bot_name in bot_names:
|
72
|
+
self.__main_queue.put({'type': "START", 'bot_name': bot_name})
|
73
|
+
results.append(self.__get_data_queue())
|
74
|
+
return results
|
75
|
+
|
76
|
+
def stop(self, *bot_names: str) -> list[dict[str, str]]:
|
77
|
+
"""
|
78
|
+
Stop bots
|
79
|
+
:param bot_names: Bots name to start
|
80
|
+
:return: Data status dict
|
81
|
+
"""
|
82
|
+
results = []
|
83
|
+
for bot_name in bot_names:
|
84
|
+
self.__main_queue.put({'type': "STOP", 'bot_name': bot_name})
|
85
|
+
results.append(self.__get_data_queue())
|
86
|
+
return results
|
87
|
+
|
88
|
+
def start_all(self) -> list[dict[str, list[str]]]:
|
89
|
+
"""
|
90
|
+
Start all bots in the process.
|
91
|
+
"""
|
92
|
+
self.__main_queue.put({'type': "STARTALL"})
|
93
|
+
return self.__get_data_queue()
|
94
|
+
|
95
|
+
def stop_all(self) -> list[dict[str, list[str]]]:
|
96
|
+
"""
|
97
|
+
Stop all bots in the process.
|
98
|
+
This function is slow ! It's shutdown all bots properly.
|
99
|
+
"""
|
100
|
+
self.__main_queue.put({'type': "STOPALL"})
|
101
|
+
return self.__get_data_queue()
|
102
|
+
|
103
|
+
def is_started(self, bot_name: str) -> bool:
|
104
|
+
"""
|
105
|
+
Return the current Websocket connexion status
|
106
|
+
:param bot_name: Bot name
|
107
|
+
:return: True if the Websocket is online, else False
|
108
|
+
"""
|
109
|
+
self.__main_queue.put({'type': "IS_STARTED", 'bot_name': bot_name})
|
110
|
+
return self.__get_data_queue()['message']
|
111
|
+
|
112
|
+
def is_ready(self, bot_name: str) -> bool:
|
113
|
+
"""
|
114
|
+
Return the current bot connexion status
|
115
|
+
:param bot_name: Bot name
|
116
|
+
:return: True if the bot if ready, else False
|
117
|
+
"""
|
118
|
+
self.__main_queue.put({'type': "IS_READY", 'bot_name': bot_name})
|
119
|
+
return self.__get_data_queue()['message']
|
120
|
+
|
121
|
+
def is_ws_ratelimited(self, bot_name: str) -> bool:
|
122
|
+
"""
|
123
|
+
Get the current ratelimit status of the bot
|
124
|
+
:param bot_name: Bot name
|
125
|
+
:return: True if the bot was ratelimited, else False
|
126
|
+
"""
|
127
|
+
self.__main_queue.put({'type': "IS_WS_RATELIMITED", 'bot_name': bot_name})
|
128
|
+
return self.__get_data_queue()['message']
|
129
|
+
|
130
|
+
def reload_commands(self, *bot_names: str) -> list[dict[str, str]]:
|
131
|
+
"""
|
132
|
+
Reload all commands for each bot when bots are ready
|
133
|
+
:param bot_names: Bots name to reload commands
|
134
|
+
"""
|
135
|
+
result = []
|
136
|
+
for name in bot_names:
|
137
|
+
self.__main_queue.put({'type': "RELOAD_COMMANDS", 'name': name})
|
138
|
+
result.append(self.__get_data_queue())
|
139
|
+
return result
|
140
|
+
|
141
|
+
def add_pyFile_commands(self, bot_name: str, file: str, setup_function: str = 'setup', reload_command: bool = True) -> dict[str, str]:
|
142
|
+
"""
|
143
|
+
Add and load a command bot file and dependencies.
|
144
|
+
Files must have a function called ‘setup’ or an equivalent passed as a parameter.
|
145
|
+
|
146
|
+
def setup(bot: Bot):
|
147
|
+
...
|
148
|
+
|
149
|
+
:param bot_name: The bot's name to add commands file
|
150
|
+
:param file: Relative or absolute commands file's path
|
151
|
+
:param setup_function: Function name called by the process to give the Bot instance.
|
152
|
+
:param reload_command: Reload all command in the fil and dependencies. Default : True
|
153
|
+
"""
|
154
|
+
self.__main_queue.put({'type': "ADD_COMMAND_FILE",
|
155
|
+
'bot_name': bot_name,
|
156
|
+
'file': file,
|
157
|
+
'setup_function': setup_function,
|
158
|
+
'reload_command': reload_command})
|
159
|
+
return self.__get_data_queue()
|
160
|
+
|
161
|
+
def modify_pyFile_commands(self, bot_name: str, file: str, setup_function: str = 'setup') -> dict[str, str]:
|
162
|
+
|
163
|
+
"""
|
164
|
+
Modifies a file of commands and reloads it.
|
165
|
+
Reloads only the file, not the bot commands!
|
166
|
+
:param bot_name: The bot's name
|
167
|
+
:param file: The file's relative or absolute path
|
168
|
+
"""
|
169
|
+
|
170
|
+
self.__main_queue.put({'type': "MODIFY_COMMAND_FILE",
|
171
|
+
'bot_name': bot_name,
|
172
|
+
'file': file,
|
173
|
+
'setup_function': setup_function})
|
174
|
+
return self.__get_data_queue()
|
175
|
+
|
176
|
+
@property
|
177
|
+
def bot_count(self) -> int:
|
178
|
+
"""
|
179
|
+
Return the total number of bots
|
180
|
+
"""
|
181
|
+
self.__main_queue.put({'type': "BOT_COUNT"})
|
182
|
+
return self.__get_data_queue()['message']
|
183
|
+
|
184
|
+
@property
|
185
|
+
def started_bot_count(self) -> int:
|
186
|
+
"""
|
187
|
+
Return the total number of started bots
|
188
|
+
"""
|
189
|
+
self.__main_queue.put({'type': "STARTED_BOT_COUNT"})
|
190
|
+
return self.__get_data_queue()['message']
|
191
|
+
|
192
|
+
@property
|
193
|
+
def shutdown_bot_count(self) -> int:
|
194
|
+
"""
|
195
|
+
Return the total number of shutdown bots
|
196
|
+
"""
|
197
|
+
self.__main_queue.put({'type': "SHUTDOWN_BOT_COUNT"})
|
198
|
+
return self.__get_data_queue()['message']
|
199
|
+
|
200
|
+
@property
|
201
|
+
def get_bots_name(self) -> list[str]:
|
202
|
+
"""
|
203
|
+
Return all bots name (not real name of bots)
|
204
|
+
"""
|
205
|
+
self.__main_queue.put({'type': "BOTS_NAME"})
|
206
|
+
return self.__get_data_queue()['message']
|