Remove channelhandler

This commit is contained in:
Griatch 2021-05-08 15:43:41 +02:00
parent 92624fc2c7
commit b29afb70f8
12 changed files with 61 additions and 468 deletions

View file

@ -95,7 +95,6 @@ SESSION_HANDLER = None
TASK_HANDLER = None
TICKER_HANDLER = None
MONITOR_HANDLER = None
CHANNEL_HANDLER = None
# Containers
GLOBAL_SCRIPTS = None
@ -149,7 +148,7 @@ def _init():
global signals
global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers
global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER
global CHANNEL_HANDLER, TASK_HANDLER
global TASK_HANDLER
global GLOBAL_SCRIPTS, OPTION_CLASSES
global EvMenu, EvTable, EvForm, EvMore, EvEditor
global ANSIString
@ -212,7 +211,6 @@ def _init():
from .scripts.tickerhandler import TICKER_HANDLER
from .scripts.taskhandler import TASK_HANDLER
from .server.sessionhandler import SESSION_HANDLER
from .comms.channelhandler import CHANNEL_HANDLER
from .scripts.monitorhandler import MONITOR_HANDLER
# containers

View file

@ -48,6 +48,7 @@ _MULTISESSION_MODE = settings.MULTISESSION_MODE
_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
_CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
_MUDINFO_CHANNEL = None
_CONNECT_CHANNEL = None
_CMDHANDLER = None
# Create throttles for too many account-creations and login attempts
@ -1359,30 +1360,42 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
def _send_to_connect_channel(self, message):
"""
Helper method for loading and sending to the comm channel
dedicated to connection messages.
Helper method for loading and sending to the comm channel dedicated to
connection messages. This will also be sent to the mudinfo channel.
Args:
message (str): A message to send to the connect channel.
"""
global _MUDINFO_CHANNEL
if not _MUDINFO_CHANNEL:
try:
_MUDINFO_CHANNEL = ChannelDB.objects.filter(db_key=settings.CHANNEL_MUDINFO["key"])[
0
]
except Exception:
logger.log_trace()
global _MUDINFO_CHANNEL, _CONNECT_CHANNEL
if _MUDINFO_CHANNEL is None:
if settings.CHANNEL_MUDINFO:
try:
_MUDINFO_CHANNEL = ChannelDB.objects.get(
db_key=settings.CHANNEL_MUDINFO["key"])
except ChannelDB.DoesNotExist:
logger.log_trace()
else:
_MUDINFO = False
if _CONNECT_CHANNEL is None:
if settings.CHANNEL_CONNECTINFO:
try:
_CONNECT_CHANNEL = ChannelDB.objects.get(
db_key=settings.CHANNEL_CONNECTINFO["key"])
except ChannelDB.DoesNotExist:
logger.log_trace()
else:
_CONNECT_CHANNEL = False
if settings.USE_TZ:
now = timezone.localtime()
else:
now = timezone.now()
now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute)
if _MUDINFO_CHANNEL:
_MUDINFO_CHANNEL.tempmsg(f"[{_MUDINFO_CHANNEL.key}, {now}]: {message}")
else:
logger.log_info(f"[{now}]: {message}")
_MUDINFO_CHANNEL.msg(f"[{now}]: {message}")
if _CONNECT_CHANNEL:
_CONNECT_CHANNEL.msg(f"[{now}]: {message}")
def at_post_login(self, session=None, **kwargs):
"""

View file

@ -23,14 +23,12 @@ command line. The processing of a command works as follows:
cmdset, or fallback to error message. Exit.
7. If no match was found -> check for CMD_NOMATCH in current cmdset or
fallback to error message. Exit.
8. A single match was found. If this is a channel-command (i.e. the
ommand name is that of a channel), --> check for CMD_CHANNEL in
current cmdset or use channelhandler default. Exit.
9. At this point we have found a normal command. We assign useful variables to it that
8. At this point we have found a normal command. We assign useful variables to it that
will be available to the command coder at run-time.
12. We have a unique cmdobject, primed for use. Call all hooks:
9. We have a unique cmdobject, primed for use. Call all hooks:
`at_pre_cmd()`, `cmdobj.parse()`, `cmdobj.func()` and finally `at_post_cmd()`.
13. Return deferred that will fire with the return from `cmdobj.func()` (unused by default).
10. Return deferred that will fire with the return from `cmdobj.func()` (unused by default).
"""
from collections import defaultdict
@ -44,7 +42,6 @@ from twisted.internet.task import deferLater
from twisted.internet.defer import inlineCallbacks, returnValue
from django.conf import settings
from evennia.commands.command import InterruptCommand
from evennia.comms.channelhandler import CHANNELHANDLER
from evennia.utils import logger, utils
from evennia.utils.utils import string_suggestions
@ -304,19 +301,6 @@ def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string)
"""
try:
# @inlineCallbacks
# def _get_channel_cmdset(account_or_obj):
# """
# Helper-method; Get channel-cmdsets
# """
# # Create cmdset for all account's available channels
# try:
# channel_cmdset = yield CHANNELHANDLER.get_cmdset(account_or_obj)
# returnValue([channel_cmdset])
# except Exception:
# _msg_err(caller, _ERROR_CMDSETS)
# raise ErrorReported(raw_string)
@inlineCallbacks
def _get_local_obj_cmdsets(obj):
"""

View file

@ -1,324 +0,0 @@
"""
The channel handler, accessed from this module as CHANNEL_HANDLER is a
singleton that handles the stored set of channels and how they are
represented against the cmdhandler.
If there is a channel named 'newbie', we want to be able to just write
newbie Hello!
For this to work, 'newbie', the name of the channel, must be
identified by the cmdhandler as a command name. The channelhandler
stores all channels as custom 'commands' that the cmdhandler can
import and look through.
> Warning - channel names take precedence over command names, so make
sure to not pick clashing channel names.
Unless deleting a channel you normally don't need to bother about the
channelhandler at all - the create_channel method handles the update.
To delete a channel cleanly, delete the channel object, then call
update() on the channelhandler. Or use Channel.objects.delete() which
does this for you.
"""
from django.conf import settings
from evennia.commands import cmdset
from evennia.utils.logger import tail_log_file
from evennia.utils.utils import class_from_module
from django.utils.translation import gettext as _
# we must late-import these since any overloads are likely to
# themselves be using these classes leading to a circular import.
_CHANNEL_HANDLER_CLASS = None
_CHANNEL_COMMAND_CLASS = None
_CHANNELDB = None
_COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
class ChannelCommand(_COMMAND_DEFAULT_CLASS):
"""
{channelkey} channel
{channeldesc}
Usage:
{lower_channelkey} <message>
{lower_channelkey}/history [start]
{lower_channelkey} off - mutes the channel
{lower_channelkey} on - unmutes the channel
Switch:
history: View 20 previous messages, either from the end or
from <start> number of messages from the end.
Example:
{lower_channelkey} Hello World!
{lower_channelkey}/history
{lower_channelkey}/history 30
"""
# note that channeldesc and lower_channelkey will be filled
# automatically by ChannelHandler
# this flag is what identifies this cmd as a channel cmd
# and branches off to the system send-to-channel command
# (which is customizable by admin)
is_channel = True
key = "general"
help_category = "Channel Names"
obj = None
arg_regex = r"\s.*?|/history.*?"
def parse(self):
"""
Simple parser
"""
# cmdhandler sends channame:msg here.
channelname, msg = self.args.split(":", 1)
self.history_start = None
if msg.startswith("/history"):
arg = msg[8:]
try:
self.history_start = int(arg) if arg else 0
except ValueError:
# if no valid number was given, ignore it
pass
self.args = (channelname.strip(), msg.strip())
def func(self):
"""
Create a new message and send it to channel, using
the already formatted input.
"""
global _CHANNELDB
if not _CHANNELDB:
from evennia.comms.models import ChannelDB as _CHANNELDB
channelkey, msg = self.args
caller = self.caller
if not msg:
self.msg(_("Say what?"))
return
channel = _CHANNELDB.objects.get_channel(channelkey)
if not channel:
self.msg(_("Channel '%s' not found.") % channelkey)
return
if not channel.has_connection(caller):
string = _("You are not connected to channel '%s'.")
self.msg(string % channelkey)
return
if not channel.access(caller, "send"):
string = _("You are not permitted to send to channel '%s'.")
self.msg(string % channelkey)
return
if msg == "on":
caller = caller if not hasattr(caller, "account") else caller.account
unmuted = channel.unmute(caller)
if unmuted:
self.msg(_("You start listening to %s.") % channel)
return
self.msg(_("You were already listening to %s.") % channel)
return
if msg == "off":
caller = caller if not hasattr(caller, "account") else caller.account
muted = channel.mute(caller)
if muted:
self.msg(_("You stop listening to %s.") % channel)
return
self.msg(_("You were already not listening to %s.") % channel)
return
if self.history_start is not None:
# Try to view history
log_file = channel.attributes.get("log_file", default="channel_%s.log" % channel.key)
def send_msg(lines):
return self.msg(
"".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines)
)
tail_log_file(log_file, self.history_start, 20, callback=send_msg)
else:
caller = caller if not hasattr(caller, "account") else caller.account
if caller in channel.mutelist:
self.msg(_("You currently have %s muted.") % channel)
return
channel.msg(msg, senders=self.caller, online=True)
def get_extra_info(self, caller, **kwargs):
"""
Let users know that this command is for communicating on a channel.
Args:
caller (TypedObject): A Character or Account who has entered an ambiguous command.
Returns:
A string with identifying information to disambiguate the object,
conventionally with a preceding space.
"""
return _(" (channel)")
class ChannelHandler(object):
"""
The ChannelHandler manages all active in-game channels and
dynamically creates channel commands for users so that they can
just give the channel's key or alias to write to it. Whenever a
new channel is created in the database, the update() method on
this handler must be called to sync it with the database (this is
done automatically if creating the channel with
evennia.create_channel())
"""
def __init__(self):
"""
Initializes the channel handler's internal state.
"""
self._cached_channel_cmds = {}
self._cached_cmdsets = {}
self._cached_channels = {}
def __str__(self):
"""
Returns the string representation of the handler
"""
return ", ".join(str(cmd) for cmd in self._cached_channel_cmds)
def clear(self):
"""
Reset the cache storage.
"""
self._cached_channel_cmds = {}
self._cached_cmdsets = {}
self._cached_channels = {}
def add(self, channel):
"""
Add an individual channel to the handler. This is called
whenever a new channel is created.
Args:
channel (Channel): The channel to add.
Notes:
To remove a channel, simply delete the channel object and
run self.update on the handler. This should usually be
handled automatically by one of the deletion methos of
the Channel itself.
"""
global _CHANNEL_COMMAND_CLASS
if not _CHANNEL_COMMAND_CLASS:
_CHANNEL_COMMAND_CLASS = class_from_module(settings.CHANNEL_COMMAND_CLASS)
# map the channel to a searchable command
cmd = _CHANNEL_COMMAND_CLASS(
key=channel.key.strip().lower(),
aliases=channel.aliases.all(),
locks="cmd:all();%s" % channel.locks,
help_category="Channel names",
obj=channel,
is_channel=True,
)
# format the help entry
key = channel.key
cmd.__doc__ = cmd.__doc__.format(
channelkey=key,
lower_channelkey=key.strip().lower(),
channeldesc=channel.attributes.get("desc", default="").strip(),
)
self._cached_channel_cmds[channel] = cmd
self._cached_channels[key] = channel
self._cached_cmdsets = {}
add_channel = add # legacy alias
def remove(self, channel):
"""
Remove channel from channelhandler. This will also delete it.
Args:
channel (Channel): Channel to remove/delete.
"""
if channel.pk:
channel.delete()
self.update()
def update(self):
"""
Updates the handler completely, including removing old removed
Channel objects. This must be called after deleting a Channel.
"""
global _CHANNELDB
if not _CHANNELDB:
from evennia.comms.models import ChannelDB as _CHANNELDB
self._cached_channel_cmds = {}
self._cached_cmdsets = {}
self._cached_channels = {}
for channel in _CHANNELDB.objects.get_all_channels():
self.add(channel)
def get(self, channelname=None):
"""
Get a channel from the handler, or all channels
Args:
channelame (str, optional): Channel key, case insensitive.
Returns
channels (list): The matching channels in a list, or all
channels in the handler.
"""
if channelname:
channel = self._cached_channels.get(channelname.lower(), None)
return [channel] if channel else []
return list(self._cached_channels.values())
def get_cmdset(self, source_object):
"""
Retrieve cmdset for channels this source_object has
access to send to.
Args:
source_object (Object): An object subscribing to one
or more channels.
Returns:
cmdsets (list): The Channel-Cmdsets `source_object` has
access to.
"""
if source_object in self._cached_cmdsets:
return self._cached_cmdsets[source_object]
else:
# create a new cmdset holding all viable channels
chan_cmdset = None
chan_cmds = [
channelcmd
for channel, channelcmd in self._cached_channel_cmds.items()
if channel.subscriptions.has(source_object)
and channelcmd.access(source_object, "send")
]
if chan_cmds:
chan_cmdset = cmdset.CmdSet()
chan_cmdset.key = "ChannelCmdSet"
chan_cmdset.priority = 101
chan_cmdset.duplicates = True
for cmd in chan_cmds:
chan_cmdset.add(cmd)
self._cached_cmdsets[source_object] = chan_cmdset
return chan_cmdset
# set up the singleton
CHANNEL_HANDLER = class_from_module(settings.CHANNEL_HANDLER_CLASS)()
CHANNELHANDLER = CHANNEL_HANDLER # legacy

View file

@ -12,8 +12,6 @@ from evennia.comms.managers import ChannelManager
from evennia.utils import create, logger
from evennia.utils.utils import make_iter
_CHANNEL_HANDLER = None
class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
"""
@ -78,13 +76,6 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
self.tags.batch_add(*cdict["tags"])
def basetype_setup(self):
# delayed import of the channelhandler
global _CHANNEL_HANDLER
if not _CHANNEL_HANDLER:
from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNEL_HANDLER
# register ourselves with the channelhandler.
_CHANNEL_HANDLER.add(self)
self.locks.add("send:all();listen:all();control:perm(Admin)")
def at_channel_creation(self):
@ -371,15 +362,12 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
def delete(self):
"""
Deletes channel while also cleaning up channelhandler.
Deletes channel.
"""
self.attributes.clear()
self.aliases.clear()
super().delete()
from evennia.comms.channelhandler import CHANNELHANDLER
CHANNELHANDLER.update()
def channel_prefix(self):
"""

View file

@ -34,8 +34,6 @@ _GA = object.__getattribute__
_SA = object.__setattr__
_DA = object.__delattr__
_CHANNELHANDLER = None
# ------------------------------------------------------------
#
@ -603,9 +601,6 @@ class SubscriptionHandler(object):
no hooks will be called.
"""
global _CHANNELHANDLER
if not _CHANNELHANDLER:
from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER
for subscriber in make_iter(entity):
if subscriber:
clsname = subscriber.__dbclass__.__name__
@ -614,7 +609,6 @@ class SubscriptionHandler(object):
self.obj.db_object_subscriptions.add(subscriber)
elif clsname == "AccountDB":
self.obj.db_account_subscriptions.add(subscriber)
_CHANNELHANDLER._cached_cmdsets.pop(subscriber, None)
self._recache()
def remove(self, entity):
@ -626,9 +620,6 @@ class SubscriptionHandler(object):
entities to un-subscribe from the channel.
"""
global _CHANNELHANDLER
if not _CHANNELHANDLER:
from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER
for subscriber in make_iter(entity):
if subscriber:
clsname = subscriber.__dbclass__.__name__
@ -637,7 +628,6 @@ class SubscriptionHandler(object):
self.obj.db_account_subscriptions.remove(entity)
elif clsname == "ObjectDB":
self.obj.db_object_subscriptions.remove(entity)
_CHANNELHANDLER._cached_cmdsets.pop(subscriber, None)
self._recache()
def all(self):

View file

@ -117,7 +117,11 @@ def check_errors(settings):
"Use PORTAL/SERVER_LOG_DAY_ROTATION and PORTAL/SERVER_LOG_MAX_SIZE "
"to control log cycling."
)
if hasattr(settings, "CHANNEL_COMMAND_CLASS") or hasaattr(settings, "CHANNEL_HANDLER_CLASS"):
raise DeprecationWarning(
"settings.CHANNEL_HANDLER_CLASS and CHANNEL COMMAND_CLASS are "
"unused and should be removed. The ChannelHandler is no more; "
"channels are now handled by aliasing the default 'channel' command.")
def check_warnings(settings):
"""

