Fix at_server_reload_start not firing. Resolve #3477. Add Server-Lifecycle.md docpage

This commit is contained in:
Griatch 2024-04-06 14:08:36 +02:00
parent 50d8ae2f54
commit 387533d1f0
15 changed files with 222 additions and 80 deletions

View file

@ -16,13 +16,14 @@ import time
import typing
from random import getrandbits
import evennia
from django.conf import settings
from django.contrib.auth import authenticate, password_validation
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.utils import timezone
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _
import evennia
from evennia.accounts.manager import AccountManager
from evennia.accounts.models import AccountDB
from evennia.commands.cmdsethandler import CmdSetHandler
@ -30,17 +31,24 @@ from evennia.comms.models import ChannelDB
from evennia.objects.models import ObjectDB
from evennia.scripts.scripthandler import ScriptHandler
from evennia.server.models import ServerConfig
from evennia.server.signals import (SIGNAL_ACCOUNT_POST_CREATE,
SIGNAL_ACCOUNT_POST_LOGIN_FAIL,
SIGNAL_OBJECT_POST_PUPPET,
SIGNAL_OBJECT_POST_UNPUPPET)
from evennia.server.signals import (
SIGNAL_ACCOUNT_POST_CREATE,
SIGNAL_ACCOUNT_POST_LOGIN_FAIL,
SIGNAL_OBJECT_POST_PUPPET,
SIGNAL_OBJECT_POST_UNPUPPET,
)
from evennia.server.throttle import Throttle
from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
from evennia.typeclasses.models import TypeclassBase
from evennia.utils import class_from_module, create, logger
from evennia.utils.optionhandler import OptionHandler
from evennia.utils.utils import (is_iter, lazy_property, make_iter, to_str,
variable_from_module)
from evennia.utils.utils import (
is_iter,
lazy_property,
make_iter,
to_str,
variable_from_module,
)
__all__ = ("DefaultAccount", "DefaultGuest")

View file

@ -5,13 +5,13 @@ Building and world design commands
import re
import typing
import evennia
from django.conf import settings
from django.core.paginator import Paginator
from django.db.models import Max, Min, Q
import evennia
from evennia import InterruptCommand
from evennia.commands.cmdhandler import (generate_cmdset_providers,
get_and_merge_cmdsets)
from evennia.commands.cmdhandler import generate_cmdset_providers, get_and_merge_cmdsets
from evennia.locks.lockhandler import LockException
from evennia.objects.models import ObjectDB
from evennia.prototypes import menus as olc_menus
@ -24,10 +24,18 @@ from evennia.utils.dbserialize import deserialize
from evennia.utils.eveditor import EvEditor
from evennia.utils.evmore import EvMore
from evennia.utils.evtable import EvTable
from evennia.utils.utils import (class_from_module, crop, dbref, display_len,
format_grid, get_all_typeclasses,
inherits_from, interactive, list_to_string,
variable_from_module)
from evennia.utils.utils import (
class_from_module,
crop,
dbref,
display_len,
format_grid,
get_all_typeclasses,
inherits_from,
interactive,
list_to_string,
variable_from_module,
)
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
@ -3274,11 +3282,15 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
string += f"\n |RNo match found for '{searchstring}' in #dbref interval.|n"
else:
result = result[0]
string += (f"\n|g {result.get_display_name(caller)}"
f"{result.get_extra_display_name_info(caller)} - {result.path}|n")
string += (
f"\n|g {result.get_display_name(caller)}"
f"{result.get_extra_display_name_info(caller)} - {result.path}|n"
)
if "loc" in self.switches and not is_account and result.location:
string += (f" (|wlocation|n: |g{result.location.get_display_name(caller)}"
f"{result.get_extra_display_name_info(caller)}|n)")
string += (
f" (|wlocation|n: |g{result.location.get_display_name(caller)}"
f"{result.get_extra_display_name_info(caller)}|n)"
)
else:
# Not an account/dbref search but a wider search; build a queryset.
# Searches for key and aliases

View file

@ -4,8 +4,9 @@ General Character commands usually available to all characters
import re
import evennia
from django.conf import settings
import evennia
from evennia.typeclasses.attributes import NickTemplateInvalid
from evennia.utils import utils

