Added more stable events.

- added PIDs to all events, so they can be deleted safely.
- scheduler.del_event(pid) cleanly deletes events from the scheduler
- added @delevent for deleting events based on PID (@ps shows this now)
- Events has a self.repeat property allowing them to only be repeated a certain time (default is infinitely many times). After the set number of repeats, the event deletes itself from the scheduler.

Events are currently not persistently stored; this is left for future commits.
.
Griatch
This commit is contained in:
Griatch 2009-11-18 20:10:35 +00:00
parent 642932a403
commit 5e866c6b73
5 changed files with 148 additions and 26 deletions

View file

@ -775,3 +775,21 @@ def cmd_help(command):
source_object.emit_to(string)
GLOBAL_CMD_TABLE.add_command("help", cmd_help)
## def cmd_testevent(command):
## from src import events
## from src import scheduler
## source_object = command.source_object
## if not command.command_argument:
## #event = events.IntervalEvent()
## event = events.IntervalEvent()
## event.repeats = 3
## event.interval = 5
## pid = scheduler.add_event(event)
## source_object.emit_to("event with pid %s added." % pid)
## else:
## pid = command.command_argument
## scheduler.del_event(pid)
## source_object.emit_to("event with pid %s removed (if it existed)." % pid)
## GLOBAL_CMD_TABLE.add_command("testevent", cmd_testevent)

View file

@ -135,13 +135,18 @@ def cmd_ps(command):
"""
source_object = command.source_object
source_object.emit_to("-- Interval Events --")
for event in scheduler.schedule:
source_object.emit_to(" [%d/%d] %s" % (
event.get_nextfire(),
event.interval,
event.description))
source_object.emit_to("Totals: %d interval events" % (len(scheduler.schedule),))
source_object.emit_to("Processes Scheduled:\n-- PID [time/interval] [repeats] description --")
for event in scheduler.SCHEDULE:
repeats = "[inf] "
if event.repeats != None:
repeats = "[%i] " % event.repeats
source_object.emit_to(" %i [%d/%d] %s%s" % (
event.pid,
event.get_nextfire(),
event.interval,
repeats,
event.description))
source_object.emit_to("Totals: %d interval events" % (len(scheduler.SCHEDULE),))
GLOBAL_CMD_TABLE.add_command("@ps", cmd_ps,
priv_tuple=("genperms.process_control",), help_category="Admin")

View file

@ -15,6 +15,9 @@ from src.helpsys import helpsystem
from src.config.models import CommandAlias
from src.config import edit_aliases
from src import cache
from src import scheduler
def cmd_reload(command):
"""
@reload - reload game subsystems
@ -761,3 +764,37 @@ def cmd_setcmdalias(command):
GLOBAL_CMD_TABLE.add_command("@setcmdalias", cmd_setcmdalias,
priv_tuple=("genperms.process_control",),
help_category="Admin")
def cmd_delevent(command):
"""
@delevent - remove events manually
Usage:
@delevent <pid>
Removes an event with the given pid (process ID) from the event scheduler.
To see all active events and their pids, use the @ps command.
"""
source_object = command.source_object
if not command.command_argument:
source_object.emit_to("Usage: @delevent <pid>")
return
try:
pid = int(command.command_argument)
except ValueError:
source_object.emit_to("You must supply a valid pid number.")
return
event = scheduler.get_event(pid)
if event:
desc = event.description
scheduler.del_event(pid)
source_object.emit_to("Event %i - '%s' removed." % (pid, desc))
else:
source_object.emit_to("No event found with a pid of %i. Use @ps to list process IDs." % pid)
GLOBAL_CMD_TABLE.add_command("@delevent", cmd_delevent,
priv_tuple=("genperms.process_control",),
help_category="Admin")

View file

@ -18,18 +18,28 @@ class IntervalEvent(object):
"""
Represents an event that is triggered periodically. Sub-class this and
fill in the stub function.
self.repeats decides if this event will fire indefinitely or only a
certain number of times.
"""
def __init__(self):
def __init__(self, description="IntervalEvent"):
"""
Executed when the class is instantiated.
"""
# This is a globally unique ID of this event. If None, a new one will
# be allocated when the event is added to the scheduler.
self.pid = None
# This is set to prevent a Nonetype exception on @ps before the
# event is fired for the first time.
self.time_last_executed = time.time()
# This is what shows up on @ps in-game.
self.name = None
# This used to describe the event in @ps listings.
self.description = description
# An interval (in seconds) for execution.
self.interval = None
# How many times to repeat this event.
# None : indefinitely,
# positive integer : number of times
self.repeats = None
# A reference to the task.LoopingCall object.
self.looped_task = None
@ -39,6 +49,18 @@ class IntervalEvent(object):
"""
return self.name
def __eq__(self, event2):
"""
Handles comparison operations.
"""
return self.pid == event2.pid
def __hash__(self):
"""
Used for dictionary key comparisons.
"""
return self.pid
def start_event_loop(self):
"""
Called to start up the event loop when the event is added to the
@ -78,9 +100,16 @@ class IntervalEvent(object):
def fire_event(self):
"""
Set the last ran stamp and fire off the event.
Stop repeating if number of repeats have been achieved.
"""
self.set_lastfired()
self.set_lastfired()
self.event_function()
if self.repeats != None:
self.repeats -= 1
if self.repeats <= 0 and self.pid != None:
scheduler.del_event(self.pid)
class IEvt_Check_Sessions(IntervalEvent):
"""

View file

@ -9,9 +9,23 @@ ADDING AN EVENT:
* Profit.
"""
# List of IntervalEvent sub-classed objects.
schedule = []
# dict of IntervalEvent sub-classed objects, keyed by their
# process id:s.
SCHEDULE = []
def next_free_pid():
"""
Find the next free pid
"""
pids = [event.pid for event in SCHEDULE]
if not pids:
return 0
maxpid = max(pids)
freepids = [pid for pid in xrange(maxpid+1) if pid not in pids]
if freepids:
return min(freepids)
return maxpid + 1
def add_event(event):
"""
Adds an event instance to the scheduled event list. Call this any time you
@ -19,21 +33,40 @@ def add_event(event):
Args:
* event: (IntervalEvent) The event to add to the scheduler.
"""
Returns:
* pid : (int) The process ID assigned to this event, for future reference.
#don't add multiple instances of the same event, instead replace
if event in schedule:
schedule[schedule.index(event)] = event
return
"""
# Make sure not to add multiple instances of the same event.
matches = [i for i, stored_event in enumerate(SCHEDULE) if event == stored_event]
if matches:
# Before replacing an event, stop its old incarnation.
del_event(matches[0])
SCHEDULE[matches[0]] = event
else:
schedule.append(event)
# Add a new event with a fresh pid.
event.pid = next_free_pid()
SCHEDULE.append(event)
event.start_event_loop()
return event.pid
def del_event(event):
def get_event(pid):
"""
Remove an event from scheduler.
Return an event with the given pid, if it exists,
otherwise return None.
"""
if event in schedule:
i = schedule.index(event)
schedule[i].stop_event_loop()
del schedule[i]
pid = int(pid)
imatches = [i for i, stored_event in enumerate(SCHEDULE) if stored_event.pid == pid]
if imatches:
return SCHEDULE[imatches[0]]
def del_event(pid):
"""
Remove an event from scheduler. There should never be more than one
event with a certain pid, this cleans up in case there are any multiples.
"""
pid = int(pid)
imatches = [i for i, stored_event in enumerate(SCHEDULE) if stored_event.pid == pid]
for imatch in imatches:
SCHEDULE[imatch].stop_event_loop()
del SCHEDULE[imatch]