made a siphon module

Benjamin West <[email protected]> Wed, 26 Jan 2005 03:58:13 -0600
Newsgroups gmane.comp.games.mud.client.lyntin
Message-ID <[email protected]>
This will watch for text similar to gag or action.  When it finds a
match, it will open a file with the name you gave it and start copying
mud data to the file until it sees two consecutive newlines.

Siphon allows you to capture chunks of data in files for each session.
 This might come in handy if you are trying to monitor several
characters at once.  Siphon relevant data from each, and open up
xterms to use something like "watch cat *.eq.siphon".  That would let
you see everyone's eq.


Ben
siphon.py (application/octet-stream, 7.6 KB)
"""
This module implements a siphon feature.  It will watch for a match
for a given piece of text and then log everything from that point until
a double newline to a predefined file.

TODO:
	* add a siphon now command that just starts siphoning
	* fix file header
	* add config items

"""
__author__ = "Ben West"
__version__ = ".8"
__date__ = "Wed Jan 26 03:42:16 CST 2005"
__description__ = "A siphon to stick chunks of data into files."

import string
from lyntin import exported, session, ansi, manager, utils
from lyntin.modules import modutils


commands_dict = {}


class SiphonData:
	def __init__(self):
		self._cues = {}
			
	def addSiphon(self, item, filename):
		"""
		Add a cue to the dict.
		"""
		
		compiled = utils.compile_regexp(item,1)
		siphon = {'regex': compiled, 'filename': filename, 'filehandle': 0, 'issiphoning': 0} 
		self._cues[item] = siphon


	def clear(self):
		"""
		Remove all cues.
		"""
		self_cues.clear()

	def removeSiphon(self, text):
		"""
		Remove given siphon cue.
		Returns a list of tuples of cues that were removed.
		"""
		badcues = utils.expand_text(text, self._cues.keys())
		ret = [] 
		for mem in badcues:
			ret.append(mem)
			del self._cues[mem]

		return ret
	
	def findcue(self, text):
		"""
		Looks at mud data, starts siphoning we find a cue.
		Returns key to the cue.
		"""
		if len(text) > 0:
			for key in self._cues.keys():
				if self._cues[key]['regex'].search(text):
					return key

					
	def issiphoning(self, item):
		"""
		Access function to see if we are in the process of siphoning.
		"""
		return self._cues[item]['issiphoning']

	def startSiphon(self, item):
		"""
		Open a file, store the handle in the dict, note that we've started.
		"""
		
		
		filename = self._cues[item]['filename'] + ".siphon"
		#filename = "atest.siphon"
		self._cues[item]['filehandle'] = file(filename, "w")
		header = "".ljust(6)
		header = header.replace(" ", "*", 5)
		last = "".rjust(44 - len(self._cues[item]['filename']))
		last.replace(" ", "*")
		header = header + self._cues[item]['filename'] + " " + last
		self._cues[item]['filehandle'].write(header + "\n")
		self._cues[item]['issiphoning'] = True
	
	def stopSiphon(self, item):
		"""
		Close the file, del the handle, and note that we've stopped.
		"""
		#self._cues[item]['prevnoline'] = False
		self._cues[item]['filehandle'].close()
		self._cues[item]['filehandle'] = 0
		self._cues[item]['issiphoning'] = 0
		
	
	def siphon(self, text):
		""" 
		siphon, process the text
		first ask if we are already siphoning,
		if we are, then check to see if this text
		has a double newline.  If it doesn't have a double
		newline, send to file.  If it does
		have a double newline, stop siphoning, and send it to the
		file and close it.
		"""
		
		for mem in self._cues.keys():
			if self._cues[mem]['issiphoning']:
				if text[0]  == "\n":
					self._cues[mem]['filehandle'].write(text)
					self.stopSiphon(mem)
				else:
				 	self._cues[mem]['filehandle'].write(text)
					
		
		item = self.findcue(text)
		if item:
			self.startSiphon(item)
			self._cues[item]['filehandle'].write(text)
																																										
	def getInfo(self, text=''):
		"""
		Returns information about the siphons.
		"""

		data = self._cues.keys()
		if text:
			data = utils.expand_text(text, data)

		data = ["siphon {%s}" % mem for mem in data]
		
		return data

	def getSiphonInfoMappings(self):
		l = []
		for mem in self._cues.keys():
			l.append( {"text": mem} )

		return l

	def getStatus(self):
		cues = len(self._cues.keys())

		return "%d siphon cue(s)." % (cues)


		
	

