mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Starting using multiprocessing module in Vulkan, now creating a new bot for each guild when played, multiple issues yet
This commit is contained in:
parent
7a51c22709
commit
fc7de9cb4f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.vscode
|
||||||
assets/
|
assets/
|
||||||
__pycache__
|
__pycache__
|
||||||
.env
|
.env
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class Control(commands.Cog):
|
|||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f'DEVELOPER NOTE -> Comand Error: {error}')
|
print(f'DEVELOPER NOTE -> Command Error: {error}')
|
||||||
embed = self.__embeds.UNKNOWN_ERROR()
|
embed = self.__embeds.UNKNOWN_ERROR()
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from Controllers.ClearController import ClearController
|
|||||||
from Controllers.MoveController import MoveController
|
from Controllers.MoveController import MoveController
|
||||||
from Controllers.NowPlayingController import NowPlayingController
|
from Controllers.NowPlayingController import NowPlayingController
|
||||||
from Controllers.PlayController import PlayController
|
from Controllers.PlayController import PlayController
|
||||||
from Controllers.PlayerController import PlayersController
|
from Controllers.PlayersController import PlayersController
|
||||||
from Controllers.PrevController import PrevController
|
from Controllers.PrevController import PrevController
|
||||||
from Controllers.RemoveController import RemoveController
|
from Controllers.RemoveController import RemoveController
|
||||||
from Controllers.ResetController import ResetController
|
from Controllers.ResetController import ResetController
|
||||||
@ -21,7 +21,7 @@ from Controllers.QueueController import QueueController
|
|||||||
from Controllers.LoopController import LoopController
|
from Controllers.LoopController import LoopController
|
||||||
from Views.EmoteView import EmoteView
|
from Views.EmoteView import EmoteView
|
||||||
from Views.EmbedView import EmbedView
|
from Views.EmbedView import EmbedView
|
||||||
|
from Parallelism.ProcessManager import ProcessManager
|
||||||
|
|
||||||
helper = Helper()
|
helper = Helper()
|
||||||
|
|
||||||
@ -29,6 +29,7 @@ helper = Helper()
|
|||||||
class Music(commands.Cog):
|
class Music(commands.Cog):
|
||||||
def __init__(self, bot) -> None:
|
def __init__(self, bot) -> None:
|
||||||
self.__bot: Client = bot
|
self.__bot: Client = bot
|
||||||
|
self.__processManager = ProcessManager(bot)
|
||||||
self.__cleaner = Cleaner(self.__bot)
|
self.__cleaner = Cleaner(self.__bot)
|
||||||
self.__controller = PlayersController(self.__bot)
|
self.__controller = PlayersController(self.__bot)
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from typing import List
|
|||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from discord import Client, Guild, ClientUser, Member
|
from discord import Client, Guild, ClientUser, Member
|
||||||
from Config.Messages import Messages
|
from Config.Messages import Messages
|
||||||
from Controllers.PlayerController import PlayersController
|
from Controllers.PlayersController import PlayersController
|
||||||
from Music.Player import Player
|
from Music.Player import Player
|
||||||
from Controllers.ControllerResponse import ControllerResponse
|
from Controllers.ControllerResponse import ControllerResponse
|
||||||
from Config.Configs import Configs
|
from Config.Configs import Configs
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import asyncio
|
|
||||||
from Exceptions.Exceptions import DownloadingError, InvalidInput, VulkanError
|
from Exceptions.Exceptions import DownloadingError, InvalidInput, VulkanError
|
||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from discord import Client
|
from discord import Client
|
||||||
@ -8,6 +7,8 @@ from Controllers.ControllerResponse import ControllerResponse
|
|||||||
from Music.Downloader import Downloader
|
from Music.Downloader import Downloader
|
||||||
from Music.Searcher import Searcher
|
from Music.Searcher import Searcher
|
||||||
from Music.Song import Song
|
from Music.Song import Song
|
||||||
|
from Parallelism.ProcessManager import ProcessManager
|
||||||
|
from Parallelism.Commands import VCommands, VCommandsType
|
||||||
|
|
||||||
|
|
||||||
class PlayController(AbstractController):
|
class PlayController(AbstractController):
|
||||||
@ -25,13 +26,6 @@ class PlayController(AbstractController):
|
|||||||
embed = self.embeds.NO_CHANNEL()
|
embed = self.embeds.NO_CHANNEL()
|
||||||
return ControllerResponse(self.ctx, embed, error)
|
return ControllerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
if not self.__is_connected():
|
|
||||||
success = await self.__connect()
|
|
||||||
if not success:
|
|
||||||
error = UnknownError()
|
|
||||||
embed = self.embeds.UNKNOWN_ERROR()
|
|
||||||
return ControllerResponse(self.ctx, embed, error)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
musics = await self.__searcher.search(track)
|
musics = await self.__searcher.search(track)
|
||||||
if musics is None or len(musics) == 0:
|
if musics is None or len(musics) == 0:
|
||||||
@ -63,7 +57,26 @@ class PlayController(AbstractController):
|
|||||||
embed = self.embeds.SONGS_ADDED(quant)
|
embed = self.embeds.SONGS_ADDED(quant)
|
||||||
response = ControllerResponse(self.ctx, embed)
|
response = ControllerResponse(self.ctx, embed)
|
||||||
|
|
||||||
asyncio.create_task(self.player.play(self.ctx))
|
# Get the process context for the current guild
|
||||||
|
manager = ProcessManager(self.bot)
|
||||||
|
processContext = manager.getPlayerContext(self.guild, self.ctx)
|
||||||
|
# Add the downloaded song to the process playlist
|
||||||
|
# All access to shared memory should be protect by acquire the Lock
|
||||||
|
with processContext.getLock():
|
||||||
|
processContext.getPlaylist().add_song(song)
|
||||||
|
|
||||||
|
# If process already started send a command to the player process by queue
|
||||||
|
process = processContext.getProcess()
|
||||||
|
queue = processContext.getQueue()
|
||||||
|
if process.is_alive():
|
||||||
|
command = VCommands(VCommandsType.PLAY)
|
||||||
|
queue.put(command)
|
||||||
|
else:
|
||||||
|
# Start the process
|
||||||
|
command = VCommands(VCommandsType.CONTEXT, self.ctx)
|
||||||
|
queue.put(command)
|
||||||
|
process.start()
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -72,6 +85,7 @@ class PlayController(AbstractController):
|
|||||||
error = err
|
error = err
|
||||||
embed = self.embeds.CUSTOM_ERROR(error)
|
embed = self.embeds.CUSTOM_ERROR(error)
|
||||||
else:
|
else:
|
||||||
|
print(f'DEVELOPER NOTE -> PlayController Error: {err}')
|
||||||
error = UnknownError()
|
error = UnknownError()
|
||||||
embed = self.embeds.UNKNOWN_ERROR()
|
embed = self.embeds.UNKNOWN_ERROR()
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from multiprocessing import Process
|
||||||
from typing import Dict, List, Union
|
from typing import Dict, List, Union
|
||||||
from Config.Singleton import Singleton
|
from Config.Singleton import Singleton
|
||||||
from discord import Guild, Client, VoiceClient, Member
|
from discord import Guild, Client, VoiceClient, Member
|
||||||
@ -1,8 +1,8 @@
|
|||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from discord import Client, Member
|
from discord import Client
|
||||||
from Controllers.AbstractController import AbstractController
|
from Controllers.AbstractController import AbstractController
|
||||||
from Controllers.ControllerResponse import ControllerResponse
|
from Controllers.ControllerResponse import ControllerResponse
|
||||||
from Controllers.PlayerController import PlayersController
|
from Controllers.PlayersController import PlayersController
|
||||||
|
|
||||||
|
|
||||||
class ResetController(AbstractController):
|
class ResetController(AbstractController):
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import random
|
|||||||
class Playlist:
|
class Playlist:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.__config = Configs()
|
self.__configs = Configs()
|
||||||
self.__queue = deque() # Store the musics to play
|
self.__queue = deque() # Store the musics to play
|
||||||
self.__songs_history = deque() # Store the musics played
|
self.__songs_history = deque() # Store the musics played
|
||||||
|
|
||||||
@ -17,6 +17,9 @@ class Playlist:
|
|||||||
|
|
||||||
self.__current: Song = None
|
self.__current: Song = None
|
||||||
|
|
||||||
|
def getSongs(self) -> deque[Song]:
|
||||||
|
return self.__queue
|
||||||
|
|
||||||
def validate_position(self, position: int) -> bool:
|
def validate_position(self, position: int) -> bool:
|
||||||
if position not in range(1, len(self.__queue) + 1):
|
if position not in range(1, len(self.__queue) + 1):
|
||||||
return False
|
return False
|
||||||
@ -47,7 +50,7 @@ class Playlist:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def songs_to_preload(self) -> List[Song]:
|
def songs_to_preload(self) -> List[Song]:
|
||||||
return list(self.__queue)[:self.__config.MAX_PRELOAD_SONGS]
|
return list(self.__queue)[:self.__configs.MAX_PRELOAD_SONGS]
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self.__queue)
|
return len(self.__queue)
|
||||||
@ -64,7 +67,7 @@ class Playlist:
|
|||||||
if played_song.problematic == False:
|
if played_song.problematic == False:
|
||||||
self.__songs_history.appendleft(played_song)
|
self.__songs_history.appendleft(played_song)
|
||||||
|
|
||||||
if len(self.__songs_history) > self.__config.MAX_SONGS_HISTORY:
|
if len(self.__songs_history) > self.__configs.MAX_SONGS_HISTORY:
|
||||||
self.__songs_history.pop() # Remove the older
|
self.__songs_history.pop() # Remove the older
|
||||||
|
|
||||||
elif self.__looping_one: # Insert the current song to play again
|
elif self.__looping_one: # Insert the current song to play again
|
||||||
|
|||||||
23
Parallelism/Commands.py
Normal file
23
Parallelism/Commands.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class VCommandsType(Enum):
|
||||||
|
PLAY_PREV = 'Play Prev'
|
||||||
|
SKIP = 'Skip'
|
||||||
|
PAUSE = 'Pause'
|
||||||
|
RESUME = 'Resume'
|
||||||
|
CONTEXT = 'Context'
|
||||||
|
PLAY = 'Play'
|
||||||
|
|
||||||
|
|
||||||
|
class VCommands:
|
||||||
|
def __init__(self, type: VCommandsType, args=None) -> None:
|
||||||
|
self.__type = type
|
||||||
|
self.__args = args
|
||||||
|
|
||||||
|
def getType(self) -> VCommandsType:
|
||||||
|
return self.__type
|
||||||
|
|
||||||
|
def getArgs(self) -> Tuple:
|
||||||
|
return self.__args
|
||||||
236
Parallelism/PlayerProcess.py
Normal file
236
Parallelism/PlayerProcess.py
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import asyncio
|
||||||
|
from os import listdir
|
||||||
|
from discord import Intents
|
||||||
|
from asyncio import AbstractEventLoop, Semaphore
|
||||||
|
from multiprocessing import Process, Queue
|
||||||
|
from threading import Lock, Thread
|
||||||
|
from typing import Callable, Text
|
||||||
|
from discord import Client, Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
|
||||||
|
from discord.ext.commands import Context
|
||||||
|
from Music.Playlist import Playlist
|
||||||
|
from Music.Song import Song
|
||||||
|
from Config.Configs import Configs
|
||||||
|
from discord.ext.commands import Bot
|
||||||
|
from Parallelism.Commands import VCommands, VCommandsType
|
||||||
|
|
||||||
|
|
||||||
|
class TimeoutClock:
|
||||||
|
def __init__(self, callback: Callable, loop: asyncio.AbstractEventLoop):
|
||||||
|
self.__callback = callback
|
||||||
|
self.__task = loop.create_task(self.__executor())
|
||||||
|
|
||||||
|
async def __executor(self):
|
||||||
|
await asyncio.sleep(Configs().VC_TIMEOUT)
|
||||||
|
await self.__callback()
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
self.__task.cancel()
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerProcess(Process):
|
||||||
|
"""Process that will play songs, receive commands by a received Queue"""
|
||||||
|
|
||||||
|
def __init__(self, playlist: Playlist, lock: Lock, queue: Queue) -> None:
|
||||||
|
Process.__init__(self, group=None, target=None, args=(), kwargs={})
|
||||||
|
self.__playlist: Playlist = playlist
|
||||||
|
self.__lock: Lock = lock
|
||||||
|
self.__queue: Queue = queue
|
||||||
|
|
||||||
|
# All information of discord context will be retrieved directly with discord API
|
||||||
|
self.__guild: Guild = None
|
||||||
|
self.__bot: Client = None
|
||||||
|
self.__voiceChannel: VoiceChannel = None
|
||||||
|
self.__textChannel: TextChannel = None
|
||||||
|
self.__loop: AbstractEventLoop = None
|
||||||
|
self.__configs: Configs = None
|
||||||
|
|
||||||
|
self.__playing = False
|
||||||
|
|
||||||
|
# Flag to control if the player should stop totally the playing
|
||||||
|
self.__forceStop = False
|
||||||
|
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
|
||||||
|
'options': '-vn'}
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
"""Function called in process.start(), this will exec the actually _run method it in event loop"""
|
||||||
|
print('Run')
|
||||||
|
|
||||||
|
self.__loop = asyncio.get_event_loop()
|
||||||
|
self.__configs = Configs()
|
||||||
|
|
||||||
|
# self.__loop = self.__bot.loop
|
||||||
|
self.__semStopPlaying = Semaphore(0)
|
||||||
|
self.__stopped = asyncio.Event()
|
||||||
|
# task = self.__loop.create_task(self._run())
|
||||||
|
self.__loop.run_until_complete(self._run())
|
||||||
|
|
||||||
|
async def _run(self) -> None:
|
||||||
|
# Recreate the bot instance in this new process
|
||||||
|
self.__bot = await self.__createBotInstance()
|
||||||
|
|
||||||
|
# Start the timeout function
|
||||||
|
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
|
||||||
|
# Thread that will receive commands to execute in this Process
|
||||||
|
self.__commandsReceiver = Thread(target=self.__commandsReceiver, daemon=True)
|
||||||
|
self.__commandsReceiver.start()
|
||||||
|
|
||||||
|
# Start a Task to play songs
|
||||||
|
self.__loop.create_task(self.__playPlaylistSongs())
|
||||||
|
# Try to acquire a semaphore, it'll be release when timeout function trigger, we use the Semaphore
|
||||||
|
# from the asyncio lib to not block the event loop
|
||||||
|
await self.__semStopPlaying.acquire()
|
||||||
|
|
||||||
|
async def __playPlaylistSongs(self) -> None:
|
||||||
|
if not self.__playing:
|
||||||
|
with self.__lock:
|
||||||
|
song = self.__playlist.next_song()
|
||||||
|
|
||||||
|
await self.__playSong(song)
|
||||||
|
|
||||||
|
async def __playSong(self, song: Song) -> None:
|
||||||
|
try:
|
||||||
|
source = await self.__ensureSource(song)
|
||||||
|
if source is None:
|
||||||
|
self.__playNext(None, self.__context)
|
||||||
|
self.__playing = True
|
||||||
|
|
||||||
|
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
|
||||||
|
voice = self.__guild.voice_client
|
||||||
|
voice.play(player, after=lambda e: self.__playNext(e, self.__context))
|
||||||
|
|
||||||
|
self.__timer.cancel()
|
||||||
|
self.__timer = TimeoutClock(self.__timeout_handler)
|
||||||
|
|
||||||
|
await self.__context.invoke(self.__bot.get_command('np'))
|
||||||
|
except:
|
||||||
|
self.__playNext(None)
|
||||||
|
|
||||||
|
def __playNext(self, error) -> None:
|
||||||
|
if self.__forceStop: # If it's forced to stop player
|
||||||
|
self.__forceStop = False
|
||||||
|
return None
|
||||||
|
|
||||||
|
with self.__lock:
|
||||||
|
song = self.__playlist.next_song()
|
||||||
|
|
||||||
|
if song is not None:
|
||||||
|
coro = self.__playSong(song)
|
||||||
|
self.__bot.loop.create_task(coro)
|
||||||
|
else:
|
||||||
|
self.__playing = False
|
||||||
|
|
||||||
|
def __commandsReceiver(self) -> None:
|
||||||
|
for x in range(2):
|
||||||
|
command: VCommands = self.__queue.get()
|
||||||
|
type = command.getType()
|
||||||
|
args = command.getArgs()
|
||||||
|
|
||||||
|
if type == VCommandsType.PAUSE:
|
||||||
|
self.pause()
|
||||||
|
elif type == VCommandsType.PLAY:
|
||||||
|
self.__loop.create_task(self.__playPlaylistSongs())
|
||||||
|
elif type == VCommandsType.PLAY_PREV:
|
||||||
|
self.__playPrev()
|
||||||
|
elif type == VCommandsType.RESUME:
|
||||||
|
pass
|
||||||
|
elif type == VCommandsType.SKIP:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(f'[ERROR] -> Unknown Command Received: {command}')
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
print(id(self))
|
||||||
|
|
||||||
|
async def __playPrev(self, ctx: Context) -> None:
|
||||||
|
with self.__lock:
|
||||||
|
song = self.__playlist.prev_song()
|
||||||
|
if song is not None:
|
||||||
|
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
|
||||||
|
# Will forbidden next_song to execute after stopping current player
|
||||||
|
self.__forceStop = True
|
||||||
|
self.__guild.voice_client.stop()
|
||||||
|
self.__playing = False
|
||||||
|
|
||||||
|
await self.__playSong(ctx, song)
|
||||||
|
|
||||||
|
async def __forceStop(self) -> None:
|
||||||
|
try:
|
||||||
|
if self.__guild.voice_client is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.__guild.voice_client.stop()
|
||||||
|
await self.__guild.voice_client.disconnect()
|
||||||
|
with self.__lock:
|
||||||
|
self.__playlist.clear()
|
||||||
|
self.__playlist.loop_off()
|
||||||
|
except Exception as e:
|
||||||
|
print(f'DEVELOPER NOTE -> Force Stop Error: {e}')
|
||||||
|
|
||||||
|
async def __createBotInstance(self) -> Client:
|
||||||
|
# Load a new bot instance, this bot should not receive commands directly
|
||||||
|
intents = Intents.default()
|
||||||
|
intents.members = True
|
||||||
|
bot = Bot(command_prefix='Rafael',
|
||||||
|
pm_help=True,
|
||||||
|
case_insensitive=True,
|
||||||
|
intents=intents)
|
||||||
|
bot.remove_command('help')
|
||||||
|
|
||||||
|
# Add the Cogs for this bot too
|
||||||
|
for filename in listdir(f'./{self.__configs.COMMANDS_PATH}'):
|
||||||
|
print(filename)
|
||||||
|
if filename.endswith('.py'):
|
||||||
|
bot.load_extension(f'{self.__configs.COMMANDS_PATH}.{filename[:-3]}')
|
||||||
|
|
||||||
|
# Login and connect the bot instance to discord API
|
||||||
|
task = self.__loop.create_task(bot.login(token=self.__configs.BOT_TOKEN, bot=True))
|
||||||
|
await task
|
||||||
|
self.__loop.create_task(bot.connect(reconnect=True))
|
||||||
|
# Sleep to wait connection to be established
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
self.__guild: Guild = bot.get_guild(651983781258985484)
|
||||||
|
self.__voiceChannel = self.__bot.get_channel(933437427350118450)
|
||||||
|
|
||||||
|
return bot
|
||||||
|
|
||||||
|
async def __timeoutHandler(self) -> None:
|
||||||
|
if self.__guild.voice_client is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
|
||||||
|
self.__timer = TimeoutClock(self.__timeoutHandler)
|
||||||
|
|
||||||
|
elif self.__guild.voice_client.is_connected():
|
||||||
|
with self.__lock:
|
||||||
|
self.__playlist.clear()
|
||||||
|
self.__playlist.loop_off()
|
||||||
|
await self.__guild.voice_client.disconnect()
|
||||||
|
# Release semaphore to finish process
|
||||||
|
self.__semStopPlaying.release()
|
||||||
|
|
||||||
|
async def __ensureSource(self, song: Song) -> str:
|
||||||
|
while True:
|
||||||
|
if song.source is not None: # If song got downloaded
|
||||||
|
return song.source
|
||||||
|
|
||||||
|
if song.problematic: # If song got any error
|
||||||
|
return None
|
||||||
|
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
|
def __is_connected(self) -> bool:
|
||||||
|
try:
|
||||||
|
if not self.__voiceChannel.is_connected():
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def __connect(self) -> bool:
|
||||||
|
try:
|
||||||
|
await self.__voiceChannel.connect(reconnect=True, timeout=None)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
22
Parallelism/ProcessContext.py
Normal file
22
Parallelism/ProcessContext.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from multiprocessing import Process, Queue, Lock
|
||||||
|
from Music.Playlist import Playlist
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessContext:
|
||||||
|
def __init__(self, process: Process, queue: Queue, playlist: Playlist, lock: Lock) -> None:
|
||||||
|
self.__process = process
|
||||||
|
self.__queue = queue
|
||||||
|
self.__playlist = playlist
|
||||||
|
self.__lock = lock
|
||||||
|
|
||||||
|
def getProcess(self) -> Process:
|
||||||
|
return self.__process
|
||||||
|
|
||||||
|
def getQueue(self) -> Queue:
|
||||||
|
return self.__queue
|
||||||
|
|
||||||
|
def getPlaylist(self) -> Playlist:
|
||||||
|
return self.__playlist
|
||||||
|
|
||||||
|
def getLock(self) -> Lock:
|
||||||
|
return self.__lock
|
||||||
45
Parallelism/ProcessManager.py
Normal file
45
Parallelism/ProcessManager.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from multiprocessing import Queue, Lock
|
||||||
|
from multiprocessing.managers import BaseManager, NamespaceProxy
|
||||||
|
from typing import Dict
|
||||||
|
from Config.Singleton import Singleton
|
||||||
|
from discord import Guild, Client
|
||||||
|
from discord.ext.commands import Context
|
||||||
|
from Parallelism.PlayerProcess import PlayerProcess
|
||||||
|
from Music.Playlist import Playlist
|
||||||
|
from Parallelism.ProcessContext import ProcessContext
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessManager(Singleton):
|
||||||
|
def __init__(self, bot: Client = None) -> None:
|
||||||
|
if not super().created:
|
||||||
|
Manager.register('Playlist', Playlist)
|
||||||
|
self.__manager = Manager()
|
||||||
|
self.__manager.start()
|
||||||
|
if bot is not None:
|
||||||
|
self.__bot: Client = bot
|
||||||
|
self.__playersProcess: Dict[Guild, ProcessContext] = {}
|
||||||
|
|
||||||
|
def setPlayerContext(self, guild: Guild, context: ProcessContext):
|
||||||
|
self.__playersProcess[guild] = context
|
||||||
|
|
||||||
|
def getPlayerContext(self, guild: Guild, context: Context) -> ProcessContext:
|
||||||
|
try:
|
||||||
|
print('Get')
|
||||||
|
if guild not in self.__playersProcess.keys():
|
||||||
|
playlist: Playlist = self.__manager.Playlist()
|
||||||
|
lock = Lock()
|
||||||
|
queue = Queue()
|
||||||
|
process = PlayerProcess(playlist, lock, queue)
|
||||||
|
processContext = ProcessContext(process, queue, playlist, lock)
|
||||||
|
self.__playersProcess[guild] = processContext
|
||||||
|
return self.__playersProcess[guild]
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
class Manager(BaseManager):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyBase(NamespaceProxy):
|
||||||
|
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
|
||||||
5
main.py
5
main.py
@ -33,5 +33,6 @@ class VulkanInitializer:
|
|||||||
self.__bot.run(self.__config.BOT_TOKEN, bot=True, reconnect=True)
|
self.__bot.run(self.__config.BOT_TOKEN, bot=True, reconnect=True)
|
||||||
|
|
||||||
|
|
||||||
vulkan = VulkanInitializer()
|
if __name__ == '__main__':
|
||||||
vulkan.run()
|
vulkan = VulkanInitializer()
|
||||||
|
vulkan.run()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user