class LarchServer(SimpleXMLRPCServer): def __init__(self, host='localhost', port=4966, logRequests=False, allow_none=True, keepalive_time=3*24*3600): self.out_buffer = [] self.larch = Interpreter(writer=self) self.input = InputText(prompt='', _larch=self.larch) self.larch.run_init_scripts() self.larch('_sys.client = group(keepalive_time=%f)' % keepalive_time) self.larch('_sys.wx = group(wxapp=None)') _sys = self.larch.symtable._sys _sys.color_exceptions = False _sys.client.last_event = int(time()) _sys.client.pid_server = int(os.getpid()) _sys.client.app = 'unknown' _sys.client.pid = 0 _sys.client.user = '******' _sys.client.machine = 'unknown' self.client = self.larch.symtable._sys.client SimpleXMLRPCServer.__init__(self, (host, port), logRequests=logRequests, allow_none=allow_none) self.register_introspection_functions() self.register_function(self.larch_exec, 'larch') for method in ('ls', 'chdir', 'cd', 'cwd', 'shutdown', 'set_keepalive_time', 'set_client_info', 'get_client_info', 'get_data', 'get_rawdata', 'get_messages', 'len_messages'): self.register_function(getattr(self, method), method) # sys.stdout = self self.finished = False signal.signal(signal.SIGINT, self.signal_handler) self.activity_thread = Thread(target=self.check_activity) def write(self, text, **kws): if text is None: text = '' self.out_buffer.append(str(text)) def flush(self): pass def set_keepalive_time(self, keepalive_time): """set keepalive time the server will self destruct after keepalive_time of inactivity Arguments: keepalive_time (number): time in seconds """ self.larch("_sys.client.keepalive_time = %f" % keepalive_time) def set_client_info(self, key, value): """set client info Arguments: key (str): category value (str): value to use Notes: the key can actually be any string but include by convention: app application name user user name machine machine name pid process id """ self.larch("_sys.client.%s = '%s'" % (key, value)) def get_client_info(self): """get client info: returns json dictionary of client information """ out = {} client = self.larch.symtable._sys.client for attr in dir(client): out[attr] = getattr(client, attr) return encode4js(out) def get_messages(self): """get (and clear) all output messages (say, from "print()") """ out = "".join(self.out_buffer) self.out_buffer = [] return out def len_messages(self): "length of message buffer" return len(self.out_buffer) def ls(self, dir_name): """list contents of a directory: """ return os.listdir(dir_name) def chdir(self, dir_name): """change directory""" return os.chdir(dir_name) def cd(self, dir_name): """change directory""" return os.chdir(dir_name) def cwd(self): """change directory""" ret = os.getcwd() if sys.platform == 'win32': ret = ret.replace('\\','/') return ret def signal_handler(self, sig=0, frame=None): self.kill() def kill(self): """handle alarm signal, generated by signal.alarm(t)""" sleep(2.0) self.shutdown() self.server_close() def shutdown(self): "shutdown LarchServer" self.finished = True if self.activity_thread.is_alive(): self.activity_thread.join(POLL_TIME) return 1 def check_activity(self): while not self.finished: sleep(POLL_TIME) # print("Tick ", time()- (self.client.keepalive_time + self.client.last_event)) if time() > (self.client.keepalive_time + self.client.last_event): t = Thread(target=self.kill) t.start() break def larch_exec(self, text): "execute larch command" text = text.strip() if text in ('quit', 'exit', 'EOF'): self.shutdown() else: self.input.put(text, lineno=0) if self.input.complete: self.larch('_sys.client.last_event = %i' % time()) self.input.run() self.flush() return 1 def get_rawdata(self, expr): "return non-json encoded data for a larch expression" return self.larch.eval(expr) def get_data(self, expr): "return json encoded data for a larch expression" self.larch('_sys.client.last_event = %i' % time()) return encode4js(self.larch.eval(expr)) def run(self): """run server until times out""" self.activity_thread.start() while not self.finished: try: self.handle_request() except: break
class LarchServer(SimpleXMLRPCServer): def __init__(self, host='localhost', port=4966, logRequests=False, allow_none=True, keepalive_time=3 * 24 * 3600): self.out_buffer = [] self.larch = Interpreter(writer=self) self.input = InputText(prompt='', _larch=self.larch) self.larch.run_init_scripts() self.larch('_sys.client = group(keepalive_time=%f)' % keepalive_time) self.larch('_sys.wx = group(wxapp=None)') _sys = self.larch.symtable._sys _sys.color_exceptions = False _sys.client.last_event = int(time()) _sys.client.pid_server = int(os.getpid()) _sys.client.app = 'unknown' _sys.client.pid = 0 _sys.client.user = '******' _sys.client.machine = 'unknown' self.client = self.larch.symtable._sys.client SimpleXMLRPCServer.__init__(self, (host, port), logRequests=logRequests, allow_none=allow_none) self.register_introspection_functions() self.register_function(self.larch_exec, 'larch') for method in ('ls', 'chdir', 'cd', 'cwd', 'shutdown', 'set_keepalive_time', 'set_client_info', 'get_client_info', 'get_data', 'get_rawdata', 'get_messages', 'len_messages'): self.register_function(getattr(self, method), method) # sys.stdout = self self.finished = False signal.signal(signal.SIGINT, self.signal_handler) self.activity_thread = Thread(target=self.check_activity) def write(self, text, **kws): self.out_buffer.append(text) def flush(self): pass def set_keepalive_time(self, keepalive_time): """set keepalive time the server will self destruct after keepalive_time of inactivity Arguments: keepalive_time (number): time in seconds """ self.larch("_sys.client.keepalive_time = %f" % keepalive_time) def set_client_info(self, key, value): """set client info Arguments: key (str): category value (str): value to use Notes: the key can actually be any string but include by convention: app application name user user name machine machine name pid process id """ self.larch("_sys.client.%s = '%s'" % (key, value)) def get_client_info(self): """get client info: returns json dictionary of client information """ out = {} client = self.larch.symtable._sys.client for attr in dir(client): out[attr] = getattr(client, attr) return encode4js(out) def get_messages(self): """get (and clear) all output messages (say, from "print()") """ out = "".join(self.out_buffer) self.out_buffer = [] return out def len_messages(self): "length of message buffer" return len(self.out_buffer) def ls(self, dir_name): """list contents of a directory: """ return os.listdir(dir_name) def chdir(self, dir_name): """change directory""" return os.chdir(dir_name) def cd(self, dir_name): """change directory""" return os.chdir(dir_name) def cwd(self): """change directory""" ret = os.getcwd() if sys.platform == 'win32': ret = ret.replace('\\', '/') return ret def signal_handler(self, sig=0, frame=None): self.kill() def kill(self): """handle alarm signal, generated by signal.alarm(t)""" sleep(2.0) self.shutdown() self.server_close() def shutdown(self): "shutdown LarchServer" self.finished = True if self.activity_thread.is_alive(): self.activity_thread.join(POLL_TIME) return 1 def check_activity(self): while not self.finished: sleep(POLL_TIME) # print("Tick ", time()- (self.client.keepalive_time + self.client.last_event)) if time() > (self.client.keepalive_time + self.client.last_event): t = Thread(target=self.kill) t.start() break def larch_exec(self, text): "execute larch command" text = text.strip() if text in ('quit', 'exit', 'EOF'): self.shutdown() else: self.input.put(text, lineno=0) if self.input.complete: self.larch('_sys.client.last_event = %i' % time()) self.input.run() self.flush() return 1 def get_rawdata(self, expr): "return non-json encoded data for a larch expression" return self.larch.eval(expr) def get_data(self, expr): "return json encoded data for a larch expression" self.larch('_sys.client.last_event = %i' % time()) return encode4js(self.larch.eval(expr)) def run(self): """run server until times out""" self.activity_thread.start() while not self.finished: try: self.handle_request() except: break
class SpykShell(): ps1 = 'Spyk >' ps2 = ' ... >' def __init__(self, wxparent=None, writer=None, _larch=None, prompt=None, historyfile=None, output=None, input=None): self._larch = _larch self.textstyle = None if _larch is None: self._larch = Interpreter(historyfile=historyfile, writer=self) self._larch.run_init_scripts() self.symtable = self._larch.symtable self.prompt = prompt self.input = input self.output = output self.set_textstyle(mode='text') self._larch("_sys.display.colors['text2'] = {'color': 'blue'}", add_history=False) self._larch.add_plugin('wx', wxparent=wxparent) self.symtable.set_symbol('_builtin.force_wxupdate', False) self.symtable.set_symbol('_sys.wx.force_wxupdate', False) self.symtable.set_symbol('_sys.wx.wxapp', output) self.symtable.set_symbol('_sys.wx.parent', wx.GetApp().GetTopWindow()) if self.output is not None: style = self.output.GetDefaultStyle() bgcol = style.GetBackgroundColour() sfont = style.GetFont() self.textstyle = wx.TextAttr('black', bgcol, sfont) self.SetPrompt(True) self.flush_timer = wx.Timer(wxparent) self.needs_flush = True wxparent.Bind(wx.EVT_TIMER, self.onFlushTimer, self.flush_timer) self.flush_timer.Start(500) def onUpdate(self, event=None): symtable = self.symtable if symtable.get_symbol('_builtin.force_wxupdate', create=True): app = wx.GetApp() evtloop = wx.EventLoop() while evtloop.Pending(): evtloop.Dispatch() app.ProcessIdle() symtable.set_symbol('_builtin.force_wxupdate', False) def SetPrompt(self, complete): if self.prompt is None: return sprompt, scolor = self.ps1, '#000075' if not complete: sprompt, scolor = self.ps2, '#E00075' self.prompt.SetLabel(sprompt) self.prompt.SetForegroundColour(scolor) self.prompt.Refresh() def set_textstyle(self, mode='text'): if self.output is None: return display_colors = self._larch.symtable._sys.display.colors textattrs = display_colors.get(mode, {'color':'black'}) color = textattrs['color'] style = self.output.GetDefaultStyle() bgcol = style.GetBackgroundColour() sfont = style.GetFont() self.textstyle = wx.TextAttr(color, bgcol, sfont) def write(self, text, **kws): if self.output is None: sys.stdout.write(text) sys.stdout.flush() else: pos0 = self.output.GetLastPosition() self.output.WriteText(text) pos1 = self.output.GetLastPosition() self.output.SetStyle(pos0, pos1, self.textstyle) self.needs_flush = True def flush(self, *args): try: self.output.SetInsertionPoint(self.output.GetLastPosition()) except: pass self.output.Refresh() self.output.Update() self.needs_flush = False def clear_input(self): self._larch.input.clear() self.SetPrompt(True) def onFlushTimer(self, event=None): if self.needs_flush: self.flush() def eval(self, text, add_history=True, **kws): if text is None: return if text.startswith('!'): return os.system(text[1:]) else: if add_history: self.input.AddToHistory(text) self.write(">%s\n" % text) ret = self._larch.eval(text, add_history=add_history) if self._larch.error: self._larch.input.clear() self._larch.writer.set_textstyle('error') self._larch.show_errors() self._larch.writer.set_textstyle('text') elif ret is not None: self._larch.writer.write("%s\n" % repr(ret)) self.SetPrompt(self._larch.input.complete)