.BANCHO. Use streams for public chat
This commit is contained in:
		@@ -90,3 +90,9 @@ class unknownStreamException(Exception):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class userTournamentException(Exception):
 | 
					class userTournamentException(Exception):
 | 
				
			||||||
	pass
 | 
						pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class userAlreadyInChannelException(Exception):
 | 
				
			||||||
 | 
						pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class userNotInChannelException(Exception):
 | 
				
			||||||
 | 
						pass
 | 
				
			||||||
@@ -656,7 +656,7 @@ def pp(fro, chan, message):
 | 
				
			|||||||
	pp = userUtils.getPP(token.userID, gameMode)
 | 
						pp = userUtils.getPP(token.userID, gameMode)
 | 
				
			||||||
	return "You have {:,} pp".format(pp)
 | 
						return "You have {:,} pp".format(pp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def updateBeatmap(fro, chan, to):
 | 
					def updateBeatmap(fro, chan, message):
 | 
				
			||||||
	try:
 | 
						try:
 | 
				
			||||||
		# Run the command in PM only
 | 
							# Run the command in PM only
 | 
				
			||||||
		if chan.startswith("#"):
 | 
							if chan.startswith("#"):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,11 +155,13 @@ def channelJoinSuccess(userID, chan):
 | 
				
			|||||||
	return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.STRING]])
 | 
						return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.STRING]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def channelInfo(chan):
 | 
					def channelInfo(chan):
 | 
				
			||||||
 | 
						if chan not in glob.channels.channels:
 | 
				
			||||||
 | 
							return bytes()
 | 
				
			||||||
	channel = glob.channels.channels[chan]
 | 
						channel = glob.channels.channels[chan]
 | 
				
			||||||
	return packetHelper.buildPacket(packetIDs.server_channelInfo, [
 | 
						return packetHelper.buildPacket(packetIDs.server_channelInfo, [
 | 
				
			||||||
		[chan, dataTypes.STRING],
 | 
							[channel.name, dataTypes.STRING],
 | 
				
			||||||
		[channel.description, dataTypes.STRING],
 | 
							[channel.description, dataTypes.STRING],
 | 
				
			||||||
		[len(channel.connectedUsers), dataTypes.UINT16]
 | 
							[len(glob.streams.streams["chat/{}".format(chan)].clients), dataTypes.UINT16]
 | 
				
			||||||
	])
 | 
						])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def channelInfoEnd():
 | 
					def channelInfoEnd():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,13 @@ from objects import glob
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def handle(userToken, _):
 | 
					def handle(userToken, _):
 | 
				
			||||||
	# Get usertoken data
 | 
						# Get usertoken data
 | 
				
			||||||
	userID = userToken.userID
 | 
					 | 
				
			||||||
	username = userToken.username
 | 
						username = userToken.username
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Remove user from users in lobby
 | 
						# Remove user from users in lobby
 | 
				
			||||||
	userToken.leaveStream("lobby")
 | 
						userToken.leaveStream("lobby")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Part lobby channel
 | 
						# Part lobby channel
 | 
				
			||||||
 | 
						# Done automatically by the client
 | 
				
			||||||
	chat.partChannel(channel="#lobby", token=userToken, kick=True)
 | 
						chat.partChannel(channel="#lobby", token=userToken, kick=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Console output
 | 
						# Console output
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,44 +27,32 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
 | 
				
			|||||||
				raise exceptions.userNotFoundException
 | 
									raise exceptions.userNotFoundException
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			token = token
 | 
								token = token
 | 
				
			||||||
			userID = token.userID
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Get usertoken data
 | 
					 | 
				
			||||||
		username = token.username
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Normal channel, do check stuff
 | 
							# Normal channel, do check stuff
 | 
				
			||||||
		# Make sure the channel exists
 | 
							# Make sure the channel exists
 | 
				
			||||||
		if channel not in glob.channels.channels:
 | 
							if channel not in glob.channels.channels:
 | 
				
			||||||
			raise exceptions.channelUnknownException
 | 
								raise exceptions.channelUnknownException()
 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Check channel permissions
 | 
					 | 
				
			||||||
		channelObject = glob.channels.channels[channel]
 | 
					 | 
				
			||||||
		if channelObject.publicRead == False and token.admin == False:
 | 
					 | 
				
			||||||
			raise exceptions.channelNoPermissionsException
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Add our userID to users in that channel
 | 
					 | 
				
			||||||
		channelObject.userJoin(userID)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Add the channel to our joined channel
 | 
							# Add the channel to our joined channel
 | 
				
			||||||
		token.joinChannel(channel)
 | 
							token.joinChannel(glob.channels.channels[channel])
 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Send channel joined (bancho). We use clientName here because of #multiplayer and #spectator channels
 | 
					 | 
				
			||||||
		token.enqueue(serverPackets.channelJoinSuccess(userID, channelObject.clientName))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Send channel joined (IRC)
 | 
							# Send channel joined (IRC)
 | 
				
			||||||
		if glob.irc == True and toIRC == True:
 | 
							if glob.irc == True and toIRC == True:
 | 
				
			||||||
			glob.ircServer.banchoJoinChannel(username, channel)
 | 
								glob.ircServer.banchoJoinChannel(token.username, channel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Console output
 | 
							# Console output
 | 
				
			||||||
		log.info("{} joined channel {}".format(username, channel))
 | 
							log.info("{} joined channel {}".format(token.username, channel))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# IRC code return
 | 
							# IRC code return
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
	except exceptions.channelNoPermissionsException:
 | 
						except exceptions.channelNoPermissionsException:
 | 
				
			||||||
		log.warning("{} attempted to join channel {}, but they have no read permissions".format(username, channel))
 | 
							log.warning("{} attempted to join channel {}, but they have no read permissions".format(token.username, channel))
 | 
				
			||||||
		return 403
 | 
							return 403
 | 
				
			||||||
	except exceptions.channelUnknownException:
 | 
						except exceptions.channelUnknownException:
 | 
				
			||||||
		log.warning("{} attempted to join an unknown channel ({})".format(username, channel))
 | 
							log.warning("{} attempted to join an unknown channel ({})".format(token.username, channel))
 | 
				
			||||||
 | 
							return 403
 | 
				
			||||||
 | 
						except exceptions.userAlreadyInChannelException:
 | 
				
			||||||
 | 
							log.warning("User {} already in channel {}".format(token.username, channel))
 | 
				
			||||||
		return 403
 | 
							return 403
 | 
				
			||||||
	except exceptions.userNotFoundException:
 | 
						except exceptions.userNotFoundException:
 | 
				
			||||||
		log.warning("User not connected to IRC/Bancho")
 | 
							log.warning("User not connected to IRC/Bancho")
 | 
				
			||||||
@@ -82,6 +70,10 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
 | 
				
			|||||||
	:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
 | 
						:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
 | 
				
			||||||
	"""
 | 
						"""
 | 
				
			||||||
	try:
 | 
						try:
 | 
				
			||||||
 | 
							# Make sure the client is not drunk and sends partChannel when closing a PM tab
 | 
				
			||||||
 | 
							if not channel.startswith("#"):
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Get token if not defined
 | 
							# Get token if not defined
 | 
				
			||||||
		if token is None:
 | 
							if token is None:
 | 
				
			||||||
			token = glob.tokens.getTokenFromUserID(userID)
 | 
								token = glob.tokens.getTokenFromUserID(userID)
 | 
				
			||||||
@@ -90,10 +82,6 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
 | 
				
			|||||||
				raise exceptions.userNotFoundException
 | 
									raise exceptions.userNotFoundException
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			token = token
 | 
								token = token
 | 
				
			||||||
			userID = token.userID
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Get usertoken data
 | 
					 | 
				
			||||||
		username = token.username
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Determine internal/client name if needed
 | 
							# Determine internal/client name if needed
 | 
				
			||||||
		# (toclient is used clientwise for #multiplayer and #spectator channels)
 | 
							# (toclient is used clientwise for #multiplayer and #spectator channels)
 | 
				
			||||||
@@ -113,12 +101,22 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		# Make sure the channel exists
 | 
							# Make sure the channel exists
 | 
				
			||||||
		if channel not in glob.channels.channels:
 | 
							if channel not in glob.channels.channels:
 | 
				
			||||||
			raise exceptions.channelUnknownException
 | 
								raise exceptions.channelUnknownException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Make sure the user is in the channel
 | 
				
			||||||
 | 
							if channel not in token.joinedChannels:
 | 
				
			||||||
 | 
								raise exceptions.userNotInChannelException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Part channel (token-side and channel-side)
 | 
							# Part channel (token-side and channel-side)
 | 
				
			||||||
		channelObject = glob.channels.channels[channel]
 | 
							channelObject = glob.channels.channels[channel]
 | 
				
			||||||
		token.partChannel(channel)
 | 
							token.partChannel(channelObject)
 | 
				
			||||||
		channelObject.userPart(userID)
 | 
					
 | 
				
			||||||
 | 
							# Delete temporary channel if everyone left
 | 
				
			||||||
 | 
							if "chat/{}".format(channelObject.name) in glob.streams.streams:
 | 
				
			||||||
 | 
								sas = len(glob.streams.streams["chat/{}".format(channelObject.name)].clients)
 | 
				
			||||||
 | 
								print(str(sas - 1))
 | 
				
			||||||
 | 
								if channelObject.temp == True and sas - 1 == 0:
 | 
				
			||||||
 | 
									glob.channels.removeChannel(channelObject.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Force close tab if needed
 | 
							# Force close tab if needed
 | 
				
			||||||
		# NOTE: Maybe always needed, will check later
 | 
							# NOTE: Maybe always needed, will check later
 | 
				
			||||||
@@ -127,16 +125,19 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		# IRC part
 | 
							# IRC part
 | 
				
			||||||
		if glob.irc == True and toIRC == True:
 | 
							if glob.irc == True and toIRC == True:
 | 
				
			||||||
			glob.ircServer.banchoPartChannel(username, channel)
 | 
								glob.ircServer.banchoPartChannel(token.username, channel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Console output
 | 
							# Console output
 | 
				
			||||||
		log.info("{} parted channel {} ({})".format(username, channel, channelClient))
 | 
							log.info("{} parted channel {} ({})".format(token.username, channel, channelClient))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Return IRC code
 | 
							# Return IRC code
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
	except exceptions.channelUnknownException:
 | 
						except exceptions.channelUnknownException:
 | 
				
			||||||
		log.warning("{} attempted to part an unknown channel ({})".format(username, channel))
 | 
							log.warning("{} attempted to part an unknown channel ({})".format(token.username, channel))
 | 
				
			||||||
		return 403
 | 
							return 403
 | 
				
			||||||
 | 
						except exceptions.userNotInChannelException:
 | 
				
			||||||
 | 
							log.warning("{} attempted to part {}, but he's not in that channel".format(token.username, channel))
 | 
				
			||||||
 | 
							return 442
 | 
				
			||||||
	except exceptions.userNotFoundException:
 | 
						except exceptions.userNotFoundException:
 | 
				
			||||||
		log.warning("User not connected to IRC/Bancho")
 | 
							log.warning("User not connected to IRC/Bancho")
 | 
				
			||||||
		return 442	# idk
 | 
							return 442	# idk
 | 
				
			||||||
@@ -153,7 +154,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
	:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
 | 
						:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
 | 
				
			||||||
	"""
 | 
						"""
 | 
				
			||||||
	try:
 | 
						try:
 | 
				
			||||||
		tokenString = ""
 | 
							#tokenString = ""
 | 
				
			||||||
		# Get token object if not passed
 | 
							# Get token object if not passed
 | 
				
			||||||
		if token is None:
 | 
							if token is None:
 | 
				
			||||||
			token = glob.tokens.getTokenFromUsername(fro)
 | 
								token = glob.tokens.getTokenFromUsername(fro)
 | 
				
			||||||
@@ -162,11 +163,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
		else:
 | 
							else:
 | 
				
			||||||
			# token object alredy passed, get its string and its username (fro)
 | 
								# token object alredy passed, get its string and its username (fro)
 | 
				
			||||||
			fro = token.username
 | 
								fro = token.username
 | 
				
			||||||
			tokenString = token.token
 | 
								#tokenString = token.token
 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Set some variables
 | 
					 | 
				
			||||||
		userID = token.userID
 | 
					 | 
				
			||||||
		username = token.username
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Make sure this is not a tournament client
 | 
							# Make sure this is not a tournament client
 | 
				
			||||||
		if token.tournament:
 | 
							if token.tournament:
 | 
				
			||||||
@@ -185,7 +182,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
		toClient = to
 | 
							toClient = to
 | 
				
			||||||
		if to == "#spectator":
 | 
							if to == "#spectator":
 | 
				
			||||||
			if token.spectating is None:
 | 
								if token.spectating is None:
 | 
				
			||||||
				s = userID
 | 
									s = token.userID
 | 
				
			||||||
			else:
 | 
								else:
 | 
				
			||||||
				s = token.spectatingUserID
 | 
									s = token.spectatingUserID
 | 
				
			||||||
			to = "#spect_{}".format(s)
 | 
								to = "#spect_{}".format(s)
 | 
				
			||||||
@@ -203,7 +200,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
		message = glob.chatFilters.filterMessage(message)
 | 
							message = glob.chatFilters.filterMessage(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Build packet bytes
 | 
							# Build packet bytes
 | 
				
			||||||
		packet = serverPackets.sendMessage(username, toClient, message)
 | 
							packet = serverPackets.sendMessage(token.username, toClient, message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Send the message
 | 
							# Send the message
 | 
				
			||||||
		isChannel = to.startswith("#")
 | 
							isChannel = to.startswith("#")
 | 
				
			||||||
@@ -211,35 +208,28 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
			# CHANNEL
 | 
								# CHANNEL
 | 
				
			||||||
			# Make sure the channel exists
 | 
								# Make sure the channel exists
 | 
				
			||||||
			if to not in glob.channels.channels:
 | 
								if to not in glob.channels.channels:
 | 
				
			||||||
				raise exceptions.channelUnknownException
 | 
									raise exceptions.channelUnknownException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Make sure the channel is not in moderated mode
 | 
								# Make sure the channel is not in moderated mode
 | 
				
			||||||
			if glob.channels.channels[to].moderated == True and token.admin == False:
 | 
								if glob.channels.channels[to].moderated == True and token.admin == False:
 | 
				
			||||||
				raise exceptions.channelModeratedException
 | 
									raise exceptions.channelModeratedException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Make sure we have write permissions
 | 
								# Make sure we have write permissions
 | 
				
			||||||
			if glob.channels.channels[to].publicWrite == False and token.admin == False:
 | 
								if glob.channels.channels[to].publicWrite == False and token.admin == False:
 | 
				
			||||||
				raise exceptions.channelNoPermissionsException
 | 
									raise exceptions.channelNoPermissionsException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Everything seems fine, build recipients list and send packet
 | 
								# Everything seems fine, build recipients list and send packet
 | 
				
			||||||
			recipients = glob.channels.channels[to].connectedUsers[:]
 | 
								glob.streams.broadcast("chat/{}".format(to), packet, but=[token.token])
 | 
				
			||||||
			for key, value in glob.tokens.tokens.items():
 | 
					 | 
				
			||||||
				# Skip our client and irc clients
 | 
					 | 
				
			||||||
				if key == tokenString or value.irc == True:
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				# Send to this client if it's connected to the channel
 | 
					 | 
				
			||||||
				if value.userID in recipients:
 | 
					 | 
				
			||||||
					value.enqueue(packet)
 | 
					 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			# USER
 | 
								# USER
 | 
				
			||||||
			# Make sure recipient user is connected
 | 
								# Make sure recipient user is connected
 | 
				
			||||||
			recipientToken = glob.tokens.getTokenFromUsername(to)
 | 
								recipientToken = glob.tokens.getTokenFromUsername(to)
 | 
				
			||||||
			if recipientToken is None:
 | 
								if recipientToken is None:
 | 
				
			||||||
				raise exceptions.userNotFoundException
 | 
									raise exceptions.userNotFoundException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Make sure the recipient is not a tournament client
 | 
								# Make sure the recipient is not a tournament client
 | 
				
			||||||
			if recipientToken.tournament:
 | 
								#if recipientToken.tournament:
 | 
				
			||||||
				raise exceptions.userTournamentException()
 | 
								#	raise exceptions.userTournamentException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Make sure the recipient is not restricted or we are FokaBot
 | 
								# Make sure the recipient is not restricted or we are FokaBot
 | 
				
			||||||
			if recipientToken.restricted == True and fro.lower() != "fokabot":
 | 
								if recipientToken.restricted == True and fro.lower() != "fokabot":
 | 
				
			||||||
@@ -248,7 +238,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
			# TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend
 | 
								# TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Away check
 | 
								# Away check
 | 
				
			||||||
			if recipientToken.awayCheck(userID):
 | 
								if recipientToken.awayCheck(token.userID):
 | 
				
			||||||
				sendMessage(to, fro, "\x01ACTION is away: {message}\x01".format(code=chr(int(1)), message=recipientToken.awayMessage))
 | 
									sendMessage(to, fro, "\x01ACTION is away: {message}\x01".format(code=chr(int(1)), message=recipientToken.awayMessage))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			# Check message templates (mods/admins only)
 | 
								# Check message templates (mods/admins only)
 | 
				
			||||||
@@ -263,38 +253,38 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
 | 
				
			|||||||
			glob.ircServer.banchoMessage(fro, to, message)
 | 
								glob.ircServer.banchoMessage(fro, to, message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Spam protection (ignore FokaBot)
 | 
							# Spam protection (ignore FokaBot)
 | 
				
			||||||
		if userID > 999:
 | 
							if token.userID > 999:
 | 
				
			||||||
			token.spamProtection()
 | 
								token.spamProtection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Fokabot message
 | 
							# Fokabot message
 | 
				
			||||||
		if isChannel == True or to.lower() == "fokabot":
 | 
							if isChannel == True or to.lower() == "fokabot":
 | 
				
			||||||
			fokaMessage = fokabot.fokabotResponse(username, to, message)
 | 
								fokaMessage = fokabot.fokabotResponse(token.username, to, message)
 | 
				
			||||||
			if fokaMessage:
 | 
								if fokaMessage:
 | 
				
			||||||
				sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
 | 
									sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# File and discord logs (public chat only)
 | 
							# File and discord logs (public chat only)
 | 
				
			||||||
		if to.startswith("#") and not (message.startswith("\x01ACTION is playing") and to.startswith("#spect_")):
 | 
							if to.startswith("#") and not (message.startswith("\x01ACTION is playing") and to.startswith("#spect_")):
 | 
				
			||||||
			log.chat("{fro} @ {to}: {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))))
 | 
								log.chat("{fro} @ {to}: {message}".format(fro=token.username, to=to, message=str(message.encode("utf-8"))))
 | 
				
			||||||
			glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))[2:-1]))
 | 
								glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format(fro=token.username, to=to, message=str(message.encode("utf-8"))[2:-1]))
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
	except exceptions.userSilencedException:
 | 
						except exceptions.userSilencedException:
 | 
				
			||||||
		token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
 | 
							token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
 | 
				
			||||||
		log.warning("{} tried to send a message during silence".format(username))
 | 
							log.warning("{} tried to send a message during silence".format(token.username))
 | 
				
			||||||
		return 404
 | 
							return 404
 | 
				
			||||||
	except exceptions.channelModeratedException:
 | 
						except exceptions.channelModeratedException:
 | 
				
			||||||
		log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(username, to))
 | 
							log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(token.username, to))
 | 
				
			||||||
		return 404
 | 
							return 404
 | 
				
			||||||
	except exceptions.channelUnknownException:
 | 
						except exceptions.channelUnknownException:
 | 
				
			||||||
		log.warning("{} tried to send a message to an unknown channel ({})".format(username, to))
 | 
							log.warning("{} tried to send a message to an unknown channel ({})".format(token.username, to))
 | 
				
			||||||
		return 403
 | 
							return 403
 | 
				
			||||||
	except exceptions.channelNoPermissionsException:
 | 
						except exceptions.channelNoPermissionsException:
 | 
				
			||||||
		log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(username, to))
 | 
							log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(token.username, to))
 | 
				
			||||||
		return 404
 | 
							return 404
 | 
				
			||||||
	except exceptions.userRestrictedException:
 | 
						except exceptions.userRestrictedException:
 | 
				
			||||||
		log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(username, to))
 | 
							log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(token.username, to))
 | 
				
			||||||
		return 404
 | 
							return 404
 | 
				
			||||||
	except exceptions.userTournamentException:
 | 
						except exceptions.userTournamentException:
 | 
				
			||||||
		log.warning("{} tried to send a message {}, but the recipient is a tournament client".format(username, to))
 | 
							log.warning("{} tried to send a message {}, but the recipient is a tournament client".format(token.username, to))
 | 
				
			||||||
		return 404
 | 
							return 404
 | 
				
			||||||
	except exceptions.userNotFoundException:
 | 
						except exceptions.userNotFoundException:
 | 
				
			||||||
		log.warning("User not connected to IRC/Bancho")
 | 
							log.warning("User not connected to IRC/Bancho")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ class channel:
 | 
				
			|||||||
		self.publicWrite = publicWrite
 | 
							self.publicWrite = publicWrite
 | 
				
			||||||
		self.moderated = False
 | 
							self.moderated = False
 | 
				
			||||||
		self.temp = temp
 | 
							self.temp = temp
 | 
				
			||||||
		self.connectedUsers = [999]	# Fokabot is always connected to every channels (otherwise it doesn't show up in IRC users list)
 | 
					 | 
				
			||||||
		self.hidden = hidden
 | 
							self.hidden = hidden
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Client name (#spectator/#multiplayer)
 | 
							# Client name (#spectator/#multiplayer)
 | 
				
			||||||
@@ -28,27 +27,7 @@ class channel:
 | 
				
			|||||||
		elif self.name.startswith("#multi_"):
 | 
							elif self.name.startswith("#multi_"):
 | 
				
			||||||
			self.clientName = "#multiplayer"
 | 
								self.clientName = "#multiplayer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def userJoin(self, userID):
 | 
							# Make Foka join the channel
 | 
				
			||||||
		"""
 | 
							fokaToken = glob.tokens.getTokenFromUserID(999)
 | 
				
			||||||
		Add a user to connected users
 | 
							if fokaToken is not None:
 | 
				
			||||||
 | 
								fokaToken.joinChannel(self)
 | 
				
			||||||
		:param userID:
 | 
					 | 
				
			||||||
		:return:
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		if userID not in self.connectedUsers:
 | 
					 | 
				
			||||||
			self.connectedUsers.append(userID)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def userPart(self, userID):
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		Remove a user from connected users
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		:param userID:
 | 
					 | 
				
			||||||
		:return:
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		if userID in self.connectedUsers:
 | 
					 | 
				
			||||||
			self.connectedUsers.remove(userID)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Remove temp channels if empty or there's only fokabot connected
 | 
					 | 
				
			||||||
		l = len(self.connectedUsers)
 | 
					 | 
				
			||||||
		if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)):
 | 
					 | 
				
			||||||
			glob.channels.removeChannel(self.name)
 | 
					 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
from common.log import logUtils as log
 | 
					from common.log import logUtils as log
 | 
				
			||||||
 | 
					from constants import serverPackets
 | 
				
			||||||
from objects import channel
 | 
					from objects import channel
 | 
				
			||||||
from objects import glob
 | 
					from objects import glob
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,6 +35,7 @@ class channelList:
 | 
				
			|||||||
		:param hidden: if True, thic channel won't be shown in channels list
 | 
							:param hidden: if True, thic channel won't be shown in channels list
 | 
				
			||||||
		:return:
 | 
							:return:
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
 | 
							glob.streams.add("chat/{}".format(name))
 | 
				
			||||||
		self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden)
 | 
							self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden)
 | 
				
			||||||
		log.info("Created channel {}".format(name))
 | 
							log.info("Created channel {}".format(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,6 +49,7 @@ class channelList:
 | 
				
			|||||||
		"""
 | 
							"""
 | 
				
			||||||
		if name in self.channels:
 | 
							if name in self.channels:
 | 
				
			||||||
			return False
 | 
								return False
 | 
				
			||||||
 | 
							glob.streams.add("chat/{}".format(name))
 | 
				
			||||||
		self.channels[name] = channel.channel(name, "Chat", True, True, True, True)
 | 
							self.channels[name] = channel.channel(name, "Chat", True, True, True, True)
 | 
				
			||||||
		log.info("Created temp channel {}".format(name))
 | 
							log.info("Created temp channel {}".format(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,5 +63,8 @@ class channelList:
 | 
				
			|||||||
		if name not in self.channels:
 | 
							if name not in self.channels:
 | 
				
			||||||
			log.debug("{} is not in channels list".format(name))
 | 
								log.debug("{} is not in channels list".format(name))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 | 
							glob.streams.broadcast("chat/{}".format(name), serverPackets.channelKicked(name))
 | 
				
			||||||
 | 
							glob.streams.dispose("chat/{}".format(name))
 | 
				
			||||||
 | 
							glob.streams.remove("chat/{}".format(name))
 | 
				
			||||||
		self.channels.pop(name)
 | 
							self.channels.pop(name)
 | 
				
			||||||
		log.info("Removed channel {}".format(name))
 | 
							log.info("Removed channel {}".format(name))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import uuid
 | 
				
			|||||||
from common.constants import gameModes, actions
 | 
					from common.constants import gameModes, actions
 | 
				
			||||||
from common.log import logUtils as log
 | 
					from common.log import logUtils as log
 | 
				
			||||||
from common.ripple import userUtils
 | 
					from common.ripple import userUtils
 | 
				
			||||||
 | 
					from constants import exceptions
 | 
				
			||||||
from constants import serverPackets
 | 
					from constants import serverPackets
 | 
				
			||||||
from events import logoutEvent
 | 
					from events import logoutEvent
 | 
				
			||||||
from helpers import chatHelper as chat
 | 
					from helpers import chatHelper as chat
 | 
				
			||||||
@@ -98,7 +99,12 @@ class token:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		:param bytes: (packet) bytes to enqueue
 | 
							:param bytes: (packet) bytes to enqueue
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		# TODO: reduce max queue size
 | 
					
 | 
				
			||||||
 | 
							# Never enqueue for IRC clients or Foka
 | 
				
			||||||
 | 
							if self.irc or self.userID < 999:
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Avoid memory leaks
 | 
				
			||||||
		if len(bytes_) < 10 * 10 ** 6:
 | 
							if len(bytes_) < 10 * 10 ** 6:
 | 
				
			||||||
			self.queue += bytes_
 | 
								self.queue += bytes_
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
@@ -108,23 +114,30 @@ class token:
 | 
				
			|||||||
		"""Resets the queue. Call when enqueued packets have been sent"""
 | 
							"""Resets the queue. Call when enqueued packets have been sent"""
 | 
				
			||||||
		self.queue = bytes()
 | 
							self.queue = bytes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def joinChannel(self, channel):
 | 
						def joinChannel(self, channelObject):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		Add channel to joined channels list
 | 
							Join a channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param channel: channel name
 | 
							:param channelObject: channel object
 | 
				
			||||||
 | 
							:raises: exceptions.userAlreadyInChannelException()
 | 
				
			||||||
 | 
									 exceptions.channelNoPermissionsException()
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		if channel not in self.joinedChannels:
 | 
							if channelObject.name in self.joinedChannels:
 | 
				
			||||||
			self.joinedChannels.append(channel)
 | 
								raise exceptions.userAlreadyInChannelException()
 | 
				
			||||||
 | 
							if channelObject.publicRead == False and self.admin == False:
 | 
				
			||||||
 | 
								raise exceptions.channelNoPermissionsException()
 | 
				
			||||||
 | 
							self.joinedChannels.append(channelObject.name)
 | 
				
			||||||
 | 
							self.joinStream("chat/{}".format(channelObject.name))
 | 
				
			||||||
 | 
							self.enqueue(serverPackets.channelJoinSuccess(self.userID, channelObject.clientName))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def partChannel(self, channel):
 | 
						def partChannel(self, channelObject):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		Remove channel from joined channels list
 | 
							Remove channel from joined channels list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param channel: channel name
 | 
							:param channelObject: channel object
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		if channel in self.joinedChannels:
 | 
							self.joinedChannels.remove(channelObject.name)
 | 
				
			||||||
			self.joinedChannels.remove(channel)
 | 
							self.leaveStream("chat/{}".format(channelObject.name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def setLocation(self, latitude, longitude):
 | 
						def setLocation(self, latitude, longitude):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
@@ -233,7 +246,7 @@ class token:
 | 
				
			|||||||
		chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True)
 | 
							chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Console output
 | 
							# Console output
 | 
				
			||||||
		log.info("{} is no longer spectating {}".format(self.username, self.spectatingUserID))
 | 
							log.info("{} is no longer spectating {}. Current spectators: {}".format(self.username, self.spectatingUserID, hostToken.spectators))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Set our spectating user to 0
 | 
							# Set our spectating user to 0
 | 
				
			||||||
		self.spectating = None
 | 
							self.spectating = None
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,15 +43,29 @@ class stream:
 | 
				
			|||||||
			log.info("{} has left stream {}".format(token, self.name))
 | 
								log.info("{} has left stream {}".format(token, self.name))
 | 
				
			||||||
			self.clients.remove(token)
 | 
								self.clients.remove(token)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def broadcast(self, data):
 | 
						def broadcast(self, data, but=None):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		Send some data to all clients connected to this stream
 | 
							Send some data to all (or some) clients connected to this stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param data: data to send
 | 
							:param data: data to send
 | 
				
			||||||
 | 
							:param but: array of tokens to ignore. Default: None (send to everyone)
 | 
				
			||||||
 | 
							:return:
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
 | 
							if but is None:
 | 
				
			||||||
 | 
								but = []
 | 
				
			||||||
 | 
							for i in self.clients:
 | 
				
			||||||
 | 
								if i in glob.tokens.tokens:
 | 
				
			||||||
 | 
									if i not in but:
 | 
				
			||||||
 | 
										glob.tokens.tokens[i].enqueue(data)
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									self.removeClient(token=i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def dispose(self):
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
 | 
							Tell every client in this stream to leave the stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:return:
 | 
							:return:
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		for i in self.clients:
 | 
							for i in self.clients:
 | 
				
			||||||
			if i in glob.tokens.tokens:
 | 
								if i in glob.tokens.tokens:
 | 
				
			||||||
				glob.tokens.tokens[i].enqueue(data)
 | 
									glob.tokens.tokens[i].leaveStream(self.name)
 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				self.removeClient(token=i)
 | 
					 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
from objects import stream
 | 
					from objects import stream
 | 
				
			||||||
from objects import glob
 | 
					from objects import glob
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: use *args and **kwargs
 | 
				
			||||||
class streamList:
 | 
					class streamList:
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		self.streams = {}
 | 
							self.streams = {}
 | 
				
			||||||
@@ -55,25 +56,28 @@ class streamList:
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		self.streams[streamName].removeClient(client=client, token=token)
 | 
							self.streams[streamName].removeClient(client=client, token=token)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def broadcast(self, streamName, data):
 | 
						def broadcast(self, streamName, data, but=None):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		Send some data to all clients in a stream
 | 
							Send some data to all clients in a stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param streamName: stream name
 | 
							:param streamName: stream name
 | 
				
			||||||
		:param data: data to send
 | 
							:param data: data to send
 | 
				
			||||||
 | 
							:param but: array of tokens to ignore. Default: None (send to everyone)
 | 
				
			||||||
		:return:
 | 
							:return:
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		if streamName not in self.streams:
 | 
							if streamName not in self.streams:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		self.streams[streamName].broadcast(data)
 | 
							self.streams[streamName].broadcast(data, but)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'''def getClients(self, streamName):
 | 
						def dispose(self, streamName, *args, **kwargs):
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		Get all clients in a stream
 | 
							Call `dispose` on `streamName`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param streamName: name of the stream
 | 
							:param streamName: name of the stream
 | 
				
			||||||
 | 
							:param args:
 | 
				
			||||||
 | 
							:param kwargs:
 | 
				
			||||||
		:return:
 | 
							:return:
 | 
				
			||||||
		"""
 | 
							"""
 | 
				
			||||||
		if streamName not in self.streams:
 | 
							if streamName not in self.streams:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		return self.streams[streamName].clients'''
 | 
							self.streams[streamName].dispose(*args, **kwargs)
 | 
				
			||||||
							
								
								
									
										10
									
								
								pep.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								pep.py
									
									
									
									
									
								
							@@ -154,6 +154,11 @@ if __name__ == "__main__":
 | 
				
			|||||||
			consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
 | 
								consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
 | 
				
			||||||
			raise
 | 
								raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Start fokabot
 | 
				
			||||||
 | 
							consoleHelper.printNoNl("> Connecting FokaBot... ")
 | 
				
			||||||
 | 
							fokabot.connect()
 | 
				
			||||||
 | 
							consoleHelper.printDone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Initialize chat channels
 | 
							# Initialize chat channels
 | 
				
			||||||
		print("> Initializing chat channels... ")
 | 
							print("> Initializing chat channels... ")
 | 
				
			||||||
		glob.channels.loadChannels()
 | 
							glob.channels.loadChannels()
 | 
				
			||||||
@@ -165,11 +170,6 @@ if __name__ == "__main__":
 | 
				
			|||||||
		glob.streams.add("lobby")
 | 
							glob.streams.add("lobby")
 | 
				
			||||||
		consoleHelper.printDone()
 | 
							consoleHelper.printDone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Start fokabot
 | 
					 | 
				
			||||||
		consoleHelper.printNoNl("> Connecting FokaBot... ")
 | 
					 | 
				
			||||||
		fokabot.connect()
 | 
					 | 
				
			||||||
		consoleHelper.printDone()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Initialize user timeout check loop
 | 
							# Initialize user timeout check loop
 | 
				
			||||||
		consoleHelper.printNoNl("> Initializing user timeout check loop... ")
 | 
							consoleHelper.printNoNl("> Initializing user timeout check loop... ")
 | 
				
			||||||
		glob.tokens.usersTimeoutCheckLoop()
 | 
							glob.tokens.usersTimeoutCheckLoop()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user