From: <umg...@us...> - 2007-04-03 11:39:45
|
Revision: 391 http://svn.sourceforge.net/pybridge/?rev=391&view=rev Author: umgangee Date: 2007-04-03 04:39:46 -0700 (Tue, 03 Apr 2007) Log Message: ----------- Add ISubject (observer) facility to NetworkClient. Modified Paths: -------------- trunk/pybridge/pybridge/network/client.py Modified: trunk/pybridge/pybridge/network/client.py =================================================================== --- trunk/pybridge/pybridge/network/client.py 2007-04-03 11:36:47 UTC (rev 390) +++ trunk/pybridge/pybridge/network/client.py 2007-04-03 11:39:46 UTC (rev 391) @@ -20,11 +20,14 @@ from twisted.cred import credentials from twisted.internet import reactor from twisted.spread import pb +from zope.interface import implements -from pybridge.network.localbridge import LocalBridgeTable -from pybridge.network.remotebridge import RemoteBridgeTable -pb.setUnjellyableForClass(LocalBridgeTable, RemoteBridgeTable) +from pybridge.interfaces.observer import ISubject +from pybridge.network.localtable import LocalTable +from pybridge.network.remotetable import RemoteTable +pb.setUnjellyableForClass(LocalTable, RemoteTable) + from pybridge.network.tablemanager import LocalTableManager, RemoteTableManager pb.setUnjellyableForClass(LocalTableManager, RemoteTableManager) @@ -35,21 +38,49 @@ class NetworkClient(pb.Referenceable): """Provides the glue between the client code and the server.""" + implements(ISubject) + def __init__(self): + self.listeners = [] + self.avatar = None # Remote avatar reference. self.factory = pb.PBClientFactory() - self.eventHandler = None - + self.factory.clientConnectionLost = self.connectionLost + self.username = None self.tables = {} # Tables observed. self.tablesAvailable = None self.usersOnline = None + def connectionLost(self, connector, reason): + print "Connection lost:", reason.getErrorMessage() + self.notify('connectionLost', message=reason.getErrorMessage()) + + +# Implementation of ISubject. + + + def attach(self, listener): + self.listeners.append(listener) + + + def detach(self, listener): + self.listeners.remove(listener) + + + def notify(self, event, *args, **kwargs): + for listener in self.listeners: + listener.update(event, *args, **kwargs) + + +# Methods + + def setEventHandler(self, handler): + print "REMOVE THIS" self.eventHandler = handler - self.factory.clientConnectionLost = handler.connectionLost def connect(self, hostname, port): @@ -66,6 +97,7 @@ self.factory.disconnect() self.avatar = None self.username = None + self.notify('disconnect') def login(self, username, password): @@ -94,6 +126,7 @@ """Actions to perform when connection succeeds.""" self.avatar = avatar self.username = username + self.notify('connect') avatar.callRemote('getTables').addCallback(gotTables) avatar.callRemote('getUsers').addCallback(gotUsers) @@ -112,6 +145,7 @@ """Register user account on server.""" hash = sha.new(password).hexdigest() d = avatar.callRemote('register', username, hash) + print "TODO: after registration, need to disconnect from server" return d anon = credentials.UsernamePassword('', '') @@ -126,11 +160,10 @@ def joinTable(self, tableid, host=False): - def success(args): - table, remote = args # RemoteBridgeTable, RemoteReference. - table.master = remote # Set RemoteReference. - table.setEventHandler(self.eventHandler) + def success((table, remote)): + table.master = remote # Set RemoteReference for RemoteBridgeTable. self.tables[tableid] = table + self.notify('joinTable', tableid=tableid, table=table) return table if host: @@ -146,6 +179,7 @@ def success(r): del self.tables[tableid] + self.notify('leaveTable', tableid=tableid) d = self.avatar.callRemote('leaveTable', tableid=tableid) d.addCallback(success) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-04-06 17:55:22
|
Revision: 400 http://svn.sourceforge.net/pybridge/?rev=400&view=rev Author: umgangee Date: 2007-04-06 10:54:58 -0700 (Fri, 06 Apr 2007) Log Message: ----------- Update references to roster classes, remove old event handler mechanism. Modified Paths: -------------- trunk/pybridge/pybridge/network/client.py Modified: trunk/pybridge/pybridge/network/client.py =================================================================== --- trunk/pybridge/pybridge/network/client.py 2007-04-06 17:52:49 UTC (rev 399) +++ trunk/pybridge/pybridge/network/client.py 2007-04-06 17:54:58 UTC (rev 400) @@ -29,12 +29,12 @@ pb.setUnjellyableForClass(LocalTable, RemoteTable) from pybridge.network.tablemanager import LocalTableManager, RemoteTableManager +from pybridge.network.usermanager import LocalUserManager, RemoteUserManager pb.setUnjellyableForClass(LocalTableManager, RemoteTableManager) - -from pybridge.network.usermanager import LocalUserManager, RemoteUserManager pb.setUnjellyableForClass(LocalUserManager, RemoteUserManager) + class NetworkClient(pb.Referenceable): """Provides the glue between the client code and the server.""" @@ -50,15 +50,25 @@ self.username = None self.tables = {} # Tables observed. - self.tablesAvailable = None - self.usersOnline = None + self.tableRoster = None + self.userRoster = None def connectionLost(self, connector, reason): - print "Connection lost:", reason.getErrorMessage() - self.notify('connectionLost', message=reason.getErrorMessage()) + # Reset invalidated remote references. + self.avatar = None + self.tables.clear() + self.tableRoster.clear() + self.userRoster.clear() + print "Lost connection: %s" % reason.getErrorMessage() + self.notify('connectionLost', reason=reason.getErrorMessage()) + + def errback(self, failure): + print "Error: %s" % failure.getErrorMessage() + + # Implementation of ISubject. @@ -78,11 +88,6 @@ # Methods - def setEventHandler(self, handler): - print "REMOVE THIS" - self.eventHandler = handler - - def connect(self, hostname, port): """Connect to server. @@ -95,9 +100,6 @@ def disconnect(self): """Drops connection to server.""" self.factory.disconnect() - self.avatar = None - self.username = None - self.notify('disconnect') def login(self, username, password): @@ -109,49 +111,48 @@ The SHA-1 hash of the password string is transmitted, protecting the user's password from eavesdroppers. """ - - def gotTables(tables): - self.tablesAvailable = tables - tables.setEventHandler(self.eventHandler) - for table in self.tablesAvailable.keys(): - self.eventHandler.tableOpened(table) - - def gotUsers(users): - self.usersOnline = users - users.setEventHandler(self.eventHandler) - for user in self.usersOnline.keys(): - self.eventHandler.userLoggedIn(user) - + + def gotRoster(roster, name): + if name == 'tables': + self.tableRoster = roster + elif name == 'users': + self.userRoster = roster + self.notify('gotRoster', name=name, roster=roster) + def connectedAsUser(avatar): """Actions to perform when connection succeeds.""" self.avatar = avatar self.username = username - self.notify('connect') - avatar.callRemote('getTables').addCallback(gotTables) - avatar.callRemote('getUsers').addCallback(gotUsers) - + self.notify('connectedAsUser', username=username) + + # Request services from server. + for rostername in ['tables', 'users']: + d = avatar.callRemote('getRoster', rostername) + d.addCallbacks(gotRoster, self.errback, callbackArgs=[rostername]) + hash = sha.new(password).hexdigest() creds = credentials.UsernamePassword(username, hash) d = self.factory.login(creds, client=self) - d.addCallback(connectedAsUser) - + d.addCallbacks(connectedAsUser, self.errback) + # for rostername... + return d def register(self, username, password): """Register user account on connected server.""" - + def connectedAsAnonymousUser(avatar): """Register user account on server.""" hash = sha.new(password).hexdigest() d = avatar.callRemote('register', username, hash) - print "TODO: after registration, need to disconnect from server" + # TODO: after registration, need to disconnect from server? return d - + anon = credentials.UsernamePassword('', '') d = self.factory.login(anon, client=None) d.addCallback(connectedAsAnonymousUser) - + return d @@ -159,13 +160,13 @@ def joinTable(self, tableid, host=False): - + def success((table, remote)): table.master = remote # Set RemoteReference for RemoteBridgeTable. self.tables[tableid] = table self.notify('joinTable', tableid=tableid, table=table) return table - + if host: d = self.avatar.callRemote('hostTable', tableid=tableid, tabletype='bridge') @@ -176,11 +177,11 @@ def leaveTable(self, tableid): - + def success(r): del self.tables[tableid] self.notify('leaveTable', tableid=tableid) - + d = self.avatar.callRemote('leaveTable', tableid=tableid) d.addCallback(success) return d This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-13 15:18:36
|
Revision: 417 http://svn.sourceforge.net/pybridge/?rev=417&view=rev Author: umgangee Date: 2007-06-13 08:18:35 -0700 (Wed, 13 Jun 2007) Log Message: ----------- Fix a bug in connectionLost(), which would call .clear() on rosters even if they were NoneType objects. Modified Paths: -------------- trunk/pybridge/pybridge/network/client.py Modified: trunk/pybridge/pybridge/network/client.py =================================================================== --- trunk/pybridge/pybridge/network/client.py 2007-06-13 15:14:20 UTC (rev 416) +++ trunk/pybridge/pybridge/network/client.py 2007-06-13 15:18:35 UTC (rev 417) @@ -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. @@ -55,11 +55,12 @@ def connectionLost(self, connector, reason): - # Reset invalidated remote references. - self.avatar = None - self.tables.clear() - self.tableRoster.clear() - self.userRoster.clear() + if self.avatar: + # Reset invalidated remote references. + self.avatar = None + self.tables.clear() + self.tableRoster.clear() + self.userRoster.clear() print "Lost connection: %s" % reason.getErrorMessage() self.notify('connectionLost', reason=reason.getErrorMessage()) @@ -133,8 +134,7 @@ hash = sha.new(password).hexdigest() creds = credentials.UsernamePassword(username, hash) d = self.factory.login(creds, client=self) - d.addCallbacks(connectedAsUser, self.errback) - # for rostername... + d.addCallback(connectedAsUser) return d This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-20 15:07:37
|
Revision: 428 http://svn.sourceforge.net/pybridge/?rev=428&view=rev Author: umgangee Date: 2007-06-20 08:07:38 -0700 (Wed, 20 Jun 2007) Log Message: ----------- Add code to determine when loss of connection is expected (disconnection) and when the connection is severed unexpectedly (network failure). Modified Paths: -------------- trunk/pybridge/pybridge/network/client.py Modified: trunk/pybridge/pybridge/network/client.py =================================================================== --- trunk/pybridge/pybridge/network/client.py 2007-06-20 15:04:58 UTC (rev 427) +++ trunk/pybridge/pybridge/network/client.py 2007-06-20 15:07:38 UTC (rev 428) @@ -48,6 +48,8 @@ self.factory = pb.PBClientFactory() self.factory.clientConnectionLost = self.connectionLost + self.expectLoseConnection = False # Indicates when disconnecting. + self.username = None self.tables = {} # Tables observed. self.tableRoster = None @@ -61,11 +63,17 @@ self.tables.clear() self.tableRoster.clear() self.userRoster.clear() + self.username = None - print "Lost connection: %s" % reason.getErrorMessage() - self.notify('connectionLost', reason=reason.getErrorMessage()) + self.notify('loggedOut') + if not self.expectLoseConnection: + # Connection lost unexpectedly, so notify user. + print "Lost connection: %s" % reason.getErrorMessage() + self.notify('connectionLost', host=connector.host, + port=connector.port) + def errback(self, failure): print "Error: %s" % failure.getErrorMessage() @@ -89,17 +97,21 @@ # Methods - def connect(self, hostname, port): + def connect(self, host, port): """Connect to server. - @param hostname: - @param port: + @param host: the host name or IP address of the server. + @type host: string + @param port: the port number on which the server is listening. + @type port: int """ - connector = reactor.connectTCP(hostname, port, self.factory) + connector = reactor.connectTCP(host, port, self.factory) + self.expectLoseConnection = False def disconnect(self): """Drops connection to server.""" + self.expectLoseConnection = True self.factory.disconnect() @@ -124,7 +136,7 @@ """Actions to perform when connection succeeds.""" self.avatar = avatar self.username = username - self.notify('connectedAsUser', username=username) + self.notify('loggedIn', username=username) # Request services from server. for rostername in ['tables', 'users']: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-07-22 18:02:39
|
Revision: 489 http://svn.sourceforge.net/pybridge/?rev=489&view=rev Author: umgangee Date: 2007-07-22 11:02:34 -0700 (Sun, 22 Jul 2007) Log Message: ----------- Do not provide server with Referenceable object, as it is unnecessary. Modified Paths: -------------- trunk/pybridge/pybridge/network/client.py Modified: trunk/pybridge/pybridge/network/client.py =================================================================== --- trunk/pybridge/pybridge/network/client.py 2007-07-22 15:52:02 UTC (rev 488) +++ trunk/pybridge/pybridge/network/client.py 2007-07-22 18:02:34 UTC (rev 489) @@ -35,7 +35,7 @@ -class NetworkClient(pb.Referenceable): +class NetworkClient(object): """Provides the glue between the client code and the server.""" implements(ISubject) @@ -145,7 +145,7 @@ hash = sha.new(password).hexdigest() creds = credentials.UsernamePassword(username, hash) - d = self.factory.login(creds, client=self) + d = self.factory.login(creds, client=None) d.addCallback(connectedAsUser) return d @@ -208,5 +208,11 @@ return d + def getUserInformation(self, username): + # TODO: cache user information once retrieved. + d = self.avatar.callRemote('getUserInformation', username) + return d + + client = NetworkClient() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |