Merge branch 'add_signals' of https://github.com/volundmush/evennia into volundmush-add_signals

This commit is contained in:
Griatch 2019-04-14 22:19:36 +02:00
commit 9e366b757f
5 changed files with 83 additions and 5 deletions

View file

@ -29,6 +29,8 @@ from evennia.utils import class_from_module, create, logger
from evennia.utils.utils import (lazy_property, to_str, from evennia.utils.utils import (lazy_property, to_str,
make_iter, is_iter, make_iter, is_iter,
variable_from_module) variable_from_module)
from evennia.server.signals import (SIGNAL_ACCOUNT_POST_CREATE, SIGNAL_OBJECT_POST_PUPPET,
SIGNAL_OBJECT_POST_UNPUPPET)
from evennia.typeclasses.attributes import NickHandler from evennia.typeclasses.attributes import NickHandler
from evennia.scripts.scripthandler import ScriptHandler from evennia.scripts.scripthandler import ScriptHandler
from evennia.commands.cmdsethandler import CmdSetHandler from evennia.commands.cmdsethandler import CmdSetHandler
@ -52,6 +54,7 @@ _CONNECT_CHANNEL = None
CREATION_THROTTLE = Throttle(limit=2, timeout=10 * 60) CREATION_THROTTLE = Throttle(limit=2, timeout=10 * 60)
LOGIN_THROTTLE = Throttle(limit=5, timeout=5 * 60) LOGIN_THROTTLE = Throttle(limit=5, timeout=5 * 60)
class AccountSessionHandler(object): class AccountSessionHandler(object):
""" """
Manages the session(s) attached to an account. Manages the session(s) attached to an account.
@ -312,6 +315,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
obj.locks.cache_lock_bypass(obj) obj.locks.cache_lock_bypass(obj)
# final hook # final hook
obj.at_post_puppet() obj.at_post_puppet()
SIGNAL_OBJECT_POST_PUPPET.send(sender=obj, account=self, session=session)
def unpuppet_object(self, session): def unpuppet_object(self, session):
""" """
@ -334,6 +338,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
if not obj.sessions.count(): if not obj.sessions.count():
del obj.account del obj.account
obj.at_post_unpuppet(self, session=session) obj.at_post_unpuppet(self, session=session)
SIGNAL_OBJECT_POST_UNPUPPET.send(sender=obj, session=session, account=self)
# Just to be sure we're always clear. # Just to be sure we're always clear.
session.puppet = None session.puppet = None
session.puid = None session.puid = None
@ -746,7 +751,9 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
logger.log_trace() logger.log_trace()
# Update the throttle to indicate a new account was created from this IP # Update the throttle to indicate a new account was created from this IP
if ip and not guest: CREATION_THROTTLE.update(ip, 'Too many accounts being created.') if ip and not guest:
CREATION_THROTTLE.update(ip, 'Too many accounts being created.')
SIGNAL_ACCOUNT_POST_CREATE.send(sender=account, ip=ip)
return account, errors return account, errors
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):

View file

@ -25,6 +25,7 @@ from django.utils.encoding import smart_str
from evennia.accounts.manager import AccountDBManager from evennia.accounts.manager import AccountDBManager
from evennia.typeclasses.models import TypedObject from evennia.typeclasses.models import TypedObject
from evennia.utils.utils import make_iter from evennia.utils.utils import make_iter
from evennia.server.signals import SIGNAL_ACCOUNT_POST_RENAME
__all__ = ("AccountDB",) __all__ = ("AccountDB",)
@ -146,8 +147,10 @@ class AccountDB(TypedObject, AbstractUser):
return self.username return self.username
def __username_set(self, value): def __username_set(self, value):
old_name = self.username
self.username = value self.username = value
self.save(update_fields=["username"]) self.save(update_fields=["username"])
SIGNAL_ACCOUNT_POST_RENAME.send(self, old_name=old_name, new_name=value)
def __username_del(self): def __username_del(self):
del self.username del self.username

View file

