def run(self, task, arg): self.cleanup(task) self.game.now = time.time() end_task = (False, None) try: #log('sending %s' % repr(arg)) cmd = task.generator.send(arg) except StopIteration as e: task.value = e.value task.done = True end_task = (True, e.value) #log('cmd = %s' % repr(cmd)) if end_task[0] or cmd is None: for t in task.waiters: websocketd.add_idle(lambda: self.run(t, end_task[1])) self.tasks.remove(task) if len(self.tasks) == 0: self.end_game(end_task[1]) return # Convert cmd to dict if it isn't. if not isinstance(cmd, (tuple, list, set, frozenset, dict)): cmd = (cmd,) if isinstance(cmd, (tuple, list, set, frozenset)): def mkcmd(src): for c in src: if isinstance(c, (Task, str)): yield (c, None) else: yield (None, c) cmd = {x: y for x, y in mkcmd(cmd)} #log('new cmd: %s' % repr(cmd)) # Check if we're waiting for a task that is already finished. for c in cmd: if isinstance(c, Task) and c.done: websocketd.add_idle(lambda: self.run(task, c.value)) return # Schedule new timeout. if None in cmd: self.timeouts[task] = websocketd.add_timeout(cmd.pop(None), lambda: self.timeouts.pop(task) and self.run(task, None)) # Add waiters to tasks. for c in cmd: if not isinstance(c, Task): continue c.waiters.append(task) # Add new commands. for c in cmd: if isinstance(c, Task): continue if c in self.cmds: assert task not in self.cmds[c] else: self.cmds[c] = {} self.cmds[c][task] = cmd[c]
def call(self, name, args, kargs, cb): # {{{ #log('calling {}'.format(repr((name, args, kargs)))) data = json.dumps([self.next_mid, name, args, kargs]) + '\n' #log('calling %s on %d' % (repr(data), self.process.stdin.fileno())) try: self.process.stdin.write(data.encode('utf-8')) self.process.stdin.flush() except: log('killing machine handle because of error') #traceback.print_exc() def kill(): cb(False, None) disable(self.uuid, 'error from machine') # Schedule this as a callback, so the generator isn't called recursively. websocketd.add_idle(kill) return self.waiters[0][self.next_mid] = cb self.next_mid += 1
def call(self, name, args, kargs, cb): # {{{ #log('calling {}'.format(repr((name, args, kargs)))) data = json.dumps([self.next_mid, name, args, kargs]) + '\n' #log('calling %s on %d' % (repr(data), self.process.stdin.fileno())) try: self.process.stdin.write(data.encode('utf-8')) self.process.stdin.flush() except: log('killing machine handle because of error') #traceback.print_exc() def kill(): cb(False, None) disable(self.uuid, 'error from machine') # Schedule this as a callback, so the generator isn't called recursively. websocketd.add_idle(kill) return #def debug_cb(success, ret): # log('call {} returned: {}: {}'.format(name, success, ret)) # cb(success, ret) self.waiters[0][self.next_mid] = cb self.next_mid += 1
def call(instance, func, args, task): if func is not None: websocketd.add_idle(lambda: func(args) and False) if task is not None: instance.cleanup(task); websocketd.add_idle(lambda: instance.run(task, args))
def launch(self, f, name = 'nameless task'): '''Record a generator as a task and schedule it for idle running.''' t = Task(f, name) self.tasks.append(t) websocketd.add_idle(lambda: self.run(t, None)) return t