mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
task handler, updated to only return task id
Updated task handler to only return task id. updated code within evennia that relied on the deferral directly. Including unit test for one. all unit tests pass. Test server functional after restarting, no issues found would telnet web client. (delay was used in the telnet module in the portal folder. I needed to commit this before continuing forward. There is already a high line count change.
This commit is contained in:
parent
c7bf773605
commit
97f7806348
6 changed files with 86 additions and 41 deletions
|
|
@ -36,6 +36,7 @@ TickerHandler might be better.
|
|||
"""
|
||||
|
||||
from evennia import DefaultExit, utils, Command
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
MOVE_DELAY = {"stroll": 6, "walk": 4, "run": 2, "sprint": 1}
|
||||
|
||||
|
|
@ -70,11 +71,11 @@ class SlowExit(DefaultExit):
|
|||
|
||||
traversing_object.msg("You start moving %s at a %s." % (self.key, move_speed))
|
||||
# create a delayed movement
|
||||
deferred = utils.delay(move_delay, move_callback)
|
||||
task_id = utils.delay(move_delay, move_callback)
|
||||
# we store the deferred on the character, this will allow us
|
||||
# to abort the movement. We must use an ndb here since
|
||||
# deferreds cannot be pickled.
|
||||
traversing_object.ndb.currently_moving = deferred
|
||||
traversing_object.ndb.currently_moving = _TASK_HANDLER.get_deferred(task_id)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1152,13 +1152,7 @@ from evennia.contrib import slow_exit
|
|||
slow_exit.MOVE_DELAY = {"stroll": 0, "walk": 0, "run": 0, "sprint": 0}
|
||||
|
||||
|
||||
def _cancellable_mockdelay(time, callback, *args, **kwargs):
|
||||
callback(*args, **kwargs)
|
||||
return Mock()
|
||||
|
||||
|
||||
class TestSlowExit(CommandTest):
|
||||
@patch("evennia.utils.delay", _cancellable_mockdelay)
|
||||
def test_exit(self):
|
||||
exi = create_object(
|
||||
slow_exit.SlowExit, key="slowexit", location=self.room1, destination=self.room2
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import random
|
|||
from evennia import DefaultObject, DefaultExit, Command, CmdSet
|
||||
from evennia.utils import search, delay, dedent
|
||||
from evennia.prototypes.spawner import spawn
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
# -------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -389,7 +390,8 @@ class LightSource(TutorialObject):
|
|||
# start the burn timer. When it runs out, self._burnout
|
||||
# will be called. We store the deferred so it can be
|
||||
# killed in unittesting.
|
||||
self.deferred = delay(60 * 3, self._burnout)
|
||||
task_id = delay(60 * 3, self._burnout)
|
||||
self.deferred = _TASK_HANDLER.get_deferred(task_id)
|
||||
return True
|
||||
|
||||
|
||||
|
|
@ -687,7 +689,8 @@ class CrumblingWall(TutorialObject, DefaultExit):
|
|||
self.db.exit_open = True
|
||||
# start a 45 second timer before closing again. We store the deferred so it can be
|
||||
# killed in unittesting.
|
||||
self.deferred = delay(45, self.reset)
|
||||
task_id = delay(45, self.reset)
|
||||
self.deferred = _TASK_HANDLER.get_deferred(task_id)
|
||||
return True
|
||||
|
||||
def _translate_position(self, root, ipos):
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ class TaskHandler(object):
|
|||
Dev notes:
|
||||
deferLater creates an instance of IDelayedCall using reactor.callLater.
|
||||
deferLater uses the cancel method on the IDelayedCall instance to create
|
||||
the defer instance it returns.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -79,16 +78,18 @@ class TaskHandler(object):
|
|||
continue
|
||||
|
||||
callback = getattr(obj, method)
|
||||
self.tasks[task_id] = (date, callback, args, kwargs)
|
||||
self.tasks[task_id] = date, callback, args, kwargs, True, None
|
||||
|
||||
if to_save:
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
"""Save the tasks in ServerConfig."""
|
||||
for task_id, (date, callback, args, kwargs) in self.tasks.items():
|
||||
for task_id, (date, callback, args, kwargs, persistent, _) in self.tasks.items():
|
||||
if task_id in self.to_save:
|
||||
continue
|
||||
if not persistent:
|
||||
continue
|
||||
|
||||
if getattr(callback, "__self__", None):
|
||||
# `callback` is an instance method
|
||||
|
|
@ -127,8 +128,8 @@ class TaskHandler(object):
|
|||
any (any): additional keyword arguments to send to the callback
|
||||
|
||||
Returns:
|
||||
twisted.internet.defer.Deferred instance of the deferred task
|
||||
task_id (int), the task's id intended for use with this class.
|
||||
False, if the task has completed before addition finishes.
|
||||
|
||||
Notes:
|
||||
This method has two return types.
|
||||
|
|
@ -144,19 +145,23 @@ class TaskHandler(object):
|
|||
As those memory references will no longer acurately point to
|
||||
the variable desired.
|
||||
"""
|
||||
# set the completion time
|
||||
# Only used on persistent tasks after a restart
|
||||
now = datetime.now()
|
||||
delta = timedelta(seconds=timedelay)
|
||||
comp_time = now + delta
|
||||
# get an open task id
|
||||
used_ids = list(self.tasks.keys())
|
||||
task_id = 1
|
||||
while task_id in used_ids:
|
||||
task_id += 1
|
||||
|
||||
# record the task to the tasks dictionary
|
||||
persistent = kwargs.get("persistent", False)
|
||||
if persistent:
|
||||
del kwargs["persistent"]
|
||||
now = datetime.now()
|
||||
delta = timedelta(seconds=timedelay)
|
||||
|
||||
# Choose a free task_id
|
||||
safe_args = []
|
||||
safe_kwargs = {}
|
||||
used_ids = list(self.tasks.keys())
|
||||
task_id = 1
|
||||
while task_id in used_ids:
|
||||
task_id += 1
|
||||
|
||||
# Check that args and kwargs contain picklable information
|
||||
for arg in args:
|
||||
|
|
@ -183,17 +188,28 @@ class TaskHandler(object):
|
|||
else:
|
||||
safe_kwargs[key] = value
|
||||
|
||||
self.tasks[task_id] = (now + delta, callback, safe_args, safe_kwargs)
|
||||
self.tasks[task_id] = (comp_time, callback, safe_args, safe_kwargs, True, None)
|
||||
self.save()
|
||||
callback = self.do_task
|
||||
args = [task_id]
|
||||
kwargs = {}
|
||||
deferLater(self.clock, timedelay, callback, *args, **kwargs)
|
||||
return task_id
|
||||
else: # this is a non-persitent task
|
||||
self.tasks[task_id] = (comp_time, callback, args, kwargs, True, None)
|
||||
|
||||
# defer the task
|
||||
callback = self.do_task
|
||||
args = [task_id]
|
||||
kwargs = {}
|
||||
d = deferLater(self.clock, timedelay, callback, *args, **kwargs)
|
||||
d.addErrback(handle_error)
|
||||
return d
|
||||
|
||||
# some tasks may complete before the deferal can be added
|
||||
if task_id in self.tasks:
|
||||
task = self.tasks.get(task_id)
|
||||
task = list(task)
|
||||
task[4] = persistent
|
||||
task[5] = d
|
||||
self.tasks[task_id] = task
|
||||
else: # the task already completed
|
||||
return False
|
||||
return task_id
|
||||
|
||||
def remove(self, task_id):
|
||||
"""Remove a persistent task without executing it.
|
||||
|
|
@ -206,7 +222,8 @@ class TaskHandler(object):
|
|||
in the TaskHandler.
|
||||
|
||||
"""
|
||||
del self.tasks[task_id]
|
||||
if task_id in self.tasks:
|
||||
del self.tasks[task_id]
|
||||
if task_id in self.to_save:
|
||||
del self.to_save[task_id]
|
||||
|
||||
|
|
@ -222,13 +239,30 @@ class TaskHandler(object):
|
|||
This will also remove it from the list of current tasks.
|
||||
|
||||
"""
|
||||
date, callback, args, kwargs = self.tasks.pop(task_id)
|
||||
date, callback, args, kwargs, persistent, d = self.tasks.pop(task_id)
|
||||
|
||||
if task_id in self.to_save:
|
||||
del self.to_save[task_id]
|
||||
|
||||
self.save()
|
||||
callback(*args, **kwargs)
|
||||
|
||||
def get_deferred(self, task_id):
|
||||
"""
|
||||
Return the instance of the deferred the task id is using.
|
||||
|
||||
Args:
|
||||
task_id (int): a valid task ID.
|
||||
|
||||
Returns:
|
||||
An instance of a deferral or False if there is no task with the id.
|
||||
None is returned if there is no deferral affiliated with this id.
|
||||
"""
|
||||
if task_id in self.tasks:
|
||||
return self.tasks[task_id][5]
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_delays(self):
|
||||
"""Create the delayed tasks for the persistent tasks.
|
||||
|
||||
|
|
@ -237,9 +271,14 @@ class TaskHandler(object):
|
|||
|
||||
"""
|
||||
now = datetime.now()
|
||||
for task_id, (date, callbac, args, kwargs) in self.tasks.items():
|
||||
for task_id, (date, callbac, args, kwargs, _, _) in self.tasks.items():
|
||||
self.tasks[task_id] = date, callbac, args, kwargs, True, None
|
||||
seconds = max(0, (date - now).total_seconds())
|
||||
deferLater(self.clock, seconds, self.do_task, task_id)
|
||||
d = deferLater(self.clock, seconds, self.do_task, task_id)
|
||||
d.addErrback(handle_error)
|
||||
# some tasks may complete before the deferal can be added
|
||||
if self.tasks.get(task_id, False):
|
||||
self.tasks[task_id] = date, callbac, args, kwargs, True, d
|
||||
|
||||
|
||||
# Create the soft singleton
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
|
|||
from evennia.server.portal.mxp import Mxp, mxp_parse
|
||||
from evennia.utils import ansi
|
||||
from evennia.utils.utils import to_bytes
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
_RE_N = re.compile(r"\|n$")
|
||||
_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
|
||||
|
|
@ -127,8 +128,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
|
||||
from evennia.utils.utils import delay
|
||||
|
||||
# timeout the handshakes in case the client doesn't reply at all
|
||||
self._handshake_delay = delay(2, callback=self.handshake_done, timeout=True)
|
||||
task_id = delay(2, callback=self.handshake_done, timeout=True)
|
||||
self._handshake_delay = _TASK_HANDLER.get_deferred(task_id)
|
||||
|
||||
# TCP/IP keepalive watches for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
|
|
|
|||
|
|
@ -323,24 +323,31 @@ class TestDelay(EvenniaTest):
|
|||
|
||||
def test_delay(self):
|
||||
# get a reference of TASK_HANDLER
|
||||
timedelay = 5
|
||||
global _TASK_HANDLER
|
||||
if _TASK_HANDLER is None:
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
_TASK_HANDLER.clock = task.Clock()
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a persistent deferral, that completes after delay time
|
||||
task_id = utils.delay(1, dummy_func, self.char1.dbref, persistent=True)
|
||||
_TASK_HANDLER.clock.advance(1) # make time pass
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref, persistent=True)
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a non persisten deferral, that completes after delay time.
|
||||
deferal_inst = utils.delay(1, dummy_func, self.char1.dbref)
|
||||
_TASK_HANDLER.clock.advance(1) # make time pass
|
||||
utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a non persisten deferral, with a short timedelay
|
||||
utils.delay(.1, dummy_func, self.char1.dbref)
|
||||
_TASK_HANDLER.clock.advance(.1) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test canceling a deferral.
|
||||
deferal_inst = utils.delay(1, dummy_func, self.char1.dbref)
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
deferal_inst = _TASK_HANDLER.get_deferred(task_id)
|
||||
deferal_inst.cancel()
|
||||
_TASK_HANDLER.clock.advance(1) # make time pass
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
self.char1.ndb.dummy_var = False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue