| OLD | NEW |
| (Empty) |
| 1 | |
| 2 """Base classes handy for use with PB clients. | |
| 3 """ | |
| 4 | |
| 5 from twisted.spread import pb | |
| 6 | |
| 7 from twisted.spread.pb import PBClientFactory | |
| 8 from twisted.internet import protocol | |
| 9 from twisted.python import log | |
| 10 | |
| 11 class NewCredPerspective(pb.Avatar): | |
| 12 def attached(self, mind): | |
| 13 return self | |
| 14 def detached(self, mind): | |
| 15 pass | |
| 16 | |
| 17 class ReconnectingPBClientFactory(PBClientFactory, | |
| 18 protocol.ReconnectingClientFactory): | |
| 19 """Reconnecting client factory for PB brokers. | |
| 20 | |
| 21 Like PBClientFactory, but if the connection fails or is lost, the factory | |
| 22 will attempt to reconnect. | |
| 23 | |
| 24 Instead of using f.getRootObject (which gives a Deferred that can only | |
| 25 be fired once), override the gotRootObject method. | |
| 26 | |
| 27 Instead of using the newcred f.login (which is also one-shot), call | |
| 28 f.startLogin() with the credentials and client, and override the | |
| 29 gotPerspective method. | |
| 30 | |
| 31 Instead of using the oldcred f.getPerspective (also one-shot), call | |
| 32 f.startGettingPerspective() with the same arguments, and override | |
| 33 gotPerspective. | |
| 34 | |
| 35 gotRootObject and gotPerspective will be called each time the object is | |
| 36 received (once per successful connection attempt). You will probably want | |
| 37 to use obj.notifyOnDisconnect to find out when the connection is lost. | |
| 38 | |
| 39 If an authorization error occurs, failedToGetPerspective() will be | |
| 40 invoked. | |
| 41 | |
| 42 To use me, subclass, then hand an instance to a connector (like | |
| 43 TCPClient). | |
| 44 """ | |
| 45 | |
| 46 def __init__(self): | |
| 47 PBClientFactory.__init__(self) | |
| 48 self._doingLogin = False | |
| 49 self._doingGetPerspective = False | |
| 50 | |
| 51 def clientConnectionFailed(self, connector, reason): | |
| 52 PBClientFactory.clientConnectionFailed(self, connector, reason) | |
| 53 # Twisted-1.3 erroneously abandons the connection on non-UserErrors. | |
| 54 # To avoid this bug, don't upcall, and implement the correct version | |
| 55 # of the method here. | |
| 56 if self.continueTrying: | |
| 57 self.connector = connector | |
| 58 self.retry() | |
| 59 | |
| 60 def clientConnectionLost(self, connector, reason): | |
| 61 PBClientFactory.clientConnectionLost(self, connector, reason, | |
| 62 reconnecting=True) | |
| 63 RCF = protocol.ReconnectingClientFactory | |
| 64 RCF.clientConnectionLost(self, connector, reason) | |
| 65 | |
| 66 def clientConnectionMade(self, broker): | |
| 67 self.resetDelay() | |
| 68 PBClientFactory.clientConnectionMade(self, broker) | |
| 69 if self._doingLogin: | |
| 70 self.doLogin(self._root) | |
| 71 if self._doingGetPerspective: | |
| 72 self.doGetPerspective(self._root) | |
| 73 self.gotRootObject(self._root) | |
| 74 | |
| 75 # oldcred methods | |
| 76 | |
| 77 def getPerspective(self, *args): | |
| 78 raise RuntimeError, "getPerspective is one-shot: use startGettingPerspec
tive instead" | |
| 79 | |
| 80 def startGettingPerspective(self, username, password, serviceName, | |
| 81 perspectiveName=None, client=None): | |
| 82 self._doingGetPerspective = True | |
| 83 if perspectiveName == None: | |
| 84 perspectiveName = username | |
| 85 self._oldcredArgs = (username, password, serviceName, | |
| 86 perspectiveName, client) | |
| 87 | |
| 88 def doGetPerspective(self, root): | |
| 89 # oldcred getPerspective() | |
| 90 (username, password, | |
| 91 serviceName, perspectiveName, client) = self._oldcredArgs | |
| 92 d = self._cbAuthIdentity(root, username, password) | |
| 93 d.addCallback(self._cbGetPerspective, | |
| 94 serviceName, perspectiveName, client) | |
| 95 d.addCallbacks(self.gotPerspective, self.failedToGetPerspective) | |
| 96 | |
| 97 | |
| 98 # newcred methods | |
| 99 | |
| 100 def login(self, *args): | |
| 101 raise RuntimeError, "login is one-shot: use startLogin instead" | |
| 102 | |
| 103 def startLogin(self, credentials, client=None): | |
| 104 self._credentials = credentials | |
| 105 self._client = client | |
| 106 self._doingLogin = True | |
| 107 | |
| 108 def doLogin(self, root): | |
| 109 # newcred login() | |
| 110 d = self._cbSendUsername(root, self._credentials.username, | |
| 111 self._credentials.password, self._client) | |
| 112 d.addCallbacks(self.gotPerspective, self.failedToGetPerspective) | |
| 113 | |
| 114 | |
| 115 # methods to override | |
| 116 | |
| 117 def gotPerspective(self, perspective): | |
| 118 """The remote avatar or perspective (obtained each time this factory | |
| 119 connects) is now available.""" | |
| 120 pass | |
| 121 | |
| 122 def gotRootObject(self, root): | |
| 123 """The remote root object (obtained each time this factory connects) | |
| 124 is now available. This method will be called each time the connection | |
| 125 is established and the object reference is retrieved.""" | |
| 126 pass | |
| 127 | |
| 128 def failedToGetPerspective(self, why): | |
| 129 """The login process failed, most likely because of an authorization | |
| 130 failure (bad password), but it is also possible that we lost the new | |
| 131 connection before we managed to send our credentials. | |
| 132 """ | |
| 133 log.msg("ReconnectingPBClientFactory.failedToGetPerspective") | |
| 134 if why.check(pb.PBConnectionLost): | |
| 135 log.msg("we lost the brand-new connection") | |
| 136 # retrying might help here, let clientConnectionLost decide | |
| 137 return | |
| 138 # probably authorization | |
| 139 self.stopTrying() # logging in harder won't help | |
| 140 log.err(why) | |
| OLD | NEW |