Fixed an elusive bug in utils.get_variable_from_module() that caused the connection screen to sometimes not load properly, due to the imported modules being erroneously extracted and used.

This commit is contained in:
Griatch 2012-04-15 19:05:50 +02:00
parent 5264dc85bb
commit 6501f30cbc
7 changed files with 80 additions and 78 deletions

View file

@ -40,7 +40,6 @@ from traceback import format_exc
from twisted.internet.defer import inlineCallbacks, returnValue from twisted.internet.defer import inlineCallbacks, returnValue
from django.conf import settings from django.conf import settings
from src.comms.channelhandler import CHANNELHANDLER from src.comms.channelhandler import CHANNELHANDLER
from src.commands.cmdsethandler import import_cmdset
from src.utils import logger, utils from src.utils import logger, utils
from src.commands.cmdparser import at_multimatch_cmd from src.commands.cmdparser import at_multimatch_cmd
@ -150,7 +149,6 @@ def get_and_merge_cmdsets(caller):
for cset in (cset for cset in local_objects_cmdsets if cset): for cset in (cset for cset in local_objects_cmdsets if cset):
cset.duplicates = cset.old_duplicates cset.duplicates = cset.old_duplicates
returnValue(cmdset) returnValue(cmdset)
@ -255,7 +253,6 @@ def cmdhandler(caller, raw_string, testing=False):
caller.ndb.last_cmd = yield copy(cmd) caller.ndb.last_cmd = yield copy(cmd)
else: else:
caller.ndb.last_cmd = None caller.ndb.last_cmd = None
# Done! This returns a deferred. By default, Evennia does # Done! This returns a deferred. By default, Evennia does
# not use this at all. # not use this at all.
returnValue(ret) returnValue(ret)

View file

@ -55,7 +55,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
and (not cmd.arg_regex or and (not cmd.arg_regex or
cmd.arg_regex.match(l_raw_string[len(cmdname):]))]) cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
except Exception: except Exception:
log_trace() log_trace("raw_input:%s" % raw_string)
if not matches: if not matches:
# no matches found. # no matches found.

View file

