From: <umg...@us...> - 2007-07-10 17:25:04
|
Revision: 471 http://svn.sourceforge.net/pybridge/?rev=471&view=rev Author: umgangee Date: 2007-07-10 10:25:05 -0700 (Tue, 10 Jul 2007) Log Message: ----------- Tidy up server stuff, particularly the server 'hub'. Modified Paths: -------------- trunk/pybridge/pybridge/server/__init__.py trunk/pybridge/pybridge/server/checker.py trunk/pybridge/pybridge/server/realm.py trunk/pybridge/pybridge/server/server.py trunk/pybridge/pybridge/server/user.py Modified: trunk/pybridge/pybridge/server/__init__.py =================================================================== --- trunk/pybridge/pybridge/server/__init__.py 2007-07-10 17:19:10 UTC (rev 470) +++ trunk/pybridge/pybridge/server/__init__.py 2007-07-10 17:25:05 UTC (rev 471) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# Copyright (C) 2004-2007 PyBridge Project. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -10,29 +10,22 @@ # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. - +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -from twisted.cred import checkers, credentials, portal -from twisted.spread import pb - import config config.load() +from twisted.cred import portal +from twisted.spread import pb from pybridge.server.checker import Checker from pybridge.server.realm import Realm -from pybridge.server.server import Server -server = Server() realm = Realm() checker = Checker() - -realm.server = server -checker.users = server.users - p = portal.Portal(realm) p.registerChecker(checker) Modified: trunk/pybridge/pybridge/server/checker.py =================================================================== --- trunk/pybridge/pybridge/server/checker.py 2007-07-10 17:19:10 UTC (rev 470) +++ trunk/pybridge/pybridge/server/checker.py 2007-07-10 17:25:05 UTC (rev 471) @@ -22,9 +22,10 @@ from zope.interface import implements import database as db +import server -class Checker: +class Checker(object): """A database-driven implementation of ICredentialsChecker.""" implements(checkers.ICredentialsChecker) @@ -33,10 +34,6 @@ credentials.IUsernameHashedPassword) - def __init__(self): - self.users = {} # Users online, from Server object. - - def requestAvatarId(self, credentials): def unauthorized(reason): @@ -52,16 +49,16 @@ if credentials.username == '': return checkers.ANONYMOUS # TODO: if allowAnonymousRegistration. - users = db.UserAccount.selectBy(username=credentials.username) - if users.count() is 0: - return unauthorized("User not known on server") - elif users[0].allowLogin is False: + userQuery = db.UserAccount.selectBy(username=credentials.username) + if userQuery.count() == 0: + return unauthorized("User account does not exist on server") + elif userQuery[0].allowLogin is False: # TODO: list index breaks on MySQL. return unauthorized("User account is disabled") - elif credentials.username in self.users: + elif credentials.username in server.onlineUsers: # TODO: delete old session and use this one instead? return unauthorized("User is already logged in") - d = defer.maybeDeferred(credentials.checkPassword, users[0].password) + d = defer.maybeDeferred(credentials.checkPassword, userQuery[0].password) d.addCallback(passwordMatch) return d - + Modified: trunk/pybridge/pybridge/server/realm.py =================================================================== --- trunk/pybridge/pybridge/server/realm.py 2007-07-10 17:19:10 UTC (rev 470) +++ trunk/pybridge/pybridge/server/realm.py 2007-07-10 17:25:05 UTC (rev 471) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# Copyright (C) 2004-2007 PyBridge Project. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -10,7 +10,7 @@ # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. - +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -18,13 +18,14 @@ from twisted.cred import checkers, portal from twisted.spread import pb +from zope.interface import implements -from user import User, AnonymousUser +from user import AnonymousUser, RegisteredUser -class Realm: +class Realm(object): - __implements__ = portal.IRealm + implements(portal.IRealm) def requestAvatar(self, avatarId, mind, *interfaces): @@ -33,11 +34,9 @@ if avatarId == checkers.ANONYMOUS: avatar = AnonymousUser() - avatar.server = self.server # Provide reference to server. return pb.IPerspective, avatar, lambda:None else: - avatar = User(avatarId) - avatar.server = self.server # Provide reference to server. + avatar = RegisteredUser(avatarId) avatar.attached(mind) return pb.IPerspective, avatar, lambda a=avatar:a.detached(mind) Modified: trunk/pybridge/pybridge/server/server.py =================================================================== --- trunk/pybridge/pybridge/server/server.py 2007-07-10 17:19:10 UTC (rev 470) +++ trunk/pybridge/pybridge/server/server.py 2007-07-10 17:25:05 UTC (rev 471) @@ -20,7 +20,7 @@ from twisted.python import log import database as db -from pybridge import __version__ +from pybridge import __version__ as version from pybridge.network.error import DeniedRequest, IllegalRequest from pybridge.network.localtable import LocalTable @@ -30,62 +30,54 @@ from pybridge.bridge.game import BridgeGame -class Server(object): +availableTables = LocalTableManager() +onlineUsers = LocalUserManager() - def __init__(self): - # Set up rosters. - self.tables = LocalTableManager() - self.users = LocalUserManager() +def getServerInfo(): + return {'supported': (version, version), # minimum, maximum + 'version': version} - self.version = __version__ - self.supported = ['bridge'] - - def userConnects(self, user): - """""" - log.msg("User %s connected" % user.name) - self.users.userLogin(user) - db.UserAccount.byUsername(user.name).set(lastLogin=datetime.now()) - - - def userDisconnects(self, user): - """""" - log.msg("User %s disconnected" % user.name) - self.users.userLogout(user) - - # Methods invoked by user perspectives. - def registerUser(self, username, password): - """Registers a new user account in the database. - - @param username: the unique username requested by user. - @param password: the password to be associated with the account. - """ - # Check that username has not already been registered. - if db.UserAccount.selectBy(username=username).count() > 0: - raise DeniedRequest, "Username already registered" - try: - # Create user account. - db.UserAccount(username=username, password=password, allowLogin=True) - log.msg("New user %s registered" % username) - except ValueError, err: - raise IllegalRequest, err +def registerUser(username, password): + """Registers a new user account in the database. + + @param username: the unique username requested by user. + @param password: the password to be associated with the account. + """ + # Check that username has not already been registered. + if db.UserAccount.selectBy(username=username).count() > 0: + raise DeniedRequest, "Username already registered" + try: + # Create user account. + db.UserAccount(username=username, password=password, allowLogin=True) + log.msg("New user %s registered" % username) + except ValueError, err: + raise IllegalRequest, err - def userChangePassword(self, user, password): - """""" - pass +def changePasswordOfUser(username, password): + """Sets the password of user to specified password. + + @param username: the user identifier. + @param password: the new password for user. + """ + pass # TODO implement - def createTable(self, tableid, tabletype): - # Ignore specified tabletype, for now. - if tableid not in self.tables: - table = LocalTable(tableid, BridgeGame) - table.id = tableid - table.server = self - self.tables.openTable(table) - #self.tables[tableid] = table +def createTable(tableid, gametype): + """Create a new table for the specified game type. + + @param tableid: a unique identifier for the table. + @param gametype: a game identifier. + """ + # TODO: convert gametype string to corresponding class. + if tableid not in availableTables: + table = LocalTable(tableid, BridgeGame) # Ignore gametype for now. + # Provide table instance with a means of closing itself. + table.close = lambda: availableTables.closeTable(table) + availableTables.openTable(table) Modified: trunk/pybridge/pybridge/server/user.py =================================================================== --- trunk/pybridge/pybridge/server/user.py 2007-07-10 17:19:10 UTC (rev 470) +++ trunk/pybridge/pybridge/server/user.py 2007-07-10 17:25:05 UTC (rev 471) @@ -16,60 +16,58 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +from datetime import datetime import re -#from twisted.internet import defer -#from twisted.python import failure +from twisted.python import log from twisted.spread import pb from pybridge.network.error import DeniedRequest, IllegalRequest +import database as db +import server -class User(pb.Avatar): +class RegisteredUser(pb.Avatar): + info = property(lambda self: {}) def __init__(self, name): self.name = name # User name. - self.server = None # Set by Realm. - self.tables = {} # For each joined table name, its instance. + self.accountRecord = db.UserAccount.byUsername(self.name) + self.joinedTables = {} # All tables which client is observing. + def attached(self, mind): """Called when connection to client is established.""" self.remote = mind - self.server.userConnects(self) + self.accountRecord.set(lastLogin=datetime.now()) + server.onlineUsers.userLogin(self) # Inform system of client's arrival. + log.msg("User %s connected" % self.name) def detached(self, mind): """Called when connection to client is lost.""" self.remote = None - self.server.userDisconnects(self) # Inform server. + server.onlineUsers.userLogout(self) + log.msg("User %s disconnected" % self.name) - def callEvent(self, eventName, **kwargs): - """Calls remote event listener with arguments.""" - if self.remote: - self.remote.callRemote(eventName, **kwargs) - - # Perspective methods, accessible by client. def perspective_getServerInfo(self): """Provides a dict of information about the server.""" - info = {} - info['supported'] = self.server.supported - info['version'] = self.server.version - return info + return server.getServerInfo() def perspective_getRoster(self, name): """Provides roster requested by client.""" if name == 'tables': - return self.server.tables + return server.availableTables elif name == 'users': - return self.server.users + return server.onlineUsers else: raise DeniedRequest, "Unknown roster name \'%s\'" % name @@ -80,37 +78,37 @@ raise IllegalRequest, "Invalid parameter for table identifier" elif not(0 < len(tableid) < 21) or re.search("[^A-Za-z0-9_ ]", tableid): raise IllegalRequest, "Invalid table identifier format" - elif tableid in self.server.tables: + elif tableid in server.availableTables: raise DeniedRequest, "Table name exists" - elif tabletype not in self.server.supported: - raise DeniedRequest, "Table type not suppported by this server" +# elif tabletype not in server.supported: +# raise DeniedRequest, "Table type not suppported by this server" - self.server.createTable(tableid, tabletype) + server.createTable(tableid, tabletype) return self.perspective_joinTable(tableid) # Force join to table. def perspective_joinTable(self, tableid): """Joins an existing table.""" if not isinstance(tableid, str): - raise IllegalRequest, "Invalid parameter for table name" - elif tableid not in self.server.tables: + raise IllegalRequest, "Invalid parameter for table identifier" + elif tableid not in server.availableTables: raise DeniedRequest, "No such table" - elif tableid in self.tables: + elif tableid in self.joinedTables: raise DeniedRequest, "Already joined table" - table = self.server.tables[tableid] - self.tables[tableid] = table + table = server.availableTables[tableid] + self.joinedTables[tableid] = table return table def perspective_leaveTable(self, tableid): """Leaves a table.""" if not isinstance(tableid, str): - raise IllegalRequest, "Invalid parameter for table name" - elif tableid not in self.tables: + raise IllegalRequest, "Invalid parameter for table identifier" + elif tableid not in self.joinedTables: raise DeniedRequest, "Not joined to table" - del self.tables[tableid] # Implicitly removes user from table. + del self.joinedTables[tableid] # Implicitly removes user from table. @@ -121,5 +119,5 @@ def perspective_register(self, username, password): """Create a user account with specified username and password.""" # TODO: consider defer.succeed, defer.fail, failure.Failure - self.server.registerUser(username, password) + server.registerUser(username, password) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |