From 31edce0ba1e64a8d2b9a30617f1eabe5c2630891 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 21 Oct 2010 20:15:11 +0000 Subject: [PATCH] Added utils.utils.run_async as a simple wrapper to the Twisted deferred system. This allows for easily making a long-time-running process or command asynchronous. --- game/gamesrc/commands/default/tests.py | 36 ++++++++++++++++++++------ src/utils/utils.py | 33 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/game/gamesrc/commands/default/tests.py b/game/gamesrc/commands/default/tests.py index 4c895827f2..f249ef18b2 100644 --- a/game/gamesrc/commands/default/tests.py +++ b/game/gamesrc/commands/default/tests.py @@ -7,8 +7,7 @@ from django.conf import settings from django.db import IntegrityError from src.comms.models import Msg from src.permissions import permissions -from src.utils import create -from src.utils import debug +from src.utils import create, debug, utils from game.gamesrc.commands.default.muxcommand import MuxCommand from src.commands import cmdsethandler @@ -29,17 +28,38 @@ class CmdTest(MuxCommand): key = "@test" aliases = ["@te", "@test all"] - permissions = "cmd:Immortals Wizards" + #permissions = "cmd:Immortals" #Wizards # the muxcommand class itself handles the display # so we just defer to it by not adding any function. def func(self): - cmdsetname = "game.gamesrc.commands.default.cmdset_default.DefaultCmdSet" - self.caller.msg(cmdsethandler.CACHED_CMDSETS) - cmdsethandler.import_cmdset(cmdsetname, self, self) - self.caller.msg("Imported %s" % cmdsetname) - self.caller.msg(cmdsethandler.CACHED_CMDSETS) + + def test(): + li = [] + for l in range(10000): + li.append(l) + self.caller.msg(li[-1]) + return "This is the return text" + #print 1/0 + def succ(f): + self.caller.msg("This is called after successful completion. Return value: %s" % f) + def err(e): + self.caller.msg("An error was encountered... %s" % e) + + #self.caller.msg("printed before call to sync run ...") + #test() + #self.caller.msg("after after call to sync run...") + + self.caller.msg("printed before call to async run ...") + utils.run_async(test, at_return=succ, at_err=err) + self.caller.msg("printed after call to async run ...") + + #cmdsetname = "game.gamesrc.commands.default.cmdset_default.DefaultCmdSet" + #self.caller.msg(cmdsethandler.CACHED_CMDSETS) + #cmdsethandler.import_cmdset(cmdsetname, self, self) + #self.caller.msg("Imported %s" % cmdsetname) + #self.caller.msg(cmdsethandler.CACHED_CMDSETS) diff --git a/src/utils/utils.py b/src/utils/utils.py index 365e26f1d3..b9dad415d6 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -7,6 +7,7 @@ be of use when designing your own game. import os import textwrap import datetime +from twisted.internet import threads from django.conf import settings from src.utils import ansi @@ -335,3 +336,35 @@ def format_table(table, extra_space=1): ftable.append([str(col[irow]).ljust(max_widths[icol]) + " " * extra_space for icol, col in enumerate(table)]) return ftable + +def run_async(async_func, at_return=None, at_err=None): + """ + This wrapper will use Twisted's asynchronous features to run a slow + function using a separate reactor thread. In effect this means that + the server will not be blocked while the slow process finish. + + Use this function with restrain and only for features/commands + that you know has no influence on the cause-and-effect order of your + game (commands given after the async function might be executed before + it has finished). + + async_func() - function that should be run asynchroneously + at_return(r) - if given, this function will be called when async_func returns + value r at the end of a successful execution + at_err(e) - if given, this function is called if async_func fails with an exception e. + use e.trap(ExceptionType1, ExceptionType2) + + """ + # create deferred object + + deferred = threads.deferToThread(async_func) + if at_return: + deferred.addCallback(at_return) + if at_err: + deferred.addErrback(at_err) + # always add a logging errback as a last catch + def default_errback(e): + from src.utils import logger + logger.log_trace(e) + deferred.addErrback(default_errback) +