Working on cleaning some strange behavior when trying to submitting faulty typeclasses to script system. Also fixing bugs here and there.

This commit is contained in:
Griatch 2011-07-03 21:01:06 +00:00
parent dae375d1c4
commit 6cb2b8b745
12 changed files with 301 additions and 141 deletions

View file

@ -6,6 +6,8 @@ It also defines a few common scripts.
"""
from time import time
from twisted.internet.defer import maybeDeferred
from twisted.internet.task import LoopingCall
from twisted.internet import task
from src.server.sessionhandler import SESSIONS
from src.typeclasses.typeclass import TypeClass
@ -18,54 +20,67 @@ from src.utils import logger
#
class ScriptClass(TypeClass):
"""
Base class for all Scripts.
Base class for scripts
"""
# private methods for handling timers.
# private methods
def __eq__(self, other):
"""
This has to be located at this level, having it in the
parent doesn't work.
"""
if other:
try:
return other.id == self.id
return False
except Exception:
return False
def _start_task(self):
"start the task runner."
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()
"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())
def _stop_task(self):
"stop the task runner"
if hasattr(self.ndb, "twisted_task"):
"stop task runner"
try:
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')
except Exception:
pass
def _step_err_callback(self, e):
"callback for runner errors"
cname = self.__class__.__name__
estring = "Script %s(#%i) of type '%s': at_repeat() error '%s'." % (self.key, self.id, cname, e.getErrorMessage())
try:
self.dbobj.db_obj.msg(estring)
except Exception:
pass
logger.log_errmsg(estring)
def _step_succ_callback(self):
"step task runner. No try..except needed due to defer wrap."
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()
self.at_repeat()
repeats = self.dbobj.db_repeats
if repeats <= 0:
pass # infinite repeat
elif repeats == 1:
self.stop()
return
else:
self.dbobj.db_repeats -= 1
self.ndb.time_last_called = int(time())
self.save()
def _step_task(self):
"step task"
try:
d = maybeDeferred(self._step_succ_callback)
d.addErrback(self._step_err_callback)
return d
except Exception:
logger.log_trace()
self._stop_task()
logger.log_trace()
def time_until_next_repeat(self):
"""
@ -75,9 +90,9 @@ class ScriptClass(TypeClass):
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:
try:
return max(0, (self.ndb.time_last_called + self.dbobj.db_interval) - int(time()))
except Exception:
return None
def start(self, force_restart=False):
@ -87,42 +102,37 @@ class ScriptClass(TypeClass):
force_restart - if True, will always restart the script, regardless
of if it has started before.
returns 0 or 1 to indicated the script has been started or not. Used in counting.
"""
#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:
if self.dbobj.db_is_active and not force_restart:
# script already runs.
return 0
if self.obj:
# check so the scripted object is valid and initalized
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()
# this means the object is not initialized.
self.dbobj.db_is_active = False
return 0
# try to start the script
try:
self.dbobj.db_is_active = True
self.dbobj.save()
self.at_start()
if self.dbobj.db_interval > 0:
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
return 1
except Exception:
logger.log_trace()
self.dbobj.db_is_active = False
self.dbobj.save()
return 0
def stop(self, kill=False):
"""
Called to stop the script from running.
@ -136,18 +146,21 @@ class ScriptClass(TypeClass):
self.at_stop()
except Exception:
logger.log_trace()
if self.interval:
if self.dbobj.db_interval > 0:
try:
self._stop_task()
except Exception:
pass
self.is_running = False
try:
self.delete()
self.dbobj.delete()
except AssertionError:
return 0
return 1
# hooks
def at_script_creation(self):
"placeholder"
pass
def is_valid(self):
"placeholder"
pass
@ -162,6 +175,153 @@ class ScriptClass(TypeClass):
pass
# class ScriptClassOld(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
#
@ -178,9 +338,9 @@ class Script(ScriptClass):
"""
self.key = "<unnamed>"
self.desc = ""
self.interval = 0
self.interval = 0 # infinite
self.start_delay = False
self.repeats = 0
self.repeats = 0 # infinite
self.persistent = False
def is_valid(self):
@ -212,18 +372,17 @@ class Script(ScriptClass):
"""
pass
# Some useful default Script types
# Some useful default Script types used by Evennia.
class DoNothing(Script):
"An script that does nothing. Used as default."
"An script that does nothing. Used as default."
def at_script_creation(self):
"Setup the script"
self.key = "sys_do_nothing"
self.desc = "This does nothing."
self.persistent = False
def is_valid(self):
"This script disables itself as soon as possible"
return False
"Setup the script"
self.key = "sys_do_nothing"
self.desc = "This does nothing."
class CheckSessions(Script):
"Check sessions regularly."
@ -272,17 +431,9 @@ class ValidateChannelHandler(Script):
class AddCmdSet(Script):
"""
This script permanently assigns a command set
to an object. This is called automatically by the cmdhandler
when an object is assigned a persistent cmdset.
To use, create this script, then assign to the two attributes
'cmdset' and 'add_default' as appropriate:
> from src.utils import create
> script = create.create_script('src.scripts.scripts.AddCmdSet')
> script.db.cmdset = 'game.gamesrc.commands.mycmdset.MyCmdSet'
> script.db.add_default = False
> obj.scripts.add(script)
to an object whenever it is started. This is not
used by the core system anymore, it's here mostly
as an example.
"""
def at_script_creation(self):
"Setup the script"