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 |