Finishing work with the second queue

This commit is contained in:
Rafael Vargas 2022-07-28 11:32:04 -03:00
parent 60a36425ee
commit c5885f3093
6 changed files with 94 additions and 111 deletions

View File

@ -18,7 +18,7 @@ class VConfigs(Singleton):
self.CLEANER_MESSAGES_QUANT = 5
self.ACQUIRE_LOCK_TIMEOUT = 10
self.COMMANDS_PATH = 'DiscordCogs'
self.VC_TIMEOUT = 600
self.VC_TIMEOUT = 300
self.MAX_PLAYLIST_LENGTH = 50
self.MAX_PLAYLIST_FORCED_LENGTH = 5

View File

@ -22,7 +22,6 @@ class ClearHandler(AbstractHandler):
if acquired:
playlist.clear()
processLock.release()
processLock.release()
return HandlerResponse(self.ctx)
else:
processManager.resetProcess(self.guild, self.ctx)

View File

@ -1,5 +1,5 @@
from typing import List
from discord import Embed, Message
from discord import Embed, Message, TextChannel
from Music.VulkanBot import VulkanBot
from Parallelism.ProcessInfo import ProcessInfo
from Config.Configs import VConfigs
@ -19,23 +19,25 @@ class MessagesController:
async def sendNowPlaying(self, processInfo: ProcessInfo, song: Song) -> None:
# Get the lock of the playlist
print('Entrei')
playlistLock = processInfo.getLock()
playlist = processInfo.getPlaylist()
with playlistLock:
print('A')
if playlist.isLoopingOne():
title = self.__messages.ONE_SONG_LOOPING
else:
title = self.__messages.SONG_PLAYING
if playlist.isLoopingOne():
title = self.__messages.ONE_SONG_LOOPING
else:
title = self.__messages.SONG_PLAYING
embed = self.__embeds.SONG_INFO(song.info, title)
view = PlayerView(self.__bot)
channel = processInfo.getTextChannel()
# Create View and Embed
embed = self.__embeds.SONG_INFO(song.info, title)
view = PlayerView(self.__bot)
channel = processInfo.getTextChannel()
# Delete the previous and send the message
await self.__deletePreviousNPMessages()
await channel.send(embed=embed, view=view)
await self.__deletePreviousNPMessages()
await channel.send(embed=embed, view=view)
self.__previousMessages.append(await self.__getSendedMessage())
# Get the sended message
sendedMessage = await self.__getSendedMessage(channel)
# Set the message witch contains the view
view.set_message(message=sendedMessage)
self.__previousMessages.append(sendedMessage)
async def __deletePreviousNPMessages(self) -> None:
for message in self.__previousMessages:
@ -45,9 +47,9 @@ class MessagesController:
pass
self.__previousMessages.clear()
async def __getSendedMessage(self) -> Message:
async def __getSendedMessage(self, channel: TextChannel) -> Message:
stringToIdentify = 'Uploader:'
last_messages: List[Message] = await self.__textChannel.history(limit=5).flatten()
last_messages: List[Message] = await channel.history(limit=5).flatten()
for message in last_messages:
try:

View File