View file

@ -20,11 +20,11 @@ import uuid
from collections import defaultdict
from django.core import exceptions as django_exceptions
from evennia.prototypes import spawner
from evennia.utils.utils import class_from_module
from .utils import (BIGVAL, MAPSCAN, REVERSE_DIRECTIONS, MapError,
MapParserError)
from .utils import BIGVAL, MAPSCAN, REVERSE_DIRECTIONS, MapError, MapParserError
NodeTypeclass = None
ExitTypeclass = None
@ -331,7 +331,8 @@ class MapNode:
raise MapError(
f"Multiple objects found: {NodeTypeclass.objects.filter_xyz(xyz=xyz)}. "
"This may be due to manual creation of XYZRooms at this position. "
"Delete duplicates.", self
"Delete duplicates.",
self,
)
else:
self.log(f" updating existing room (if changed) at xyz={xyz}")

View file

@ -9,6 +9,7 @@ used as stand-alone XYZ-coordinate-aware rooms.
from django.conf import settings
from django.db.models import Q
from evennia.objects.manager import ObjectManager
from evennia.objects.objects import DefaultExit, DefaultRoom
@ -307,8 +308,7 @@ class XYZRoom(DefaultRoom):
def xyzgrid(self):
global GET_XYZGRID
if not GET_XYZGRID:
from evennia.contrib.grid.xyzgrid.xyzgrid import \
get_xyzgrid as GET_XYZGRID
from evennia.contrib.grid.xyzgrid.xyzgrid import get_xyzgrid as GET_XYZGRID
return GET_XYZGRID()
@property
@ -532,8 +532,7 @@ class XYZExit(DefaultExit):
def xyzgrid(self):
global GET_XYZGRID
if not GET_XYZGRID:
from evennia.contrib.grid.xyzgrid.xyzgrid import \
get_xyzgrid as GET_XYZGRID
from evennia.contrib.grid.xyzgrid.xyzgrid import get_xyzgrid as GET_XYZGRID
return GET_XYZGRID()
@property

View file

@ -4,6 +4,7 @@ EvAdventure character generation.
"""
from django.conf import settings
from evennia.objects.models import ObjectDB
from evennia.prototypes.spawner import spawn
from evennia.utils.create import create_object

View file

@ -10,10 +10,11 @@ import time
import typing
from collections import defaultdict
import evennia
import inflect
from django.conf import settings
from django.utils.translation import gettext as _
import evennia
from evennia.commands import cmdset
from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.objects.manager import ObjectManager
@ -23,9 +24,17 @@ from evennia.server.signals import SIGNAL_EXIT_TRAVERSED
from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
from evennia.typeclasses.models import TypeclassBase
from evennia.utils import ansi, create, funcparser, logger, search
from evennia.utils.utils import (class_from_module, compress_whitespace, dbref,
is_iter, iter_to_str, lazy_property,
make_iter, to_str, variable_from_module)
from evennia.utils.utils import (
class_from_module,
compress_whitespace,
dbref,
is_iter,
iter_to_str,
lazy_property,
make_iter,
to_str,
variable_from_module,
)
_INFLECT = inflect.engine()
_MULTISESSION_MODE = settings.MULTISESSION_MODE
@ -1425,7 +1434,8 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
return [
obj
for obj in obj_list
if obj != looker and (obj.access(looker, "view") and obj.access(looker, "search", default=True))
if obj != looker
and (obj.access(looker, "view") and obj.access(looker, "search", default=True))
]
# name and return_appearance hooks

View file

@ -642,6 +642,8 @@ def send_instruction(operation, arguments, callback=None, errback=None):
"""
global AMP_CONNECTION, REACTOR_RUN
# print("launcher: Sending to portal: {} + {}".format(ord(operation), arguments))
if None in (AMP_HOST, AMP_PORT, AMP_INTERFACE):
print(ERROR_AMP_UNCONFIGURED)
sys.exit()

View file