@ -20,12 +20,12 @@ from django.conf import settings
from evennia.commands.cmdhandler import CMD_LOGINSTART from evennia.commands.cmdhandler import CMD_LOGINSTART
from evennia.utils.logger import log_trace from evennia.utils.logger import log_trace
from evennia.utils.utils import (variable_from_module, is_iter, from evennia.utils.utils import (variable_from_module, is_iter,
to_str, make_iter, delay, callables_from_module) make_iter, delay, callables_from_module)
from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT
from evennia.server.signals import SIGNAL_ACCOUNT_POST_CONNECT, SIGNAL_ACCOUNT_POST_DISCONNECT
from evennia.utils.inlinefuncs import parse_inlinefunc from evennia.utils.inlinefuncs import parse_inlinefunc
from codecs import decode as codecs_decode from codecs import decode as codecs_decode
import pickle
_INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED _INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED
# delayed imports # delayed imports
@ -483,7 +483,6 @@ class ServerSessionHandler(SessionHandler):
faking login without any AMP being actually active. faking login without any AMP being actually active.
""" """
if session.logged_in and not force: if session.logged_in and not force:
# don't log in a session that is already logged in. # don't log in a session that is already logged in.
return return
@ -519,6 +518,9 @@ class ServerSessionHandler(SessionHandler):
sessiondata={"logged_in": True, sessiondata={"logged_in": True,
"uid": session.uid}) "uid": session.uid})
account.at_post_login(session=session) account.at_post_login(session=session)
if nsess < 2:
SIGNAL_ACCOUNT_POST_LOGIN.send(sender=account, session=session)
SIGNAL_ACCOUNT_POST_CONNECT.send(sender=account, session=session)
def disconnect(self, session, reason="", sync_portal=True): def disconnect(self, session, reason="", sync_portal=True):
""" """
@ -545,7 +547,11 @@ class ServerSessionHandler(SessionHandler):
string = string.format(reason=sreason, account=session.account, address=session.address, nsessions=nsess) string = string.format(reason=sreason, account=session.account, address=session.address, nsessions=nsess)
session.log(string) session.log(string)
if nsess == 0:
SIGNAL_ACCOUNT_POST_LOGOUT.send(sender=session.account, session=session)
session.at_disconnect(reason) session.at_disconnect(reason)
SIGNAL_ACCOUNT_POST_DISCONNECT.send(sender=session.account, session=session)
sessid = session.sessid sessid = session.sessid
if sessid in self and not hasattr(self, "_disconnect_all"): if sessid in self and not hasattr(self, "_disconnect_all"):
del self[sessid] del self[sessid]

60
evennia/server/signals.py Normal file
View file

@ -0,0 +1,60 @@
"""
This module brings Django Signals into Evennia. These are events that
can be subscribed to by importing a given Signal and using the
following code.
THIS_SIGNAL.connect(callback, sender_object)
When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback
will be triggered.
Callbacks must be in the following format:
def my_callback(sender, **kwargs):
...
This is used on top of hooks to make certain features easier to
add to contribs without necessitating a full takeover of hooks
that may be in high demand.
"""
from django.dispatch import Signal
# The sender is the created Account. This is triggered at the very end of Account.create()
# after the Account is created.
SIGNAL_ACCOUNT_POST_CREATE = Signal(providing_args=['ip', ])
# The Sender is the renamed Account. This is triggered by the username setter in AccountDB.
SIGNAL_ACCOUNT_POST_RENAME = Signal(providing_args=['old_name', 'new_name'])
# The Sender is the connecting Account. This is triggered when an Account connects cold;
# that is, it had no other sessions connected.
SIGNAL_ACCOUNT_POST_LOGIN = Signal(providing_args=['session', ])
# The Sender is the Account attempting to authenticate. This is triggered whenever a
# session tries to login to an Account but fails.
SIGNAL_ACCOUNT_POST_LOGIN_FAIL = Signal(providing_args=['session', ])
# The sender is the connecting Account. This is triggered whenever a session authenticates
# to an Account regardless of existing sessions.
SIGNAL_ACCOUNT_POST_CONNECT = Signal(providing_args=['session', ])
# The sender is the Account. This is triggered when an Account's final session disconnects.
SIGNAL_ACCOUNT_POST_LOGOUT = Signal(providing_args=['session', ])
# The sender is the disconnecting Account. This is triggered whenever a session disconnects
# from the account, regardless of how many it started with or remain.
SIGNAL_ACCOUNT_POST_DISCONNECT = Signal(providing_args=['session', ])
# The sender is the Object being puppeted. This is triggered after all puppeting hooks have
# been called. The Object has already been puppeted by this point.
SIGNAL_OBJECT_POST_PUPPET = Signal(providing_args=['session', 'account'])
# The sender is the Object being released. This is triggered after all hooks are called.
# The Object is no longer puppeted by this point.
SIGNAL_OBJECT_POST_UNPUPPET = Signal(providing_args=['session', 'account'])
# The sender is the Typed Object being released. This isn't necessarily an Object;
# it could be a script. It fires whenever the value of the Typed object's 'key'
# changes. Will need to use isinstance() or other filtering on things that use this.
SIGNAL_TYPED_OBJECT_POST_RENAME = Signal(providing_args=['old_key', 'new_key'])

View file

@ -42,6 +42,7 @@ from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttribu
from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler
from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase
from evennia.server.signals import SIGNAL_TYPED_OBJECT_POST_RENAME
from evennia.typeclasses import managers from evennia.typeclasses import managers
from evennia.locks.lockhandler import LockHandler from evennia.locks.lockhandler import LockHandler
@ -326,6 +327,7 @@ class TypedObject(SharedMemoryModel):
self.db_key = value self.db_key = value
self.save(update_fields=["db_key"]) self.save(update_fields=["db_key"])
self.at_rename(oldname, value) self.at_rename(oldname, value)
SIGNAL_TYPED_OBJECT_POST_RENAME.send(sender=self, old_key=oldname, new_key=value)
# #
# #