Introduce a debug service; spawn a Python REPL on a random local TCP port. Supports basic telnet commands, ^C and ^D work, etc.
This commit is contained in:
parent
807921372b
commit
d0d81fc152
11
terminator
11
terminator
|
@ -143,9 +143,20 @@ See the following bug report for more details:
|
|||
except IOError:
|
||||
pass
|
||||
|
||||
import terminatorlib.debugserver as debugserver
|
||||
(serverthread, server) = debugserver.spawn()
|
||||
import threading
|
||||
|
||||
gtk.gdk.threads_init()
|
||||
|
||||
dbg ('profile_cb: settled on profile: "%s"' % options.profile)
|
||||
term = Terminator (options.profile, command, options.fullscreen, options.maximise,
|
||||
options.borderless, options.no_gconf)
|
||||
|
||||
gtk.main()
|
||||
|
||||
# guithread = threading.Thread(target=gtk.main, name="Main GUI thread")
|
||||
# guithread.start()
|
||||
# guithread.join()
|
||||
server.socket.close()
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
#!/usr/local/bin/python
|
||||
#
|
||||
# Copyright (c) 2008, Thomas Hurst <tom@hur.st>
|
||||
#
|
||||
# Use of this file is unrestricted provided this notice is retained.
|
||||
# If you use it, it'd be nice if you dropped me a note. Also beer.
|
||||
|
||||
from terminatorlib.config import dbg, err
|
||||
from terminatorlib.version import APP_NAME, APP_VERSION
|
||||
|
||||
import socket
|
||||
import threading
|
||||
import SocketServer
|
||||
import code
|
||||
import sys
|
||||
import readline
|
||||
import rlcompleter
|
||||
import re
|
||||
|
||||
class PythonConsoleServer(SocketServer.BaseRequestHandler):
|
||||
def setup(self):
|
||||
dbg('debugserver: connect from %s' % str(self.client_address))
|
||||
self.console = TerminatorConsole()
|
||||
|
||||
def handle(self):
|
||||
dbg("debugserver: handling")
|
||||
try:
|
||||
self.socketio = self.request.makefile()
|
||||
sys.stdout = self.socketio
|
||||
sys.stdin = self.socketio
|
||||
# sys.stderr = self.socketio
|
||||
self.console.run(self)
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stdin = sys.__stdin__
|
||||
# sys.stderr = sys.__stderr__
|
||||
self.socketio.close()
|
||||
dbg("debugserver: done handling")
|
||||
|
||||
def verify_request(self, request, client_address):
|
||||
return True
|
||||
|
||||
def finish(self):
|
||||
dbg('debugserver: disconnect from %s' % str(self.client_address))
|
||||
|
||||
BareLF = re.compile('([^\015])\015')
|
||||
DoDont = re.compile('(^|[^\377])\377[\375\376](.)')
|
||||
WillWont = re.compile('(^|[^\377])\377[\373\374](.)')
|
||||
AreYouThere = re.compile('(^|[^\377])\377\366')
|
||||
IpTelnet = re.compile('(^|[^\377])\377\364')
|
||||
OtherTelnet = re.compile('(^|[^\377])\377[^\377]')
|
||||
|
||||
# See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/205335 for telnet bits
|
||||
# Python doesn't make this an especially neat conversion :(
|
||||
class TerminatorConsole(code.InteractiveConsole):
|
||||
def parse_telnet(self, data):
|
||||
odata = data
|
||||
data = re.sub(BareLF, '\\1', data)
|
||||
data = data.replace('\015\000', '')
|
||||
data = data.replace('\000', '')
|
||||
|
||||
bits = re.findall(DoDont, data)
|
||||
dbg("bits = %s" % repr(bits))
|
||||
if bits:
|
||||
data = re.sub(DoDont, '\\1', data)
|
||||
dbg("telnet: DO/DON'T answer")
|
||||
# answer DO and DON'T with WON'T
|
||||
for bit in bits:
|
||||
self.write("\377\374" + bit[1])
|
||||
|
||||
bits = re.findall(WillWont, data)
|
||||
if bits:
|
||||
data = re.sub(WillWont, '\\1', data)
|
||||
dbg("telnet: WILL/WON'T answer")
|
||||
for bit in bits:
|
||||
# answer WILLs and WON'T with DON'Ts
|
||||
self.write("\377\376" + bit[1])
|
||||
|
||||
bits = re.findall(AreYouThere, data)
|
||||
if bits:
|
||||
dbg("telnet: am I there answer")
|
||||
data = re.sub(AreYouThere, '\\1', data)
|
||||
for bit in bits:
|
||||
self.write("Yes, I'm still here, I think.\n")
|
||||
|
||||
bits = re.findall(IpTelnet, data) # IP (Interrupt Process)
|
||||
for bit in bits:
|
||||
dbg("debugserver: Ctrl-C detected")
|
||||
raise KeyboardInterrupt
|
||||
|
||||
data = re.sub(IpTelnet, '\\1', data) # ignore IP Telnet codes
|
||||
data = re.sub(OtherTelnet, '\\1', data) # and any other Telnet codes
|
||||
data = data.replace('\377\377', '\377') # and handle escapes
|
||||
|
||||
if data != odata:
|
||||
dbg("debugserver: Replaced %s with %s" % (repr(odata), repr(data)))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def raw_input(self, prompt = None):
|
||||
dbg("debugserver: raw_input prompt = %s" % repr(prompt))
|
||||
if prompt:
|
||||
self.write(prompt)
|
||||
|
||||
buf = ''
|
||||
compstate = 0
|
||||
while True:
|
||||
data = self.server.socketio.read(1) # should get the client sending unbuffered for tab complete?
|
||||
dbg('raw_input: char=%s' % repr(data))
|
||||
if data == '\n' or data == '\006':
|
||||
buf = self.parse_telnet(buf + data).lstrip()
|
||||
if buf != '':
|
||||
return buf
|
||||
elif data == '\004' or data == '': # ^D
|
||||
raise EOFError
|
||||
else:
|
||||
buf += data
|
||||
|
||||
def write(self, data):
|
||||
dbg("debugserver: write %s" % repr(data))
|
||||
self.server.socketio.write(data)
|
||||
self.server.socketio.flush()
|
||||
|
||||
def run(self, server):
|
||||
self.server = server
|
||||
|
||||
self.write("Welcome to the %s-%s debug server, have a nice stay\n" % (APP_NAME, APP_VERSION))
|
||||
self.interact()
|
||||
try:
|
||||
self.write("Time to go. Bye!\n")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def server():
|
||||
tcpserver = SocketServer.TCPServer(('127.0.0.1', 0), PythonConsoleServer)
|
||||
print "Serving on %s" % str(tcpserver.server_address)
|
||||
tcpserver.serve_forever()
|
||||
|
||||
def spawn():
|
||||
# server()
|
||||
# tcpserver = SocketServer.ThreadingTCPServer(('', 0), PythonConsoleServer)
|
||||
tcpserver = SocketServer.TCPServer(('', 0), PythonConsoleServer)
|
||||
print("debugserver: listening on %s" % str(tcpserver.server_address))
|
||||
dbg("debugserver: about to spawn thread")
|
||||
debugserver = threading.Thread(target=tcpserver.serve_forever, name="DebugServer")
|
||||
debugserver.setDaemon(True)
|
||||
dbg("debugserver: about to start thread")
|
||||
debugserver.start()
|
||||
dbg("debugserver: started thread")
|
||||
return(debugserver, tcpserver)
|
||||
|
|
@ -200,9 +200,9 @@ class Terminator:
|
|||
self.window.fullscreen ()
|
||||
|
||||
def on_window_state_changed (self, window, event):
|
||||
state = event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN
|
||||
self._fullscreen = bool (state)
|
||||
|
||||
self._fullscreen = bool (event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN)
|
||||
self._maximised = bool (event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED)
|
||||
dbg("window state changed: fullscreen: %s, maximised: %s" % (self._fullscreen, self._maximised))
|
||||
return (False)
|
||||
|
||||
def on_delete_event (self, window, event, data=None):
|
||||
|
@ -493,7 +493,12 @@ class Terminator:
|
|||
notebooktablabel = TerminatorNotebookTabLabel(notebooklabel, notebook, self)
|
||||
notebook.set_tab_label(child, notebooktablabel)
|
||||
notebook.set_tab_label_packing(child, True, True, gtk.PACK_START)
|
||||
self.window.resize(self.window.allocation.width, min(self.window.allocation.height + notebooktablabel.height_request(), gtk.gdk.screen_height()))
|
||||
|
||||
wal = self.window.allocation
|
||||
if not (self._maximised or self._fullscreen):
|
||||
self.window.resize(wal.width,
|
||||
min(wal.height + notebooktablabel.height_request(), gtk.gdk.screen_height()))
|
||||
|
||||
notebook.show()
|
||||
elif isinstance(parent, gtk.Notebook):
|
||||
notebook = parent
|
||||
|
|
Loading…
Reference in New Issue