@ -1,8 +1,8 @@
import asyncio
from Music.VulkanInitializer import VulkanInitializer
from discord import User, Member, Message, Embed
from discord import User, Member, Message
from asyncio import AbstractEventLoop, Semaphore, Queue
from multiprocessing import Process, RLock, Lock
from multiprocessing import Process, RLock, Lock, Queue
from threading import Thread
from typing import Callable, List
from discord import Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
@ -97,7 +97,8 @@ class PlayerProcess(Process):
# Start the timeout function
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
# Thread that will receive commands to be executed in this Process
self.__loop.create_task(self.__commandsReceiver())
self.__commandsReceiver = Thread(target=self.__commandsReceiver, daemon=True)
self.__commandsReceiver.start()
# Start a Task to play songs
self.__loop.create_task(self.__playPlaylistSongs())
@ -147,9 +148,7 @@ class PlayerProcess(Process):
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
nowPlayingCommand = VCommands(VCommandsType.NOW_PLAYING, song)
await self.__queueSend.put(nowPlayingCommand)
# await self.__deletePrevNowPlaying()
# await self.__showNowPlaying()
self.__queueSend.put(nowPlayingCommand)
except Exception as e:
print(f'[ERROR IN PLAY SONG] -> {e}, {type(e)}')
self.__playNext(None)
@ -171,6 +170,11 @@ class PlayerProcess(Process):
self.__playlist.loop_off()
self.__playingSong = None
self.__playing = False
# Send a command to the main process put this one to sleep
sleepCommand = VCommands(VCommandsType.SLEEPING)
self.__queueSend.put(sleepCommand)
# Release the semaphore to finish the process
self.__semStopPlaying.release()
async def __playPrev(self, voiceChannelID: int) -> None:
with self.__playlistLock:
@ -192,9 +196,9 @@ class PlayerProcess(Process):
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
async def __commandsReceiver(self) -> None:
def __commandsReceiver(self) -> None:
while True:
command: VCommands = await self.__queueReceive.get()
command: VCommands = self.__queueReceive.get()
type = command.getType()
args = command.getArgs()
@ -207,13 +211,13 @@ class PlayerProcess(Process):
elif type == VCommandsType.SKIP:
self.__skip()
elif type == VCommandsType.PLAY:
await self.__playPlaylistSongs()
asyncio.run_coroutine_threadsafe(self.__playPlaylistSongs(), self.__loop)
elif type == VCommandsType.PREV:
await self.__playPrev(args)
asyncio.run_coroutine_threadsafe(self.__playPrev(args), self.__loop)
elif type == VCommandsType.RESET:
await self.__reset()
asyncio.run_coroutine_threadsafe(self.__reset(), self.__loop)
elif type == VCommandsType.STOP:
await self.__stop()
asyncio.run_coroutine_threadsafe(self.__stop(), self.__loop)
else:
print(f'[ERROR] -> Unknown Command Received: {command}')
except Exception as e:
@ -242,9 +246,11 @@ class PlayerProcess(Process):
if self.__guild.voice_client is not None:
if self.__guild.voice_client.is_connected():
with self.__playlistLock:
self.__playlist.clear()
self.__playlist.loop_off()
# Send a command to the main process put this to sleep
sleepCommand = VCommands(VCommandsType.SLEEPING)
self.__queueSend.put(sleepCommand)
self.__guild.voice_client.stop()
self.__playingSong = None
await self.__guild.voice_client.disconnect()
@ -291,20 +297,35 @@ class PlayerProcess(Process):
return
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
if not self.__isBotAloneInChannel(): # If bot is not alone continue to play
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
return
elif self.__guild.voice_client.is_connected():
# Finish the process
if self.__guild.voice_client.is_connected():
with self.__playerLock:
with self.__playlistLock:
self.__playlist.clear()
self.__playlist.loop_off()
self.__playing = False
await self.__guild.voice_client.disconnect()
# Send command to main process to finish this one
sleepCommand = VCommands(VCommandsType.SLEEPING)
self.__queueSend.put(sleepCommand)
# Release semaphore to finish process
self.__semStopPlaying.release()
except Exception as e:
print(f'[Error in Timeout] -> {e}')
def __isBotAloneInChannel(self) -> bool:
try:
if len(self.__guild.voice_client.channel.members) <= 1:
return True
else:
return False
except Exception as e:
print(f'[ERROR IN CHECK BOT ALONE] -> {e}')
return False
async def __ensureDiscordConnection(self, bot: VulkanBot) -> None:
"""Await in this point until connection to discord is established"""
guild = None
@ -325,46 +346,3 @@ class PlayerProcess(Process):
for member in guild_members:
if member.id == self.__bot.user.id:
return member
async def __showNowPlaying(self) -> None:
# Get the lock of the playlist
with self.__playlistLock:
if not self.__playing or self.__playingSong is None:
embed = self.__embeds.NOT_PLAYING()
await self.__textChannel.send(embed=embed)
return
if self.__playlist.isLoopingOne():
title = self.__messages.ONE_SONG_LOOPING
else:
title = self.__messages.SONG_PLAYING
info = self.__playingSong.info
embed = self.__embeds.SONG_INFO(info, title)
await self.__textChannel.send(embed=embed)
self.__messagesToDelete.append(await self.__getSendedMessage())
async def __deletePrevNowPlaying(self) -> None:
for message in self.__messagesToDelete:
try:
await message.delete()
except:
pass
self.__messagesToDelete.clear()
async def __getSendedMessage(self) -> Message:
stringToIdentify = 'Uploader:'
last_messages: List[Message] = await self.__textChannel.history(limit=5).flatten()
for message in last_messages:
try:
if message.author == self.__bot.user:
if len(message.embeds) > 0:
embed: Embed = message.embeds[0]
if len(embed.fields) > 0:
if embed.fields[0].name == stringToIdentify:
return message
except Exception as e:
print(f'DEVELOPER NOTE -> Error cleaning messages {e}')
continue

View File

