Skip to content

Commit

Permalink
Finishing work with the second queue
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelSolVargas committed Jul 28, 2022
1 parent 60a3642 commit c5885f3
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Config/Configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self) -> None:
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
Expand Down
1 change: 0 additions & 1 deletion Handlers/ClearHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ async def run(self) -> HandlerResponse:
if acquired:
playlist.clear()
processLock.release()
processLock.release()
return HandlerResponse(self.ctx)
else:
processManager.resetProcess(self.guild, self.ctx)
Expand Down
36 changes: 19 additions & 17 deletions Music/MessagesController.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,23 +19,25 @@ def __init__(self, bot: VulkanBot) -> None:

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:
Expand All @@ -45,9 +47,9 @@ async def __deletePreviousNPMessages(self) -> None:
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:
Expand Down
96 changes: 37 additions & 59 deletions Parallelism/PlayerProcess.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -97,7 +97,8 @@ async def _run(self) -> None:
# 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())
Expand Down Expand Up @@ -147,9 +148,7 @@ async def __playSong(self, song: Song) -> None:
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)
Expand All @@ -171,6 +170,11 @@ def __playNext(self, error) -> None:
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:
Expand All @@ -192,9 +196,9 @@ async def __playPrev(self, voiceChannelID: int) -> None:

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()

Expand All @@ -207,13 +211,13 @@ async def __commandsReceiver(self) -> None:
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:
Expand Down Expand Up @@ -242,9 +246,11 @@ async def __stop(self) -> None:
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()
Expand Down Expand Up @@ -291,20 +297,35 @@ async def __timeoutHandler(self) -> None:
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
Expand All @@ -325,46 +346,3 @@ def __getBotMember(self) -> Member:
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
57 changes: 25 additions & 32 deletions Parallelism/ProcessManager.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -15,7 +14,6 @@
from Parallelism.ProcessInfo import ProcessInfo
from Parallelism.Commands import VCommands, VCommandsType
from Music.VulkanBot import VulkanBot
from Tests.LoopRunner import LoopRunner


class ProcessManager(Singleton):
Expand All @@ -31,8 +29,7 @@ def __init__(self, bot: VulkanBot = None) -> None:
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):
Expand Down Expand Up @@ -94,11 +91,11 @@ def __createProcessInfo(self, guild: Guild, context: Context) -> ProcessInfo:
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)
Expand All @@ -118,48 +115,46 @@ def __recreateProcess(self, guild: Guild, context: Context) -> ProcessInfo:
queueToSend = Queue()
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend,
queueToListen, guildID, textID, voiceID, authorID)
processInfo = ProcessInfo(process, queueToSend, queueToListen, playlist, lock)

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()
processInfo = ProcessInfo(process, queueToSend, queueToListen,
playlist, lock, context.channel)

# 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:
Expand All @@ -179,12 +174,10 @@ def __sleepingProcess(self, guildID: int) -> None:
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):
Expand Down
Loading

0 comments on commit c5885f3

Please sign in to comment.