View file

@ -131,10 +131,9 @@ def create_channels():
goduser = get_god_account()
channel_mudinfo = settings.CHANNEL_MUDINFO
if not channel_mudinfo:
raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.")
channel = create.create_channel(**channel_mudinfo)
channel.connect(goduser)
if channel_mudinfo:
channel = create.create_channel(**channel_mudinfo)
channel.connect(goduser)
channel_connectinfo = settings.CHANNEL_CONNECTINFO
if channel_connectinfo:

View file

@ -36,7 +36,6 @@ from evennia.server.models import ServerConfig
from evennia.utils.utils import get_evennia_version, mod_import, make_iter
from evennia.utils import logger
from evennia.comms import channelhandler
from evennia.server.sessionhandler import SESSIONS
from django.utils.translation import gettext as _
@ -143,9 +142,6 @@ def _server_maintenance():
if _MAINTENANCE_COUNT % 5 == 0:
# check cache size every 5 minutes
_FLUSH_CACHE(_IDMAPPER_CACHE_MAXSIZE)
if _MAINTENANCE_COUNT % 61 == 0:
# validate channels off-sync with scripts
evennia.CHANNEL_HANDLER.update()
if _MAINTENANCE_COUNT % (60 * 7) == 0:
# drop database connection every 7 hrs to avoid default timeouts on MySQL
# (see https://github.com/evennia/evennia/issues/1376)
@ -202,12 +198,6 @@ class Evennia:
self.start_time = time.time()
# initialize channelhandler
try:
channelhandler.CHANNELHANDLER.update()
except OperationalError:
print("channelhandler couldn't update - db not set up")
# wrap the SIGINT handler to make sure we empty the threadpool
# even when we reload and we have long-running requests in queue.
# this is necessary over using Twisted's signal handler.
@ -544,11 +534,10 @@ class Evennia:
god_account = AccountDB.objects.get(id=1)
# mudinfo
mudinfo_chan = settings.CHANNEL_MUDINFO
if not mudinfo_chan:
raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.")
if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]):
channel = create_channel(**mudinfo_chan)
channel.connect(god_account)
if mudinfo_chan:
if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]):
channel = create_channel(**mudinfo_chan)
channel.connect(god_account)
# connectinfo
connectinfo_chan = settings.CHANNEL_MUDINFO
if connectinfo_chan:

