mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
init commit. Simple web based object inspector. Top frame has basic system info, left frame lists objects, right frame lists obj attribs when left frame is clicked.
This commit is contained in:
parent
ed42b62afa
commit
9143737a1b
343
direct/src/http/webAIInspector.py
Executable file
343
direct/src/http/webAIInspector.py
Executable file
@ -0,0 +1,343 @@
|
||||
"""This is a web based inspector for the AI System. It can be accessed via
|
||||
http://hostname.domain:port/ai
|
||||
|
||||
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
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.http import WebRequest
|
||||
from socket import gethostname
|
||||
from direct.task.Task import Task
|
||||
from sys import platform
|
||||
|
||||
# Need to figure out which systeminfo module to import
|
||||
if platform == 'win32':
|
||||
from windowsSystemInfo import SystemInformation
|
||||
else:
|
||||
from linuxSystemInfo import SystemInformation
|
||||
|
||||
if __debug__:
|
||||
notify = directNotify.newCategory('AIWebInterface')
|
||||
|
||||
class aiWebServer(SystemInformation):
|
||||
def __init__(self, air, listenPort=8080):
|
||||
SystemInformation.__init__(self)
|
||||
self.listenPort = listenPort
|
||||
# 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('oType', self.oType)
|
||||
self.web.registerGETHandler('oInst', self.oInst)
|
||||
self.web.registerGETHandler('blank', self.blank)
|
||||
self.startCheckingIncomingHTTP()
|
||||
|
||||
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 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('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>BLANK</title>\n</head><body></body>\n</HTML>')
|
||||
|
||||
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 = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>member List</title>\n</head>\n<body>\n<UL>'
|
||||
foot = '</ul></body></HTML>'
|
||||
body = ''
|
||||
doIdRequested = ''
|
||||
for j, k in kw.iteritems():
|
||||
doIdRequested = int(k)
|
||||
#print j,k
|
||||
memberList = inspect.getmembers(simbase.air.doId2do[doIdRequested])
|
||||
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) and (tempMember[0] != '__doc__') or (tempMember[0] != 'DtoolClassDict') :
|
||||
body = '%s<LI>%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 = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>Object List</title>\n</head>\n<body>\n<UL>'
|
||||
foot = '</ul></body></HTML>'
|
||||
objList = self.generateSortedIDList()
|
||||
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<LI><A HREF="oInst?id=%s" target="oInst">%s</A>\n' % (body, 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 = '<frameset rows="35\%,65\%">\n<frame src="systemInfo" name="systemInfo" frameborder=1>\n<frameset cols="25\%,25\%,50\%">\n<frame src="oType" name="oType" frameborder=1>\n<frame src="blank" name="oInst" frameborder=1>\n<frame src="blank" name="oAttrib" frameborder=1>\n</frameset>\n</frameset>\n</html>'
|
||||
# Two Frames on the bottom row
|
||||
frameset = '<frameset rows="35\%,65\%">\n<frame src="systemInfo" name="systemInfo" frameborder=1>\n<frameset cols="50\%,50\%">\n<frame src="oType" name="oType" frameborder=1>\n<frame src="blank" name="oInst" frameborder=1>\n</frameset>\n</frameset>\n</html>'
|
||||
#print "%s|Index Frame Accessed" % self.timeStamp()
|
||||
# print str(simbase.air.doid2do)
|
||||
replyTo.respond('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">\n<html lang="en">\n<head>\n<title>AI HTTP Interface: %s</title>\n</head>\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('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>System Info</title>\n</head>\n<body>\n<center><table style="text-align: left; width: 443px; height: 128px;" border="1" cellpadding="2" cellspacing="2">\n<tbody>\n<tr>\n<td style="text-align: center;" colspan="4">Hostname: %s<br>\nOperating System: %s<br>\nCPU: %s</td>\n</tr>\n<tr>\n<td>Total RAM:</td>\n<td>%d</td>\n<td>Total VM</td>\n<td>%d</td>\n</tr>\n<tr>\n<td>Available RAM:</td>\n<td>%d</td>\n<td>Available VM</td>\n<td>%d</td>\n</tr>\n</tbody>\n</table></center>\n</body>\n</html>' % (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 _InspectorMap.has_key(typeName):
|
||||
inspectorName = _InspectorMap[typeName]
|
||||
else:
|
||||
print "Can't find an inspector for " + typeName
|
||||
inspectorName = 'Inspector'
|
||||
inspector = eval(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(eval('self.object.' + each)):
|
||||
# self._partsList.append(each)
|
||||
|
||||
def initializePartNames(self):
|
||||
self._partNames = ['up'] + map(lambda each: str(each), 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 eval('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 self.object.has_key(key):
|
||||
return self.object[key]
|
||||
else:
|
||||
return eval('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 eval('self.object.' + index)
|
||||
|
||||
class SliceInspector(Inspector):
|
||||
def namedParts(self):
|
||||
return ['start', 'stop', 'step']
|
||||
|
||||
### Initialization
|
||||
initializeInspectorMap()
|
Loading…
x
Reference in New Issue
Block a user