@ -197,8 +197,6 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
if process and not _is_windows():
# avoid zombie-process on Unix/BSD
process.wait()
# unset the reset-mode flag on the portal
self.factory.portal.server_restart_mode = None
return
def wait_for_disconnect(self, callback, *args, **kwargs):
@ -232,11 +230,18 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
"""
if mode == "reload":
self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SRELOAD)
self.send_AdminPortal2Server(
amp.DUMMYSESSION, operation=amp.SRELOAD, server_restart_mode=mode
)
elif mode == "reset":
self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SRESET)
self.send_AdminPortal2Server(
amp.DUMMYSESSION, operation=amp.SRESET, server_restart_mode=mode
)
elif mode == "shutdown":
self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SSHUTD)
self.send_AdminPortal2Server(
amp.DUMMYSESSION, operation=amp.SSHUTD, server_restart_mode=mode
)
# store the mode for use once server comes back up again
self.factory.portal.server_restart_mode = mode
# sending amp data
@ -326,7 +331,6 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
_, server_connected, _, _, _, _ = self.get_status()
# logger.log_msg("Evennia Launcher->Portal operation %s:%s received" % (ord(operation), arguments))
# logger.log_msg("operation == amp.SSTART: {}: {}".format(operation == amp.SSTART, amp.loads(arguments)))
if operation == amp.SSTART: # portal start #15
@ -405,11 +409,11 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
sessid, kwargs = self.data_in(packed_data)
# logger.log_msg("Evennia Server->Portal admin data %s:%s received" % (sessid, kwargs))
operation = kwargs.pop("operation")
portal_sessionhandler = evennia.PORTAL_SESSION_HANDLER
# logger.log_msg(f"Evennia Server->Portal admin data operation {ord(operation)}")
if operation == amp.SLOGIN: # server_session_login
# a session has authenticated; sync it.
session = portal_sessionhandler.get(sessid)
@ -427,22 +431,28 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
portal_sessionhandler.server_disconnect_all(reason=kwargs.get("reason"))
elif operation == amp.SRELOAD: # server reload
# set up callback to restart server once it has disconnected
self.factory.server_connection.wait_for_disconnect(
self.start_server, self.factory.portal.server_twistd_cmd
)
# tell server to reload
self.stop_server(mode="reload")
elif operation == amp.SRESET: # server reset
# set up callback to restart server once it has disconnected
self.factory.server_connection.wait_for_disconnect(
self.start_server, self.factory.portal.server_twistd_cmd
)
# tell server to reset
self.stop_server(mode="reset")
elif operation == amp.SSHUTD: # server-only shutdown
self.stop_server(mode="shutdown")
elif operation == amp.PSHUTD: # full server+server shutdown
# set up callback to shut down portal once server has disconnected
self.factory.server_connection.wait_for_disconnect(self.factory.portal.shutdown)
# tell server to shut down
self.stop_server(mode="shutdown")
elif operation == amp.PSYNC: # portal sync
@ -451,6 +461,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
self.factory.portal.server_process_id = kwargs.get("spid", None)
# this defaults to 'shutdown' or whatever value set in server_stop
server_restart_mode = self.factory.portal.server_restart_mode
# print("Server has connected. Sending session data to Server ... mode: {}".format(server_restart_mode))
sessdata = evennia.PORTAL_SESSION_HANDLER.get_all_sync_data()
self.send_AdminPortal2Server(
@ -461,6 +472,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
portal_start_time=self.factory.portal.start_time,
)
evennia.PORTAL_SESSION_HANDLER.at_server_connection()
self.factory.portal.server_restart_mode = None
if self.factory.server_connection:
# this is an indication the server has successfully connected, so
@ -480,7 +492,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
)
# set a flag in case we are about to shut down soon
self.factory.server_restart_mode = True
self.factory.server_restart_mode = "shutdown"
elif operation == amp.SCONN: # server_force_connection (for irc/etc)
portal_sessionhandler.server_connect(**kwargs)

View file

@ -44,6 +44,7 @@ import re
from django.conf import settings
from django.utils.translation import gettext as _
from evennia import CmdSet
from evennia.commands import cmdhandler
from evennia.utils import dedent, fill, is_iter, justify, logger, to_str, utils