mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
202 lines
6.6 KiB
Python
202 lines
6.6 KiB
Python
"""
|
|
This module handles sessions of users connecting
|
|
to the server.
|
|
|
|
Since Evennia supports several different connection
|
|
protocols, it is important to have a joint place
|
|
to store session info. It also makes it easier
|
|
to dispatch data.
|
|
|
|
Whereas server.py handles all setup of the server
|
|
and database itself, this file handles all that
|
|
comes after initial startup.
|
|
|
|
All new sessions (of whatever protocol) are responsible for
|
|
registering themselves with this module.
|
|
|
|
"""
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import User
|
|
from src.config.models import ConfigValue
|
|
|
|
ALLOW_MULTISESSION = settings.ALLOW_MULTISESSION
|
|
|
|
#------------------------------------------------------------
|
|
# SessionHandler class
|
|
#------------------------------------------------------------
|
|
|
|
class SessionHandler(object):
|
|
"""
|
|
This object holds the stack of sessions active in the game at
|
|
any time.
|
|
|
|
A session register with the handler in two steps, first by
|
|
registering itself with the connect() method. This indicates an
|
|
non-authenticated session. Whenever the session is authenticated
|
|
the session together with the related player is sent to the login()
|
|
method.
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""
|
|
Init the handler. We track two types of sessions, those
|
|
who have just connected (unloggedin) and those who have
|
|
logged in (authenticated).
|
|
"""
|
|
self.unloggedin = []
|
|
self.loggedin = []
|
|
|
|
# we keep a link to the server here, for the rest of the game to access.
|
|
self.server = None
|
|
|
|
def add_unloggedin_session(self, session):
|
|
"""
|
|
Call at first connect. This adds a not-yet authenticated session.
|
|
"""
|
|
self.unloggedin.insert(0, session)
|
|
|
|
def add_loggedin_session(self, session):
|
|
"""
|
|
Log in the previously unloggedin session and the player we by
|
|
now should know is connected to it. After this point we
|
|
assume the session to be logged in one way or another.
|
|
"""
|
|
# prep the session with player/user info
|
|
|
|
|
|
if not ALLOW_MULTISESSION:
|
|
# disconnect previous sessions.
|
|
self.disconnect_duplicate_sessions(session)
|
|
|
|
# store/move the session to the right list
|
|
try:
|
|
self.unloggedin.remove(session)
|
|
except ValueError:
|
|
pass
|
|
self.loggedin.insert(0, session)
|
|
self.session_count(1)
|
|
|
|
def remove_session(self, session):
|
|
"""
|
|
Remove session from the handler
|
|
"""
|
|
removed = False
|
|
try:
|
|
self.unloggedin.remove(session)
|
|
except Exception:
|
|
try:
|
|
self.loggedin.remove(session)
|
|
except Exception:
|
|
return
|
|
self.session_count(-1)
|
|
|
|
def get_sessions(self, include_unloggedin=False):
|
|
"""
|
|
Returns the connected session objects.
|
|
"""
|
|
if include_unloggedin:
|
|
return self.loggedin + self.unloggedin
|
|
else:
|
|
return self.loggedin
|
|
|
|
def disconnect_all_sessions(self, reason="You have been disconnected."):
|
|
"""
|
|
Cleanly disconnect all of the connected sessions.
|
|
"""
|
|
sessions = self.get_sessions(include_unloggedin=True)
|
|
for session in sessions:
|
|
session.at_data_out(reason)
|
|
session.session_disconnect()
|
|
self.session_count(0)
|
|
|
|
def disconnect_duplicate_sessions(self, curr_session):
|
|
"""
|
|
Disconnects any existing sessions with the same game object.
|
|
"""
|
|
reason = "Your account has been logged in from elsewhere. Disconnecting."
|
|
curr_char = curr_session.get_character()
|
|
doublet_sessions = [sess for sess in self.get_sessions()
|
|
if sess.get_character() == curr_char and sess != curr_session]
|
|
logged_out = 0
|
|
for session in doublet_sessions:
|
|
session.msg(reason)
|
|
self.remove_session(session)
|
|
logged_out += 1
|
|
self.session_count(-logged_out)
|
|
return logged_out
|
|
|
|
def validate_sessions(self):
|
|
"""
|
|
Check all currently connected sessions (logged in and not)
|
|
and see if any are dead.
|
|
"""
|
|
for session in self.get_sessions(include_unloggedin=True):
|
|
session.session_validate()
|
|
|
|
def session_count(self, num=None):
|
|
"""
|
|
Count up/down the number of connected, authenticated users.
|
|
If num is None, the current number of sessions is returned.
|
|
|
|
num can be a positive or negative value to be added to the current count.
|
|
If 0, the counter will be reset to 0.
|
|
"""
|
|
if num == None:
|
|
# show the current value. This also syncs it.
|
|
return int(ConfigValue.objects.conf('nr_sessions', default=0))
|
|
elif num == 0:
|
|
# reset value to 0
|
|
ConfigValue.objects.conf('nr_sessions', 0)
|
|
else:
|
|
# add/remove session count from value
|
|
add = int(ConfigValue.objects.conf('nr_sessions', default=0))
|
|
num = max(0, num + add)
|
|
ConfigValue.objects.conf('nr_sessions', str(num))
|
|
|
|
def player_count(self):
|
|
"""
|
|
Get the number of connected players (not sessions since a player
|
|
may have more than one session connected if ALLOW_MULTISESSION is True)
|
|
Only logged-in players are counted here.
|
|
"""
|
|
return len(set(sess.uid for sess in self.get_sessions()))
|
|
|
|
def sessions_from_player(self, player):
|
|
"""
|
|
Given a player, return any matching sessions.
|
|
"""
|
|
username = player.user.username
|
|
try:
|
|
uobj = User.objects.get(username=username)
|
|
except User.DoesNotExist:
|
|
return None
|
|
uid = uobj.id
|
|
return [session for session in self.loggedin if session.uid == uid]
|
|
|
|
def sessions_from_character(self, character):
|
|
"""
|
|
Given a game character, return any matching sessions.
|
|
"""
|
|
player = character.player
|
|
if player:
|
|
return self.sessions_from_player(player)
|
|
return None
|
|
|
|
def session_from_suid(self, suid):
|
|
"""
|
|
Given a session id, retrieve the session (this is primarily
|
|
intended to be called by web clients)
|
|
"""
|
|
return [sess for sess in self.get_sessions(include_unloggedin=True) if sess.suid and sess.suid == suid]
|
|
|
|
def announce_all(self, message):
|
|
"""
|
|
Send message to all connected sessions
|
|
"""
|
|
for sess in self.get_sessions(include_unloggedin=True):
|
|
sess.msg(message)
|
|
|
|
SESSIONS = SessionHandler()
|
|
|
|
|