Trunk: Merged griatch-branch. This implements a new reload mechanism - splitting Evennia into two processes: Server and Portal with different tasks. Also cleans and fixes several bugs in script systems as well as introduces i18n (courtesy of raydeejay).

This commit is contained in:
Griatch 2011-09-03 10:22:19 +00:00
parent 14dae44a46
commit f13e8cdf7c
50 changed files with 3175 additions and 2565 deletions

View file

@ -35,17 +35,26 @@ class ScriptClass(TypeClass):
except Exception:
return False
def _start_task(self):
def _start_task(self, start_now=True):
"start task runner"
#print "_start_task: self.interval:", self.key, self.interval, self.dbobj.db_interval
self.ndb.twisted_task = LoopingCall(self._step_task)
self.ndb.twisted_task.start(self.interval, now=not self.start_delay)
self.ndb.time_last_called = int(time())
if self.ndb._paused_time:
# we had paused the script, restarting
#print " start with paused time:", self.key, self.ndb._paused_time
self.ndb.twisted_task.start(self.ndb._paused_time, now=False)
else:
# starting script anew.
#print "_start_task: self.interval:", self.key, self.dbobj.interval
self.ndb.twisted_task.start(self.dbobj.interval, now=start_now and not self.start_delay)
self.ndb.time_last_called = int(time())
def _stop_task(self):
"stop task runner"
try:
#print "stopping twisted task:", id(self.ndb.twisted_task), self.obj
self.ndb.twisted_task.stop()
if self.ndb.twisted_task and not self.ndb.twisted_task.running:
self.ndb.twisted_task.stop()
except Exception:
logger.log_trace()
def _step_err_callback(self, e):
@ -73,6 +82,16 @@ class ScriptClass(TypeClass):
self.dbobj.db_repeats -= 1
self.ndb.time_last_called = int(time())
self.save()
if self.ndb._paused_time:
# this means we were running an unpaused script, for the time remaining
# after the pause. Now we start a normal-running timer again.
#print "switching to normal run:", self.key
del self.ndb._paused_time
self._stop_task()
self._start_task(start_now=False)
def _step_task(self):
"step task"
try:
@ -92,7 +111,10 @@ class ScriptClass(TypeClass):
check in on their scripts and when they will next be run.
"""
try:
return max(0, (self.ndb.time_last_called + self.dbobj.db_interval) - int(time()))
if self.ndb._paused_time:
return max(0, (self.ndb.time_last_called + self.ndb._paused_time) - int(time()))
else:
return max(0, (self.ndb.time_last_called + self.dbobj.db_interval) - int(time()))
except Exception:
return None
@ -122,7 +144,12 @@ class ScriptClass(TypeClass):
# this means the object is not initialized.
self.dbobj.is_active = False
return 0
# try to start the script
# try to restart a paused script
if self.unpause():
return 1
# try to start the script from scratch
try:
self.dbobj.is_active = True
self.at_start()
@ -162,6 +189,37 @@ class ScriptClass(TypeClass):
return 0
return 1
def pause(self):
"""
This stops a running script and stores its active state.
"""
#print "pausing", self.key, self.time_until_next_repeat()
dt = self.time_until_next_repeat()
if dt == None:
return
self.db._paused_time = dt
self._stop_task()
def unpause(self):
"""
Restart a paused script. This WILL call at_start().
"""
#print "unpausing", self.key, self.db._paused_time
dt = self.db._paused_time
if dt == None:
return False
try:
self.dbobj.is_active = True
self.at_start()
self.ndb._paused_time = dt
self._start_task(start_now=False)
del self.db._paused_time
except Exception, e:
logger.log_trace()
self.dbobj.is_active = False
return False
return True
# hooks
def at_script_creation(self):
"placeholder"
@ -178,154 +236,7 @@ class ScriptClass(TypeClass):
def at_repeat(self):
"placeholder"
pass
# class ScriptClass(TypeClass):
# """
# Base class for all Scripts.
# """
# # private methods for handling timers.
# def __eq__(self, other):
# """
# This has to be located at this level, having it in the
# parent doesn't work.
# """
# if other:
# return other.id == self.id
# return False
# def _start_task(self):
# "start the task runner."
# print "self_interval:", self.interval
# if self.interval > 0:
# #print "Starting task runner"
# start_now = not self.start_delay
# self.ndb.twisted_task = task.LoopingCall(self._step_task)
# self.ndb.twisted_task.start(self.interval, now=start_now)
# self.ndb.time_last_called = int(time())
# #self.save()
# def _stop_task(self):
# "stop the task runner"
# if hasattr(self.ndb, "twisted_task"):
# self.ndb.twisted_task.stop()
# def _step_task(self):
# "perform one repeat step of the script"
# #print "Stepping task runner (obj %s)" % id(self)
# #print "Has dbobj: %s" % hasattr(self, 'dbobj')
# if not self.is_valid():
# #the script is not valid anymore. Abort.
# self.stop()
# return
# try:
# self.at_repeat()
# if self.repeats:
# if self.repeats <= 1:
# self.stop()
# return
# else:
# self.repeats -= 1
# self.ndb.time_last_called = int(time())
# self.save()
# except Exception:
# logger.log_trace()
# self._stop_task()
# def time_until_next_repeat(self):
# """
# Returns the time in seconds until the script will be
# run again. If this is not a stepping script, returns None.
# This is not used in any way by the script's stepping
# system; it's only here for the user to be able to
# check in on their scripts and when they will next be run.
# """
# if self.interval and hasattr(self.ndb, 'time_last_called'):
# return max(0, (self.ndb.time_last_called + self.interval) - int(time()))
# else:
# return None
# def start(self, force_restart=False):
# """
# Called every time the script is started (for
# persistent scripts, this is usually once every server start)
# force_restart - if True, will always restart the script, regardless
# of if it has started before.
# """
# #print "Script %s (%s) start (active:%s, force:%s) ..." % (self.key, id(self.dbobj),
# # self.is_active, force_restart)
# if force_restart:
# self.is_active = False
# should_start = True
# if self.obj:
# try:
# #print "checking cmdset ... for obj", self.obj
# dummy = object.__getattribute__(self.obj, 'cmdset')
# #print "... checked cmdset"
# except AttributeError:
# #print "self.obj.cmdset not found. Setting is_active=False."
# self.is_active = False
# should_start = False
# if self.is_active and not force_restart:
# should_start = False
# if should_start:
# #print "... starting."
# try:
# self.is_active = True
# self.at_start()
# self._start_task()
# return 1
# except Exception:
# #print ".. error when starting"
# logger.log_trace()
# self.is_active = False
# return 0
# else:
# # avoid starting over.
# #print "... Start cancelled (invalid start or already running)."
# return 0 # this is used by validate() for counting started scripts
# def stop(self, kill=False):
# """
# Called to stop the script from running.
# This also deletes the script.
# kill - don't call finishing hooks.
# """
# #print "stopping script %s" % self.key
# if not kill:
# try:
# self.at_stop()
# except Exception:
# logger.log_trace()
# if self.interval:
# try:
# self._stop_task()
# except Exception:
# pass
# self.is_running = False
# try:
# self.delete()
# except AssertionError:
# return 0
# return 1
# def is_valid(self):
# "placeholder"
# pass
# def at_start(self):
# "placeholder."
# pass
# def at_stop(self):
# "placeholder"
# pass
# def at_repeat(self):
# "placeholder"
# pass
#
# Base Script - inherit from this
@ -359,7 +270,8 @@ class Script(ScriptClass):
def at_start(self):
"""
Called whenever the script is started, which for persistent
scripts is at least once every server start.
scripts is at least once every server start. It will also be called
when starting again after a pause (such as after a server reload)
"""
pass
@ -377,6 +289,20 @@ class Script(ScriptClass):
"""
pass
def at_server_reload(self):
"""
This hook is called whenever the server is shutting down for restart/reboot.
If you want to, for example, save non-persistent properties across a restart,
this is the place to do it.
"""
pass
def at_server_shutdown(self):
"""
This hook is called whenever the server is shutting down fully (i.e. not for
a restart).
"""
pass