@ -3,9 +3,8 @@ Commands that are available from the connect screen.
""" """
import re import re
import traceback import traceback
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from src.server import sessionhandler
from src.players.models import PlayerDB from src.players.models import PlayerDB
from src.objects.models import ObjectDB from src.objects.models import ObjectDB
from src.server.models import ServerConfig from src.server.models import ServerConfig
@ -19,16 +18,24 @@ from src.commands.cmdhandler import CMD_LOGINSTART
__all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate", "CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp") __all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate", "CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp")
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
CONNECTION_SCREEN = ""
try:
CONNECTION_SCREEN = ansi.parse_ansi(utils.string_from_module(CONNECTION_SCREEN_MODULE))
except Exception:
pass
if not CONNECTION_SCREEN:
CONNECTION_SCREEN = "\nEvennia: Error in CONNECTION_SCREEN MODULE. Connect screen not found. Enter 'help' for aid."
class CmdUnconnectedConnect(MuxCommand): class CmdUnconnectedConnect(MuxCommand):
""" """
Connect to the game. Connect to the game.
Usage (at login screen): Usage (at login screen):
connect <email> <password> connect <email> <password>
Use the create command to first create an account before logging in. Use the create command to first create an account before logging in.
""" """
key = "connect" key = "connect"
aliases = ["conn", "con", "co"] aliases = ["conn", "con", "co"]
locks = "cmd:all()" # not really needed locks = "cmd:all()" # not really needed
@ -42,7 +49,7 @@ class CmdUnconnectedConnect(MuxCommand):
there is no object yet before the player has logged in) there is no object yet before the player has logged in)
""" """
session = self.caller session = self.caller
arglist = self.arglist arglist = self.arglist
if not arglist or len(arglist) < 2: if not arglist or len(arglist) < 2:
@ -50,7 +57,7 @@ class CmdUnconnectedConnect(MuxCommand):
return return
email = arglist[0] email = arglist[0]
password = arglist[1] password = arglist[1]
# Match an email address to an account. # Match an email address to an account.
player = PlayerDB.objects.get_player_from_email(email) player = PlayerDB.objects.get_player_from_email(email)
# No playername match # No playername match
@ -63,21 +70,21 @@ class CmdUnconnectedConnect(MuxCommand):
# We have at least one result, so we can check the password. # We have at least one result, so we can check the password.
if not player.user.check_password(password): if not player.user.check_password(password):
session.msg("Incorrect password.") session.msg("Incorrect password.")
return return
# Check IP and/or name bans # Check IP and/or name bans
bans = ServerConfig.objects.conf("server_bans") bans = ServerConfig.objects.conf("server_bans")
if bans and (any(tup[0]==player.name for tup in bans) if bans and (any(tup[0]==player.name for tup in bans)
or or
any(tup[2].match(session.address[0]) for tup in bans if tup[2])): any(tup[2].match(session.address[0]) for tup in bans if tup[2])):
# this is a banned IP or name! # this is a banned IP or name!
string = "{rYou have been banned and cannot continue from here." string = "{rYou have been banned and cannot continue from here."
string += "\nIf you feel this ban is in error, please email an admin.{x" string += "\nIf you feel this ban is in error, please email an admin.{x"
session.msg(string) session.msg(string)
session.execute_cmd("quit") session.execute_cmd("quit")
return return
# actually do the login. This will call all hooks. # actually do the login. This will call all hooks.
session.session_login(player) session.session_login(player)
# we are logged in. Look around. # we are logged in. Look around.
@ -102,7 +109,7 @@ class CmdUnconnectedCreate(MuxCommand):
key = "create" key = "create"
aliases = ["cre", "cr"] aliases = ["cre", "cr"]
locks = "cmd:all()" locks = "cmd:all()"
def parse(self): def parse(self):
""" """
The parser must handle the multiple-word player The parser must handle the multiple-word player
@ -113,16 +120,16 @@ class CmdUnconnectedCreate(MuxCommand):
self.playerinfo = [] self.playerinfo = []
if len(self.arglist) < 3: if len(self.arglist) < 3:
return return
if len(self.arglist) > 3: if len(self.arglist) > 3:
# this means we have a multi_word playername. pop from the back. # this means we have a multi_word playername. pop from the back.
password = self.arglist.pop() password = self.arglist.pop()
email = self.arglist.pop() email = self.arglist.pop()
# what remains is the playername. # what remains is the playername.
playername = " ".join(self.arglist) playername = " ".join(self.arglist)
else: else:
playername, email, password = self.arglist playername, email, password = self.arglist
playername = playername.replace('"', '') # remove " playername = playername.replace('"', '') # remove "
playername = playername.replace("'", "") playername = playername.replace("'", "")
self.playerinfo = (playername, email, password) self.playerinfo = (playername, email, password)
@ -132,46 +139,46 @@ class CmdUnconnectedCreate(MuxCommand):
session = self.caller session = self.caller
try: try:
playername, email, password = self.playerinfo playername, email, password = self.playerinfo
except ValueError: except ValueError:
string = "\n\r Usage (without <>): create \"<playername>\" <email> <password>" string = "\n\r Usage (without <>): create \"<playername>\" <email> <password>"
session.msg(string) session.msg(string)
return return
if not re.findall('^[\w. @+-]+$', playername) or not (0 < len(playername) <= 30): if not re.findall('^[\w. @+-]+$', playername) or not (0 < len(playername) <= 30):
session.msg("\n\r Playername can max be 30 characters or fewer. Letters, spaces, dig\ session.msg("\n\r Playername can max be 30 characters or fewer. Letters, spaces, dig\
its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth module. its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth module.
return return
if not email or not password: if not email or not password:
session.msg("\n\r You have to supply an e-mail address followed by a password." ) session.msg("\n\r You have to supply an e-mail address followed by a password." )
return return
if not utils.validate_email_address(email): if not utils.validate_email_address(email):
# check so the email at least looks ok. # check so the email at least looks ok.
session.msg("'%s' is not a valid e-mail address." % email) session.msg("'%s' is not a valid e-mail address." % email)
return return
# Run sanity and security checks
# Run sanity and security checks
if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername): if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername):
# player already exists # player already exists
session.msg("Sorry, there is already a player with the name '%s'." % playername) session.msg("Sorry, there is already a player with the name '%s'." % playername)
return return
if PlayerDB.objects.get_player_from_email(email): if PlayerDB.objects.get_player_from_email(email):
# email already set on a player # email already set on a player
session.msg("Sorry, there is already a player with that email address.") session.msg("Sorry, there is already a player with that email address.")
return return
if len(password) < 3: if len(password) < 3:
# too short password # too short password
string = "Your password must be at least 3 characters or longer." string = "Your password must be at least 3 characters or longer."
string += "\n\rFor best security, make it at least 8 characters long, " string += "\n\rFor best security, make it at least 8 characters long, "
string += "avoid making it a real word and mix numbers into it." string += "avoid making it a real word and mix numbers into it."
session.msg(string) session.msg(string)
return return
# everything's ok. Create the new player account. # everything's ok. Create the new player account.
try: try:
default_home = ObjectDB.objects.get_id(settings.CHARACTER_DEFAULT_HOME) default_home = ObjectDB.objects.get_id(settings.CHARACTER_DEFAULT_HOME)
typeclass = settings.BASE_CHARACTER_TYPECLASS typeclass = settings.BASE_CHARACTER_TYPECLASS
permissions = settings.PERMISSION_PLAYER_DEFAULT permissions = settings.PERMISSION_PLAYER_DEFAULT
@ -180,43 +187,43 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m
permissions=permissions, permissions=permissions,
character_typeclass=typeclass, character_typeclass=typeclass,
character_location=default_home, character_location=default_home,
character_home=default_home) character_home=default_home)
if not new_character: if not new_character:
session.msg("There was an error creating the default Character/Player. This error was logged. Contact an admin.") session.msg("There was an error creating the default Character/Player. This error was logged. Contact an admin.")
return return
new_player = new_character.player new_player = new_character.player
# This needs to be called so the engine knows this player is logging in for the first time. # This needs to be called so the engine knows this player is logging in for the first time.
# (so it knows to call the right hooks during login later) # (so it knows to call the right hooks during login later)
utils.init_new_player(new_player) utils.init_new_player(new_player)
# join the new player to the public channel # join the new player to the public channel
pchanneldef = settings.CHANNEL_PUBLIC pchanneldef = settings.CHANNEL_PUBLIC
if pchanneldef: if pchanneldef:
pchannel = Channel.objects.get_channel(pchanneldef[0]) pchannel = Channel.objects.get_channel(pchanneldef[0])
if not pchannel.connect_to(new_player): if not pchannel.connect_to(new_player):
string = "New player '%s' could not connect to public channel!" % new_player.key string = "New player '%s' could not connect to public channel!" % new_player.key
logger.log_errmsg(string) logger.log_errmsg(string)
# allow only the character itself and the player to puppet this character (and Immortals). # allow only the character itself and the player to puppet this character (and Immortals).
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" % new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
(new_character.id, new_player.id)) (new_character.id, new_player.id))
# set a default description # set a default description
new_character.db.desc = "This is a Player." new_character.db.desc = "This is a Player."
# tell the caller everything went well. # tell the caller everything went well.
string = "A new account '%s' was created with the email address %s. Welcome!" string = "A new account '%s' was created with the email address %s. Welcome!"
string += "\n\nYou can now log with the command 'connect %s <your password>'." string += "\n\nYou can now log with the command 'connect %s <your password>'."
session.msg(string % (playername, email, email)) session.msg(string % (playername, email, email))
except Exception: except Exception:
# We are in the middle between logged in and -not, so we have to handle tracebacks # We are in the middle between logged in and -not, so we have to handle tracebacks
# ourselves at this point. If we don't, we won't see any errors at all. # ourselves at this point. If we don't, we won't see any errors at all.
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists." string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
session.msg(string % (traceback.format_exc())) session.msg(string % (traceback.format_exc()))
logger.log_errmsg(traceback.format_exc()) logger.log_errmsg(traceback.format_exc())
class CmdUnconnectedQuit(MuxCommand): class CmdUnconnectedQuit(MuxCommand):
""" """
@ -236,29 +243,23 @@ class CmdUnconnectedQuit(MuxCommand):
class CmdUnconnectedLook(MuxCommand): class CmdUnconnectedLook(MuxCommand):
""" """
This is an unconnected version of the look command for simplicity. This is an unconnected version of the look command for simplicity.
This is called by the server and kicks everything in gear. This is called by the server and kicks everything in gear.
All it does is display the connect screen. All it does is display the connect screen.
""" """
key = CMD_LOGINSTART key = CMD_LOGINSTART
aliases = ["look", "l"] aliases = ["look", "l"]
locks = "cmd:all()" locks = "cmd:all()"
def func(self): def func(self):
"Show the connect screen." "Show the connect screen."
try: self.caller.msg(CONNECTION_SCREEN)
screen = utils.string_from_module(CONNECTION_SCREEN_MODULE)
string = ansi.parse_ansi(screen)
self.caller.msg(string)
except Exception, e:
self.caller.msg("Error in CONNECTION_SCREEN MODULE: " + str(e))
self.caller.msg("Connect screen not found. Enter 'help' for aid.")
class CmdUnconnectedHelp(MuxCommand): class CmdUnconnectedHelp(MuxCommand):
""" """
This is an unconnected version of the help command, This is an unconnected version of the help command,
for simplicity. It shows a pane of info. for simplicity. It shows a pane of info.
""" """
key = "help" key = "help"
aliases = ["h", "?"] aliases = ["h", "?"]
@ -266,7 +267,7 @@ class CmdUnconnectedHelp(MuxCommand):
def func(self): def func(self):
"Shows help" "Shows help"
string = \ string = \
""" """
You are not yet logged into the game. Commands available at this point: You are not yet logged into the game. Commands available at this point:
@ -280,18 +281,18 @@ To login to the system, you need to do one of the following:
{wcreate "Anna the Barbarian" anna@myemail.com c67jHL8p{n {wcreate "Anna the Barbarian" anna@myemail.com c67jHL8p{n
It's always a good idea (not only here, but everywhere on the net) It's always a good idea (not only here, but everywhere on the net)
to not use a regular word for your password. Make it longer than to not use a regular word for your password. Make it longer than
3 characters (ideally 6 or more) and mix numbers and capitalization 3 characters (ideally 6 or more) and mix numbers and capitalization
into it. into it.
{w2){n If you have an account already, either because you just created {w2){n If you have an account already, either because you just created
one in {w1){n above or you are returning, use the 'connect' command: one in {w1){n above or you are returning, use the 'connect' command:
{wconnect anna@myemail.com c67jHL8p{n {wconnect anna@myemail.com c67jHL8p{n
This should log you in. Run {whelp{n again once you're logged in This should log you in. Run {whelp{n again once you're logged in
to get more aid. Hope you enjoy your stay! to get more aid. Hope you enjoy your stay!
You can use the {wlook{n command if you want to see the connect screen again. You can use the {wlook{n command if you want to see the connect screen again.
""" """
self.caller.msg(string) self.caller.msg(string)

View file

@ -55,7 +55,6 @@ class ServerSession(Session):
self.cmdset = cmdsethandler.CmdSetHandler(self) self.cmdset = cmdsethandler.CmdSetHandler(self)
self.cmdset_storage = [settings.CMDSET_UNLOGGEDIN] self.cmdset_storage = [settings.CMDSET_UNLOGGEDIN]
self.cmdset.update(init_mode=True) self.cmdset.update(init_mode=True)
self.cmdset.update(init_mode=True)
return return
character = self.get_character() character = self.get_character()
@ -192,7 +191,6 @@ class ServerSession(Session):
# all other inputs, including empty inputs # all other inputs, including empty inputs
character = self.get_character() character = self.get_character()
if character: if character:
character.execute_cmd(command_string) character.execute_cmd(command_string)
else: else:
@ -227,7 +225,6 @@ class ServerSession(Session):
"update_counter", (["counter1"], {"now":True}) } "update_counter", (["counter1"], {"now":True}) }
""" """
print "server: "
outdata = {} outdata = {}
entity = self.get_character() entity = self.get_character()

View file

@ -16,7 +16,6 @@ import time
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from src.server.models import ServerConfig from src.server.models import ServerConfig
from src.utils import utils
from src.commands.cmdhandler import CMD_LOGINSTART from src.commands.cmdhandler import CMD_LOGINSTART
@ -210,7 +209,7 @@ class ServerSessionHandler(SessionHandler):
if sess.logged_in if sess.logged_in
and sess.get_character() == curr_char and sess.get_character() == curr_char
and sess != curr_session] and sess != curr_session]
for sessid in doublet_sessions: for session in doublet_sessions:
self.disconnect(session, reason) self.disconnect(session, reason)
self.session_count(-1) self.session_count(-1)
@ -414,6 +413,7 @@ class PortalSessionHandler(SessionHandler):
in from the protocol to the server. data is in from the protocol to the server. data is
serialized before passed on. serialized before passed on.
""" """
print "portal_data_in:", string
self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid, self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid,
msg=string, msg=string,
data=data) data=data)
@ -437,6 +437,7 @@ class PortalSessionHandler(SessionHandler):
""" """
OOB (Out-of-band) data Portal -> Server OOB (Out-of-band) data Portal -> Server
""" """
print "portal_oob_data_in:", data
self.portal.amp_protocol.call_remote_OOBPortal2Server(session.sessid, self.portal.amp_protocol.call_remote_OOBPortal2Server(session.sessid,
data=data) data=data)
@ -444,6 +445,7 @@ class PortalSessionHandler(SessionHandler):
""" """
OOB (Out-of-band) data Server -> Portal OOB (Out-of-band) data Server -> Portal
""" """
print "portal_oob_data_out:", data
session = self.sessions.get(sessid, None) session = self.sessions.get(sessid, None)
if session: if session:
session.oob_data_out(data) session.oob_data_out(data)

View file

@ -78,20 +78,24 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
starts with IAC (a telnet command) or not. All other data will starts with IAC (a telnet command) or not. All other data will
be handled in line mode. be handled in line mode.
""" """
# print "dataRcv:", data, print "dataRcv (%s):" % data,
# try: try:
# for b in data: for b in data:
# print ord(b), print ord(b),
# print "" print ""
# except Exception, e: except Exception, e:
# print str(e) + ":", str(data) print str(e) + ":", str(data)
if data and data[0] == IAC: if data and data[0] == IAC:
try: try:
print "IAC mode"
super(TelnetProtocol, self).dataReceived(data) super(TelnetProtocol, self).dataReceived(data)
return return
except Exception: except Exception:
pass pass
# if we get to this point the command must end with a linebreak.
#data = data.rstrip("\r\n") + "\r\n"
print "line mode: (%s)" % data
StatefulTelnetProtocol.dataReceived(self, data) StatefulTelnetProtocol.dataReceived(self, data)
def _write(self, data): def _write(self, data):

View file

@ -6,6 +6,7 @@ be of use when designing your own game.
""" """
from inspect import ismodule
import os, sys, imp import os, sys, imp
import textwrap import textwrap
import datetime import datetime
@ -623,7 +624,7 @@ def variable_from_module(modpath, variable=None, default=None):
return mod.__dict__.get(variable, default) return mod.__dict__.get(variable, default)
else: else:
# random selection # random selection
mvars = [val for key, val in mod.__dict__.items() if not key.startswith("_")] mvars = [val for key, val in mod.__dict__.items() if not (key.startswith("_") or ismodule(val))]
return mvars and random.choice(mvars) return mvars and random.choice(mvars)
def string_from_module(modpath, variable=None, default=None): def string_from_module(modpath, variable=None, default=None):