Updated parts of server/ dir to google docstrings as per #709.

This commit is contained in:
Griatch 2015-06-22 21:02:03 +02:00
parent abff559a61
commit b2ddd34efd
7 changed files with 382 additions and 85 deletions

View file

@ -75,15 +75,27 @@ class AmpServerFactory(protocol.ServerFactory):
""" """
def __init__(self, server): def __init__(self, server):
""" """
server: The Evennia server service instance Initialize the factory.
protocol: The protocol the factory creates instances of.
Args:
server (Server): The Evennia server service instance.
protocol (Protocol): The protocol the factory creates
instances of.
""" """
self.server = server self.server = server
self.protocol = AMPProtocol self.protocol = AMPProtocol
def buildProtocol(self, addr): def buildProtocol(self, addr):
""" """
Start a new connection, and store it on the service object Start a new connection, and store it on the service object.
Args:
addr (str): Connection address. Not used.
Returns:
protocol (Protocol): The created protocol.
""" """
#print "Evennia Server connected to Portal at %s." % addr #print "Evennia Server connected to Portal at %s." % addr
self.server.amp_protocol = AMPProtocol() self.server.amp_protocol = AMPProtocol()
@ -95,6 +107,7 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
""" """
This factory creates an instance of the Portal, an AMPProtocol This factory creates an instance of the Portal, an AMPProtocol
instances to use to connect instances to use to connect
""" """
# Initial reconnect delay in seconds. # Initial reconnect delay in seconds.
initialDelay = 1 initialDelay = 1
@ -102,12 +115,24 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
maxDelay = 1 maxDelay = 1
def __init__(self, portal): def __init__(self, portal):
"""
Initializes the client factory.
Args:
portal (Portal): Portal instance.
"""
self.portal = portal self.portal = portal
self.protocol = AMPProtocol self.protocol = AMPProtocol
def startedConnecting(self, connector): def startedConnecting(self, connector):
""" """
Called when starting to try to connect to the MUD server. Called when starting to try to connect to the MUD server.
Args:
connector (Connector): Twisted Connector instance representing
this connection.
""" """
pass pass
#print 'AMP started to connect:', connector #print 'AMP started to connect:', connector
@ -115,6 +140,10 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
def buildProtocol(self, addr): def buildProtocol(self, addr):
""" """
Creates an AMPProtocol instance when connecting to the server. Creates an AMPProtocol instance when connecting to the server.
Args:
addr (str): Connection address. Not used.
""" """
#print "Portal connected to Evennia server at %s." % addr #print "Portal connected to Evennia server at %s." % addr
self.resetDelay() self.resetDelay()
@ -125,6 +154,12 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
def clientConnectionLost(self, connector, reason): def clientConnectionLost(self, connector, reason):
""" """
Called when the AMP connection to the MUD server is lost. Called when the AMP connection to the MUD server is lost.
Args:
connector (Connector): Twisted Connector instance representing
this connection.
reason (str): Eventual text describing why connection was lost.
""" """
if hasattr(self, "server_restart_mode"): if hasattr(self, "server_restart_mode"):
self.maxDelay = 1 self.maxDelay = 1
@ -137,6 +172,12 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
def clientConnectionFailed(self, connector, reason): def clientConnectionFailed(self, connector, reason):
""" """
Called when an AMP connection attempt to the MUD server fails. Called when an AMP connection attempt to the MUD server fails.
Args:
connector (Connector): Twisted Connector instance representing
this connection.
reason (str): Eventual text describing why connection failed.
""" """
if hasattr(self, "server_restart_mode"): if hasattr(self, "server_restart_mode"):
self.maxDelay = 1 self.maxDelay = 1
@ -150,7 +191,8 @@ class AmpClientFactory(protocol.ReconnectingClientFactory):
class MsgPortal2Server(amp.Command): class MsgPortal2Server(amp.Command):
""" """
Message portal -> server Message Portal -> Server
""" """
key = "MsgPortal2Server" key = "MsgPortal2Server"
arguments = [('hashid', amp.String()), arguments = [('hashid', amp.String()),
@ -163,7 +205,8 @@ class MsgPortal2Server(amp.Command):
class MsgServer2Portal(amp.Command): class MsgServer2Portal(amp.Command):
""" """
Message server -> portal Message Server -> Portal
""" """
key = "MsgServer2Portal" key = "MsgServer2Portal"
arguments = [('hashid', amp.String()), arguments = [('hashid', amp.String()),
@ -176,11 +219,11 @@ class MsgServer2Portal(amp.Command):
class ServerAdmin(amp.Command): class ServerAdmin(amp.Command):
""" """
Portal -> Server Administration Portal -> Server
Sent when the portal needs to perform admin operations on the
server, such as when a new session connects or resyncs
Sent when the portal needs to perform admin
operations on the server, such as when a new
session connects or resyncs
""" """
key = "ServerAdmin" key = "ServerAdmin"
arguments = [('hashid', amp.String()), arguments = [('hashid', amp.String()),
@ -193,10 +236,11 @@ class ServerAdmin(amp.Command):
class PortalAdmin(amp.Command): class PortalAdmin(amp.Command):
""" """
Server -> Portal Administration Server -> Portal
Sent when the server needs to perform admin operations on the
portal.
Sent when the server needs to perform admin
operations on the portal.
""" """
key = "PortalAdmin" key = "PortalAdmin"
arguments = [('hashid', amp.String()), arguments = [('hashid', amp.String()),
@ -209,11 +253,11 @@ class PortalAdmin(amp.Command):
class FunctionCall(amp.Command): class FunctionCall(amp.Command):
""" """
Bidirectional Bidirectional Server <-> Portal
Sent when either process needs to call an arbitrary function in
the other. This does not use the batch-send functionality.
Sent when either process needs to call an
arbitrary function in the other. This does
not use the batch-send functionality.
""" """
key = "FunctionCall" key = "FunctionCall"
arguments = [('module', amp.String()), arguments = [('module', amp.String()),
@ -224,7 +268,7 @@ class FunctionCall(amp.Command):
response = [('result', amp.String())] response = [('result', amp.String())]
# Helper functions # Helper functions for pickling.
dumps = lambda data: to_str(pickle.dumps(to_str(data), pickle.HIGHEST_PROTOCOL)) dumps = lambda data: to_str(pickle.dumps(to_str(data), pickle.HIGHEST_PROTOCOL))
loads = lambda data: pickle.loads(to_str(data)) loads = lambda data: pickle.loads(to_str(data))
@ -237,19 +281,22 @@ loads = lambda data: pickle.loads(to_str(data))
class AMPProtocol(amp.AMP): class AMPProtocol(amp.AMP):
""" """
This is the protocol that the MUD server and the proxy server This is the protocol that the MUD server and the proxy server
communicate to each other with. AMP is a bi-directional protocol, so communicate to each other with. AMP is a bi-directional protocol,
both the proxy and the MUD use the same commands and protocol. so both the proxy and the MUD use the same commands and protocol.
AMP specifies responder methods here and connect them to
amp.Command subclasses that specify the datatypes of the
input/output of these methods.
AMP specifies responder methods here and connect them to amp.Command
subclasses that specify the datatypes of the input/output of these methods.
""" """
# helper methods # helper methods
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
Initialize protocol with some things that need to be Initialize protocol with some things that need to be in place
in place already before connecting both on portal and server. already before connecting both on portal and server.
""" """
self.min_batch_step = 1.0 / BATCH_RATE self.min_batch_step = 1.0 / BATCH_RATE
self.lastsend = time() self.lastsend = time()
@ -259,13 +306,13 @@ class AMPProtocol(amp.AMP):
def connectionMade(self): def connectionMade(self):
""" """
This is called when a connection is established This is called when a connection is established between server
between server and portal. AMP calls it on both sides, and portal. AMP calls it on both sides, so we need to make
so we need to make sure to only trigger resync from the sure to only trigger resync from the portal side.
portal side.
""" """
self.transport.setTcpNoDelay(True) # this makes for a factor x10 faster sends! # this makes for a factor x10 faster sends!
self.transport.setTcpNoDelay(True)
if hasattr(self.factory, "portal"): if hasattr(self.factory, "portal"):
# only the portal has the 'portal' property, so we know we are # only the portal has the 'portal' property, so we know we are
# on the portal side and can initialize the connection. # on the portal side and can initialize the connection.
@ -280,7 +327,15 @@ class AMPProtocol(amp.AMP):
# Error handling # Error handling
def errback(self, e, info): def errback(self, e, info):
"error handler, to avoid dropping connections on server tracebacks." """
Error callback.
Handles errors to avoid dropping connections on server tracebacks.
Args:
e (Failure): Deferred error instance.
info (str): Error string.
"""
e.trap(Exception) e.trap(Exception)
print "AMP Error for %(info)s: %(e)s" % {'info': info, print "AMP Error for %(info)s: %(e)s" % {'info': info,
'e': e.getErrorMessage()} 'e': e.getErrorMessage()}
@ -289,8 +344,17 @@ class AMPProtocol(amp.AMP):
""" """
This will batch data together to send fewer, large batches. This will batch data together to send fewer, large batches.
Args:
command (AMP Command): A protocol send command.
sessid (int): A unique Session id.
Kwargs: Kwargs:
force_direct: send direct force_direct (bool): Send direct, without batching data.
Returns:
deferreds (list or None): A list of deferreds firing with
as batch parts get sent (or fails).
""" """
#print "batch_send 1:", command, sessid #print "batch_send 1:", command, sessid
global _SENDBATCH global _SENDBATCH
@ -343,6 +407,17 @@ class AMPProtocol(amp.AMP):
This will receive and unpack data sent as a batch. This both This will receive and unpack data sent as a batch. This both
handles too-long data as well as batch-sending very fast- handles too-long data as well as batch-sending very fast-
arriving commands. arriving commands.
Args:
hashid (str): Unique hash id representing this batch in
the cache buffer.
data (str): Data coming over the wire.
ipart (int): Index of this part of the batch (ipart/nparts)
nparts (int): Total number of parts in this batch.
Returns:
data (str or list): The received data.
""" """
global _MSGBUFFER global _MSGBUFFER
if nparts == 1: if nparts == 1:
@ -364,11 +439,20 @@ class AMPProtocol(amp.AMP):
def amp_msg_portal2server(self, hashid, data, ipart, nparts): def amp_msg_portal2server(self, hashid, data, ipart, nparts):
""" """
Relays message to server. This method is executed on the Server. Relays message to server. This method is executed on the
Server.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args:
hashid (str): Unique hash identifying this data batch.
data (str): Data to send (often a part of a batch)
ipart (int): Index of this part of the batch.
nparts (int): Total number of batches.
Since AMP has a limit of 65355 bytes per message, it's possible the
data comes in multiple chunks; if so (nparts>1) we buffer the data
and wait for the remaining parts to arrive before continuing.
""" """
batch = self.batch_recv(hashid, data, ipart, nparts) batch = self.batch_recv(hashid, data, ipart, nparts)
for (sessid, kwargs) in batch: for (sessid, kwargs) in batch:
@ -382,6 +466,15 @@ class AMPProtocol(amp.AMP):
def call_remote_MsgPortal2Server(self, sessid, msg, data=""): def call_remote_MsgPortal2Server(self, sessid, msg, data=""):
""" """
Access method called by the Portal and executed on the Portal. Access method called by the Portal and executed on the Portal.
Args:
sessid (int): Unique Session id.
msg (str): Message to send over the wire.
data (str, optional): Optional data.
Returns:
deferred (Deferred): Asynchronous return.
""" """
#print "msg portal->server (portal side):", sessid, msg, data #print "msg portal->server (portal side):", sessid, msg, data
return self.batch_send(MsgPortal2Server, sessid, return self.batch_send(MsgPortal2Server, sessid,
@ -393,6 +486,18 @@ class AMPProtocol(amp.AMP):
def amp_msg_server2portal(self, hashid, data, ipart, nparts): def amp_msg_server2portal(self, hashid, data, ipart, nparts):
""" """
Relays message to Portal. This method is executed on the Portal. Relays message to Portal. This method is executed on the Portal.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args:
hashid (str): Unique hash identifying this data batch.
data (str): Data to send (often a part of a batch)
ipart (int): Index of this part of the batch.
nparts (int): Total number of batches.
""" """
batch = self.batch_recv(hashid, data, ipart, nparts) batch = self.batch_recv(hashid, data, ipart, nparts)
for (sessid, kwargs) in batch: for (sessid, kwargs) in batch:
@ -406,6 +511,18 @@ class AMPProtocol(amp.AMP):
def amp_batch_server2portal(self, hashid, data, ipart, nparts): def amp_batch_server2portal(self, hashid, data, ipart, nparts):
""" """
Relays batch data to Portal. This method is executed on the Portal. Relays batch data to Portal. This method is executed on the Portal.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args:
hashid (str): Unique hash identifying this data batch.
data (str): Data to send (often a part of a batch)
ipart (int): Index of this part of the batch.
nparts (int): Total number of batches.
""" """
batch = self.batch_recv(hashid, data, ipart, nparts) batch = self.batch_recv(hashid, data, ipart, nparts)
if batch is not None: if batch is not None:
@ -418,7 +535,13 @@ class AMPProtocol(amp.AMP):
def call_remote_MsgServer2Portal(self, sessid, msg, data=""): def call_remote_MsgServer2Portal(self, sessid, msg, data=""):
""" """
Access method called by the Server and executed on the Server. Send Message - access method called by the Server and executed on the Server.
Args:
sessid (int): Unique Session id.
msg (str): Message to send over the wire.
data (str, optional): Extra data.
""" """
#print "msg server->portal (server side):", sessid, msg, data #print "msg server->portal (server side):", sessid, msg, data
return self.batch_send(MsgServer2Portal, sessid, msg=msg, data=data) return self.batch_send(MsgServer2Portal, sessid, msg=msg, data=data)
@ -429,6 +552,17 @@ class AMPProtocol(amp.AMP):
This allows the portal to perform admin This allows the portal to perform admin
operations on the server. This is executed on the Server. operations on the server. This is executed on the Server.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args:
hashid (str): Unique hash identifying this data batch.
data (str): Data to send (often a part of a batch)
ipart (int): Index of this part of the batch.
nparts (int): Total number of batches.
""" """
#print "serveradmin (server side):", hashid, ipart, nparts #print "serveradmin (server side):", hashid, ipart, nparts
batch = self.batch_recv(hashid, data, ipart, nparts) batch = self.batch_recv(hashid, data, ipart, nparts)
@ -465,7 +599,15 @@ class AMPProtocol(amp.AMP):
def call_remote_ServerAdmin(self, sessid, operation="", data=""): def call_remote_ServerAdmin(self, sessid, operation="", data=""):
""" """
Access method called by the Portal and Executed on the Portal. Administrative access method called by the Portal and Executed
on the Portal.
Args:
sessid (int): Session id.
operation (char, optional): Identifier for the server operation, as defined by the
global variables in `evennia/server/amp.py`.
data (str, optional): Data going into the adminstrative operation.
""" """
#print "serveradmin (portal side):", sessid, ord(operation), data #print "serveradmin (portal side):", sessid, ord(operation), data
if hasattr(self.factory, "server_restart_mode"): if hasattr(self.factory, "server_restart_mode"):
@ -478,6 +620,18 @@ class AMPProtocol(amp.AMP):
""" """
This allows the server to perform admin This allows the server to perform admin
operations on the portal. This is executed on the Portal. operations on the portal. This is executed on the Portal.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args:
hashid (str): Unique hash identifying this data batch.
data (str): Data to send (often a part of a batch)
ipart (int): Index of this part of the batch.
nparts (int): Total number of batches.
""" """
#print "portaladmin (portal side):", sessid, ord(operation), data #print "portaladmin (portal side):", sessid, ord(operation), data
batch = self.batch_recv(hashid, data, ipart, nparts) batch = self.batch_recv(hashid, data, ipart, nparts)
@ -519,7 +673,17 @@ class AMPProtocol(amp.AMP):
def call_remote_PortalAdmin(self, sessid, operation="", data=""): def call_remote_PortalAdmin(self, sessid, operation="", data=""):
""" """
Access method called by the server side. Administrative access method called by the Server side and executed
onthe Portal.
Args:
sessid (int): Session id.
operation (char, optional): Identifier for the server
operation, as defined by the global variables in
`evennia/server/amp.py`.
data (str, optional): Data going into the adminstrative
operation.
""" """
if operation == SSYNC: if operation == SSYNC:
return self.batch_send(PortalAdmin, sessid, force_direct=True, operation=operation, data=data) return self.batch_send(PortalAdmin, sessid, force_direct=True, operation=operation, data=data)
@ -529,8 +693,18 @@ class AMPProtocol(amp.AMP):
def amp_function_call(self, module, function, args, **kwargs): def amp_function_call(self, module, function, args, **kwargs):
""" """
This allows Portal- and Server-process to call an arbitrary function This allows Portal- and Server-process to call an arbitrary
in the other process. It is intended for use by plugin modules. function in the other process. It is intended for use by
plugin modules.
Args:
module (str or module): The module containing the
`function` to call.
function (str): The name of the function to call in
`module`.
args, kwargs (any): These will be used as args/kwargs to
`function`.
""" """
args = loads(args) args = loads(args)
kwargs = loads(kwargs) kwargs = loads(kwargs)
@ -561,6 +735,7 @@ class AMPProtocol(amp.AMP):
Returns: Returns:
A deferred that fires with the return value of the remote A deferred that fires with the return value of the remote
function call function call
""" """
return self.callRemote(FunctionCall, return self.callRemote(FunctionCall,
module=modulepath, module=modulepath,

View file

@ -315,6 +315,7 @@ ERROR_NODJANGO = \
def evennia_version(): def evennia_version():
""" """
Get the Evennia version info from the main package. Get the Evennia version info from the main package.
""" """
version = "Unknown" version = "Unknown"
try: try:
@ -338,6 +339,7 @@ def check_main_evennia_dependencies():
Returns: Returns:
not_error (bool): True if no dependency error was found. not_error (bool): True if no dependency error was found.
""" """
error = False error = False
@ -381,6 +383,7 @@ def set_gamedir(path):
""" """
Set GAMEDIR based on path, by figuring out where the setting file Set GAMEDIR based on path, by figuring out where the setting file
is inside the directory tree. is inside the directory tree.
""" """
global GAMEDIR global GAMEDIR
@ -405,6 +408,7 @@ def set_gamedir(path):
def create_secret_key(): def create_secret_key():
""" """
Randomly create the secret key for the settings file Randomly create the secret key for the settings file
""" """
import random import random
import string import string
@ -419,6 +423,7 @@ def create_settings_file():
""" """
Uses the template settings file to build a working Uses the template settings file to build a working
settings file. settings file.
""" """
settings_path = os.path.join(GAMEDIR, "server", "conf", "settings.py") settings_path = os.path.join(GAMEDIR, "server", "conf", "settings.py")
with open(settings_path, 'r') as f: with open(settings_path, 'r') as f:
@ -441,6 +446,10 @@ def create_game_directory(dirname):
Initialize a new game directory named dirname Initialize a new game directory named dirname
at the current path. This means copying the at the current path. This means copying the
template directory from evennia's root. template directory from evennia's root.
Args:
dirname (str): The directory name to create.
""" """
global GAMEDIR global GAMEDIR
GAMEDIR = os.path.abspath(os.path.join(CURRENT_DIR, dirname)) GAMEDIR = os.path.abspath(os.path.join(CURRENT_DIR, dirname))
@ -454,14 +463,20 @@ def create_game_directory(dirname):
def create_superuser(): def create_superuser():
"Create the superuser player" """
Create the superuser player
"""
print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n" print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n"
django.core.management.call_command("createsuperuser", interactive=True) django.core.management.call_command("createsuperuser", interactive=True)
def check_database(): def check_database():
""" """
Check database exists Check so the database exists.
Returns:
exists (bool): `True` if the database exists, otherwise `False`.
""" """
# Check so a database exists and is accessible # Check so a database exists and is accessible
from django.db import connection from django.db import connection
@ -517,7 +532,11 @@ def check_database():
def getenv(): def getenv():
""" """
Get current environment and add PYTHONPATH Get current environment and add PYTHONPATH.
Returns:
env (dict): Environment global dict.
""" """
sep = ";" if os.name == 'nt' else ":" sep = ";" if os.name == 'nt' else ":"
env = os.environ.copy() env = os.environ.copy()
@ -527,8 +546,14 @@ def getenv():
def get_pid(pidfile): def get_pid(pidfile):
""" """
Get the PID (Process ID) by trying to access Get the PID (Process ID) by trying to access an PID file.
an PID file.
Args:
pidfile (str): The path of the pid file.
Returns:
pid (str): The process id.
""" """
pid = None pid = None
if os.path.exists(pidfile): if os.path.exists(pidfile):
@ -542,6 +567,10 @@ def del_pid(pidfile):
The pidfile should normally be removed after a process has The pidfile should normally be removed after a process has
finished, but when sending certain signals they remain, so we need finished, but when sending certain signals they remain, so we need
to clean them manually. to clean them manually.
Args:
pidfile (str): The path of the pid file.
""" """
if os.path.exists(pidfile): if os.path.exists(pidfile):
os.remove(pidfile) os.remove(pidfile)
@ -552,6 +581,15 @@ def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART
Send a kill signal to a process based on PID. A customized Send a kill signal to a process based on PID. A customized
success/error message will be returned. If clean=True, the system success/error message will be returned. If clean=True, the system
will attempt to manually remove the pid file. will attempt to manually remove the pid file.
Args:
pidfile (str): The path of the pidfile to get the PID from.
signal (int, optional): Signal identifier.
succmsg (str, optional): Message to log on success.
errmsg (str, optional): Message to log on failure.
restart_file (str, optional): Restart file location.
restart (bool, optional): Are we in restart mode or not.
""" """
pid = get_pid(pidfile) pid = get_pid(pidfile)
if pid: if pid:
@ -579,7 +617,14 @@ def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART
def show_version_info(about=False): def show_version_info(about=False):
""" """
Display version info Display version info.
Args:
about (bool): Include ABOUT info as well as version numbers.
Returns:
version_info (str): A complete version info string.
""" """
import os, sys import os, sys
import twisted import twisted
@ -595,10 +640,15 @@ def show_version_info(about=False):
def error_check_python_modules(): def error_check_python_modules():
""" """
Import settings modules in settings. This will raise exceptions on Import settings modules in settings. This will raise exceptions on
pure python-syntax issues which are hard to catch gracefully pure python-syntax issues which are hard to catch gracefully with
with exceptions in the engine (since they are formatting errors in exceptions in the engine (since they are formatting errors in the
the python source files themselves). Best they fail already here python source files themselves). Best they fail already here
before we get any further. before we get any further.
Raises:
DeprecationWarning: For trying to access various modules
(usually in `settings.py`) which are no longer supported.
""" """
from django.conf import settings from django.conf import settings
def imp(path, split=True): def imp(path, split=True):
@ -661,8 +711,13 @@ def error_check_python_modules():
def init_game_directory(path, check_db=True): def init_game_directory(path, check_db=True):
""" """
Try to analyze the given path to find settings.py - this defines Try to analyze the given path to find settings.py - this defines
the game directory and also sets PYTHONPATH as well as the the game directory and also sets PYTHONPATH as well as the django
django path. path.
Args:
path (str): Path to new game directory, including its name.
check_db (bool, optional): Check if the databae exists.
""" """
# set the GAMEDIR path # set the GAMEDIR path
set_gamedir(path) set_gamedir(path)
@ -758,8 +813,14 @@ def run_dummyrunner(number_of_dummies):
""" """
Start an instance of the dummyrunner Start an instance of the dummyrunner
The dummy players' behavior can be customized by adding a Args:
dummyrunner_settings.py config file in the game's conf directory. number_of_dummies (int): The number of dummy players to start.
Notes:
The dummy players' behavior can be customized by adding a
´dummyrunner_settings.py´ config file in the game's conf/
directory.
""" """
number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1 number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1
cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies] cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies]
@ -773,8 +834,12 @@ def run_dummyrunner(number_of_dummies):
def list_settings(keys): def list_settings(keys):
""" """
Display the server settings. We only display Display the server settings. We only display the Evennia specific
the Evennia specific settings here. settings here. The result will be printed to the terminal.
Args:
keys (str or list): Setting key or keys to inspect.
""" """
from importlib import import_module from importlib import import_module
from evennia.utils import evtable from evennia.utils import evtable
@ -800,6 +865,7 @@ def list_settings(keys):
def run_menu(): def run_menu():
""" """
This launches an interactive menu. This launches an interactive menu.
""" """
while True: while True:
# menu loop # menu loop
@ -864,10 +930,12 @@ def server_operation(mode, service, interactive, profiler):
""" """
Handle argument options given on the command line. Handle argument options given on the command line.
mode - str; start/stop etc Args:
service - str; server, portal or all mode (str): Start/stop/restart and so on.
interactive - bool; use interactive mode or daemon service (str): "server", "portal" or "all".
profiler - run the service under the profiler interactive (bool). Use interactive mode or daemon.
profiler (bool): Run the service under the profiler.
""" """
cmdstr = [sys.executable, EVENNIA_RUNNER] cmdstr = [sys.executable, EVENNIA_RUNNER]
@ -936,7 +1004,8 @@ def server_operation(mode, service, interactive, profiler):
def main(): def main():
""" """
Run the evennia main program. Run the evennia launcher main program.
""" """
# set up argument parser # set up argument parser

View file

@ -46,6 +46,7 @@ WARNING_POSTGRESQL_FIX = \
def create_config_values(): def create_config_values():
""" """
Creates the initial config values. Creates the initial config values.
""" """
ServerConfig.objects.conf("site_name", settings.SERVERNAME) ServerConfig.objects.conf("site_name", settings.SERVERNAME)
ServerConfig.objects.conf("idle_timeout", settings.IDLE_TIMEOUT) ServerConfig.objects.conf("idle_timeout", settings.IDLE_TIMEOUT)
@ -53,6 +54,7 @@ def create_config_values():
def get_god_player(): def get_god_player():
""" """
Creates the god user and don't take no for an answer. Creates the god user and don't take no for an answer.
""" """
try: try:
god_player = PlayerDB.objects.get(id=1) god_player = PlayerDB.objects.get(id=1)
@ -64,6 +66,7 @@ def get_god_player():
def create_objects(): def create_objects():
""" """
Creates the #1 player and Limbo room. Creates the #1 player and Limbo room.
""" """
print " Creating objects (Player #1 and Limbo room) ..." print " Creating objects (Player #1 and Limbo room) ..."
@ -122,6 +125,7 @@ def create_objects():
def create_channels(): def create_channels():
""" """
Creates some sensible default channels. Creates some sensible default channels.
""" """
print " Creating default channels ..." print " Creating default channels ..."
@ -137,6 +141,7 @@ def at_initial_setup():
setup. Called very last in the sequence. It tries to import and setup. Called very last in the sequence. It tries to import and
srun a module settings.AT_INITIAL_SETUP_HOOK_MODULE and will fail srun a module settings.AT_INITIAL_SETUP_HOOK_MODULE and will fail
silently if this does not exist or fails to load. silently if this does not exist or fails to load.
""" """
modname = settings.AT_INITIAL_SETUP_HOOK_MODULE modname = settings.AT_INITIAL_SETUP_HOOK_MODULE
if not modname: if not modname:
@ -152,10 +157,11 @@ def at_initial_setup():
def reset_server(): def reset_server():
""" """
We end the initialization by resetting the server. This We end the initialization by resetting the server. This makes sure
makes sure the first login is the same as all the following the first login is the same as all the following ones,
ones, particularly it cleans all caches for the special objects. particularly it cleans all caches for the special objects. It
It also checks so the warm-reset mechanism works as it should. also checks so the warm-reset mechanism works as it should.
""" """
from evennia.server.sessionhandler import SESSIONS from evennia.server.sessionhandler import SESSIONS
print " Initial setup complete. Restarting Server once." print " Initial setup complete. Restarting Server once."
@ -164,9 +170,14 @@ def reset_server():
def handle_setup(last_step): def handle_setup(last_step):
""" """
Main logic for the module. It allows for restarting Main logic for the module. It allows for restarting the
the initialization at any point if one of the modules initialization at any point if one of the modules should crash.
should crash.
Args:
last_step (int): The last stored successful step, for starting
over on errors. If `< 0`, initialization has finished and no
steps need to be redone.
""" """
if last_step < 0: if last_step < 0:

View file

@ -6,22 +6,31 @@ from django.db import models
class ServerConfigManager(models.Manager): class ServerConfigManager(models.Manager):
""" """
This ServerConfigManager implements methods for searching This ServerConfigManager implements methods for searching and
and manipulating ServerConfigs directly from the database. manipulating ServerConfigs directly from the database.
These methods will all return database objects These methods will all return database objects (or QuerySets)
(or QuerySets) directly. directly.
ServerConfigs are used to store certain persistent settings for the ServerConfigs are used to store certain persistent settings for
server at run-time. the server at run-time.
Evennia-specific:
conf
""" """
def conf(self, key=None, value=None, delete=False, default=None): def conf(self, key=None, value=None, delete=False, default=None):
""" """
Access and manipulate config values Add, retrieve and manipulate config values.
Args:
key (str, optional): Name of config.
value (str, optional): Data to store in this config value.
delete (bool, optional): If `True`, delete config with `key`.
default (str, optional): Use when retrieving a config value
by a key that does not exist.
Returns:
all (list): If `key` was not given - all stored config values.
value (str): If `key` was given, this is the stored value, or
`default` if no matching `key` was found.
""" """
if not key: if not key:
return self.all() return self.all()
@ -43,8 +52,13 @@ class ServerConfigManager(models.Manager):
def get_mysql_db_version(self): def get_mysql_db_version(self):
""" """
This is a helper method for getting the version string This is a helper method for specifically getting the version
of a mysql database. string of a MySQL database.
Returns:
mysql_version (str): The currently used mysql database
version.
""" """
from django.db import connection from django.db import connection
conn = connection.cursor() conn = connection.cursor()

View file

@ -30,8 +30,9 @@ class ServerConfig(WeakSharedMemoryModel):
On-the fly storage of global settings. On-the fly storage of global settings.
Properties defined on ServerConfig: Properties defined on ServerConfig:
key - main identifier
value - value stored in key. This is a pickled storage. - key: Main identifier
- value: Value stored in key. This is a pickled storage.
""" """
@ -112,7 +113,12 @@ class ServerConfig(WeakSharedMemoryModel):
def store(self, key, value): def store(self, key, value):
""" """
Wrap the storage (handles pickling) Wrap the storage.
Args:
key (str): The name of this store.
value (str): The data to store with this `key`.
""" """
self.key = key self.key = key
self.value = value self.value = value

View file

@ -237,6 +237,7 @@ def oob_report(session, *args, **kwargs):
Notes: Notes:
When the property updates, the monitor will send a MSDP_ARRAY When the property updates, the monitor will send a MSDP_ARRAY
to the session of the form `(SEND, fieldname, new_value)` to the session of the form `(SEND, fieldname, new_value)`
Examples: Examples:
("REPORT", "CHARACTER_NAME") ("REPORT", "CHARACTER_NAME")
("MSDP_TABLE", "CHARACTER_NAME", "Amanda") ("MSDP_TABLE", "CHARACTER_NAME", "Amanda")
@ -268,6 +269,11 @@ def oob_return_field_report(session, fieldname, obj, *args, **kwargs):
changes. It is not part of the official MSDP specification but is changes. It is not part of the official MSDP specification but is
a callback used by the monitor to format the result before sending a callback used by the monitor to format the result before sending
it on. it on.
Args:
session (Session): The Session object controlling this oob function.
fieldname (str): The name of the Field to report on.
""" """
session.msg(oob=("MSDP_TABLE", (), session.msg(oob=("MSDP_TABLE", (),
{fieldname: to_str(getattr(obj, fieldname), force_string=True)})) {fieldname: to_str(getattr(obj, fieldname), force_string=True)}))
@ -283,6 +289,11 @@ def oob_return_attribute_report(session, fieldname, obj, *args, **kwargs):
This command is not part of the official MSDP specification but is This command is not part of the official MSDP specification but is
a callback used by the monitor to format the result before sending a callback used by the monitor to format the result before sending
it on. it on.
Args:
session (Session): The Session object controlling this oob function.
fieldname (str): The name of the Attribute to report on.
""" """
session.msg(oob=("MSDP_TABLE", (), session.msg(oob=("MSDP_TABLE", (),
{obj.db_key: to_str(getattr(obj, fieldname), force_string=True)})) {obj.db_key: to_str(getattr(obj, fieldname), force_string=True)}))
@ -292,6 +303,10 @@ def oob_return_attribute_report(session, fieldname, obj, *args, **kwargs):
def oob_unreport(session, *args, **kwargs): def oob_unreport(session, *args, **kwargs):
""" """
This removes tracking for the given data. This removes tracking for the given data.
Args:
session (Session): Session controling this command.
""" """
obj = session.get_puppet_or_player() obj = session.get_puppet_or_player()
if obj: if obj:
@ -330,6 +345,7 @@ def oob_list(session, mode, *args, **kwargs):
Examples: Examples:
oob in: LIST COMMANDS oob in: LIST COMMANDS
oob out: (COMMANDS, (SEND, REPORT, LIST, ...) oob out: (COMMANDS, (SEND, REPORT, LIST, ...)
""" """
mode = mode.upper() mode = mode.upper()
if mode == "COMMANDS": if mode == "COMMANDS":

View file

@ -43,6 +43,7 @@ class OOBFieldMonitor(object):
the update() method w ill be called by the the update() method w ill be called by the
save mechanism, which in turn will call the save mechanism, which in turn will call the
user-customizable func() user-customizable func()
""" """
def __init__(self, obj): def __init__(self, obj):
""" """
@ -50,14 +51,19 @@ class OOBFieldMonitor(object):
Args: Args:
obj (Object): object handler is defined on. obj (Object): object handler is defined on.
""" """
self.obj = obj self.obj = obj
self.subscribers = defaultdict(list) self.subscribers = defaultdict(list)
def __call__(self, fieldname): def __call__(self, fieldname):
""" """
Called by the save() mechanism when the given Called by the save() mechanism when the given field has
field has updated. updated.
Args:
fieldname (str): The field to monitor
""" """
for sessid, oobtuples in self.subscribers.items(): for sessid, oobtuples in self.subscribers.items():
# oobtuples is a list [(oobfuncname, args, kwargs), ...], # oobtuples is a list [(oobfuncname, args, kwargs), ...],
@ -73,12 +79,13 @@ class OOBFieldMonitor(object):
Args: Args:
sessid (int): Session id sessid (int): Session id
oobfuncname (str): oob command to call when field updates oobfuncname (str): oob command to call when field updates
args,kwargs: arguments to pass to oob commjand args,kwargs (any): arguments to pass to oob commjand
Notes: Notes:
Each sessid may have a list of (oobfuncname, args, kwargs) Each sessid may have a list of (oobfuncname, args, kwargs)
tuples, all of which will be executed when the tuples, all of which will be executed when the
field updates. field updates.
""" """
self.subscribers[sessid].append((oobfuncname, args, kwargs)) self.subscribers[sessid].append((oobfuncname, args, kwargs))
@ -88,7 +95,6 @@ class OOBFieldMonitor(object):
Args: Args:
sessid(int): Session id sessid(int): Session id
Keyword Args:
oobfuncname (str, optional): Only delete this cmdname. oobfuncname (str, optional): Only delete this cmdname.
If not given, delete all. If not given, delete all.