Ejemplo n.º 1
0
	def __init__ (self, config):
		# Create logger
		self.logger = logging.getLogger(__name__)

		# Load the database
		try:
			# Create logger
			self.db_logger = logging.getLogger(__name__+".database")

			# Get the database address and port from the config,
			# or use the mongodb defaults
			address	= config.pop('db_address', 'localhost')
			port	= config.pop('db_port', 27017)

			# The database connection
			self.connection	= Connection(address, port)
			self.database	= self.connection[config.pop('db_name', 'tactics')]

			# The main quote collection
			self.phrases	= Phrases(self.database, config)

			# The users collection
			# self.users = Users(self.connection['users'])
		except Exception as e:
			self.logger.error("Database could not be loaded: {}".format(e.message))
			traceback.print_exc()
			exit()

		# Call __init__ on the Aleph superclass
		EventInterface.__init__(self, config)

		# Commands
		self.commands = OrderedDict()

		# Add phrase types to command list
		for link_name in static.links:
			link_regex = "^{}$".format(static.links[link_name][0])
			self.commands[link_regex] = self.add_phrase_command(link_name)

		# Load static commands
		self.commands.update({
			"^delete #(?P<id>\d+)$": self.delete_phrase,
		})
		
		self.logger.debug("Loaded static commands")

		# Load dynamic commands
		import commands
		self.commands_module = commands
		self.commands.update(self.commands_module.dynamic_commands)
		self.logger.debug("Loaded dynamic commands")
Ejemplo n.º 2
0
class Tactics (EventInterface):
	def __init__ (self, config):
		# Create logger
		self.logger = logging.getLogger(__name__)

		# Load the database
		try:
			# Create logger
			self.db_logger = logging.getLogger(__name__+".database")

			# Get the database address and port from the config,
			# or use the mongodb defaults
			address	= config.pop('db_address', 'localhost')
			port	= config.pop('db_port', 27017)

			# The database connection
			self.connection	= Connection(address, port)
			self.database	= self.connection[config.pop('db_name', 'tactics')]

			# The main quote collection
			self.phrases	= Phrases(self.database, config)

			# The users collection
			# self.users = Users(self.connection['users'])
		except Exception as e:
			self.logger.error("Database could not be loaded: {}".format(e.message))
			traceback.print_exc()
			exit()

		# Call __init__ on the Aleph superclass
		EventInterface.__init__(self, config)

		# Commands
		self.commands = OrderedDict()

		# Add phrase types to command list
		for link_name in static.links:
			link_regex = "^{}$".format(static.links[link_name][0])
			self.commands[link_regex] = self.add_phrase_command(link_name)

		# Load static commands
		self.commands.update({
			"^delete #(?P<id>\d+)$": self.delete_phrase,
		})
		
		self.logger.debug("Loaded static commands")

		# Load dynamic commands
		import commands
		self.commands_module = commands
		self.commands.update(self.commands_module.dynamic_commands)
		self.logger.debug("Loaded dynamic commands")

	""" Dynamic commands """

	def reload_commands (self):
		"""	Reloads commands from the dynamic commands list """
		# Remove old commands
		for key in self.commands_module.dynamic_commands:
			del self.commands[key]
		# Reload the commands module and load it
		reload(self.commands_module)
		self.commands.update(self.commands_module.dynamic_commands)
		self.logger.debug("Reloaded dynamic commands")

	def show_commands (self):
		"""	Returns a string of the loaded commands """
		string = ""
		for command in self.commands:
			string += "\n\t\t" + command
		return string

	"""	Input """

	def on_privmsg (self, message):
		"""	Respond to messages """
		if message.pm or message.to_me:
			return self.respond(message)

		# Look for related phrases
		try:
			return self.find_related_phrase(message)
		except NoPhraseFound:
			pass

	def respond (self, message):
		"""	Respond to direct messages """
		command = self.is_command(message.text)
		if command:
			try:
				return self.run_command(command, message)
			except ReplyException as error:
				self.logger.warning(error.message)
				return message.reply(error.message)

		# Message has not parsed
		return message.reply("Message does not parse.")

	def is_command(self, text):
		"""	Check if a message matches any of the commands """
		command = filter(lambda c: match(c,text), self.commands)
		# Return first matching command, or False if there are no matching commands
		return command[0] if command else False

	def run_command (self, c, message):
		"""	Run the given command,
			calling it if it is a function, or replying with it as a string """
		command = self.commands[c]
		self.logger.debug(c)
		if hasattr(command, '__call__'):
			# Search the regex for arguments, and pass them as kwargs
			kwargs = search(c, message.text).groupdict()
			command(self, message, **kwargs)
		else:
			message.reply(str(command))

	"""	Phrases - Adding """

	def add_phrase_command (self, link_name):
		"""	Returns a lambda function for adding links of a set type
			Used for creating commands with the static link data """
		return lambda self, message, **kwargs: self.add_phrase(message, link_name, **kwargs)

	def add_phrase (self, message, link_name, **phrase):
		""" If the phrase has been matched by a link type, try and add it """
		id = self.phrases.create(phrase, link_name, {
			'author-nick': str(message.source['nick']),
			'author-host': str(message.source),
		})

		# Notify
		self.logger.info('Iserted phrase: "{}" [#{:>06}]'.format(self.phrases.format(phrase), id))
		message.reply('Phrase "{}" added to my collection [#{:>06}].'.format(self.phrases.format(phrase), id))

	def delete_phrase (self, _, message, id):
		"""	Try and remove a phrase from the database """
		self.phrases.delete(int(id))
		message.reply("Phrase #{:>06} deleted.".format(id))

	""" Phrases - fetching """

	def find_related_phrase (self, message):
		"""	Finds a random phrase related to the given text
		Throws a NoPhraseFound exception if it cannot find a related phrase """
		debug_msg = "Attempting to find phrase for text '{}'... ".format(message.text)

		# Remove trailing spaces and full stops from message text, then split into words
		words = message.text.strip(' .').split(' ')

		# Find the subject with the most phrases
		best_count, best_subject = 0, None
		best_phrases = None
		for subject in words:
			phrases = self.phrases.get_phrases_by_subject(subject)
			if phrases.count() > best_count:
				best_count, best_subject = phrases.count(), subject
				best_phrases = phrases

		# Finish if no phrases found
		if not best_subject:
			self.logger.debug(debug_msg + "No phrases found")
			return None

		# Select a random phrase from the list
		r = randint(0,best_count-1)
		self.logger.debug(debug_msg + "Using phrase {} of {}".format(r+1, best_phrases.count()))

		# Record it as the last used phrase
		self.phrases.last = best_phrases[r]

		# Return the phrase
		return message.msg(self.format(message, best_phrases[r]))
	
	def format (self, message, phrase):
		"""	Formats a phrase with variables from the message and bot """
		text = self.phrases.format(phrase)
		text = text.format(**{
			'nick': message.source.name()
		})
		return text