diff --git a/direct/src/distributed/ClientRepository.py b/direct/src/distributed/ClientRepository.py index 7b23e82d97..009415101c 100644 --- a/direct/src/distributed/ClientRepository.py +++ b/direct/src/distributed/ClientRepository.py @@ -89,7 +89,7 @@ class ClientRepository(DirectObject.DirectObject): self.name2cdc[dcClass.getName()]=clientDistClass return None - def connect(self, serverURL, + def connect(self, serverList, successCallback = None, successArgs = [], failureCallback = None, failureArgs = []): """ @@ -113,77 +113,56 @@ class ClientRepository(DirectObject.DirectObject): self.connectHttp = 0 else: self.connectHttp = self.hasProxy - + self.bootedIndex = None self.bootedText = None if self.connectHttp: - self.notify.info("Connecting via HTTP interface.") + # In the HTTP case, we can't just iterate through the list + # of servers, because each server attempt requires + # spawning a request and then coming back later to check + # the success or failure. Instead, we start the ball + # rolling by calling the connect callback, which will call + # itself repeatedly until we establish a connection (or + # run out of servers). + ch = self.http.makeChannel(0) - ch.beginConnectTo(DocumentSpec(serverURL)) - ch.spawnTask(name = 'connect-to-server', - callback = self.httpConnectCallback, - extraArgs = [ch, successCallback, successArgs, - failureCallback, failureArgs]) + self.httpConnectCallback(ch, serverList, 0, + successCallback, successArgs, + failureCallback, failureArgs) + else: - self.notify.info("Connecting via NSPR interface.") self.qcm = QueuedConnectionManager() # A big old 20 second timeout. gameServerTimeoutMs = base.config.GetInt("game-server-timeout-ms", 20000) - if self.hasProxy: - url = self.proxy - else: - url = serverURL - self.tcpConn = self.qcm.openTCPClientConnection( - url.getServer(), url.getPort(), - gameServerTimeoutMs) - if self.tcpConn: - self.tcpConn.setNoDelay(1) - self.qcr=QueuedConnectionReader(self.qcm, 0) - self.qcr.addConnection(self.tcpConn) - minLag = config.GetFloat('min-lag', 0.) - maxLag = config.GetFloat('max-lag', 0.) - if minLag or maxLag: - self.qcr.startDelay(minLag, maxLag) - self.cw=ConnectionWriter(self.qcm, 0) - if self.hasProxy: - # Now we send an http CONNECT message on that - # connection to initiate a connection to the real - # game server - realGameServer = (serverURL.getServer() + ":" + str(serverURL.getPort())) - connectString = "CONNECT " + realGameServer + " HTTP/1.0\012\012" - datagram = Datagram() - # Use appendData and sendRaw so we do not send the length of the string - datagram.appendData(connectString) - self.notify.info("Sending CONNECT string: " + connectString) - self.cw.setRawMode(1) - self.qcr.setRawMode(1) - self.notify.info("done set raw mode") - self.send(datagram) - self.notify.info("done send datagram") - # Find the end of the http response, then call callback - self.findRawString(["\015\012", "\015\015"], - self.proxyConnectCallback, [successCallback, successArgs]) - self.notify.info("done find raw string") - # Now start the raw reader poll task and look for - # the HTTP response When this is finished, it will - # call the connect callback just like the non - # proxy case - self.startRawReaderPollTask() - self.notify.info("done start raw reader poll task") + # Try each of the servers in turn. + for url in serverList: + self.notify.info("Connecting to %s via NSPR interface." % (url.cStr())) + self.tcpConn = self.qcm.openTCPClientConnection( + url.getServer(), url.getPort(), + gameServerTimeoutMs) - else: - # no proxy. We're done connecting. + if self.tcpConn: + self.tcpConn.setNoDelay(1) + self.qcr=QueuedConnectionReader(self.qcm, 0) + self.qcr.addConnection(self.tcpConn) + minLag = config.GetFloat('min-lag', 0.) + maxLag = config.GetFloat('max-lag', 0.) + if minLag or maxLag: + self.qcr.startDelay(minLag, maxLag) + self.cw=ConnectionWriter(self.qcm, 0) self.startReaderPollTask() if successCallback: successCallback(*successArgs) - else: - # Failed to connect. - if failureCallback: - failureCallback(0, *failureArgs) + return - def httpConnectCallback(self, ch, successCallback, successArgs, + # Failed to connect. + if failureCallback: + failureCallback(0, *failureArgs) + + def httpConnectCallback(self, ch, serverList, serverIndex, + successCallback, successArgs, failureCallback, failureArgs): if ch.isConnectionReady(): self.tcpConn = ch.getConnection() @@ -192,68 +171,21 @@ class ClientRepository(DirectObject.DirectObject): if successCallback: successCallback(*successArgs) + elif serverIndex < len(serverList): + # No connection yet, but keep trying. + + url = serverList[serverIndex] + self.notify.info("Connecting to %s via HTTP interface." % (url.cStr())) + ch.beginConnectTo(DocumentSpec(url)) + ch.spawnTask(name = 'connect-to-server', + callback = self.httpConnectCallback, + extraArgs = [ch, serverList, serverIndex + 1, + successCallback, successArgs, + failureCallback, failureArgs]) else: - # Failed to connect. + # No more servers to try; we have to give up now. if failureCallback: failureCallback(ch.getStatusCode(), *failureArgs) - - def proxyConnectCallback(self, successCallback, successArgs): - # Make sure we are not in raw mode anymore - self.cw.setRawMode(0) - self.qcr.setRawMode(0) - self.stopRawReaderPollTask() - if successCallback: - successCallback(*successArgs) - - def startRawReaderPollTask(self): - # Stop any tasks we are running now - self.stopRawReaderPollTask() - self.stopReaderPollTask() - task = Task.Task(self.rawReaderPollUntilEmpty) - # Start with empty string - task.currentRawString = "" - taskMgr.add(task, "rawReaderPollTask", priority=self.TASK_PRIORITY) - return None - - def stopRawReaderPollTask(self): - taskMgr.remove("rawReaderPollTask") - return None - - def rawReaderPollUntilEmpty(self, task): - while self.rawReaderPollOnce(): - pass - return Task.cont - - def rawReaderPollOnce(self): - self.notify.debug("rawReaderPollOnce") - self.ensureValidConnection() - availGetVal = self.qcr.dataAvailable() - if availGetVal: - datagram = NetDatagram() - readRetVal = self.qcr.getData(datagram) - if readRetVal: - str = datagram.getMessage() - self.notify.debug("rawReaderPollOnce: found str: " + str) - self.handleRawString(str) - else: - ClientRepository.notify.warning("getData returned false") - return availGetVal - - def handleRawString(self, str): - self.notify.info("handleRawString: str = <%s>" % (str)) - self.currentRawString += str - self.notify.info("currentRawString = <%s>" % (self.currentRawString)) - # Look in all the match strings to see if we got it yet - for matchString in self.rawStringMatchList: - if (self.currentRawString.find(matchString) >= 0): - self.rawStringCallback(*self.rawStringExtraArgs) - return - - def findRawString(self, matchList, callback, extraArgs = []): - self.currentRawString = "" - self.rawStringMatchList = matchList - self.rawStringCallback = callback - self.rawStringExtraArgs = extraArgs def startReaderPollTask(self): # Stop any tasks we are running now