@ -1,6 +1,5 @@
from asyncio import Queue, Task
import asyncio
from multiprocessing import Lock
from multiprocessing import Lock, Queue
from multiprocessing.managers import BaseManager, NamespaceProxy
from queue import Empty
from threading import Thread
@ -15,7 +14,6 @@ from Music.Playlist import Playlist
from Parallelism.ProcessInfo import ProcessInfo
from Parallelism.Commands import VCommands, VCommandsType
from Music.VulkanBot import VulkanBot
from Tests.LoopRunner import LoopRunner
class ProcessManager(Singleton):
@ -31,8 +29,7 @@ class ProcessManager(Singleton):
self.__manager = VManager()
self.__manager.start()
self.__playersProcess: Dict[Guild, ProcessInfo] = {}
# self.__playersListeners: Dict[Guild, Tuple[Thread, bool]] = {}
self.__playersListeners: Dict[Guild, Task] = {}
self.__playersListeners: Dict[Guild, Tuple[Thread, bool]] = {}
self.__playersMessages: Dict[Guild, MessagesController] = {}
def setPlayerInfo(self, guild: Guild, info: ProcessInfo):
@ -94,11 +91,11 @@ class ProcessManager(Singleton):
processInfo = ProcessInfo(process, queueToSend, queueToListen,
playlist, lock, context.channel)
task = asyncio.create_task(self.__listenToCommands(queueToListen, guild))
# Create a Thread to listen for the queue coming from the Player Process
# thread = Thread(target=self.__listenToCommands, args=(queueToListen, guild), daemon=True)
self.__playersListeners[guildID] = task
# thread.start()
# Create a Thread to listen for the queue coming from the Player Process, this will redirect the Queue to a async
thread = Thread(target=self.__listenToCommands,
args=(queueToListen, guild), daemon=True)
self.__playersListeners[guildID] = (thread, False)
thread.start()
# Create a Message Controller for this player
self.__playersMessages[guildID] = MessagesController(self.__bot)
@ -118,48 +115,46 @@ class ProcessManager(Singleton):
queueToSend = Queue()
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend,
queueToListen, guildID, textID, voiceID, authorID)
processInfo = ProcessInfo(process, queueToSend, queueToListen, playlist, lock)
processInfo = ProcessInfo(process, queueToSend, queueToListen,
playlist, lock, context.channel)
task = asyncio.create_task(self.__listenToCommands(queueToListen, guild))
# Create a Thread to listen for the queue coming from the Player Process
# thread = Thread(target=self.__listenToCommands, args=(queueToListen, guild), daemon=True)
self.__playersListeners[guildID] = task
# thread.start()
# Create a Message Controller for this player
self.__playersMessages[guildID] = MessagesController(self.__bot)
# Create a Thread to listen for the queue coming from the Player Process, this will redirect the Queue to a async
thread = Thread(target=self.__listenToCommands,
args=(queueToListen, guild), daemon=True)
self.__playersListeners[guildID] = (thread, False)
thread.start()
return processInfo
async def __listenToCommands(self, queue: Queue, guild: Guild) -> None:
shouldEnd = False
def __listenToCommands(self, queue: Queue, guild: Guild) -> None:
guildID = guild.id
while not shouldEnd:
while True:
shouldEnd = self.__playersListeners[guildID][1]
if shouldEnd:
break
try:
print('Esperando')
command: VCommands = await queue.get()
command: VCommands = queue.get(timeout=5)
commandType = command.getType()
args = command.getArgs()
print(f'Process {guild.name} sended command {commandType}')
if commandType == VCommandsType.NOW_PLAYING:
print('Aqui dentro')
await self.__showNowPlaying(args, guildID)
asyncio.run_coroutine_threadsafe(self.showNowPlaying(
guild.id, args), self.__bot.loop)
elif commandType == VCommandsType.TERMINATE:
# Delete the process elements and return, to finish task
self.__terminateProcess()
self.__terminateProcess(guildID)
return
elif commandType == VCommandsType.SLEEPING:
# The process might be used again
self.__sleepingProcess()
self.__sleepingProcess(guildID)
return
else:
print(f'[ERROR] -> Unknown Command Received from Process: {commandType}')
except Empty:
continue
except Exception as e:
print(e)
print(f'[ERROR IN LISTENING PROCESS] -> {guild.name} - {e}')
def __terminateProcess(self, guildID: int) -> None:
@ -179,12 +174,10 @@ class ProcessManager(Singleton):
queue2.close()
queue2.join_thread()
async def __showNowPlaying(self, guildID: int, song: Song) -> None:
async def showNowPlaying(self, guildID: int, song: Song) -> None:
messagesController = self.__playersMessages[guildID]
processInfo = self.__playersProcess[guildID]
print('Aq1')
await messagesController.sendNowPlaying(processInfo, song)
print('Aq2')
class VManager(BaseManager):

View File

@ -1,3 +1,4 @@
from discord import Message
from discord.ui import View
from Config.Emojis import VEmojis
from UI.Buttons.PauseButton import PauseButton
@ -15,9 +16,10 @@ emojis = VEmojis()
class PlayerView(View):
def __init__(self, bot: VulkanBot, timeout: float = 180):
def __init__(self, bot: VulkanBot, timeout: float = 6000):
super().__init__(timeout=timeout)
self.__bot = bot
self.__message: Message = None
self.add_item(BackButton(self.__bot))
self.add_item(PauseButton(self.__bot))
self.add_item(PlayButton(self.__bot))
@ -27,3 +29,12 @@ class PlayerView(View):
self.add_item(LoopOneButton(self.__bot))
self.add_item(LoopOffButton(self.__bot))
self.add_item(LoopAllButton(self.__bot))
async def on_timeout(self) -> None:
# Disable all itens and, if has the message, edit it
self.disable_all_items()
if self.__message is not None and isinstance(self.__message, Message):
await self.__message.edit(view=self)
def set_message(self, message: Message) -> None:
self.__message = message