class SiphonManager(manager.Manager):
	def __init__(self):
		self._siphondata = {}	

	def getSiphonData(self, ses):
		if not self._siphondata.has_key(ses):
			self._siphondata[ses] = SiphonData()
		return self._siphondata[ses]

	def addSession(self, newsession, basesession=None):
		if basesession:
			if self._siphondata.has_key(basesession):
				bdata = self.getSiphonData(basesession)
				ndata = self.getSiphonData(newsession)

				for mem in bdata._cues.keys():
					ndata.addSiphon(mem, bdata._cues[mem]["filename"])
 
	def persist(self, args):
		ses = args["session"]
		quiet = args["quiet"]

		siphon = self.getSiphonData(ses)
		data = siphon.getInfo()
		if quiet == 1:
			data = [m + " quiet={true}" for m in data]

		return data

		
	def clear(self, ses):
		if not self._siphondata.has_key(ses):
			self._siphondata[ses].clear()
			
	def getInfo(self, ses, text=''):
		return self.getSiphonData(ses).getInfo(text)

	def getInfoMappings(self, item, ses):
		if item != "siphon cues": 
			raise ValueError("%s is not a valid item for this manager." % item)

		if not self._siphondata.has_key(ses):
			return []

		return self._siphondata.getSiphonInfoMappings()

	def getItems(self):
		return ["siphon cues"]

	def getParameters(self, item):
		if item == "siphon cues":
			return [ ("text", "The text which serves as a cue to start siphoning text." ) ]
		raise ValueError("%s is not a valid item for this manager." % item)

	def getStatus(self, ses):
		return self.getSiphonData(ses).getStatus()

	def removeSession(self, ses):
		if self._siphondata.has_key(ses):
			del self._siphondata[ses]
	
	
	def handle_mudfilter(self, args):
		"""
		mud_filter hook function
		first ask if we are already siphoning,
		if we are, then check to see if this text
		has a double newline.  If it doesn't have a double
		newline, tuck it away in our storage place.  If it does
		have a double newline, stop siphoning, and send it to the
		file and close it.  Note that we stopped siphoning.
		"""
		ses = args["session"]
		mudtext = args["dataadj"]
		mudtext = ansi.filter_ansi(mudtext)
		
		if self._siphondata.has_key(ses):
			self._siphondata[ses].siphon(mudtext)
			
		return args["dataadj"]
		
								                


def uncue_cmd(ses, args, input):
	"""
	Remove a cue.

	see also: cue
	category: siphons
	"""
	str = args["str"]

	sm = exported.get_manager("siphon")
	sd = sm.getSiphonData(ses)

	func = sd.removeSiphon
	modutils.unsomething_helper(args, func, None, "cue", "cues")

commands_dict["uncue"] = (uncue_cmd, "str= quiet:boolean=false")


def cue_cmd(ses, args, input):
		"""
		This takes the name of the siphon, and siphons all text from 
		when this command is called until we see a double newline.  
		We'll put this text in a file, indicated by the filename 
		with a .siphon extension.  It will automatically create  a 
		header and a footer about 50 characters long based on the 
		name and filled with "****".
		
		Similar to gag or action or substitute, except that it only 
		siphons the data and does not modify it in any way.
		
		category: siphons
		"""
		cuetext = args["item"]
		quiet = args["quiet"]
		filename = args["name"]

		sm = exported.get_manager("siphon")
		sd = sm.getSiphonData(ses)
		if not cuetext:
			data = sd.getInfo()
			if not data:
				data = ["cue: no siphon cues defined."]

			exported.write_message("siphon cues\n" + "\n".join(data), ses)
			return

		sd.addSiphon(cuetext, filename)
		if not quiet:
			exported.write_message("siphon cue: {%s} added." % cuetext, ses)

commands_dict["cue"] = (cue_cmd, "item= name:string=~/muds/siphon quiet:boolean=false")

sm = None


def load():
	""" Initialize module... """
	global sm
	modutils.load_commands(commands_dict)
	sm = SiphonManager()
	exported.add_manager("siphon", sm)
	exported.hook_register("mud_filter_hook", sm.handle_mudfilter, 77)
	exported.hook_register("write_hook", sm.persist)

def unload():
	"""  Unload module... """
	global sm
	modutils.unload_commands(commands_dict.keys())
	exported.remove_manager("siphon")

	exported.hook_unregister("write_hook", sm.persist)
	exported.hook_unregister("mud_filter_hook", sm.handle_mudfilter)

# Local variables:
# mode:python
# py-indent-offset:2
# tab-width:2
# End: