mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Started removing the global maintenance scripts, but ran into strange AMP issues.
This commit is contained in:
parent
17400ede6b
commit
71e9038c62
7 changed files with 112 additions and 195 deletions
|
|
@ -540,71 +540,3 @@ class Store(DefaultScript):
|
|||
"Setup the script"
|
||||
self.key = "sys_storage"
|
||||
self.desc = _("This is a generic storage container.")
|
||||
|
||||
|
||||
class CheckSessions(DefaultScript):
|
||||
"Check sessions regularly."
|
||||
def at_script_creation(self):
|
||||
"Setup the script"
|
||||
self.key = "sys_session_check"
|
||||
self.desc = _("Checks sessions so they are live.")
|
||||
self.interval = 60 # repeat every 60 seconds
|
||||
self.persistent = True
|
||||
|
||||
def at_repeat(self):
|
||||
"called every 60 seconds"
|
||||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from evennia.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
#print "session check!"
|
||||
#print "ValidateSessions run"
|
||||
_SESSIONS.validate_sessions()
|
||||
|
||||
_FLUSH_CACHE = None
|
||||
_IDMAPPER_CACHE_MAX_MEMORY = settings.IDMAPPER_CACHE_MAXSIZE
|
||||
class ValidateIdmapperCache(DefaultScript):
|
||||
"""
|
||||
Check memory use of idmapper cache
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
self.key = "sys_cache_validate"
|
||||
self.desc = _("Restrains size of idmapper cache.")
|
||||
self.interval = 61 * 5 # staggered compared to session check
|
||||
self.persistent = True
|
||||
|
||||
def at_repeat(self):
|
||||
"Called every ~5 mins"
|
||||
global _FLUSH_CACHE
|
||||
if not _FLUSH_CACHE:
|
||||
from evennia.utils.idmapper.models import conditional_flush as _FLUSH_CACHE
|
||||
_FLUSH_CACHE(_IDMAPPER_CACHE_MAX_MEMORY)
|
||||
|
||||
class ValidateScripts(DefaultScript):
|
||||
"Check script validation regularly"
|
||||
def at_script_creation(self):
|
||||
"Setup the script"
|
||||
self.key = "sys_scripts_validate"
|
||||
self.desc = _("Validates all scripts regularly.")
|
||||
self.interval = 3600 # validate every hour.
|
||||
self.persistent = True
|
||||
|
||||
def at_repeat(self):
|
||||
"called every hour"
|
||||
#print "ValidateScripts run."
|
||||
ScriptDB.objects.validate()
|
||||
|
||||
|
||||
class ValidateChannelHandler(DefaultScript):
|
||||
"Update the channelhandler to make sure it's in sync."
|
||||
def at_script_creation(self):
|
||||
"Setup the script"
|
||||
self.key = "sys_channels_validate"
|
||||
self.desc = _("Updates the channel handler")
|
||||
self.interval = 3700 # validate a little later than ValidateScripts
|
||||
self.persistent = True
|
||||
|
||||
def at_repeat(self):
|
||||
"called every hour+"
|
||||
#print "ValidateChannelHandler run."
|
||||
channelhandler.CHANNELHANDLER.update()
|
||||
|
||||
|
|
|
|||
|
|
@ -130,39 +130,6 @@ def create_channels():
|
|||
channel = create.create_channel(**channeldict)
|
||||
channel.connect(goduser)
|
||||
|
||||
def create_system_scripts():
|
||||
"""
|
||||
Setup the system repeat scripts. They are automatically started
|
||||
by the create_script function.
|
||||
"""
|
||||
from evennia.scripts import scripts
|
||||
|
||||
print " Creating and starting global scripts ..."
|
||||
|
||||
# check so that all sessions are alive.
|
||||
script1 = create.create_script(scripts.CheckSessions)
|
||||
# validate all scripts in script table.
|
||||
script2 = create.create_script(scripts.ValidateScripts)
|
||||
# update the channel handler to make sure it's in sync
|
||||
script3 = create.create_script(scripts.ValidateChannelHandler)
|
||||
# flush the idmapper cache
|
||||
script4 = create.create_script(scripts.ValidateIdmapperCache)
|
||||
|
||||
if not script1 or not script2 or not script3 or not script4:
|
||||
print " Error creating system scripts."
|
||||
|
||||
|
||||
def start_game_time():
|
||||
"""
|
||||
This starts a persistent script that keeps track of the
|
||||
in-game time (in whatever accelerated reference frame), but also
|
||||
the total run time of the server as well as its current uptime
|
||||
(the uptime can also be found directly from the server though).
|
||||
"""
|
||||
print " Starting in-game time ..."
|
||||
from evennia.utils import gametime
|
||||
gametime.init_gametime()
|
||||
|
||||
|
||||
def at_initial_setup():
|
||||
"""
|
||||
|
|
@ -206,20 +173,15 @@ def handle_setup(last_step):
|
|||
# this means we don't need to handle setup since
|
||||
# it already ran sucessfully once.
|
||||
return
|
||||
elif last_step is None:
|
||||
# config doesn't exist yet. First start of server
|
||||
last_step = 0
|
||||
# if None, set it to 0
|
||||
last_step = last_step or 0
|
||||
|
||||
# setting up the list of functions to run
|
||||
setup_queue = [
|
||||
create_config_values,
|
||||
create_objects,
|
||||
create_channels,
|
||||
create_system_scripts,
|
||||
start_game_time,
|
||||
at_initial_setup,
|
||||
reset_server
|
||||
]
|
||||
setup_queue = [create_config_values,
|
||||
create_objects,
|
||||
create_channels,
|
||||
at_initial_setup,
|
||||
reset_server]
|
||||
|
||||
#print " Initial setup: %s steps." % (len(setup_queue))
|
||||
|
||||
|
|
@ -241,6 +203,7 @@ def handle_setup(last_step):
|
|||
from evennia.comms.models import ChannelDB
|
||||
ChannelDB.objects.all().delete()
|
||||
raise
|
||||
# save this step
|
||||
ServerConfig.objects.conf("last_initial_setup_step", last_step + num + 1)
|
||||
# We got through the entire list. Set last_step to -1 so we don't
|
||||
# have to run this again.
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ by game/evennia.py).
|
|||
|
||||
"""
|
||||
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
from twisted.application import internet, service
|
||||
from twisted.internet import protocol, reactor
|
||||
from twisted.internet.task import LoopingCall
|
||||
from twisted.web import server
|
||||
import django
|
||||
django.setup()
|
||||
|
|
@ -67,6 +69,28 @@ AMP_INTERFACE = settings.AMP_INTERFACE
|
|||
AMP_ENABLED = AMP_HOST and AMP_PORT and AMP_INTERFACE
|
||||
|
||||
|
||||
# Maintenance function - this is called repeatedly by the portal.
|
||||
|
||||
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
def _portal_maintenance():
|
||||
"""
|
||||
The maintenance function handles repeated checks and updates
|
||||
that the server needs to do. It is called every minute.
|
||||
"""
|
||||
# check for idle sessions
|
||||
now = time.time()
|
||||
|
||||
reason = "Idle timeout exceeded, disconnecting."
|
||||
for session in [sess for sess in PORTAL_SESSIONS.sessions.values()
|
||||
if (now - sess.cmd_last) > _IDLE_TIMEOUT]:
|
||||
session.data_out(reason)
|
||||
PORTAL_SESSIONS.disconnect(session)
|
||||
if _IDLE_TIMEOUT > 0:
|
||||
# only start the maintenance task if we care about idling.
|
||||
_maintenance_task = LoopingCall(_portal_maintenance)
|
||||
_maintenance_task.start(60) # called every minute
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Portal Service object
|
||||
#------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
serialized before passed on.
|
||||
|
||||
"""
|
||||
self.cmd_last = time()
|
||||
self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid,
|
||||
msg=text,
|
||||
data=kwargs)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ sessions etc.
|
|||
"""
|
||||
|
||||
import re
|
||||
from twisted.internet.task import LoopingCall
|
||||
from twisted.conch.telnet import Telnet, StatefulTelnetProtocol, IAC, LINEMODE, GA, WILL, WONT, ECHO
|
||||
from evennia.server.session import Session
|
||||
from evennia.server.portal import ttype, mssp, telnet_oob, naws
|
||||
|
|
@ -15,6 +16,8 @@ from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
|
|||
from evennia.server.portal.mxp import Mxp, mxp_parse
|
||||
from evennia.utils import utils, ansi, logger
|
||||
|
||||
NOP = chr(241)
|
||||
|
||||
_RE_N = re.compile(r"\{n$")
|
||||
_RE_LEND = re.compile(r"\n$|\r$", re.MULTILINE)
|
||||
|
||||
|
|
@ -60,6 +63,11 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
from evennia.utils.utils import delay
|
||||
delay(2, callback=self.handshake_done, retval=True)
|
||||
|
||||
# set up a keep-alive
|
||||
self.keep_alive = LoopingCall(self._write, NOP)
|
||||
self.keep_alive.start(30)
|
||||
|
||||
|
||||
def handshake_done(self, force=False):
|
||||
"""
|
||||
This is called by all telnet extensions once they are finished.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import os
|
|||
from twisted.web import server, static
|
||||
from twisted.application import internet, service
|
||||
from twisted.internet import reactor, defer
|
||||
from twisted.internet.task import LoopingCall
|
||||
|
||||
import django
|
||||
django.setup()
|
||||
|
||||
|
|
@ -72,6 +74,42 @@ RSS_ENABLED = settings.RSS_ENABLED
|
|||
WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
|
||||
|
||||
|
||||
# Maintenance function - this is called repeatedly by the server
|
||||
|
||||
_MAINTENANCE_COUNT = 0
|
||||
_FLUSH_CACHE = None
|
||||
_IDMAPPER_CACHE_MAXSIZE = settings.IDMAPPER_CACHE_MAXSIZE
|
||||
def _server_maintenance():
|
||||
"""
|
||||
This maintenance function handles repeated checks and updates that
|
||||
the server needs to do. It is called every 5 minutes.
|
||||
"""
|
||||
global EVENNIA, _MAINTENANCE_COUNT
|
||||
global _FLUSH_CACHE
|
||||
if not _FLUSH_CACHE:
|
||||
from evennia.utils.idmapper.models import conditional_flush as _FLUSH_CACHE
|
||||
|
||||
_MAINTENANCE_COUNT += 1
|
||||
|
||||
# update game time
|
||||
EVENNIA.runtime += 60.0
|
||||
ServerConfig.objects.conf("runtime", EVENNIA.runtime)
|
||||
EVENNIA.runtime_last_saved = time.time()
|
||||
|
||||
if _MAINTENANCE_COUNT % 300 == 0:
|
||||
# check cache size every 5 minutes
|
||||
print "maintenance: check flush cache..."
|
||||
_FLUSH_CACHE(_IDMAPPER_CACHE_MAXSIZE)
|
||||
if _MAINTENANCE_COUNT % 3600 == 0:
|
||||
# validate scripts every hour
|
||||
print "maintenance: validate scripts..."
|
||||
evennia.ScriptDB.objects.validate()
|
||||
if _MAINTENANCE_COUNT % 3700 == 0:
|
||||
# validate channels off-sync with scripts
|
||||
print "maintenance: validate channels..."
|
||||
evennia.CHANNEL_HANDLER.update()
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Evennia Main Server object
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -104,8 +142,6 @@ class Evennia(object):
|
|||
# Run the initial setup if needed
|
||||
self.run_initial_setup()
|
||||
|
||||
self.start_time = time.time()
|
||||
|
||||
# initialize channelhandler
|
||||
channelhandler.CHANNELHANDLER.update()
|
||||
|
||||
|
|
@ -113,9 +149,13 @@ class Evennia(object):
|
|||
# by Ctrl-C, reboot etc.
|
||||
reactor.addSystemEventTrigger('before', 'shutdown',
|
||||
self.shutdown, _reactor_stopping=True)
|
||||
|
||||
self.game_running = True
|
||||
|
||||
# track the server time
|
||||
self.start_time = time.time()
|
||||
self.runtime = ServerConfig.objects.conf("runtime", default=0.0)
|
||||
self.runtime_last_saved = self.start_time
|
||||
|
||||
self.run_init_hooks()
|
||||
|
||||
# Server startup methods
|
||||
|
|
@ -323,10 +363,6 @@ class Evennia(object):
|
|||
|
||||
self.at_server_cold_stop()
|
||||
|
||||
# stopping time
|
||||
from evennia.utils import gametime
|
||||
gametime.save()
|
||||
|
||||
self.at_server_stop()
|
||||
# if _reactor_stopping is true, reactor does not need to
|
||||
# be stopped again.
|
||||
|
|
@ -486,6 +522,9 @@ ServerConfig.objects.conf("server_starting_mode", delete=True)
|
|||
|
||||
if os.name == 'nt':
|
||||
# Windows only: Set PID file manually
|
||||
f = open(os.path.join(settings.GAME_DIR, 'server.pid'), 'w')
|
||||
f.write(str(os.getpid()))
|
||||
f.close()
|
||||
with open(os.path.join(settings.GAME_DIR, 'server.pid'), 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
|
||||
# start the maintenance task
|
||||
maintenance_task = LoopingCall(_server_maintenance)
|
||||
maintenance_task.start(60) # call every minute
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ total runtime of the server and the current uptime.
|
|||
|
||||
from time import time
|
||||
from django.conf import settings
|
||||
from evennia.scripts.scripts import DefaultScript
|
||||
from evennia.utils.create import create_script
|
||||
|
||||
GAMETIME_SCRIPT_NAME = "sys_game_time"
|
||||
|
||||
# Speed-up factor of the in-game time compared
|
||||
# to real time.
|
||||
|
|
@ -35,67 +31,25 @@ WEEK = DAY * settings.TIME_DAY_PER_WEEK
|
|||
MONTH = WEEK * settings.TIME_WEEK_PER_MONTH
|
||||
YEAR = MONTH * settings.TIME_MONTH_PER_YEAR
|
||||
|
||||
# Cached time stamps
|
||||
SERVER_STARTTIME = time()
|
||||
SERVER_RUNTIME = 0.0
|
||||
# link to the main Server
|
||||
_EVENNIA = None
|
||||
|
||||
|
||||
class GameTime(DefaultScript):
|
||||
"""
|
||||
This script repeatedly saves server times so
|
||||
it can be retrieved after server downtime.
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
"""
|
||||
Setup the script
|
||||
"""
|
||||
self.key = GAMETIME_SCRIPT_NAME
|
||||
self.desc = "Saves uptime/runtime"
|
||||
self.interval = 60
|
||||
self.persistent = True
|
||||
self.start_delay = True
|
||||
self.attributes.add("run_time", 0.0) # OOC time
|
||||
self.attributes.add("up_time", 0.0) # OOC time
|
||||
|
||||
def at_repeat(self):
|
||||
"""
|
||||
Called every minute to update the timers.
|
||||
"""
|
||||
self.attributes.add("run_time", runtime())
|
||||
self.attributes.add("up_time", uptime())
|
||||
|
||||
def at_start(self):
|
||||
"""
|
||||
This is called once every server restart.
|
||||
We reset the up time and load the relevant
|
||||
times.
|
||||
"""
|
||||
global SERVER_RUNTIME
|
||||
SERVER_RUNTIME = self.attributes.get("run_time")
|
||||
|
||||
def save():
|
||||
"Force save of time. This is called by server when shutting down/reloading."
|
||||
from evennia.scripts.models import ScriptDB
|
||||
try:
|
||||
script = ScriptDB.objects.get(db_key=GAMETIME_SCRIPT_NAME)
|
||||
script.at_repeat()
|
||||
except Exception:
|
||||
from evennia.utils import logger
|
||||
logger.log_trace()
|
||||
|
||||
def _format(seconds, *divisors) :
|
||||
"""
|
||||
Helper function. Creates a tuple of even dividends given
|
||||
a range of divisors.
|
||||
Helper function. Creates a tuple of even dividends given a range
|
||||
of divisors.
|
||||
|
||||
Inputs
|
||||
seconds - number of seconds to format
|
||||
*divisors - a number of integer dividends. The number of seconds will be
|
||||
integer-divided by the first number in this sequence, the remainder
|
||||
will be divided with the second and so on.
|
||||
Output:
|
||||
A tuple of length len(*args)+1, with the last element being the last remaining
|
||||
seconds not evenly divided by the supplied dividends.
|
||||
Args:
|
||||
seconds (int): Number of seconds to format
|
||||
*divisors (int): a sequence of numbers of integer dividends. The
|
||||
number of seconds will be integer-divided by the first number in
|
||||
this sequence, the remainder will be divided with the second and
|
||||
so on.
|
||||
Returns:
|
||||
time (tuple): This tuple has length len(*args)+1, with the
|
||||
last element being the last remaining seconds not evenly
|
||||
divided by the supplied dividends.
|
||||
|
||||
"""
|
||||
results = []
|
||||
|
|
@ -111,14 +65,20 @@ def _format(seconds, *divisors) :
|
|||
|
||||
def runtime(format=False):
|
||||
"Get the total runtime of the server since first start (minus downtimes)"
|
||||
runtime = SERVER_RUNTIME + (time() - SERVER_STARTTIME)
|
||||
global _EVENNIA
|
||||
if not _EVENNIA:
|
||||
from evennia.server.server import EVENNIA as _EVENNIA
|
||||
runtime = _EVENNIA.runtime + (time() - _EVENNIA.runtime_last_saved)
|
||||
if format:
|
||||
return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
||||
return runtime
|
||||
|
||||
def uptime(format=False):
|
||||
"Get the current uptime of the server since last reload"
|
||||
uptime = time() - SERVER_STARTTIME
|
||||
global _EVENNIA
|
||||
if not _EVENNIA:
|
||||
from evennia.server.server import EVENNIA as _EVENNIA
|
||||
uptime = time() - _EVENNIA.start_time
|
||||
if format:
|
||||
return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
||||
return uptime
|
||||
|
|
@ -167,13 +127,3 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0,
|
|||
return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN)
|
||||
return gametime
|
||||
|
||||
|
||||
# Time administration routines
|
||||
|
||||
def init_gametime():
|
||||
"""
|
||||
This is called once, when the server starts for the very first time.
|
||||
"""
|
||||
# create the GameTime script and start it
|
||||
game_time = create_script(GameTime)
|
||||
game_time.start()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue