From 04963f45123a02f302fd166efc3ba88784799f3f Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sat, 27 Jun 2020 15:39:10 -0400 Subject: [PATCH] Port to greenlet; nix-based dev environment --- .envrc | 1 + .gitignore | 1 + ansi_cython.pyx | 1 + basetoken.py | 2 +- haxor.py | 14 ++++---- scripting.py | 2 +- shell.nix | 11 +++++++ stackless.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 .envrc create mode 100644 shell.nix create mode 100644 stackless.py diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..051d09d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/.gitignore b/.gitignore index 9f926f2..3cfe9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build *.h *.marm *.marm.* +*.so \ No newline at end of file diff --git a/ansi_cython.pyx b/ansi_cython.pyx index 61a6cf4..e25adb7 100644 --- a/ansi_cython.pyx +++ b/ansi_cython.pyx @@ -35,6 +35,7 @@ rgcolorFg.extend([col | FBRIGHT for col in range(8)]) K_BACKSPACE = chr(8) K_TAB = chr(9) K_RETURN = chr(10) +K_NEWLINE = chr(13) K_DEL = chr(127) K_LEFT = 256 K_RIGHT = 257 diff --git a/basetoken.py b/basetoken.py index 9cbfb86..fab6a3b 100644 --- a/basetoken.py +++ b/basetoken.py @@ -131,7 +131,7 @@ class Terminal(Token): elif (ansi.FKeyPrintable(key)): self.stLine = self.stLine[:self.x - self.xLine] + key + self.stLine[(self.x + 1) - self.xLine:] self.moveTo(self.x + 1, self.y) - elif key == ansi.K_RETURN: + elif key == ansi.K_RETURN or key == ansi.K_NEWLINE: break else: print "weird key", ansi.StrKey(key) diff --git a/haxor.py b/haxor.py index 2c1625c..88b4a52 100644 --- a/haxor.py +++ b/haxor.py @@ -45,13 +45,13 @@ class IntroTerm(Terminal): self.newLine() self.client.quit() -class Haxor(object): - def __init__(self): - self.game = GmSimple([AutoJoiner, IntroTerm]) +class HaxorGame(Game): + def GetRgclsTokTrans(self): + return [[AutoJoiner, IntroTerm]] + +class HaxorRunner(Runner): def RunGame(self, client): - client.joinGame(self.game) - def RunServer(self): - telnet.RunServer(self.RunGame) + client.joinGame(HaxorGame()) if __name__ == "__main__": - Haxor().RunServer() + HaxorRunner().RunServer() diff --git a/scripting.py b/scripting.py index fccda79..ae2d206 100644 --- a/scripting.py +++ b/scripting.py @@ -671,7 +671,7 @@ class PwButton(PwStatic): def ColFg(self): return ansi.BLUE | ansi.FBRIGHT def HandleKey(self, pov, psel, key): - if key == ansi.K_RETURN: + if key == ansi.K_RETURN or key == ansi.K_NEWLINE: self.dgEnter(self.Value(), psel) return True return False diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..ae704f3 --- /dev/null +++ b/shell.nix @@ -0,0 +1,11 @@ +let + pkgs = import {}; + pyenv = pypkgs: with pypkgs; [ + greenlet twisted cython mysqlclient bcrypt + ]; +in +pkgs.mkShell { + buildInputs = [ + (pkgs.python2.withPackages pyenv) + ]; +} diff --git a/stackless.py b/stackless.py new file mode 100644 index 0000000..8697b4a --- /dev/null +++ b/stackless.py @@ -0,0 +1,85 @@ +from greenlet import greenlet +import traceback +from collections import deque + +class Scheduler(object): + def __init__(self): + self.running = None + self.rgtasklet = [] + self.g = None + + def schedule(self, tasklet, *args): + tasklet.args = args + tasklet.scheduled = True + self.rgtasklet.append(tasklet) + + def kill(self, tasklet): + if not tasklet.g.dead: + tasklet.g.parent = greenlet.getcurrent() + tasklet.g.throw() + try: + self.rgtasklet.remove(tasklet) + except: + pass + + def run(self): + self.g = greenlet.getcurrent() + while len(self.rgtasklet) > 0: + tasklets = self.rgtasklet + self.rgtasklet = [] + for tasklet in tasklets: + try: + self.running = tasklet + args = tasklet.args + tasklet.args = None + tasklet.scheduled = False + tasklet.g.parent = self.g + tasklet.g.switch(*args) + except: + traceback.print_exc() + self.kill(tasklet) + self.running = None + self.g = None + + def suspend(self): + self.g.switch() + +class Tasklet(object): + def __init__(self, cb, scheduler): + self.g = greenlet(cb) + self.args = None + self.scheduler = scheduler + self.scheduled = False + + def __call__(self, *args): + self.scheduler.schedule(self, *args) + + def kill(self): + self.scheduler.kill(self) + +class Channel(object): + def __init__(self, scheduler): + self.queue = deque() + self.tasklet = None + self.scheduler = scheduler + + def receive(self): + while len(self.queue) == 0: + self.tasklet = self.scheduler.running + self.tasklet.scheduled = True + self.scheduler.suspend() + self.tasklet = None + return self.queue.popleft() + + def send(self, val): + self.queue.append(val) + if self.tasklet: + self.scheduler.schedule(self.tasklet) + +scheduler = Scheduler() +def tasklet(cb): + return Tasklet(cb, scheduler) +def channel(): + return Channel(scheduler) +def run(): + scheduler.run()