| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 | |
| 5 """An input/output window for the glade reactor inspector. | |
| 6 """ | |
| 7 | |
| 8 import time | |
| 9 import gtk | |
| 10 import gobject | |
| 11 import gtk.glade | |
| 12 from twisted.python.util import sibpath | |
| 13 from twisted.python import reflect | |
| 14 | |
| 15 from twisted.manhole.ui import gtk2manhole | |
| 16 from twisted.python.components import Adapter, registerAdapter | |
| 17 from twisted.python import log | |
| 18 from twisted.protocols import policies | |
| 19 from zope.interface import implements, Interface | |
| 20 | |
| 21 # the glade file uses stock icons, which requires gnome to be installed | |
| 22 import gnome | |
| 23 version = "$Revision: 1.1 $"[11:-2] | |
| 24 gnome.init("gladereactor Inspector", version) | |
| 25 | |
| 26 class ConsoleOutput(gtk2manhole.ConsoleOutput): | |
| 27 def _captureLocalLog(self): | |
| 28 self.fobs = log.FileLogObserver(gtk2manhole._Notafile(self, "log")) | |
| 29 self.fobs.start() | |
| 30 | |
| 31 def stop(self): | |
| 32 self.fobs.stop() | |
| 33 del self.fobs | |
| 34 | |
| 35 class ConsoleInput(gtk2manhole.ConsoleInput): | |
| 36 def sendMessage(self): | |
| 37 buffer = self.textView.get_buffer() | |
| 38 iter1, iter2 = buffer.get_bounds() | |
| 39 text = buffer.get_text(iter1, iter2, False) | |
| 40 self.do(text) | |
| 41 | |
| 42 def do(self, text): | |
| 43 self.toplevel.do(text) | |
| 44 | |
| 45 class INode(Interface): | |
| 46 """A node in the inspector tree model. | |
| 47 """ | |
| 48 | |
| 49 def __adapt__(adaptable, default): | |
| 50 if hasattr(adaptable, "__dict__"): | |
| 51 return InstanceNode(adaptable) | |
| 52 return AttributesNode(adaptable) | |
| 53 | |
| 54 class InspectorNode(Adapter): | |
| 55 implements(INode) | |
| 56 | |
| 57 def postInit(self, offset, parent, slot): | |
| 58 self.offset = offset | |
| 59 self.parent = parent | |
| 60 self.slot = slot | |
| 61 | |
| 62 def getPath(self): | |
| 63 L = [] | |
| 64 x = self | |
| 65 while x.parent is not None: | |
| 66 L.append(x.offset) | |
| 67 x = x.parent | |
| 68 L.reverse() | |
| 69 return L | |
| 70 | |
| 71 def __getitem__(self, index): | |
| 72 slot, o = self.get(index) | |
| 73 n = INode(o, persist=False) | |
| 74 n.postInit(index, self, slot) | |
| 75 return n | |
| 76 | |
| 77 def origstr(self): | |
| 78 return str(self.original) | |
| 79 | |
| 80 def format(self): | |
| 81 return (self.slot, self.origstr()) | |
| 82 | |
| 83 | |
| 84 class ConstantNode(InspectorNode): | |
| 85 def __len__(self): | |
| 86 return 0 | |
| 87 | |
| 88 class DictionaryNode(InspectorNode): | |
| 89 def get(self, index): | |
| 90 L = self.original.items() | |
| 91 L.sort() | |
| 92 return L[index] | |
| 93 | |
| 94 def __len__(self): | |
| 95 return len(self.original) | |
| 96 | |
| 97 def origstr(self): | |
| 98 return "Dictionary" | |
| 99 | |
| 100 class ListNode(InspectorNode): | |
| 101 def get(self, index): | |
| 102 return index, self.original[index] | |
| 103 | |
| 104 def origstr(self): | |
| 105 return "List" | |
| 106 | |
| 107 def __len__(self): | |
| 108 return len(self.original) | |
| 109 | |
| 110 class AttributesNode(InspectorNode): | |
| 111 def __len__(self): | |
| 112 return len(dir(self.original)) | |
| 113 | |
| 114 def get(self, index): | |
| 115 L = dir(self.original) | |
| 116 L.sort() | |
| 117 return L[index], getattr(self.original, L[index]) | |
| 118 | |
| 119 class InstanceNode(InspectorNode): | |
| 120 def __len__(self): | |
| 121 return len(self.original.__dict__) + 1 | |
| 122 | |
| 123 def get(self, index): | |
| 124 if index == 0: | |
| 125 if hasattr(self.original, "__class__"): | |
| 126 v = self.original.__class__ | |
| 127 else: | |
| 128 v = type(self.original) | |
| 129 return "__class__", v | |
| 130 else: | |
| 131 index -= 1 | |
| 132 L = self.original.__dict__.items() | |
| 133 L.sort() | |
| 134 return L[index] | |
| 135 | |
| 136 import types | |
| 137 | |
| 138 for x in dict, types.DictProxyType: | |
| 139 registerAdapter(DictionaryNode, x, INode) | |
| 140 for x in list, tuple: | |
| 141 registerAdapter(ListNode, x, INode) | |
| 142 for x in int, str: | |
| 143 registerAdapter(ConstantNode, x, INode) | |
| 144 | |
| 145 | |
| 146 class InspectorTreeModel(gtk.GenericTreeModel): | |
| 147 def __init__(self, root): | |
| 148 gtk.GenericTreeModel.__init__(self) | |
| 149 self.root = INode(root, persist=False) | |
| 150 self.root.postInit(0, None, 'root') | |
| 151 | |
| 152 def on_get_flags(self): | |
| 153 return 0 | |
| 154 | |
| 155 def on_get_n_columns(self): | |
| 156 return 1 | |
| 157 | |
| 158 def on_get_column_type(self, index): | |
| 159 return gobject.TYPE_STRING | |
| 160 | |
| 161 def on_get_path(self, node): | |
| 162 return node.getPath() | |
| 163 | |
| 164 def on_get_iter(self, path): | |
| 165 x = self.root | |
| 166 for elem in path: | |
| 167 x = x[elem] | |
| 168 return x | |
| 169 | |
| 170 def on_get_value(self, node, column): | |
| 171 return node.format()[column] | |
| 172 | |
| 173 def on_iter_next(self, node): | |
| 174 try: | |
| 175 return node.parent[node.offset + 1] | |
| 176 except IndexError: | |
| 177 return None | |
| 178 | |
| 179 def on_iter_children(self, node): | |
| 180 return node[0] | |
| 181 | |
| 182 def on_iter_has_child(self, node): | |
| 183 return len(node) | |
| 184 | |
| 185 def on_iter_n_children(self, node): | |
| 186 return len(node) | |
| 187 | |
| 188 def on_iter_nth_child(self, node, n): | |
| 189 if node is None: | |
| 190 return None | |
| 191 return node[n] | |
| 192 | |
| 193 def on_iter_parent(self, node): | |
| 194 return node.parent | |
| 195 | |
| 196 | |
| 197 class Inspectro: | |
| 198 selected = None | |
| 199 def __init__(self, o=None): | |
| 200 self.xml = x = gtk.glade.XML(sibpath(__file__, "inspectro.glade")) | |
| 201 self.tree_view = x.get_widget("treeview") | |
| 202 colnames = ["Name", "Value"] | |
| 203 for i in range(len(colnames)): | |
| 204 self.tree_view.append_column( | |
| 205 gtk.TreeViewColumn( | |
| 206 colnames[i], gtk.CellRendererText(), text=i)) | |
| 207 d = {} | |
| 208 for m in reflect.prefixedMethods(self, "on_"): | |
| 209 d[m.im_func.__name__] = m | |
| 210 self.xml.signal_autoconnect(d) | |
| 211 if o is not None: | |
| 212 self.inspect(o) | |
| 213 self.ns = {'inspect': self.inspect} | |
| 214 iwidget = x.get_widget('input') | |
| 215 self.input = ConsoleInput(iwidget) | |
| 216 self.input.toplevel = self | |
| 217 iwidget.connect("key_press_event", self.input._on_key_press_event) | |
| 218 self.output = ConsoleOutput(x.get_widget('output')) | |
| 219 | |
| 220 def select(self, o): | |
| 221 self.selected = o | |
| 222 self.ns['it'] = o | |
| 223 self.xml.get_widget("itname").set_text(repr(o)) | |
| 224 self.xml.get_widget("itpath").set_text("???") | |
| 225 | |
| 226 def inspect(self, o): | |
| 227 self.model = InspectorTreeModel(o) | |
| 228 self.tree_view.set_model(self.model) | |
| 229 self.inspected = o | |
| 230 | |
| 231 def do(self, command): | |
| 232 filename = '<inspector>' | |
| 233 try: | |
| 234 print repr(command) | |
| 235 try: | |
| 236 code = compile(command, filename, 'eval') | |
| 237 except: | |
| 238 code = compile(command, filename, 'single') | |
| 239 val = eval(code, self.ns, self.ns) | |
| 240 if val is not None: | |
| 241 print repr(val) | |
| 242 self.ns['_'] = val | |
| 243 except: | |
| 244 log.err() | |
| 245 | |
| 246 def on_inspect(self, *a): | |
| 247 self.inspect(self.selected) | |
| 248 | |
| 249 def on_inspect_new(self, *a): | |
| 250 Inspectro(self.selected) | |
| 251 | |
| 252 def on_row_activated(self, tv, path, column): | |
| 253 self.select(self.model.on_get_iter(path).original) | |
| 254 | |
| 255 | |
| 256 class LoggingProtocol(policies.ProtocolWrapper): | |
| 257 """Log network traffic.""" | |
| 258 | |
| 259 logging = True | |
| 260 logViewer = None | |
| 261 | |
| 262 def __init__(self, *args): | |
| 263 policies.ProtocolWrapper.__init__(self, *args) | |
| 264 self.inLog = [] | |
| 265 self.outLog = [] | |
| 266 | |
| 267 def write(self, data): | |
| 268 if self.logging: | |
| 269 self.outLog.append((time.time(), data)) | |
| 270 if self.logViewer: | |
| 271 self.logViewer.updateOut(self.outLog[-1]) | |
| 272 policies.ProtocolWrapper.write(self, data) | |
| 273 | |
| 274 def dataReceived(self, data): | |
| 275 if self.logging: | |
| 276 self.inLog.append((time.time(), data)) | |
| 277 if self.logViewer: | |
| 278 self.logViewer.updateIn(self.inLog[-1]) | |
| 279 policies.ProtocolWrapper.dataReceived(self, data) | |
| 280 | |
| 281 def __repr__(self): | |
| 282 r = "wrapped " + repr(self.wrappedProtocol) | |
| 283 if self.logging: | |
| 284 r += " (logging)" | |
| 285 return r | |
| 286 | |
| 287 | |
| 288 class LoggingFactory(policies.WrappingFactory): | |
| 289 """Wrap protocols with logging wrappers.""" | |
| 290 | |
| 291 protocol = LoggingProtocol | |
| 292 logging = True | |
| 293 | |
| 294 def buildProtocol(self, addr): | |
| 295 p = self.protocol(self, self.wrappedFactory.buildProtocol(addr)) | |
| 296 p.logging = self.logging | |
| 297 return p | |
| 298 | |
| 299 def __repr__(self): | |
| 300 r = "wrapped " + repr(self.wrappedFactory) | |
| 301 if self.logging: | |
| 302 r += " (logging)" | |
| 303 return r | |
| 304 | |
| 305 | |
| 306 class LogViewer: | |
| 307 """Display log of network traffic.""" | |
| 308 | |
| 309 def __init__(self, p): | |
| 310 self.p = p | |
| 311 vals = [time.time()] | |
| 312 if p.inLog: | |
| 313 vals.append(p.inLog[0][0]) | |
| 314 if p.outLog: | |
| 315 vals.append(p.outLog[0][0]) | |
| 316 self.startTime = min(vals) | |
| 317 p.logViewer = self | |
| 318 self.xml = x = gtk.glade.XML(sibpath(__file__, "logview.glade")) | |
| 319 self.xml.signal_autoconnect(self) | |
| 320 self.loglist = self.xml.get_widget("loglist") | |
| 321 # setup model, connect it to my treeview | |
| 322 self.model = gtk.ListStore(str, str, str) | |
| 323 self.loglist.set_model(self.model) | |
| 324 self.loglist.set_reorderable(1) | |
| 325 self.loglist.set_headers_clickable(1) | |
| 326 # self.servers.set_headers_draggable(1) | |
| 327 # add a column | |
| 328 for col in [ | |
| 329 gtk.TreeViewColumn('Time', | |
| 330 gtk.CellRendererText(), | |
| 331 text=0), | |
| 332 gtk.TreeViewColumn('D', | |
| 333 gtk.CellRendererText(), | |
| 334 text=1), | |
| 335 gtk.TreeViewColumn('Data', | |
| 336 gtk.CellRendererText(), | |
| 337 text=2)]: | |
| 338 self.loglist.append_column(col) | |
| 339 col.set_resizable(1) | |
| 340 r = [] | |
| 341 for t, data in p.inLog: | |
| 342 r.append(((str(t - self.startTime), "R", repr(data)[1:-1]))) | |
| 343 for t, data in p.outLog: | |
| 344 r.append(((str(t - self.startTime), "S", repr(data)[1:-1]))) | |
| 345 r.sort() | |
| 346 for i in r: | |
| 347 self.model.append(i) | |
| 348 | |
| 349 def updateIn(self, (time, data)): | |
| 350 self.model.append((str(time - self.startTime), "R", repr(data)[1:-1])) | |
| 351 | |
| 352 def updateOut(self, (time, data)): | |
| 353 self.model.append((str(time - self.startTime), "S", repr(data)[1:-1])) | |
| 354 | |
| 355 def on_logview_destroy(self, w): | |
| 356 self.p.logViewer = None | |
| 357 del self.p | |
| 358 | |
| 359 | |
| 360 def main(): | |
| 361 x = Inspectro() | |
| 362 x.inspect(x) | |
| 363 gtk.main() | |
| 364 | |
| 365 if __name__ == '__main__': | |
| 366 import sys | |
| 367 log.startLogging(sys.stdout) | |
| 368 main() | |
| 369 | |
| OLD | NEW |