|
|
@@ -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")
|
|
|
-
|
|
|
- else:
|
|
|
- # no proxy. We're done connecting.
|
|
|
+
|
|
|
+ # 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)
|
|
|
+
|
|
|
+ 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
|