View file

@ -57,41 +57,6 @@ class TestServer(TestCase):
self.server._server_maintenance()
mocks["_FLUSH_CACHE"].assert_called_with(1000)
def test__server_maintenance_validate_scripts(self):
with patch.multiple(
"evennia.server.server",
LoopingCall=DEFAULT,
Evennia=DEFAULT,
_FLUSH_CACHE=DEFAULT,
connection=DEFAULT,
_IDMAPPER_CACHE_MAXSIZE=1000,
_MAINTENANCE_COUNT=60 - 1,
_LAST_SERVER_TIME_SNAPSHOT=0,
ServerConfig=DEFAULT,
) as mocks:
mocks["connection"].close = MagicMock()
mocks["ServerConfig"].objects.conf = MagicMock(return_value=100)
self.server._server_maintenance()
mocks["_FLUSH_CACHE"].assert_called_with(1000)
def test__server_maintenance_channel_handler_update(self):
with patch.multiple(
"evennia.server.server",
LoopingCall=DEFAULT,
Evennia=DEFAULT,
_FLUSH_CACHE=DEFAULT,
connection=DEFAULT,
_IDMAPPER_CACHE_MAXSIZE=1000,
_MAINTENANCE_COUNT=61 - 1,
_LAST_SERVER_TIME_SNAPSHOT=0,
ServerConfig=DEFAULT,
) as mocks:
mocks["connection"].close = MagicMock()
mocks["ServerConfig"].objects.conf = MagicMock(return_value=100)
with patch("evennia.server.server.evennia.CHANNEL_HANDLER.update") as mock:
self.server._server_maintenance()
mock.assert_called()
def test__server_maintenance_close_connection(self):
with patch.multiple(
"evennia.server.server",

View file

@ -450,18 +450,6 @@ COMMAND_DEFAULT_ARG_REGEX = None
COMMAND_DEFAULT_MSG_ALL_SESSIONS = False
# The default lockstring of a command.
COMMAND_DEFAULT_LOCKS = ""
# The Channel Handler is responsible for managing all available channels. By
# default it builds the current channels into a channel-cmdset that it feeds
# to the cmdhandler. Overloading this can completely change how Channels
# are identified and called.
CHANNEL_HANDLER_CLASS = "evennia.comms.channelhandler.ChannelHandler"
# The (default) Channel Handler will create a command to represent each
# channel, creating it with the key of the channel, its aliases, locks etc. The
# default class logs channel messages to a file and allows for /history. This
# setting allows to override the command class used with your own.
# If you implement CHANNEL_HANDLER_CLASS, you can change this directly and will
# likely not need this setting.
CHANNEL_COMMAND_CLASS = "evennia.comms.channelhandler.ChannelCommand"
######################################################################
# Typeclasses and other paths
@ -724,36 +712,36 @@ GUEST_LIST = ["Guest" + str(s + 1) for s in range(9)]
# In-game Channels created from server start
######################################################################
# The mudinfo channel must always exist; it is used by Evennia itself to
# relay status messages, connection info etc to staff. The superuser will be
# automatically subscribed to this channel and it will be recreated on a
# reload if deleted. This is a dict specifying the kwargs needed to create
# the channel .
# The mudinfo channel is a read-only channel used by Evennia to replay status
# messages, connection info etc to staff. The superuser will automatically be
# subscribed to this channel. If set to None, the channel is disabled and
# status messages will only be logged (not recommended).
CHANNEL_MUDINFO = {
"key": "MudInfo",
"aliases": "",
"desc": "Connection log",
"locks": "control:perm(Developer);listen:perm(Admin);send:false()",
}
# These are additional channels to offer. Usually, at least 'public'
# should exist. The superuser will automatically be subscribed to all channels
# in this list. New entries will be created on the next reload. But
# removing or updating a same-key channel from this list will NOT automatically
# change/remove it in the game, that needs to be done manually.
# Optional channel (same form as CHANNEL_MUDINFO) that will receive connection
# messages like ("<account> has (dis)connected"). While the MudInfo channel
# will also receieve this info, this channel is meant for non-staffers. If
# None, this information will only be logged.
CHANNEL_CONNECTINFO = None
# New accounts will auto-sub to the default channels given below (but they can
# unsub at any time). Traditionally, at least 'public' should exist. Entries
# will be (re)created on the next reload, but removing or updating a same-key
# channel from this list will NOT automatically change/remove it in the game,
# that needs to be done manually. Note: To create other, non-auto-subbed
# channels, create them manually in server/conf/at_initial_setup.py.
DEFAULT_CHANNELS = [
# public channel
{
"key": "Public",
"aliases": ("pub"),
"aliases": ("pub",),
"desc": "Public discussion",
"locks": "control:perm(Admin);listen:all();send:all()",
"typeclass": BASE_CHANNEL_TYPECLASS,
}
]
# Optional channel info (same form as CHANNEL_MUDINFO) for the channel to
# receive connection messages ("<account> has (dis)connected"). While the
# MudInfo channel will also receieve this info, this channel is meant for
# non-staffers.
CHANNEL_CONNECTINFO = None
######################################################################
# External Connections

View file

@ -32,7 +32,6 @@ _Account = None
_AccountDB = None
_to_object = None
_ChannelDB = None
_channelhandler = None
# limit symbol import from API