"""This is a web based inspector for the AI System. It can be accessed via http://hostname.domain:port/inspect The hostname.domain would of course be the computer that the AI is running on. The port will need to be defined when the instance is inited. """ import string, time, direct, inspect, socket from operator import itemgetter from direct.http import WebRequest from socket import gethostname from direct.task.Task import Task from sys import platform from pirates.uberdog.AIMagicWordTrade import AIMagicWordTrade from pirates.quest.QuestDB import QuestDict # Need to figure out which systeminfo module to import if platform == 'win32': from windowsSystemInfo import SystemInformation else: from linuxSystemInfo import SystemInformation class aiWebServer(SystemInformation): def __init__(self, air, listenPort=8080): SystemInformation.__init__(self) self.listenPort = listenPort self.air = simbase.air # self.taskMgr = Task.TaskManager() if __debug__: print "Listen port set to: %d" % self.listenPort # Start dispatcher self.web = WebRequest.WebRequestDispatcher() self.web.listenOnPort(self.listenPort) self.localHostName = gethostname() self.web.registerGETHandler('inspect', self.inspect) self.web.registerGETHandler('systemInfo', self.systemInfo) self.web.registerGETHandler('oMenu', self.oMenu) self.web.registerGETHandler('oType', self.oType) self.web.registerGETHandler('oInst', self.oInst) self.web.registerGETHandler('blank', self.blank) self.web.registerGETHandler('magicWord', self.magicWord) self.startCheckingIncomingHTTP() self.air.setConnectionURL("http://%s:%s/" % (socket.gethostbyname(socket.gethostname()),self.HTTPListenPort)) def magicWord(self, replyTo, **kw): # This will process Magic Word requests # Currently the following words are supported: # ~aiobjectcount # ~aitaskmgr # ~aijobmgr # ~assignQuest # ~money # First we need to figure out which magic word is being called try: theMagicWord = kw['magicWord'] except KeyError: # MagicWord issue. Malformed URL replyTo.respond('\n\n\n\nMagic Word Error\nPlease check the URL. Transaction could not be completed. Malformed URL.\n') return # Next we execute the magic word request if theMagicWord == 'aiobjectcount': replyTo.respond('\n\n\n\n%s\n
%s
\n' % (theMagicWord, simbase.air.webPrintObjectCount())) return elif theMagicWord == 'aitaskmgr': replyTo.respond('\n\n\n\n%s\n
%s
\n' % (theMagicWord, taskMgr)) return elif theMagicWord == 'aijobmgr': replyTo.respond('\n\n\n\n%s\n
%s
\n' % (theMagicWord, jobMgr)) elif theMagicWord == 'money': # First, generate the Avatar HTML Select widget. selectWidget = self.genAvSelect() # Now that we've built the avatar list, we can repond with the HTML replyTo.respond('\n\n\n\nMoney\n
AvatarID: %s\nAmmount:

\n' % selectWidget) elif theMagicWord == 'MONEY_ADD': av = kw['avatarId'] count = kw['amount'] try: av = int(av) count = int(count) except ValueError: # One or both of the two args could not be converted into a int # This being the case, the transaction mut be stopped. # The most likely cause is the input of a non num type into # the amount field print 'Incorrect value entered.' replyTo.respond('\n\n\n\nMoney Error\nPlease check the Amount field. Transaction could not be completed.\n') return try: av = simbase.air.doId2do[av] except KeyError: replyTo.respond('\n\n\n\nMoney Error\nPlease check the AvatarID field; the Avatar might have logged out. Transaction could not be completed.\n') return curGold = av.getInventory().getGoldInPocket() # print "Debug: Args being passed to AIMAgicWordTrade:\t%s" % av trade = AIMagicWordTrade(av, av.getDoId(), avatarId = av.getDoId()) if count > curGold: trade.giveGoldInPocket(count - curGold) else: trade.takeGoldInPocket(curGold - count) trade.sendTrade() # I don't think I need to issue a tradeRejected or # tradeSucceesed call here. replyTo.respond('\n\n\n\nMoney Modified\nTransaction complete.\n') return elif theMagicWord == 'assignQuest': avSelectWidget = self.genAvSelect() questSelectWidget = self.genQuestSelect() # Present HTML menu with options replyTo.respond('\n\n\n\nAssignQuest\n
AvatarID: %s\nQuest to Assign: %s

\n' % (avSelectWidget, questSelectWidget)) elif theMagicWord == 'QUEST_ADD': av = kw['avatarId'] av = int(av) questId = kw['questId'] # print 'Avatarid = %s\nQuestID = %s' % (av, questId) try: av = simbase.air.doId2do[av] except KeyError: replyTo.respond('\n\n\n\nMoney Error\nPlease check the AvatarID field; the Avatar might have logged out. Transaction could not be completed.\n') return av.assignQuest(questId) replyTo.respond('\n\n\n\nQuest Assigned\nThe avatar with id: %s
Has been assigned Quest: %s\n' % (kw['avatarId'], questId)) return else: # No word Matches replyTo.respond('\n\n\n\nNo Word Matches\nThe Magic word provided does not exist or is not accessable via the web interface at this time.\n') return def timeStamp(self): # Returns the local time in the following string format: # Month-Day-Year Hour:Minute:Seconds # Example: 09-17-2007 15:36:04 return time.strftime("%m-%d-%Y %H:%M:%S", time.localtime()) def oMenu(self, replyTo, **kw): # Menu listing Magic words and Raw object list (all HTML links) replyTo.respond('\n\n\n\nMenu Options\nMagic Words:

Raw Object List\n') return def genAvSelect(self): # We will need to populate HTML FORM menus to make this work. # We will need to provide a list of Avatars on the AI # along with a field to allow an int value to be sent # First, we need to get a dict of DistributedPlayerPirateAI's playerPirates = [] objList = self.generateSortedIDList() objList.reverse() while objList: tempObjElement = objList.pop() if str(tempObjElement[0]).find('DistributedPlayerPirateAI') != -1: playerPirates.append(tempObjElement[1]) # OK, now playerPirates should be a list of avatar ids # We should build a HTML select widget with the new list selectWidget = '
\n' % selectWidget return selectWidget def genQuestSelect(self): # Will generate an HTML select widget, with the Key vals from the QuestDB selectWidget = '
\n' % selectWidget return selectWidget def blank(self, replyTo, **kw): # This simple generates a blank page for the middle and right # frames;( for when the page is first accessed) replyTo.respond('\n\n\n\nWord not found\n\n') def oInst(self, replyTo, **kw): # This will populate the middle frame with list of the members of # the object selected in the left frame #print "%s|oInst Frame Accessed, Request ID %s" % (self.timeStamp(), str(kw)) head = '\n\n\n\nmember List\n\n\n

' body = '' doIdRequested = '' for j, k in kw.iteritems(): doIdRequested = int(k) #print j,k try: memberList = inspect.getmembers(simbase.air.doId2do[doIdRequested]) except KeyError: replyTo.respond('\n\n\n\nOBJ Gone\nThe object is no longer on the system\n') return memberList.sort() memberList.reverse() while memberList: tempMember = memberList.pop() if (type(tempMember[1]) == str or type(tempMember[1]) == int or type(tempMember[1]) == float or type(tempMember[1]) == dict): body = '%s
  • %s\n' % (body, str(tempMember)) replyTo.respond('%s%s%s' % (head,body,foot)) def oType(self, replyTo, **kw): # This will populate the left frame with a alpha sorted list of # objects. # print "%s|oType Frame Accessed" % self.timeStamp() head = '\n\n\n\nObject List\n\n\n' objList = self.generateSortedIDList() # Need to sort objList by second col (the doid) objList = sorted(objList, key=itemgetter(1)) objList.reverse() body = '' # Pop off the Null entry while objList: tempObjElement = objList.pop() # tempObjElement[0].replace('<','') # tempObjElement[0].replace('>','') # if str(tempObjElement[0]).find('render') == -1: body = '%s
  • %s:%s\n' % (body, tempObjElement[1], tempObjElement[1], str(tempObjElement[0]).replace('<','').replace('>','')) replyTo.respond('%s%s%s' % (head,body,foot)) def inspect(self, replyTo, **kw): # This is the index. Basically, it will generate the frames for the # other functions to populate: systemInfo, oType, oInst, oAttrib # Three frames on the bottom row # frameset = '\n\n\n\n\n\n\n\n' # Two Frames on the bottom row frameset = '\n\n\n\n\n\n\n' #print "%s|Index Frame Accessed" % self.timeStamp() # print str(simbase.air.doid2do) replyTo.respond('\n\n\nAI HTTP Interface: %s\n\n%s' % (self.localHostName, frameset)) def systemInfo(self, replyTo, **kw): # This is the contents of the top frame; i.e. system information self.refresh() #print "%s|SystemInfo Frame Accessed" % self.timeStamp() replyTo.respond('\n\n\n\nSystem Info\n\n\n
    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
    Hostname: %s
    \nOperating System: %s
    \nCPU: %s
    Total RAM:%dTotal VM%d
    Available RAM:%dAvailable VM%d
    \n\n' % (self.localHostName, self.os, self.cpu, self.totalRAM, self.totalVM, self.availableRAM, self.availableVM)) def startCheckingIncomingHTTP(self): taskMgr.remove('pollHTTPTask') taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask') def stopCheckingIncomingHTTP(self): taskMgr.remove('pollHTTPTask') def pollHTTPTask(self,task): """ Task that polls the HTTP server for new requests. """ # print 'Polling...' self.web.poll() #taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask') return Task.again def generateSortedIDList(self): # looks at the simbase.air.doID2do dict, and returns a list # sorted by alpha order. IDlist = [] for key, val in simbase.air.doId2do.iteritems(): IDlist.append([val,key]) IDlist.sort() return IDlist def inspectObject(anObject): inspector = inspectorFor(anObject) # inspectorWindow = InspectorWindow(inspector) # inspectorWindow.open() # return inspectorWindow return inspector ### private def inspectorFor(anObject): typeName = string.capitalize(type(anObject).__name__) + 'Type' if typeName in _InspectorMap: inspectorName = _InspectorMap[typeName] else: print "Can't find an inspector for " + typeName inspectorName = 'Inspector' inspector = globals()[inspectorName](anObject) return inspector def initializeInspectorMap(): global _InspectorMap notFinishedTypes = ['BufferType', 'EllipsisType', 'FrameType', 'TracebackType', 'XRangeType'] _InspectorMap = { 'Builtin_function_or_methodType': 'FunctionInspector', 'BuiltinFunctionType': 'FunctionInspector', 'BuiltinMethodType': 'FunctionInspector', 'ClassType': 'ClassInspector', 'CodeType': 'CodeInspector', 'ComplexType': 'Inspector', 'DictionaryType': 'DictionaryInspector', 'DictType': 'DictionaryInspector', 'FileType': 'Inspector', 'FloatType': 'Inspector', 'FunctionType': 'FunctionInspector', 'Instance methodType': 'InstanceMethodInspector', 'InstanceType': 'InstanceInspector', 'IntType': 'Inspector', 'LambdaType': 'Inspector', 'ListType': 'SequenceInspector', 'LongType': 'Inspector', 'MethodType': 'FunctionInspector', 'ModuleType': 'ModuleInspector', 'NoneType': 'Inspector', 'SliceType': 'SliceInspector', 'StringType': 'SequenceInspector', 'TupleType': 'SequenceInspector', 'TypeType': 'Inspector', 'UnboundMethodType': 'FunctionInspector', 'DistributedshipcannonaiType': 'ClassInspector'} for each in notFinishedTypes: _InspectorMap[each] = 'Inspector' class Inspector: def __init__(self, anObject): self.object = anObject self.lastPartNumber = 0 self.initializePartsList() self.initializePartNames() def __str__(self): return __name__ + '(' + str(self.object) + ')' def initializePartsList(self): self._partsList = [] keys = self.namedParts() keys.sort() for each in keys: self._partsList.append(each) #if not callable(getattr(self.object, each)): # self._partsList.append(each) def initializePartNames(self): self._partNames = ['up'] + [str(each) for each in self._partsList] def title(self): "Subclasses may override." return string.capitalize(self.objectType().__name__) def getLastPartNumber(self): return self.lastPartNumber def selectedPart(self): return self.partNumber(self.getLastPartNumber()) def namedParts(self): return dir(self.object) def stringForPartNumber(self, partNumber): object = self.partNumber(partNumber) doc = None if callable(object): try: doc = object.__doc__ except: pass if doc: return (str(object) + '\n' + str(doc)) else: return str(object) def partNumber(self, partNumber): self.lastPartNumber = partNumber if partNumber == 0: return self.object else: part = self.privatePartNumber(partNumber) return getattr(self.object, part) def inspectorFor(self, part): return inspectorFor(part) def privatePartNumber(self, partNumber): return self._partsList[partNumber - 1] def partNames(self): return self._partNames def objectType(self): return type(self.object) ### class ModuleInspector(Inspector): def namedParts(self): return ['__dict__'] class ClassInspector(Inspector): def namedParts(self): return ['__bases__'] + self.object.__dict__.keys() def title(self): return self.object.__name__ + ' Class' class InstanceInspector(Inspector): def title(self): return self.object.__class__.__name__ def namedParts(self): return ['__class__'] + dir(self.object) ### class FunctionInspector(Inspector): def title(self): return self.object.__name__ + "()" class InstanceMethodInspector(Inspector): def title(self): return str(self.object.im_class) + "." + self.object.__name__ + "()" class CodeInspector(Inspector): def title(self): return str(self.object) ### class ComplexInspector(Inspector): def namedParts(self): return ['real', 'imag'] ### class DictionaryInspector(Inspector): def initializePartsList(self): Inspector.initializePartsList(self) keys = self.object.keys() keys.sort() for each in keys: self._partsList.append(each) def partNumber(self, partNumber): self.lastPartNumber = partNumber if partNumber == 0: return self.object key = self.privatePartNumber(partNumber) if key in self.object: return self.object[key] else: return getattr(self.object, key) class SequenceInspector(Inspector): def initializePartsList(self): Inspector.initializePartsList(self) for each in range(len(self.object)): self._partsList.append(each) def partNumber(self, partNumber): self.lastPartNumber = partNumber if partNumber == 0: return self.object index = self.privatePartNumber(partNumber) if type(index) == IntType: return self.object[index] else: return getattr(self.object, index) class SliceInspector(Inspector): def namedParts(self): return ['start', 'stop', 'step'] ### Initialization initializeInspectorMap()